溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點(diǎn)擊 登錄注冊 即表示同意《億速云用戶服務(wù)條款》

C++?opencv如何將圖片動漫化

發(fā)布時(shí)間:2022-01-25 10:45:44 來源:億速云 閱讀:168 作者:小新 欄目:開發(fā)技術(shù)

這篇文章給大家分享的是有關(guān)C++ opencv如何將圖片動漫化的內(nèi)容。小編覺得挺實(shí)用的,因此分享給大家做個參考,一起跟隨小編過來看看吧。

最近對圖像處理十分感興趣,也學(xué)著用opencv 實(shí)現(xiàn)各種簡單的圖像處理,因此,有了下面的實(shí)驗(yàn),就是將照片處理成漫畫的風(fēng)格。

對照片進(jìn)行動漫話一般需要四個步驟
1、邊緣檢測
2、將邊緣檢測得到的邊緣 以黑色的形式貼在原來的畫上。
3、對貼了邊緣的圖進(jìn)行雙邊濾波,雙邊濾波可以較好的濾波的同時(shí)保留邊緣。
4、修改圖像的顏色的飽和度,本文采用的是將RGB轉(zhuǎn)化為HSI空間,然后調(diào)整S分量。

邊緣檢測

對于邊緣檢測,本文采用的是canny算法
此文中將低閾值設(shè)定在70,高閾值則為70*3。
執(zhí)行后的結(jié)果為:

C++?opencv如何將圖片動漫化

貼邊緣圖到原圖

將邊緣圖以黑色貼到原圖上,原圖上非邊緣區(qū)域仍然為原來的顏色,動漫就是邊緣很明顯,且邊緣不是很多,不注重細(xì)節(jié),因此這里將邊緣貼上面當(dāng)作邊緣,后續(xù)利用雙倍濾波將圖中的其他相對小的細(xì)節(jié)邊緣去掉。針對紋理貼圖主要用到下面這個函數(shù):

// 將邊緣檢測后的圖 cannyImage 邊以黑色的形式貼在原圖 image上。
void pasteEdge(Mat &image, Mat &outImg, IplImage cannyImage)
{
    Mat cannyMat;
    //將IplImage轉(zhuǎn)化為Mat
    cannyMat = cvarrToMat(&cannyImage); 
    //顏色反轉(zhuǎn)
    cannyMat = cannyMat < 100;
    image.copyTo(outImg, cannyMat);
}

執(zhí)行后的效果如下:

C++?opencv如何將圖片動漫化

雙邊濾波

雙邊濾波(Bilateral filter)在圖像美化,美顏上有廣泛的運(yùn)用,是一種可以保邊去噪的濾波器,由兩個函數(shù)構(gòu)成。為了節(jié)約時(shí)間,這里就借用一張圖來充當(dāng)介紹了

C++?opencv如何將圖片動漫化

opencv也對此有函數(shù)調(diào)用:

void bilateralFilter( InputArray src, OutputArray dst, int d,
                                   double sigmaColor, double sigmaSpace,
                                   int borderType = BORDER_DEFAULT );

前面2個參數(shù)為輸入圖像,輸出圖像,d為雙倍濾波的算子大小,sigmacolor ,sigmaSpace是2個濾波函數(shù)的nameda值(這里節(jié)約時(shí)間不打符號了)
本文相關(guān)代碼:

    // 雙邊濾波
    Mat binateMat;
    bilateralFilter(pasteEdgeMat, binateMat, 10, 50, 50, BORDER_DEFAULT);

執(zhí)行后的結(jié)果如下:

C++?opencv如何將圖片動漫化

HSI空間修改飽和度

關(guān)于HSI顏色空間這里就不詳細(xì)介紹了,大家可以百度下,很多文章介紹,后續(xù)我也可能總結(jié)一下各個顏色空間,并且與rgb轉(zhuǎn)換方法。主要思路:將貼有邊緣 且 雙邊濾波后的圖像 轉(zhuǎn)化為 HSI 空間,而將S分量增大到原來的SRadio倍,然后將HSI空間圖像轉(zhuǎn)化回Rgb,并顯示。

將顏色空間轉(zhuǎn)化HSI,并增加S分量為原來的sRadio倍,主要是使用了下面這個函數(shù):

// 將image 像素轉(zhuǎn)化到 HSI 空間,并調(diào)整S 即顏色的飽和度,
void changeSImage(Mat &image, IplImage &outImg, float sRadio)
{
    int rows = image.rows;
    int cols = image.cols;
    // 三個HSI空間數(shù)據(jù)矩陣
    CvMat* HSI_H = cvCreateMat(rows, cols, CV_32FC1);
    CvMat* HSI_S = cvCreateMat(rows, cols, CV_32FC1);
    CvMat* HSI_I = cvCreateMat(rows, cols, CV_32FC1);

    // 原始圖像數(shù)據(jù)指針, HSI矩陣數(shù)據(jù)指針
    uchar* data;

    // rgb分量
    int img_r, img_g, img_b;
    int min_rgb;  // rgb分量中的最小值
    // HSI分量
    float fHue, fSaturation, fIntensity;
    int channels = image.channels();
    for (int i = 0; i < rows; i++)
    {
        for (int j = 0; j < cols; j++)
        {
            data = image.ptr<uchar>(i);
            data = data + j*channels;
            img_b = *data;
            data++;
            img_g = *data;
            data++;
            img_r = *data;

            // Intensity分量[0, 1]
            fIntensity = (float)((img_b + img_g + img_r) / 3) / 255;

            // 得到RGB分量中的最小值
            float fTemp = img_r < img_g ? img_r : img_g;
            min_rgb = fTemp < img_b ? fTemp : img_b;
            // Saturation分量[0, 1]
            fSaturation = 1 - (float)(3 * min_rgb) / (img_r + img_g + img_b);

            // 計(jì)算theta角
            float numerator = (img_r - img_g + img_r - img_b) / 2;
            float denominator = sqrt(
                pow((img_r - img_g), 2) + (img_r - img_b)*(img_g - img_b));

            // 計(jì)算Hue分量
            if (denominator != 0)
            {
                float theta = acos(numerator / denominator) * 180 / 3.14;

                if (img_b <= img_g)
                {
                    fHue = theta;
                }
                else
                {
                    fHue = 360 - theta;
                }
            }
            else
            {
                fHue = 0;
            }

            // 賦值
            cvmSet(HSI_H, i, j, fHue);
            cvmSet(HSI_S, i, j, fSaturation * sRadio);
            cvmSet(HSI_I, i, j, fIntensity);
        }
    }
    outImg = *HSI2RGBImage(HSI_H, HSI_S, HSI_I);    
}

HSI2RGBImage(HSI_H, HSI_S, HSI_I)是將三個分類的Mat 合并并轉(zhuǎn)化為BGR的圖,函數(shù)如下:

IplImage* HSI2RGBImage(CvMat* HSI_H, CvMat* HSI_S, CvMat* HSI_I)
{
    IplImage * RGB_Image = cvCreateImage(cvGetSize(HSI_H), IPL_DEPTH_8U, 3);

    int iB, iG, iR;
    for (int i = 0; i < RGB_Image->height; i++)
    {
        for (int j = 0; j < RGB_Image->width; j++)
        {
            // 該點(diǎn)的色度H
            double dH = cvmGet(HSI_H, i, j);
            // 該點(diǎn)的色飽和度S
            double dS = cvmGet(HSI_S, i, j);
            // 該點(diǎn)的亮度
            double dI = cvmGet(HSI_I, i, j);

            double dTempB, dTempG, dTempR;
            // RG扇區(qū)
            if (dH < 120 && dH >= 0)
            {
                // 將H轉(zhuǎn)為弧度表示
                dH = dH * 3.1415926 / 180;
                dTempB = dI * (1 - dS);
                dTempR = dI * (1 + (dS * cos(dH)) / cos(3.1415926 / 3 - dH));
                dTempG = (3 * dI - (dTempR + dTempB));
            }
            // GB扇區(qū)
            else if (dH < 240 && dH >= 120)
            {
                dH -= 120;

                // 將H轉(zhuǎn)為弧度表示
                dH = dH * 3.1415926 / 180;

                dTempR = dI * (1 - dS);
                dTempG = dI * (1 + dS * cos(dH) / cos(3.1415926 / 3 - dH));
                dTempB = (3 * dI - (dTempR + dTempG));
            }
            // BR扇區(qū)
            else
            {
                dH -= 240;

                // 將H轉(zhuǎn)為弧度表示
                dH = dH * 3.1415926 / 180;

                dTempG = dI * (1 - dS);
                dTempB = dI * (1 + (dS * cos(dH)) / cos(3.1415926 / 3 - dH));
                dTempR = (3 * dI - (dTempG + dTempB));
            }

            iB = dTempB * 255;
            iG = dTempG * 255;
            iR = dTempR * 255;

            cvSet2D(RGB_Image, i, j, cvScalar(iB, iG, iR));
        }
    }

    return RGB_Image;
}

執(zhí)行后就大功告成了,效果如下:

C++?opencv如何將圖片動漫化

后續(xù):

上述執(zhí)行基本完成了照片的漫畫風(fēng)格,但看到天空的云的一些邊緣泰國刺眼,本著好玩的性子,去掉了第一步和第二步,直接圖原圖進(jìn)行了雙邊濾波和增加顏色飽和度,感覺圖清晰,自然了些,但漫畫風(fēng)格也少了些,具體如何見下圖:

C++?opencv如何將圖片動漫化

感謝各位的閱讀!關(guān)于“C++ opencv如何將圖片動漫化”這篇文章就分享到這里了,希望以上內(nèi)容可以對大家有一定的幫助,讓大家可以學(xué)到更多知識,如果覺得文章不錯,可以把它分享出去讓更多的人看到吧!

向AI問一下細(xì)節(jié)

免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場,如果涉及侵權(quán)請聯(lián)系站長郵箱:is@yisu.com進(jìn)行舉報(bào),并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。

AI