OpenCV实现"你的名字"滤镜

这是一个比较有意思的demo,用到了播送融合,具体效果见下图:

文件结构如图所示

主程序代码

#include"stdafx.h"
#include<opencv2/photo.hpp>
#include"HSL.hpp"

using namespace std;
using namespace cv;


const string window_name = "photo";
static Mat src;

static HSL hsl;
static int color = 0;
static int hue = 180;
static int saturation = 100;
static int brightness = 100;

#define VP vector<Point>

//寻找最大的轮廓
VP FindBigestContour(Mat src) {
	int imax = 0; //代表最大轮廓的序号
	int imaxcontour = -1; //代表最大轮廓的大小
	std::vector<std::vector<Point>>contours;
	findContours(src, contours, CV_RETR_LIST, CV_CHAIN_APPROX_SIMPLE);
	for (int i = 0; i < contours.size(); i++) {
		int itmp = contourArea(contours[i]);//这里采用的是轮廓大小
		if (imaxcontour < itmp) {
			imax = i;
			imaxcontour = itmp;
		}
	}
	return contours[imax];
}

//提高饱和度
Mat EnhanceSaturation(Mat temp)
{
	Mat matDst;
	Mat Img_out(temp.size(), CV_32FC3);
	temp.convertTo(Img_out, CV_32FC3);
	Mat Img_in(temp.size(), CV_32FC3);
	temp.convertTo(Img_in, CV_32FC3);
	// define the iterator of the input image  
	MatIterator_<Vec3f> inp_begin, inp_end;
	inp_begin = Img_in.begin<Vec3f>();
	inp_end = Img_in.end<Vec3f>();
	// define the iterator of the output image  
	MatIterator_<Vec3f> out_begin, out_end;
	out_begin = Img_out.begin<Vec3f>();
	out_end = Img_out.end<Vec3f>();
	// increment (-100.0, 100.0)  
	float Increment = 50.0 / 100.0;   //饱和度参数调整
	float delta = 0;
	float minVal, maxVal;
	float t1, t2, t3;
	float L, S;
	float alpha;

	for (; inp_begin != inp_end; inp_begin++, out_begin++)
	{
		t1 = (*inp_begin)[0];
		t2 = (*inp_begin)[1];
		t3 = (*inp_begin)[2];

		minVal = std::min(std::min(t1, t2), t3);
		maxVal = std::max(std::max(t1, t2), t3);
		delta = (maxVal - minVal) / 255.0;
		L = 0.5*(maxVal + minVal) / 255.0;
		S = std::max(0.5*delta / L, 0.5*delta / (1 - L));

		if (Increment > 0)
		{
			alpha = max(S, 1 - Increment);
			alpha = 1.0 / alpha - 1;
			(*out_begin)[0] = (*inp_begin)[0] + ((*inp_begin)[0] - L * 255.0)*alpha;
			(*out_begin)[1] = (*inp_begin)[1] + ((*inp_begin)[1] - L * 255.0)*alpha;
			(*out_begin)[2] = (*inp_begin)[2] + ((*inp_begin)[2] - L * 255.0)*alpha;
		}
		else
		{
			alpha = Increment;
			(*out_begin)[0] = L * 255.0 + ((*inp_begin)[0] - L * 255.0)*(1 + alpha);
			(*out_begin)[1] = L * 255.0 + ((*inp_begin)[1] - L * 255.0)*(1 + alpha);
			(*out_begin)[2] = L * 255.0 + ((*inp_begin)[2] - L * 255.0)*(1 + alpha);

		}
	}
	Img_out /= 255;
	Img_out.convertTo(matDst, CV_8UC3, 255);

	return matDst;
}

int _tmain(int argc, _TCHAR* argv[])
{
	Mat matSrc = imread("../src3.jpg");
	Mat matCloud = imread("../cloud2.jpg");
	Mat temp; Mat matDst; Mat mask;
	vector<Mat> planes;
	/************************************************************************/
	/* 1.背景(天空)分割                                                                  */
	/************************************************************************/
	cvtColor(matSrc, temp, COLOR_BGR2HSV);
	split(temp, planes);
	equalizeHist(planes[2], planes[2]);//对v通道进行equalizeHist
	merge(planes, temp);
	inRange(temp, Scalar(100, 43, 46), Scalar(124, 255, 255), temp);
	erode(temp, temp, Mat());//形态学变换,填补内部空洞
	dilate(temp, temp, Mat());
	mask = temp.clone();//将结果存入mask
	/************************************************************************/
	/* 2.再融合,以1的结果mask,直接将云图拷贝过来(之前需要先做尺度变换)                                                                     */
	/************************************************************************/
	//寻找白色区域最大外接矩形的代码
	VP maxCountour = FindBigestContour(mask);
	Rect maxRect = boundingRect(maxCountour);
	if (maxRect.height == 0 || maxRect.width == 0)
		maxRect = Rect(0, 0, mask.cols, mask.rows);//特殊情况
	matDst = matSrc.clone();
	//注意这里的mask 需要和matCloud同样尺寸 
	mask = mask(maxRect);
	resize(matCloud, matCloud, maxRect.size());
	//seamless clone
	//中间位置为蓝天的背景位置
	Point center = Point((maxRect.x + maxRect.width) / 2, (maxRect.y + maxRect.height) / 2);
	Mat normal_clone;
	Mat mixed_clone;
	Mat monochrome_clone;
	seamlessClone(matCloud, matSrc, mask, center, normal_clone, NORMAL_CLONE);
	seamlessClone(matCloud, matSrc, mask, center, mixed_clone, MIXED_CLONE);
	seamlessClone(matCloud, matSrc, mask, center, monochrome_clone, MONOCHROME_TRANSFER);
	/************************************************************************/
	/* 3.卡通画处理                                                            */
	/************************************************************************/
	//双边滤波
	bilateralFilter(normal_clone, temp, 5, 10.0, 2.0);
	//彩色直方图均衡,将RGB图像转到YCbCr分量,然后对Y分量上的图像进行直方图均衡化
	cvtColor(temp, temp, COLOR_BGR2YCrCb);
	split(temp, planes);
	equalizeHist(planes[0], planes[0]);
	merge(planes, temp);
	cvtColor(temp, temp, COLOR_YCrCb2BGR);
	//提高图像饱和度
	matDst = EnhanceSaturation(temp);
	imshow("原始图", matSrc);
	imshow("结果图", matDst);
	cv::waitKey();
	getchar();
	return 0;
}

其他包含的库文件放到我的链接:https://i-beta.cnblogs.com/files

posted @ 2019-12-12 08:56  博博的Blog  阅读(464)  评论(0编辑  收藏  举报