OpenCV圖像處理——iOS端人臉檢測

前言

1.OpenCV有專門的iOS平臺的包,可以真接下載導入工程,也可以用cmake把OpenCV源碼編成.a文件,以靜態庫的形式導入工程。
2.我這裏用的Xcode11,OpenCV用的是最4.20這個版本。
3.這裏用到的人臉檢測是OpenCV官方給的級聯分類器,可以在OpenCV源碼的Data目錄中找到。

iOS人臉檢測

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<cv::Rect> 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<int>(t)], cv::Scalar(0, 0, 255), 2, 8, 0);
    }

}

5.交互文件ViewController.mm裏面的代碼:

#import "Common.h"
#import "ViewController.h"
#import <AVFoundation/AVFoundation.h>
#import <AVKit/AVKit.h>

@interface ViewController () <UINavigationControllerDelegate, UIImagePickerControllerDelegate>

@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學習的可以加。

在這裏插入圖片描述

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章