首页 > 其他 > 详细

OpenCV实现"你的名字"滤镜

时间:2019-12-12 10:18:53      阅读:119      评论:0      收藏:0      [点我收藏+]

这是一个比较有意思的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

OpenCV实现"你的名字"滤镜

原文:https://www.cnblogs.com/liuboblog/p/12026925.html

(0)
(0)
   
举报
评论 一句话评论(0
关于我们 - 联系我们 - 留言反馈 - 联系我们:wmxa8@hotmail.com
© 2014 bubuko.com 版权所有
打开技术之扣,分享程序人生!