人像头部检测
2016-06-01
0. 我的图像处理项目
- 感知Hash算法计算图像相似度-PHP实现
- 图片盲水印去除 - OpenCV - C/C++实现
- 印刷品背景去除 - OpenCV - C/C++实现
- Hog特征+SVM识别卡牌 - OpenCV - C/C++实现
1. 区域分割Demo
最开始我以为只是简单的抠图,所以花一晚上做了下面这个Demo。
抠图的方法分为三步: 1. Canny算子检测; 2. 形态学上的腐蚀以连接断点; 3. 通过漫水填充分割区域。
分割的效果还不错,处理速度很快,可以批量分割图片而不用调节阈值:
部分代码如下:
int main(int argc, char* argv[])
{
char srcName[] = "test.jpg";
IplImage * rgb = cvLoadImage(srcName);
IplImage * src = cvLoadImage(srcName, 0);
IplImage * img = src;
IplImage * imgSrc = img;
CvSize sizeSrc = cvGetSize(imgSrc);
CEdge edgeTemp;
edgeTemp.setEdgeThresh(20);
edgeTemp.extractEdge(srcName);
imgSrc = edgeTemp.getEdge();
Mat element = getStructuringElement(MORPH_RECT, Size(3, 3));
dilate((Mat)imgSrc, (Mat)imgSrc, element);
cvMin(img, imgSrc, imgSrc);
cvFloodFill(imgSrc, Point(sizeSrc.width*0.5, 10), Scalar(255, 255, 255), Scalar(5, 5, 5), Scalar(5, 5, 5));
cvMax(src, imgSrc, imgSrc);
IplImage * mask = cvCreateImage(sizeSrc, imgSrc->depth, 1);
cvSet(mask, cvScalar(255, 255, 255));
for (int i = 0; i < sizeSrc.width; i += 1)
{
for (int j = 0; j < sizeSrc.height; j += 1)
{
Scalar tmp = cvGet2D(imgSrc, j, i);
if (tmp.val[0]
== 255)
{
tmp.val[0] = 0;
}
cvSet2D(mask, j, i, tmp);
}
}
IplImage * dst = cvCreateImage(sizeSrc, rgb->depth, 3);
cvCopy(rgb, dst, mask);
waitKey(0);
cvReleaseImage(&src);
cvReleaseImage(&img);
cvReleaseImage(&imgSrc);
cvReleaseImage(&mask);
cvReleaseImage(&dst);
return 0;
}
但是我对需求描述产生一个疑问,整个头部(包括头发和脸部)是指下图I和II中的哪一个:
如果是第二种,情况会复杂很多,因为需要检测头部在图片中的位置。
2. Hough随机变换+OneCut分割
针对第二种情况,我的想法是先用识别Hough变化识别近似头部的圆形区域,然后提取头部区域的骨架,作为OneCut算法的输入,最后分割头部图像。
OneCut是个开源库,可以在下面的地址找到论文: http://www.csd.uwo.ca/~ygorelic/iccv13_one_cut.pdf
论文中,该算法的效果可以达到下图的程度: