這篇的由來, 是源自於工作上的需求
這需求是希望做到黑白漫畫的效果(歡迎點開我公司的官網)
在google大神以及高手同事的協助下, 產生了兩套PhotoShop流程來做到所謂的黑白漫畫
那是一個喊出「Photoshop行!我程式就行!」的純真時光
我試著一步一步的將PS步驟轉為程式
其實是個滿有趣的過程
================分隔線=============
其實以英文的keyword來說, 當時的需求比較像是sketch(素描)
以comic這個關鍵字下去, 比較接近美式漫畫的風格
比起comic來說, photoshop的sketch effect其實大多教學都滿簡單的
這篇先來介紹這個比較簡單, 最後也被採用的作法
先來看看結果...
沒看錯, 還是長頸鹿!!
環境簡介:
Windows 7 + Visual Studio 2010 + OF 0.7.4(基本上到0.8.1測試過也ok)
Addons:
ofxOpenCV(不過使用上主要還是用源生的OpenCV語法)
單純就這個功能來說, 其實純粹用OpenCV就夠用了
接下來介紹一下作法[1]
步驟:
1.將影像A轉為灰階(Gray Level)得到G
2.將G反轉(Inverse)得到I
3.對I影像做高斯模糊(Gaussian Blur)得到S
4.以S為底, 對G影像做顏色亮化混合(Color Dodge Blending)得到影像M
5.對影像M做閾值處理(Threshold)即得到結果
是不是很簡單啊, 就像麥太太的料理一樣呦[2]
整個演算法的目的其實就是把影像中的"邊緣"找出來
關鍵就在於"Color Dodge Blending"跟"Gaussian Blur"
首先是Color Dodge Blending, 當初其實不太清楚這個要怎麼實作
在參拜google大神數次後, 看到了一個佛心來的程式碼[3]:
簡單一句話就是, 在同樣亮度A下, B越亮混合完結果就會越亮.
眼尖的朋友一定會發現, 在這個演算法的過程中B就是A的inverse, 也就是(255 - A)
所以代入後的結果就變成
到此, 第二個關鍵Gaussian Blur就要發揮作用了
不懂Gaussian Blur是啥沒關係, 只要知道他會將原來的數值跟周圍根據某個權重去平均掉就好
剛剛的公式正確版應該如下:
換句話說, 只要Gaussina(A) <= A, 就會得到白色(255)
又因為在暗→亮的地方, 做完Gaussian Blur後是會變亮的, 所以邊緣的部份就會被畫出來
讓我們用一張測試的圖看看結果, 應該就更好懂了吧
右邊是原圖, 左邊是做完Color Dodge Blending的結果
可以看到由暗到亮的邊緣都被畫出來了
以下是Source Code:
下集請到這裡:
=好寶寶Reference=
[1]How to change a photo into a pencil line drawing in Photoshop
[2]麥兜的故事─麥太太的世界
[3]Stack overflow How does photoshop blend two images together?
================分隔線=============
目前對於Blogger的使用還處於菜到不行的階段
排版什麼的還沒辦法處理到讓大家看了舒服, 實在很抱歉啊Orz
這需求是希望做到黑白漫畫的效果(歡迎點開我公司的官網)
在google大神以及高手同事的協助下, 產生了兩套PhotoShop流程來做到所謂的黑白漫畫
那是一個喊出「Photoshop行!我程式就行!」的純真時光
我試著一步一步的將PS步驟轉為程式
其實是個滿有趣的過程
================分隔線=============
其實以英文的keyword來說, 當時的需求比較像是sketch(素描)
以comic這個關鍵字下去, 比較接近美式漫畫的風格
比起comic來說, photoshop的sketch effect其實大多教學都滿簡單的
這篇先來介紹這個比較簡單, 最後也被採用的作法
先來看看結果...
沒看錯, 還是長頸鹿!!
環境簡介:
Windows 7 + Visual Studio 2010 + OF 0.7.4(基本上到0.8.1測試過也ok)
Addons:
ofxOpenCV(不過使用上主要還是用源生的OpenCV語法)
單純就這個功能來說, 其實純粹用OpenCV就夠用了
接下來介紹一下作法[1]
步驟:
1.將影像A轉為灰階(Gray Level)得到G
2.將G反轉(Inverse)得到I
3.對I影像做高斯模糊(Gaussian Blur)得到S
4.以S為底, 對G影像做顏色亮化混合(Color Dodge Blending)得到影像M
5.對影像M做閾值處理(Threshold)即得到結果
是不是很簡單啊, 就像麥太太的料理一樣呦[2]
整個演算法的目的其實就是把影像中的"邊緣"找出來
關鍵就在於"Color Dodge Blending"跟"Gaussian Blur"
首先是Color Dodge Blending, 當初其實不太清楚這個要怎麼實作
在參拜google大神數次後, 看到了一個佛心來的程式碼[3]:
#define ChannelBlend_ColorDodge(A,B) ((uint8)((B == 255) ? B:min(255, ((A << 8 ) / (255 - B)))))看到"<< 8"會怕的朋友別緊張, 把他看成*256, 所以就是
ChannelBlend_ColorDodge(A,B) = A * 256 / (255 - B)
眼尖的朋友一定會發現, 在這個演算法的過程中B就是A的inverse, 也就是(255 - A)
所以代入後的結果就變成
ChannelBlend_ColorDodge(A,B) = A * 256/A
不懂Gaussian Blur是啥沒關係, 只要知道他會將原來的數值跟周圍根據某個權重去平均掉就好
剛剛的公式正確版應該如下:
ChannelBlend_ColorDodge(A,B) = A * 256/Gaussina(A)
又因為在暗→亮的地方, 做完Gaussian Blur後是會變亮的, 所以邊緣的部份就會被畫出來
讓我們用一張測試的圖看看結果, 應該就更好懂了吧
右邊是原圖, 左邊是做完Color Dodge Blending的結果
可以看到由暗到亮的邊緣都被畫出來了
以下是Source Code:
1: void testApp::ComicFilterVerCater()
2: {
3: //RGB to Gray
4: cv::Mat oMatGrayImg_;
5: cv::cvtColor(this->m_oImage, oMatGrayImg_, CV_RGB2GRAY);
6: //Inverse
7: cv::Mat MatImageInverse_;
8: cv::bitwise_not(oMatGrayImg_, MatImageInverse_);
9: //Smooth
10: int iTmpSize_ = this->m_ucKernalSize * 2 + 1;
11: cv::Mat MatSmoothImageInverse_;
12: cv::GaussianBlur(MatImageInverse_, MatSmoothImageInverse_, cv::Size(iTmpSize_, iTmpSize_), this->m_fSigma);
13: //Color dodge
14: cv::Mat MatEdge_ = oMatGrayImg_.clone();
15: for(int _idxY = 0; _idxY < MatSmoothImageInverse_.rows; ++_idxY)
16: {
17: for(int _idxX = 0; _idxX < MatSmoothImageInverse_.cols; ++_idxX)
18: {
19: MatEdge_.at<uint8>(_idxY, _idxX) = ChannelBlend_ColorDodge(MatEdge_.at<uint8>(_idxY, _idxX), MatSmoothImageInverse_.at<uint8>(_idxY, _idxX));
20: }
21: }
22: //Threshold
23: cv::Mat oMatThreshold_;
24: cv::threshold(MatEdge_, oMatThreshold_, this->m_fThreshold, 255, cv::THRESH_BINARY);
25: this->m_oResult = MatEdge_;
26: }
下集請到這裡:
=好寶寶Reference=
[1]How to change a photo into a pencil line drawing in Photoshop
[2]麥兜的故事─麥太太的世界
[3]Stack overflow How does photoshop blend two images together?
================分隔線=============
目前對於Blogger的使用還處於菜到不行的階段
排版什麼的還沒辦法處理到讓大家看了舒服, 實在很抱歉啊Orz
沒有留言:
張貼留言