原創性聲明:以下代碼是本人改寫自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 |