環(huán)境
OpenCV 4.1.0 (CocoaPods 管理)
Xcode11
頭文件和編譯配置
OpenCV 從2.4之后蔑祟,開始支持人臉識別翠订。相對于 iOS 系統(tǒng)級的悬秉,代碼量還挺少仲锄,包括視頻流。
可以看看參考里的第1條 URL 掖桦,官方文檔。
視頻流和靜態(tài)圖片處理邏輯是一致的供汛,都是操作 cv::Mat
這個數(shù)據(jù)結(jié)構(gòu)枪汪。
這是我們這里需要用到的頭文件:
#ifdef __cplusplus
#import <opencv2/imgcodecs/ios.h> // Mat 和 UIImage互轉(zhuǎn)
#import <opencv2/objdetect/objdetect.hpp> // 物體識別相關(guān)的類
#import <opencv2/imgproc.hpp> // 顏色空間 cvtColor 等
#import <opencv2/videoio/cap_ios.h> // AVFoundation相機封裝
#endif
另外,你在 OC 文件里是 .m 可能需要改名為 .mm怔昨,或者修改編譯類型雀久,才能使用 OpenCV。
圖片識別
看一下 OpenCV 怎么識別一張圖片里的人臉趁舀。參考官方Example facedetect.cpp
首先你需要額外把 opencv 的源碼包下載回來赖捌,然后找到 /data 下的訓練好的 xml 模型來使用。
比如我下載的路徑是:opencv-4.1.0/data/haarcascades/haarcascade_frontalface_alt2
cv::Mat orignalImg;
UIImageToMat([UIImage imageNamed:@"face1"], orignalImg);
std::vector<cv::Rect> faces;
NSString *path = [[NSBundle mainBundle] pathForResource:@"haarcascade_frontalface_alt2" ofType:@"xml"];
faceDetector.load([path UTF8String]);
faceDetector.detectMultiScale(orignalImg, faces, 1.2, 6, 0, cv::Size(0, 0));
cv::Scalar color = cv::Scalar( rand() & 255, rand() & 255, rand() & 255 );
for ( size_t i = 0; i < faces.size(); i++ ) {
cv::rectangle(orignalImg, cv::Point(faces[i].x, faces[i].y), cv::Point(faces[i].x + faces[i].width, faces[i].y + faces[i].height),
color);
}
self.resultView.image = MatToUIImage(orignalImg);
UIImageToMat 和 MatToUIImage 這個是 OpenCV 專門為 iOS 提供的 UIImage 與 cv::Mat 互轉(zhuǎn)的方法矮烹。頭文件在 <opencv2/imgcodecs/ios.h>
下越庇。
faceDetector.load 將你要使用的 xml 模型加載進去。然后調(diào)用 faceDetector.detectMultiScale 傳參數(shù)進去奉狈,將識別到的臉的位置卤唉,都存進 faces 里。
然后我們還在 orignalImg 這個 Mat 上繪制矩形框仁期,標注臉的位置桑驱。
視頻流
官方文檔,已經(jīng)給出非常清晰的視頻使用方法 OpenCV iOS - Video Processing
按照文檔的寫蟀拷,就能顯示視頻了碰纬。
我們需要處理的是 CvVideoCameraDelegate
這個的回調(diào) processImage
方法的回調(diào)。
注意processImage:(cv::Mat &)image
這里的是引用傳遞问芬,所以直接修改 image 就能修改 cv::Mat 的數(shù)據(jù)悦析。
我們可以直接拿圖片識別的方法來測試,發(fā)現(xiàn)是可以的此衅,但是有很嚴重的掉幀現(xiàn)象强戴,視頻里看到的是一卡一卡的慢速運動。
參考 facedetect.cpp 文檔挡鞍,我們學習它一樣骑歹,將圖片灰度化、縮小墨微、增加對比度后道媚,然后再去識別,減小識別難度,加快速度最域。
提升性能版谴分,我們將圖片灰度化后,縮小到25%镀脂。然后再去識別牺蹄,整個速度就提上來了。
我們最終還在原圖image上畫框薄翅,但是計算是用縮小的 smallImg 圖沙兰,所以在 faces 的坐標需要轉(zhuǎn)換回去。
- (void)processImage:(cv::Mat &)image {
double scale = 1.0 / 4.0;
cv::Mat gray, smallImg;
// 灰度化翘魄、縮小鼎天、直方圖增強對比
cvtColor( image, gray, cv::COLOR_BGRA2GRAY);
resize( gray, smallImg, smallImg.size(), scale, scale, cv::INTER_LINEAR_EXACT );
equalizeHist( smallImg, smallImg );
std::vector<cv::Rect> faces;
NSString *path = [[NSBundle mainBundle] pathForResource:@"haarcascade_frontalface_alt2" ofType:@"xml"];
faceDetector.load([path UTF8String]);
faceDetector.detectMultiScale(smallImg, faces, 1.2, 6, 0, cv::Size(0, 0));
cv::Scalar color = cv::Scalar( rand() & 255, rand() & 255, rand() & 255 );
for ( size_t i = 0; i < faces.size(); i++ ) {
cv::rectangle(image, cv::Point(faces[i].x / scale, faces[i].y / scale), cv::Point(faces[i].x / scale + faces[i].width / scale, faces[i].y / scale + faces[i].height / scale),
color);
}
}
總結(jié)
OpenCV 整個使用流程還蠻順暢,且操作邏輯統(tǒng)一熟丸。OpenCV的文檔非常棒训措,又齊全,又完整光羞。
UIView 的圖片和視頻就感覺完全是2個團隊的風格绩鸣,不僅數(shù)據(jù)格式不同,坐標系也不同纱兑。實際代碼量也挺大呀闻。