Opencv学习:使用Opencv对图象进行抠图和滤镜处理,实现“你的名字”动漫图片效果
最近接到了一个坑爹题目,是这么要求的:
仿照 《你的名字》,对天坛图像。src.jpg进行处理。要求
(一)背景(天空)分割,替换后再融合
在自然界的图片中,很难出现动漫中大多大多的云彩。首先需要将背景(天空)分割出来,替换成动漫的天空,并且在很好地融合回去。
需要实现的技术:1.背景(天空)分割; 2.再融合。
(二)前景色调转换
为了实现漫画中具有卡通意味的前景色调,需要对前面切割下来的前景图片进行色调转换。需要实现的技术:3.LUT和色块制作
幸好网上的例子比较多,老师也给了个例程,现在就一步步来执行
给了两张图片,是这个样子的:
现在需要做得事情就是把云编程动漫里面那种云,然后把天坛抠出来换成那样的云。
首先要对天坛进行抠图处理。
给出代码如下:
/************************************************************************/ /* 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()); imshow("kou",temp);
原理是对图片进行了直方图均衡化:equalizeHist(),然后根据阙值二元化,白色和黑色。接着进行形态学变换,把天坛的大致轮廓抠图出来了。
接下来就是把我们的云彩图片和这个天坛融合起来了.......
记得要先进行resize,也就是尺寸控制。
/************************************************************************/ /* 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);
这里有几个问题,第一个是FindBigestContour函数,实在是不太清楚作用
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]; }
seamlessclone是一种叫做泊松融合的函数,这里用了3种融合方法。
函数原型(C++):
void inRange(InputArray src, InputArray lowerb, InputArray upperb, OutputArray dst)
官方文档中的解释:Checks if array elements lie between the elements of two other arrays.即检查数组元素是否在另外两个数组元素值之间。这里的数组通常也就是矩阵Mat或向量。请注意:该函数输出的dst是一幅二值化之后的图像。
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("结果图", matDst);
这里有个秘制小函数叫EnhanceSaturation(),目的是提高图像的饱和度,这里就不放出来了。
大致的原理是双边滤波+彩色直方图均衡。
最终的结果是这样
posted on 2020-03-31 23:03 大湿Mastwet 阅读(1966) 评论(1) 编辑 收藏 举报