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(),目的是提高图像的饱和度,这里就不放出来了。

大致的原理是双边滤波+彩色直方图均衡。

最终的结果是这样

猜你喜欢

转载自www.cnblogs.com/bigtwetwet/p/12609431.html
今日推荐