将一副图像转换成油画

来源:互联网 发布:许蕾姆 知乎 编辑:程序博客网 时间:2024/04/26 07:43

原创性声明:以下代码是本人改写自C#语言编写的软件改写自PhotoSprite (Version 3.0 ,2006,由 联骏 编写),由使用OpenCV300编写。
先看一下效果

点击看大图 点击看大图

算法未作任何优化,优化算法可以看Photoshop 油画效果滤镜。
算法原理也不用细说了,源码之前,了无秘密。

代码

cv::Mat OilPaint(cv::Mat I,int brushSize, int coarseness){    assert(!I.empty());    if (brushSize < 1) brushSize = 1;    if (brushSize > 8) brushSize = 8;    if (coarseness < 1) coarseness = 1;    if (coarseness > 255) coarseness = 255;    int width  = I.cols;    int height = I.rows;    int lenArray = coarseness + 1;    int* CountIntensity = new int[lenArray];    uint* RedAverage    = new uint[lenArray];    uint* GreenAverage  = new uint[lenArray];    uint* BlueAverage   = new uint[lenArray];    /// 图像灰度化    Mat gray;    cvtColor(I,gray,COLOR_BGR2GRAY);    /// 目标图像    Mat dst = Mat::zeros(I.size(),I.type());    for(int nY = 0;nY <height; nY++)    {        // 油画渲染范围上下边界        int top = nY - brushSize;        int bottom = nY+ brushSize+1;        if(top<0) top = 0;        if(bottom >=height) bottom = height - 1;        for(int nX = 0;nX<width;nX++)        {            // 油画渲染范围左右边界            int left = nX - brushSize;            int right = nX +brushSize+1;            if(left<0) left = 0;            if(right>=width) right = width - 1;            //初始化数组            for(int i = 0;i <lenArray;i++)            {                CountIntensity[i] = 0;                RedAverage[i] = 0;                GreenAverage[i] = 0;                BlueAverage[i] = 0;            }            // 下面这个内循环类似于外面的大循环            // 也是油画特效处理的关键部分            for(int j = top;j<bottom;j++)            {                for(int i = left;i<right;i++)                {                    uchar intensity = static_cast<uchar>(coarseness*gray.at<uchar>(j,i)/255.0);                    CountIntensity[intensity]++;                    RedAverage[intensity]  += I.at<Vec3b>(j,i)[2];                    GreenAverage[intensity]+= I.at<Vec3b>(j,i)[1];                    BlueAverage[intensity] += I.at<Vec3b>(j,i)[0];                }            }            // 求最大值,并记录下数组索引            uchar chosenIntensity = 0;            int maxInstance = CountIntensity[0];            for(int i=1;i<lenArray;i++)            {                if(CountIntensity[i]>maxInstance)                {                    chosenIntensity = (uchar)i;                    maxInstance = CountIntensity[i];                }            }            dst.at<Vec3b>(nY,nX)[2] = static_cast<uchar>(RedAverage[chosenIntensity] / static_cast<float>(maxInstance));            dst.at<Vec3b>(nY,nX)[1] = static_cast<uchar>(GreenAverage[chosenIntensity] /  static_cast<float>(maxInstance));            dst.at<Vec3b>(nY,nX)[0] = static_cast<uchar>(BlueAverage[chosenIntensity] /  static_cast<float>(maxInstance));        }    }    delete [] CountIntensity;    delete [] RedAverage;    delete [] GreenAverage;    delete [] BlueAverage;#ifdef _DEBUG    imshow("dst",dst);    waitKey();#endif    return dst;}

后续

但是这样的油画效果,还是感觉欠缺了什么。好吧,再拿了一张油画纹理渲染一下吧。其实比较简单你可以使用正片叠底混合算法就可以了。
先看一下效果。(其实你也可以认为这种效果不好看,囧)

点击看大图 点击看大图

再来一张
点击看大图 点击看大图

另一张
点击看大图 点击看大图

界面

点击看大图

界面致谢,人在旅途。
好了,油画滤镜介绍完毕。

转载请保留以下信息

作者 日期 联系方式 风吹夏天 2015年10月31日 wincoder#qq.com
1 0
原创粉丝点击