1.OpenCV有专门的iOS平台的包,可以真接下载导入工程,也可以用cmake把OpenCV源码编成.a文件,以静态库的形式导入工程。
2.我这里用的Xcode11,OpenCV用的是最4.20这个版本。
3.这里用到的人脸检测是OpenCV官方给的级联分类器,可以在OpenCV源码的Data目录中找到。
1.新建一个iOS工程,把用于与C++混编的文件后缀.m改成.mm,添加一个用于做图像处理的文件,也改成.mm文件。如下:
2.把OpenCV和人脸检测的级联分类器导入工程。
3.在main.storyboard里面添加一个UIImageView,两个Button,然后关联到事件,如下:
4.处理文件里Commom.mm里面的代码:
void UIImageToMat(UIImage *ui_image, cv::Mat &cv_dst)
{
assert(ui_image.size.width > 0 && ui_image.size.height > 0);
assert(ui_image.CGImage != nil || ui_image.CIImage != nil);
//开缓冲区
NSInteger width = ui_image.size.width;
NSInteger height = ui_image.size.height;
cv::Mat cv_mat8uc4 = cv::Mat((int)height, (int)width, CV_8UC4);
CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB();
if (ui_image.CGImage)
{
CGContextRef contextRef = CGBitmapContextCreate(cv_mat8uc4.data, cv_mat8uc4.cols, cv_mat8uc4.rows, 8, cv_mat8uc4.step, colorSpace, kCGImageAlphaPremultipliedLast | kCGBitmapByteOrderDefault);
CGContextDrawImage(contextRef, CGRectMake(0, 0, width, height), ui_image.CGImage);
CGContextRelease(contextRef);
}
else
{
static CIContext* context = nil;
if (!context)
{
context = [CIContext contextWithOptions:@{ kCIContextUseSoftwareRenderer: @NO }];
}
CGRect bounds = CGRectMake(0, 0, width, height);
[context render:ui_image.CIImage toBitmap:cv_mat8uc4.data rowBytes:cv_mat8uc4.step bounds:bounds format:kCIFormatRGBA8 colorSpace:colorSpace];
}
CGColorSpaceRelease(colorSpace);
cv::Mat cv_mat8uc3 = cv::Mat((int)width, (int)height, CV_8UC3);
cv::cvtColor(cv_mat8uc4, cv_mat8uc3, cv::COLOR_RGBA2BGR);
cv_dst = cv_mat8uc3;
}
UIImage *MatToUIImage(cv::Mat &cv_src)
{
assert(cv_src.elemSize() == 1 || cv_src.elemSize() == 3);
cv::Mat cv_rgb;
if (cv_src.elemSize() == 1)
{
cv::cvtColor(cv_src, cv_rgb, cv::COLOR_GRAY2RGB);
} else if (cv_src.elemSize() == 3)
{
cv::cvtColor(cv_src, cv_rgb, cv::COLOR_BGR2RGB);
}
NSData *data = [NSData dataWithBytes:cv_rgb.data length:(cv_rgb.elemSize() * cv_rgb.total())];
CGColorSpaceRef colorSpace;
if (cv_rgb.elemSize() == 1)
{
colorSpace = CGColorSpaceCreateDeviceGray();
} else
{
colorSpace = CGColorSpaceCreateDeviceRGB();
}
CGDataProviderRef provider = CGDataProviderCreateWithCFData((__bridge CFDataRef)data);
CGImageRef imageRef = CGImageCreate(cv_rgb.cols, cv_rgb.rows, 8, 8 * cv_rgb.elemSize(), cv_rgb.step.p[0], colorSpace, kCGImageAlphaNone|kCGBitmapByteOrderDefault, provider, NULL, false, kCGRenderingIntentDefault);
UIImage *ui_image = [UIImage imageWithCGImage:imageRef];
CGImageRelease(imageRef);
CGDataProviderRelease(provider);
CGColorSpaceRelease(colorSpace);
return ui_image;
}
void faceDetection(cv::Mat &cv_src, cv::Mat &cv_dst,std::string &face_class)
{
cv::CascadeClassifier face_classifier;
face_classifier.load(face_class);
if (cv_src.empty())
{
return;
}
cv_dst = cv_src.clone();
cv::Mat cv_gray;
//灰度化
cv::cvtColor(cv_src, cv_gray, cv::COLOR_BGR2GRAY);
//直方图均衡化,用于提高图像的质量
equalizeHist(cv_gray, cv_gray);
//存放检测到人脸的矩形
std::vector faces;
//开始检测
face_classifier.detectMultiScale(cv_gray, faces, 1.2, 3, 0, cv::Size(24, 24));
//画出检测到的矩形的位置
for (size_t t = 0; t < faces.size(); t++)
{
rectangle(cv_dst, faces[static_cast(t)], cv::Scalar(0, 0, 255), 2, 8, 0);
}
}
5.交互文件ViewController.mm里面的代码:
#import "Common.h"
#import "ViewController.h"
#import
#import
@interface ViewController ()
@property (strong, nonatomic) UIImagePickerController *ui_album_selected;/* 相册选择器 */
@property (strong, nonatomic) AVPlayerViewController *ui_player;/* 视频播放器 */
@property (weak, nonatomic) IBOutlet UIImageView *ui_show_view;/* 显示图片 */
@property (nonatomic, weak) UIImage *ui_selected_image;
@end
@implementation ViewController
- (void)viewDidLoad
{
[super viewDidLoad];
//设置显示图片可交互
self.ui_show_view.userInteractionEnabled = YES;
//创建AVPlayerViewController控制器
AVPlayerViewController *playerVC = [[AVPlayerViewController alloc] init];
playerVC.view.frame = self.ui_show_view.bounds;
[self.ui_show_view addSubview:playerVC.view];
self.ui_player = playerVC;
self.ui_player.view.hidden = YES;
}
#pragma mark - UI点击
/* 点击打开本地相册 */
- (IBAction)pickImage:(id)sender
{
//如果正在播放视频,停止播放
if (self.ui_player.player)
{
[self.ui_player.player pause];
}
//创建图片选择控制器
UIImagePickerController *ipc = [[UIImagePickerController alloc] init];
//判断设备是否有图册
if ([UIImagePickerController isSourceTypeAvailable:UIImagePickerControllerSourceTypePhotoLibrary])
{
//设置拾取源类型
ipc.sourceType = UIImagePickerControllerSourceTypePhotoLibrary;
//设置媒体类型,这里设置图册支持的所有媒体类型,图片和视频
ipc.mediaTypes = [UIImagePickerController availableMediaTypesForSourceType:ipc.sourceType];
}
ipc.delegate = self;//设置代理
ipc.allowsEditing = YES;//设置可编辑
self.ui_album_selected = ipc;
//弹出图片选择控制器
[self presentViewController:ipc animated:YES completion:nil];
}
#pragma mark - UIImagePickerControllerDelegate代理方法
/* 选择了一个图片或者视频后调用 */
- (void)imagePickerController:(UIImagePickerController *)picker didFinishPickingMediaWithInfo:(NSDictionary *)info
{
//获取选择文件的媒体类型
NSString *mediaType = [info objectForKey:UIImagePickerControllerMediaType];
NSURL *videoURL = nil;
if ([mediaType isEqualToString:@"public.image"])
{//选择了图片
//获取选择的图片
self.ui_selected_image = [info objectForKey:UIImagePickerControllerOriginalImage];
//self.ui_id = self.ui_selected_image;
//显示图片
self.ui_show_view.image = self.ui_selected_image;
self.ui_show_view.contentMode = UIViewContentModeScaleAspectFit;
NSLog(@"found an image %@",self.ui_selected_image);
//删除视频
self.ui_player.player = nil;
self.ui_player.view.hidden = YES;
}
else if ([mediaType isEqualToString:@"public.movie"])
{//选择了视频
//获取临时保存视频的URL
videoURL = [info objectForKey:UIImagePickerControllerMediaURL];
NSLog(@"found a video %@",videoURL);
//直接创建AVPlayer,它内部也是先创建AVPlayerItem,这个只是快捷方法
AVPlayer *player = [AVPlayer playerWithURL:videoURL];
self.ui_player.player = player;
self.ui_player.view.hidden = NO;
}
[self dismissViewControllerAnimated:YES completion:^{
if (videoURL) {
//调用控制器的属性player的开始播放方法
[self.ui_player.player play];
}
}];
}
/* 取消选择后调用 */
- (void)imagePickerControllerDidCancel:(UIImagePickerController *)picker
{
[self dismissViewControllerAnimated:YES completion:^
{
//取消选择后继续播放视频
if (self.ui_player.player)
{
[self.ui_player.player play];
}
}];
NSLog(@"取消选择");
}
- (IBAction)faceDetection:(id)sender
{
NSString* const model_file_name = @"haarcascade_frontalface_default";
NSString* const model_file_type = @"xml";
NSString* model = [[NSBundle mainBundle] pathForResource:model_file_name ofType:model_file_type];
std::string face_class = [model UTF8String];
cv::Mat cv_src;
UIImageToMat(self.ui_selected_image, cv_src);
cv::Mat cv_dst;
faceDetection(cv_src, cv_dst, face_class);
UIImage *face_image = MatToUIImage(cv_dst);
self.ui_show_view.image = face_image;
}
@end
6.连接到真机运行如下:
注:有兴趣于OpenCV学习的可以加。