内容简介:上篇文章人脸框检测已经介绍了我们如何从视频流中检测出人脸位置的信息,基于这些内容,我们继续向下扩展,获取人脸68个关键点的信息,之所以要获得人脸位置的信息正是为了获取关键点做的准备,因为获取关键点的时候会用到人脸的位置
上篇文章人脸框检测已经介绍了我们如何从视频流中检测出人脸位置的信息,基于这些内容,我们继续向下扩展,获取人脸68个关键点的信息,之所以要获得人脸位置的信息正是为了获取关键点做的准备,因为获取关键点的时候会用到人脸的位置
继续看那张图
这就是我们需要拿到的东西,今天我们要做的就是通过Dlib 检测出68个 人脸关键点,然后将这68个关键点绘制到视频流中
废话不多说 还是首先看下效果如何
蜗壳还是很帅的哦!
Dlib 介绍
Dlib是一个包含机器学习算法的C++开源 工具 包。Dlib可以帮助您创建很多复杂的机器学习方面的软件来帮助解决实际问题。目前Dlib已经被广泛的用在行业和学术领域,包括机器人,嵌入式设备,移动电话和大型高性能计算环境 (这个是copy 的)
Dlib 的集成
Dlib包含一个.a 和一个头文件的文件夹,我们可以在google 里搜索下载一个,或者通过cmake 来自己交叉编译一个,再或者用我的Dlib及模型 ( 密码: q6z4)
(一)将Dlib放入你的工程
将我整理好的库及模型下载后你会看到是这样的
那么你直接拖到你工程中
需要注意的
我们拖进来以后那个dlib 的文件夹不能在工程里,一定要remove 掉,否则build 不起来,这里坑了很久,但记住不是 move to trash
就是这样
(二)配置工程
(1).build setting
搜索 preprocessor macros
添加宏
DLIB_JPEG_SUPPORT
DLIB_NO_GUI_SUPPORT
NDEBUG
DDLIB_USE_BLAS
DLIB_USE_LAPACK
(2). header search path
拖一下你的目录进去就行了
(3).依赖库
Acceletrate.framework
AssetsLibrary.framework
其他几个是opencv 用到的,不知道的同学看下上篇 人脸框检测
(三)写代码了
这里需要注意的是,不要同时导入dlib 的头文件 和 opencv 的头文件,因为里面又一些宏定义 还是方法来着 会冲突,这里我们用单独的类来检测人脸的关键点
(1).新建一个FaceDlibWrapper类 将.m改成.mm 重写init 方法
#import <dlib image_processing="" h=""> #import <dlib image_io="" h=""> - (instancetype)init { self = [super init]; if (self) { //初始化 检测器 NSString *modelFileName = [[NSBundle mainBundle] pathForResource:@"shape_predictor_68_face_landmarks" ofType:@"dat"]; std::string modelFileNameCString = [modelFileName UTF8String]; dlib::deserialize(modelFileNameCString) >> sp; } return self; } </dlib> </dlib>
(2).检测方法
//之所以 return 的数组 看起来比较啰嗦 但是是为了让你们看清,也可以不这么写 - (NSArray <nsarray nbsp=""> <nsvalue nbsp=""> *>*)detecitonOnSampleBuffer:(CMSampleBufferRef)sampleBuffer inRects:(NSArray <nsvalue nbsp=""> *)rects { dlib::array2d <dlib::bgr_pixel> img; dlib::array2d <dlib::bgr_pixel> img_gray; // MARK: magic CVImageBufferRef imageBuffer = CMSampleBufferGetImageBuffer(sampleBuffer); CVPixelBufferLockBaseAddress(imageBuffer, kCVPixelBufferLock_ReadOnly); size_t width = CVPixelBufferGetWidth(imageBuffer); size_t height = CVPixelBufferGetHeight(imageBuffer); char *baseBuffer = (char *)CVPixelBufferGetBaseAddress(imageBuffer); // set_size expects rows, cols format img.set_size(height, width); // copy samplebuffer image data into dlib image format img.reset(); long position = 0; while (img.move_next()) { dlib::bgr_pixel& pixel = img.element(); // assuming bgra format here long bufferLocation = position * 4; //(row * width + column) * 4; char b = baseBuffer[bufferLocation]; char g = baseBuffer[bufferLocation + 1]; char r = baseBuffer[bufferLocation + 2]; // we do not need this // char a = baseBuffer[bufferLocation + 3]; dlib::bgr_pixel newpixel(b, g, r); pixel = newpixel; position++; } // unlock buffer again until we need it again CVPixelBufferUnlockBaseAddress(imageBuffer, kCVPixelBufferLock_ReadOnly); // convert the face bounds list to dlib format std::vector <dlib::rectangle> convertedRectangles = [self convertCGRectValueArray:rects]; dlib::assign_image(img_gray, img); NSMutableArray *facesLandmarks = [NSMutableArray arrayWithCapacity:0]; for (unsigned long j = 0; j < convertedRectangles.size(); ++j) { dlib::rectangle oneFaceRect = convertedRectangles[j]; // detect all landmarks dlib::full_object_detection shape = sp(img, oneFaceRect); //shape 里面就是我们所需要的68 个点 因为dilb 跟 opencv 冲突 所以我们转换成Foundation 的 Array NSMutableArray *landmarks = [NSMutableArray arrayWithCapacity:0]; for (int i = 0; i < shape.num_parts(); i++) { dlib::point p = shape.part(i); [landmarks addObject:[NSValue valueWithCGPoint:CGPointMake(p.x(), p.y())]]; } [facesLandmarks addObject:landmarks]; } return facesLandmarks; } - (std::vector <dlib::rectangle> )convertCGRectValueArray:(NSArray <nsvalue nbsp=""> *)rects { std::vector <dlib::rectangle> myConvertedRects; for (NSValue *rectValue in rects) { CGRect rect = [rectValue CGRectValue]; long left = rect.origin.x; long top = rect.origin.y; long right = left + rect.size.width; long bottom = top + rect.size.height; dlib::rectangle dlibRect(left, top, right, bottom); myConvertedRects.push_back(dlibRect); } return myConvertedRects; } </dlib::rectangle> </nsvalue> </dlib::rectangle> </dlib::rectangle> </dlib::bgr_pixel> </dlib::bgr_pixel> </nsvalue> </nsvalue> </nsarray>
(3).获取关键点,并绘制在流中
继续上篇文章,在绘制人脸框的位置,我们一起将68个关键点绘制出来
#pragma mark - AVCaptureSession Delegate - - (void)captureOutput:(AVCaptureOutput *)output didOutputSampleBuffer:(CMSampleBufferRef)sampleBuffer fromConnection:(AVCaptureConnection *)connection { NSMutableArray *bounds = [NSMutableArray arrayWithCapacity:0]; for (AVMetadataFaceObject *faceobject in self.currentMetadata) { AVMetadataObject *face = [output transformedMetadataObjectForMetadataObject:faceobject connection:connection]; [bounds addObject:[NSValue valueWithCGRect:face.bounds]]; } UIImage *image = [self imageFromPixelBuffer:sampleBuffer]; cv::Mat mat; UIImageToMat(image, mat); //获取关键点,将脸部信息的数组 和 相机流 传进去 NSArray *facesLandmarks = [_dr detecitonOnSampleBuffer:sampleBuffer inRects:bounds]; // 绘制68 个关键点 for (NSArray *landmarks in facesLandmarks) { for (NSValue *point in landmarks) { CGPoint p = [point CGPointValue]; cv::rectangle(mat, cv::Rect(p.x,p.y,4,4), cv::Scalar(255,0,0,255),-1); } } for (NSValue *rect in bounds) { CGRect r = [rect CGRectValue]; //画框 cv::rectangle(mat, cv::Rect(r.origin.x,r.origin.y,r.size.width,r.size.height), cv::Scalar(255,0,0,255)); } //这里不考虑性能 直接怼Image dispatch_async(dispatch_get_main_queue(), ^{ self.cameraView.image = MatToUIImage(mat); }); }
以上就是本文的全部内容,希望本文的内容对大家的学习或者工作能带来一定的帮助,也希望大家多多支持 码农网
猜你喜欢:- 人脸专集(三):人脸关键点检测(下)
- 算法升级!开源极快速CNN人脸检测新增人脸关键点功能
- 在 GPUImage 中检测人脸关键点
- 如何在五分钟内搭建人脸检测/关键点识别等服务?
- 揭秘美图影像实验室MTlab的10000点人脸关键点技术
- 深度有趣 | 27 服饰关键点定位
本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们。
High Performance Python
Micha Gorelick、Ian Ozsvald / O'Reilly Media / 2014-9-10 / USD 39.99
If you're an experienced Python programmer, High Performance Python will guide you through the various routes of code optimization. You'll learn how to use smarter algorithms and leverage peripheral t......一起来看看 《High Performance Python》 这本书的介绍吧!