您好,登錄后才能下訂單哦!
這篇文章給大家分享的是有關C++ opencv如何將圖片動漫化的內容。小編覺得挺實用的,因此分享給大家做個參考,一起跟隨小編過來看看吧。
最近對圖像處理十分感興趣,也學著用opencv 實現各種簡單的圖像處理,因此,有了下面的實驗,就是將照片處理成漫畫的風格。
對照片進行動漫話一般需要四個步驟
1、邊緣檢測
2、將邊緣檢測得到的邊緣 以黑色的形式貼在原來的畫上。
3、對貼了邊緣的圖進行雙邊濾波,雙邊濾波可以較好的濾波的同時保留邊緣。
4、修改圖像的顏色的飽和度,本文采用的是將RGB轉化為HSI空間,然后調整S分量。
對于邊緣檢測,本文采用的是canny算法
此文中將低閾值設定在70,高閾值則為70*3。
執行后的結果為:
將邊緣圖以黑色貼到原圖上,原圖上非邊緣區域仍然為原來的顏色,動漫就是邊緣很明顯,且邊緣不是很多,不注重細節,因此這里將邊緣貼上面當作邊緣,后續利用雙倍濾波將圖中的其他相對小的細節邊緣去掉。針對紋理貼圖主要用到下面這個函數:
// 將邊緣檢測后的圖 cannyImage 邊以黑色的形式貼在原圖 image上。 void pasteEdge(Mat &image, Mat &outImg, IplImage cannyImage) { Mat cannyMat; //將IplImage轉化為Mat cannyMat = cvarrToMat(&cannyImage); //顏色反轉 cannyMat = cannyMat < 100; image.copyTo(outImg, cannyMat); }
執行后的效果如下:
雙邊濾波(Bilateral filter)在圖像美化,美顏上有廣泛的運用,是一種可以保邊去噪的濾波器,由兩個函數構成。為了節約時間,這里就借用一張圖來充當介紹了
opencv也對此有函數調用:
void bilateralFilter( InputArray src, OutputArray dst, int d, double sigmaColor, double sigmaSpace, int borderType = BORDER_DEFAULT );
前面2個參數為輸入圖像,輸出圖像,d為雙倍濾波的算子大小,sigmacolor ,sigmaSpace是2個濾波函數的nameda值(這里節約時間不打符號了)
本文相關代碼:
// 雙邊濾波 Mat binateMat; bilateralFilter(pasteEdgeMat, binateMat, 10, 50, 50, BORDER_DEFAULT);
執行后的結果如下:
關于HSI顏色空間這里就不詳細介紹了,大家可以百度下,很多文章介紹,后續我也可能總結一下各個顏色空間,并且與rgb轉換方法。主要思路:將貼有邊緣 且 雙邊濾波后的圖像 轉化為 HSI 空間,而將S分量增大到原來的SRadio倍,然后將HSI空間圖像轉化回Rgb,并顯示。
將顏色空間轉化HSI,并增加S分量為原來的sRadio倍,主要是使用了下面這個函數:
// 將image 像素轉化到 HSI 空間,并調整S 即顏色的飽和度, void changeSImage(Mat &image, IplImage &outImg, float sRadio) { int rows = image.rows; int cols = image.cols; // 三個HSI空間數據矩陣 CvMat* HSI_H = cvCreateMat(rows, cols, CV_32FC1); CvMat* HSI_S = cvCreateMat(rows, cols, CV_32FC1); CvMat* HSI_I = cvCreateMat(rows, cols, CV_32FC1); // 原始圖像數據指針, HSI矩陣數據指針 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); // 計算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)); // 計算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 合并并轉化為BGR的圖,函數如下:
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++) { // 該點的色度H double dH = cvmGet(HSI_H, i, j); // 該點的色飽和度S double dS = cvmGet(HSI_S, i, j); // 該點的亮度 double dI = cvmGet(HSI_I, i, j); double dTempB, dTempG, dTempR; // RG扇區 if (dH < 120 && dH >= 0) { // 將H轉為弧度表示 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扇區 else if (dH < 240 && dH >= 120) { dH -= 120; // 將H轉為弧度表示 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扇區 else { dH -= 240; // 將H轉為弧度表示 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; }
執行后就大功告成了,效果如下:
上述執行基本完成了照片的漫畫風格,但看到天空的云的一些邊緣泰國刺眼,本著好玩的性子,去掉了第一步和第二步,直接圖原圖進行了雙邊濾波和增加顏色飽和度,感覺圖清晰,自然了些,但漫畫風格也少了些,具體如何見下圖:
感謝各位的閱讀!關于“C++ opencv如何將圖片動漫化”這篇文章就分享到這里了,希望以上內容可以對大家有一定的幫助,讓大家可以學到更多知識,如果覺得文章不錯,可以把它分享出去讓更多的人看到吧!
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。