將一副圖像轉換成油畫

原創性聲明:以下代碼是本人改寫自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
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章