zh

数据解决方案

语音合成

首页>数据实验室>全部动态>基于肤色的人脸分割技术

基于肤色的人脸分割技术

来源:数据堂2019-12-10

很多时候,我们需要对脸部位置进行提取以达到某种定位的需求,这时候就需要对脸部进行人脸分割处理,人脸分割的算法有好多种,识别的算法更是一片浩洋。

本文只探讨初步的人脸分割,最简单也最常用的方法就是基于肤色的人脸分割,现记录于此。

 

算法思想:

1.从摄像头获取图像。

2.将图像转化到YCbCr空间。

3.Cr分量进行OTSU阈值分割。

4.求取分割结果的轮廓,求取面积最大的轮廓。

5.填充最大轮廓得到脸部掩码图,根据掩码图得到人脸。


代码如下:

#include "cxcore.h"

#include "math.h"

#include <cmath>

#include <vector>

#include <stdio.h>

#include <string.h>

#include <sstream>

#include <time.h>

#include <iostream>

#include <cstring>

#include <cv.h>

#include <highgui.h>

#include <assert.h>

using namespace std;

using namespace cv;


void cvSkinOtsu(IplImage* src,IplImage* dst)

{    

assert(dst->nChannels == 1 && src->nChannels == 3);

IplImage* ycrcb = cvCreateImage(cvGetSize(src),8,3);

IplImage* cr = cvCreateImage(cvGetSize(src),8,1);

cvCvtColor(src,ycrcb,CV_BGR2YCrCb);

cvSplit(ycrcb,0,cr,0,0);

cvThreshold(cr,cr,40,255,CV_THRESH_OTSU);

cvCopyImage(cr,dst);

cvReleaseImage(&cr);

cvReleaseImage(&ycrcb);

}

 

//主函数

int main()

{        

CvCapture* capture = cvCaptureFromCAM(0);//从对摄像头的初始化捕获

if(!cvQueryFrame(capture))  cout<<"Video capture failed, please check the camera."<<endl;

else cout<<"Video camera capture status: OK"<<endl;

CvSize sz = cvGetSize(cvQueryFrame( capture));//得到摄像头图像大小

 

 

IplImage* src = cvCreateImage( sz, 8, 3 );//3通道,每个通道8

IplImage* srcTemp = cvCreateImage( sz, 8, 3 );//3通道,每个通道8

IplImage* dst_crotsu = cvCreateImage(sz, 8, 1);

IplImage* dst_MaxSecond = cvCreateImage(sz, 8, 1);

CvMemStorage* storage = cvCreateMemStorage(0);//分配大小为0的内存空间

CvSeq* contour = 0;//用于选取最大两区域

cvNamedWindow("source", CV_WINDOW_AUTOSIZE);//创建用于显示的窗口

cvNamedWindow("SkinArea", CV_WINDOW_AUTOSIZE);

cvNamedWindow("bg", CV_WINDOW_AUTOSIZE);

//两行是为了计算图形的重心做准备 

CvMoments moments;

CvMat* region;

//定义一些点和具体的参数 

double m00 = 0,max,sum,average;

int n = 0,Nc;

src = cvQueryFrame(capture);

int imageArea = src->height*src->width;

IplImage* bg = cvCreateImage( sz, 8, 3);

while(1)

{

//画矩形,参数:Image,两个顶点坐标,线的颜色,线的厚度(CV_FILLED时绘制填充了色彩的矩形),线条类型,坐标点的小数点位数

cvRectangle( bg, cvPoint(0,0), cvPoint(bg->width,bg->height), CV_RGB( 255, 255, 255), -1, 8, 0 );bg->origin = 0;//表示坐标系统的原点,0表示左上,1表示左下

for(int b = 0; b< int(bg->width/10); b++)//画网格

{

cvLine( bg, cvPoint(b*20, 0), cvPoint(b*20, bg->height), CV_RGB( 200, 200, 200), 1, 8, 0 );//画竖线

//cvLine(图像,线段的第一个端点,第二个端点,颜色,粗细,类型,坐标点的小数点位数)

cvLine( bg, cvPoint(0, b*20), cvPoint(bg->width, b*20), CV_RGB( 200, 200, 200), 1, 8, 0 );//画横线

}

src = cvQueryFrame(capture);//得到一帧图像

cvZero(dst_crotsu);

cvSkinOtsu(src, dst_crotsu);//得到二值化图像

cvCopy(src,srcTemp);

/* cvRectangle( srcTemp, cvPoint(bg->width/3,bg->height/5), cvPoint(bg->width*2/3,bg->height*4/5), CV_RGB( 0, 255, 0), 2, 8, 0 );*/

cvShowImage("source", srcTemp);

cvShowImage("SkinArea", dst_crotsu);

//得到最大轮廓

int contour_num = cvFindContours(dst_crotsu, storage, &contour, sizeof(CvContour), CV_RETR_CCOMP, CV_CHAIN_APPROX_SIMPLE);

double maxarea = 0;//

double secondarea = 0;

double minarea = 100;

cvZero(dst_MaxSecond);

CvSeq* _contour = contour;

int m = 0;

for(;contour != 0; contour = contour->h_next)

{

m++;

double tmparea = fabs(cvContourArea(contour));

if(tmparea < minarea) {cvSeqRemove(contour, 0); continue;}//删除噪声

if(tmparea > maxarea) { maxarea = tmparea;}//得到最大面积

}

contour = _contour;    

for(; contour != 0; contour = contour->h_next)//画出最大两区域

{

double tmparea = fabs(cvContourArea(contour));

if (tmparea == maxarea)

{

CvScalar color = CV_RGB(255, 255, 255);

cvDrawContours(dst_MaxSecond, contour, color, color, 0, CV_FILLED);

//bg图上确定脸的区域

CvRect rect = cvBoundingRect( contour, 0 );//返回一个2d矩形的点集合

cvRectangle( bg, cvPoint(rect.x, rect.y + rect.height), 

cvPoint(rect.x + rect.width, rect.y), 

CV_RGB(200, 0, 200), 1, 8, 0 );

}

}

 

 

//如果面积过大,则认为不是脸部区域

if(maxarea>imageArea/3)

cvZero(dst_MaxSecond);

//将脸部区域拷贝到bg图像中

for(int i = 0;i<dst_MaxSecond->height;i++)

for(int j =0;j<dst_MaxSecond->width;j++)

{

if(cvGet2D(dst_MaxSecond,i,j).val[0]==255)

{

CvScalar temp= cvGet2D(src,i,j);

cvSet2D(bg,i,j,temp);

}

}

cvShowImage("FaceArea", dst_MaxSecond);

cvShowImage("bg", bg);

cvWaitKey(33);

}

cvReleaseCapture(&capture);

cvReleaseImage(&src);

cvReleaseImage(&dst_crotsu);

cvReleaseImage(&dst_MaxSecond);

cvReleaseImage(&bg);

cvReleaseImage(&srcTemp);

cvReleaseMemStorage(&storage);

cvDestroyAllWindows();

}

————————————————

本文转载自CSDN博主「Junzzy

原文链接:https://blog.csdn.net/zhuason/article/details/79806013

语音合成(TTS)_数据堂