iOS - OpenCV 代码的一点学习记录

本文详细介绍了如何使用OpenCV库进行人脸检测,并将检测到的人脸覆盖到原始图像上,实现图像合成效果。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

其实自己也没有完全搞懂,但是还是作为学习,记录下来吧


/**
	创建一个IplImage
	@param image    目标image
	@returns        返回一个IplImage对象
 */
- (IplImage *)CreateIplImageFromUIImage:(UIImage *)image
{
	
    //将image转为CGImage
    CGImageRef imageRef = image.CGImage;
    
    //可以获取设备无关的RGB颜色空间,这个颜色空间需要调用CGColorSpaceRelease()进行释放。
	CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB();
    
    //创建一个IplImage
	IplImage *iplimage = cvCreateImage(cvSize(image.size.width, image.size.height), IPL_DEPTH_8U, 4);
    
    
    
/**
	CGBitmapContextCreate 创建图形设备上下文的缓存
    
    CGContextRef CGBitmapContextCreate(void *data, size_t width,size_t height, size_t bitsPerComponent, size_t bytesPerRow,CGColorSpaceRef space, CGBitmapInfo bitmapInfo)
 
    参数data指向绘图操作被渲染的内存区域,这个内存区域大小应该为(bytesPerRow*height)个字节。如果对绘制操作被渲染的内存区域并无特别的要求,那么可以传递NULL给参数data。

    参数width代表被渲染内存区域的宽度。

    参数height代表被渲染内存区域的高度。

    参数bitsPerComponent被渲染内存区域中组件在屏幕每个像素点上需要使用的bits位,举例来说,如果使用32-bit像素和RGB颜色格式,那么RGBA颜色格式中每个组件在屏幕每个像素点上需要使用的bits位就为32/4=8。

    参数bytesPerRow代表被渲染内存区域中每行所使用的bytes位数。

    参数colorspace用于被渲染内存区域的“位图上下文”。

    参数bitmapInfo指定被渲染内存区域的“视图”是否包含一个alpha(透视)通道以及每个像素相应的位置,除此之外还可以指定组件式是浮点值还是整数值。
 */
    CGContextRef contextRef = CGBitmapContextCreate(iplimage->imageData, iplimage->width, iplimage->height,
													iplimage->depth, iplimage->widthStep,
													colorSpace, kCGImageAlphaPremultipliedLast|kCGBitmapByteOrderDefault);

    //将图像画在图形上
	CGContextDrawImage(contextRef, CGRectMake(0, 0, image.size.width, image.size.height), imageRef);
    
    //释放
	CGContextRelease(contextRef);
	CGColorSpaceRelease(colorSpace);
    
	IplImage *ret = cvCreateImage(cvGetSize(iplimage), IPL_DEPTH_8U, 3);
	
    //颜色空间转换函数,可以实现rgb颜色向HSV,HSI等颜色空间的转换,也可以转换为灰度图像。
    cvCvtColor(iplimage, ret, CV_RGBA2BGR);
	
    //释放
    cvReleaseImage(&iplimage);
    
	return ret;
}

/**
	人脸识别的方法
	@param      overlayImage     覆盖在人脸上的image
	@param      img              目标image
	@returns                     返回一个合成好的image
 */
- (UIImage *) opencvFaceDetect:(UIImage *)overlayImage WithImg:(UIImage *)img
 {
    
	if(img) {
        
        //设置错误类型
		cvSetErrMode(CV_ErrModeParent);
        
        //创建一个IplImage对象
		IplImage *image = [self CreateIplImageFromUIImage:img];
		
		// Scaling down
		IplImage *small_image = cvCreateImage(cvSize(image->width/2,image->height/2), IPL_DEPTH_8U, 3);
        
        //输入图像向下采样
		cvPyrDown(image, small_image, CV_GAUSSIAN_5x5);
		
        int scale = 2;
		
		// Load XML
		NSString *path = [[NSBundle mainBundle] pathForResource:@"haarcascade_frontalface_default" ofType:@"xml"];
        
        //读取 CvHaarClassifierCascade 分类器文件进行人脸检测
		CvHaarClassifierCascade* cascade = (CvHaarClassifierCascade*)cvLoad([path cStringUsingEncoding:NSASCIIStringEncoding], NULL, NULL, NULL);
		
        //用来创建一个内存存储器,来统一管理各种动态对象的内存,比如说序列,这个函数返回一个新创建的内存存储器指针。
        CvMemStorage* storage = cvCreateMemStorage(0);
		
		// Detect faces and draw rectangle on them
        //人脸检测
        
/*
 CVAPI(CvSeq*) cvHaarDetectObjects( const CvArr* image,CvHaarClassifierCascade* cascade,CvMemStorage* storage, double scale_factor CV_DEFAULT(1.1),int min_neighbors CV_DEFAULT(3), int flags CV_DEFAULT(0),CvSize min_size CV_DEFAULT(cvSize(0,0)), CvSize max_size CV_DEFAULT(cvSize(0,0)));
 
 image          被检图像
 
 cascade        haar 分类器级联的内部标识形式
 
 storage        用来存储检测到的一序列候选目标矩形框的内存区域。
 
 scale_factor   在前后两次相继的扫描中,搜索窗口的比例系数。例如1.1指将搜索窗口依次扩大10%
 
 min_neighbors  构成检测目标的相邻矩形的最小个数(缺省-1)。如果组成检测目标的小矩形的个数和小于min_neighbors-1 都会被排除。如果min_neighbors 为 0, 则函数不做任何操作就返回所有的被检候选矩形框,这种设定值一般用在用户自定义对检测结果的组合程序上。
 
 flags          操作方式。当前唯一可以定义的操作方式是 CV_HAAR_DO_CANNY_PRUNING。如果被设定,函数利用Canny边缘检测器来排除一些边缘很少或者很多的图像区域,因为这样的区域一般不含被检目标。人脸检测中通过设定阈值使用了这种方法,并因此提高了检测速度。
 
 min_size       检测窗口的最小尺寸。缺省的情况下被设为分类器训练时采用的样本尺寸(人脸检测中缺省大小是~20×20)。
*/
		CvSeq* faces = cvHaarDetectObjects(small_image, cascade, storage, 1.2f, 2, CV_HAAR_DO_CANNY_PRUNING, cvSize(0,0), cvSize(20, 20));
		
        cvReleaseImage(&small_image);
		
		// Create canvas to show the results
        //创建结果的image
		CGImageRef imageRef = img.CGImage;
		CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB();
		CGContextRef contextRef = CGBitmapContextCreate(NULL, img.size.width, img.size.height,
														8, img.size.width * 4,
														colorSpace, kCGImageAlphaPremultipliedLast|kCGBitmapByteOrderDefault);
		CGContextDrawImage(contextRef, CGRectMake(0, 0, img.size.width, img.size.height), imageRef);
		
		CGContextSetLineWidth(contextRef, 4);
		CGContextSetRGBStrokeColor(contextRef, 0.0, 0.0, 1.0, 0.5);//设置颜色,蓝色,透明度0.5
		
		// Draw results on the iamge
		for(int i = 0; i < faces->total; i++) {
			
			// Calc the rect of faces
            //cvGetSeqElem : 返回索引指定的元素指针
            //CvRect : 通过方形左上角坐标和方形的高和宽来确定一个矩形区域
			CvRect cvrect = *(CvRect*)cvGetSeqElem(faces, i);
			
            //返回一个矩形,从用户空间坐标转换为设备坐标空间。
            CGRect face_rect = CGContextConvertRectToDeviceSpace(contextRef, CGRectMake(cvrect.x * scale, cvrect.y * scale, cvrect.width * scale, cvrect.height * scale));
			
            //覆盖图像
			if(overlayImage) {
				CGContextDrawImage(contextRef, face_rect, overlayImage.CGImage);
			} else {
				CGContextStrokeRect(contextRef, face_rect);
			}
			
		}
		
        img = [UIImage imageWithCGImage:CGBitmapContextCreateImage(contextRef)];
		CGContextRelease(contextRef);
		CGColorSpaceRelease(colorSpace);
		
		cvReleaseMemStorage(&storage);
		cvReleaseHaarClassifierCascade(&cascade);
		
	}
    
    NSLog(@"%@",@"opencv image ok~~~");
	return img;
    
}

- <feature>
- <rects>
<_>6 4 12 9 -1.</_>
//矩阵。前四个数值是矩阵四个点的位置,最后一个数值是矩阵像素和的权值
<_>6 7 12 3 3.</_>
//矩阵。前四个数值是矩阵四个点的位置,最后一个是像素和的权值,这样两个矩阵就形成了一个Haar特征
</rects>
<tilted>0</tilted> //是否是倾斜的Haar特征
</feature>
<threshold>-0.0315119996666908</threshold> //阈值
<left_val>2.0875380039215088</left_val> //小于阈值时取左值
<right_val>-2.2172100543975830</right_val> //大于阈值时取右值

结果是这样的



最后,再附上判断人脸的xml的一些解释,具体得可以看我下面链接的文章


参考文章:cvCvtColor 解析iPhone屏幕双缓冲技术 Adaboost原理、算法以及应用 CvMemStorage动态内存存储及操作函数 cvHaarDetectObjects

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值