基于皮肤分割的磨皮算法

	查阅了博客上绝大多数关于皮肤分割和磨皮美颜的算法,然后自己找了各位博主的代码,有自己将各部分代码组合修改调试,最终写了份参照代码。至于引用哪些博主的代码,找的博客太多分不清楚了,有博主看到引用代码可以私聊我加上你的引用。
	我感觉做出来的效果不太好,不如别人算法效果好。
	此代码只是做了皮肤分割和滤波磨皮,美白的代码还没写。还有就是发布文章我不太懂它的分类选项,只好随便选了。发布文章的规则我也不懂,有什么问题可以给我说下。

代码如下:


#include <opencv2/core/core.hpp>  
#include <opencv2/highgui/highgui.hpp>   
#include <opencv2/imgproc/imgproc.hpp>  
#include <opencv2/imgproc/imgproc_c.h>  
#include <opencv2/imgproc/types_c.h>  
#include <iostream>  
#include <vector>  


using namespace std;
using namespace cv;


//椭圆检测
Mat ellipse_detect(Mat &src)
{
	Mat img = src.clone();
	Mat skinCrCbHist = Mat::zeros(Size(256, 256), CV_8UC1);//256*256的矩阵,相当于CrCb分量的横纵坐标
														   //利用Opencv自带的椭圆生成函数生成一个肤色椭圆模型
	ellipse(skinCrCbHist, Point(113, 155.6), Size(23.4, 15.2), 43.0, 0.0, 360.0, Scalar(255, 255, 255), -1);
	Mat ycrcb_image;
	Mat output_mask = Mat::zeros(img.size(), CV_8UC1);
	cvtColor(img, ycrcb_image, CV_BGR2YCrCb); //首先转换成到YCrCb空间
	for (int i = 0; i < img.cols; i++)
	{
		for (int j = 0; j < img.rows; j++)
		{
			Vec3b ycrcb = ycrcb_image.at<Vec3b>(j, i);
			if (skinCrCbHist.at<uchar>(ycrcb[1], ycrcb[2]) > 0)//如果该点落在皮肤模型椭圆区域内,则该点是皮肤像素点。
				output_mask.at<uchar>(j, i) = 255;
		}
	}
	return output_mask;
}


/*YCrCb颜色空间Cr分量+Otsu法*/
Mat YCrCb_Otsu_detect(Mat& src)
{
	Mat ycrcb_image;
	cvtColor(src, ycrcb_image, CV_BGR2YCrCb); //首先转换成到YCrCb空间
	vector<Mat> channels;
	split(ycrcb_image, channels);//分割颜色通道
	Mat output_mask = channels[1];//取Cr通道的图像
	threshold(output_mask, output_mask, 0, 255, CV_THRESH_BINARY | CV_THRESH_OTSU);//自动阈值分割
	return output_mask;

}

Mat YCrCb_detect(Mat &src)//矩形区域分割
{
	Mat img = src.clone();
	Mat skinCrCbHist = Mat::zeros(Size(256, 256), CV_8UC1);//256*256的矩阵,相当于CrCb分量的横纵坐标
														   //利用Opencv自带的椭圆生成函数生成一个肤色椭圆模型
	ellipse(skinCrCbHist, Point(113, 155.6), Size(23.4, 15.2), 43.0, 0.0, 360.0, Scalar(255, 255, 255), -1);
	Mat ycrcb_image;
	Mat output_mask = Mat::zeros(img.size(), CV_8UC1);
	cvtColor(img, ycrcb_image, CV_BGR2YCrCb); //首先转换成到YCrCb空间
	for (int i = 0; i < img.cols; i++)
	{
		for (int j = 0; j < img.rows; j++)
		{
			Vec3b ycrcb = ycrcb_image.at<Vec3b>(j, i);
			if ((ycrcb[1] > 137) && (ycrcb[1] < 175) && (ycrcb[2] > 100) && (ycrcb[2] < 118))
				output_mask.at<uchar>(j, i) = 255;//皮肤区域
		}
	}
	return output_mask;

}


//锐化函数
Mat sharpen(Mat imageSrc, double threshold, double amount)
{
	Mat blurred;
	double sigma = 1;
	GaussianBlur(imageSrc, blurred, Size(), sigma, sigma);
	//int depth = CV_MAT_DEPTH(imageSrc.type());
	Mat lowContrastMask = abs(imageSrc - blurred) < threshold;
	Mat dst = imageSrc*(1 + amount) + blurred*(-amount);      //original + (original - blurred) * amount
	imageSrc.copyTo(dst, lowContrastMask);                  //将imageSrc中lowContrastMask对应的非0部分复制到dst中
															//lowContrastMask等于1时,说明高频分量比较小,有可能是噪声,此时不做锐化
	return dst;
}


Mat skinDivision(Mat ima)
{
	Mat detect0, detect1, detect2;
	各分割结果均返回灰度图mask
	矩形分割
	//Mat mer = YCrCb_detect(ima);
	//imshow("矩形分割", detect0);
	椭圆分割
	//resize(ima, ima, Size(ima.cols / 2, ima.rows / 2));
	//Mat mer = ellipse_detect(ima);
	//imshow("椭圆分割", detect1);
	//Cr+Otsu法阈值分割
	Mat mer = YCrCb_Otsu_detect(ima);
	imshow("阈值分割", mer);
	return mer;
}


Mat wave(Mat detect)//滤波函数
{

	Mat ret = detect.clone();
	//int g_nBilateralFilterValue = 25;  //双边滤波参数值,连通域大小
	//bilateralFilter(ret, detect, 40, g_nBilateralFilterValue * 2, g_nBilateralFilterValue / 2);//ret结果图,detect输入
	int value1 = 3, value2 = 3;
	int dx = value1 * 5;    //双边滤波参数之一
	double fc = value1*12.5; //双边滤波参数之一
	int p = 50;//透明度
	Mat temp2;
	//双边滤波
	bilateralFilter(ret, detect, dx, fc, fc);
	temp2 = (detect - ret + 128);
	//高斯模糊
	GaussianBlur(temp2, temp2, Size(2 * value2 - 1, 2 * value2 - 1), 0, 0);
	temp2 = ret + 2 * temp2 - 255;
	ret = (ret*(100 - p) + temp2*p) / 100;
	return ret;
}



int main()
{
	Mat srcImage = imread("d:\\4.jpg");
	if (!srcImage.data)
	{
		printf("could not load image...\n");
		return -1;
	}
	imshow("原图", srcImage);

	Mat mer = skinDivision(srcImage);//肤色分割的mask
	Mat detect;
	srcImage.copyTo(detect, mer);//返回肤色分割图detect
	imshow("肤色分割", detect);

	//皮肤区域磨皮
	Mat ret = wave(detect);//滤波函数

	float w = 0.3;
	//滤波图像和原图像选择性结合,把背景和皮肤区域结合
	for (int i = 0; i < detect.rows ; i++)
	{
		for (int j = 0; j < detect.cols ; j++)
		{
			if(mer.at<uchar>(i, j) == 0)
				ret.at<Vec3b>(i, j) = srcImage.at<Vec3b>(i, j);
			else
			{
				ret.at<Vec3b>(i, j) = w*srcImage.at<Vec3b>(i, j) + (1-w)*detect.at<Vec3b>(i, j);
			}
		}
	}
	imshow("双边滤波", ret);
	ret=sharpen(ret,1 ,1);	
	imshow("锐化", ret);

	
	waitKey(0);
	return 0;

}

注释的部分代码是自己调试使用的,其中有关于使用不同皮肤分割的算法。
各位有什么问题可以一起交流呀!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值