影象處理算法系列 第三章 影象模糊處理 (平滑處理)
阿新 • • 發佈:2019-01-23
本章主要講影象處理中的模糊處理部分
紅色部分是我想直接用at,而不用指標,但是效率低的厲害。
下圖是用指標的相差了20倍。。。可見指標雖然萬惡,但是確實是個好東西。
由於size(4,4)圖太小看不清, 實際用的是8
效率如下:
效果圖如下: 本文沒有考慮邊界的情況,所以都是灰色的,可以考慮一下如何處理邊界。
上面程式碼有兩處問題: 第一是在size比較小的時候,這些點的概率之和不等於1,會導致圖片出問題。修正如下:
第二個問題是本文中sigma 是個固定值,實際上它是個可變值,具體怎麼計算,我沒有搞清楚,可以檢視opencv的原始碼,下面文章有參考價值 更新一下參考opencv裡面的可以這樣計算 sigma = 0.3*((ksize-1)*0.5 - 1) + 0.8 .
修改程式之後發現和原始的高斯函式基本一致,希望廣大朋友們多多評論,本人水平有限,很多地方有紕漏,希望能夠共同提高。
英文叫做blur, 也叫做smootiing, 中文中叫做模糊或者平滑。
用過photoshop的人都應該知道,濾鏡裡面就有模糊這個選項,我們現在看看它是怎麼實現的。
一含義
模糊(平滑)是一種常用的圖片處理方式,它的作用可以用來降低噪聲,還有其他用途
看一下opencv 裡面的公式
g(i,j)是目標座標的畫素值, f(i+k,j+l)是k,l這些地方的畫素值, h(k,l)是 kernel, 我不知道怎麼去準確翻譯它的意義,它是過濾器的係數。
簡單的按照我的思路去理解,就是一個權值,模糊的含義是將所有的畫素按照一定的權值進行運算,得到一個比較均衡的結果。
二 型別
型別有很多種: 均值模糊(box blur) 高斯模糊(gaussian blur) 中值模糊(media blur) 二值模糊(bilateral blur) 本文只講均值模糊和高斯模糊三 演算法
1 均值模糊 均值模糊很簡單就是周邊所有的影響都是1,求平均值即可 2 高斯模糊 關於高斯模糊的演算法,推薦這個文章 根據這個公式計算出係數即可。 上篇文章寫得很詳細,我就不班門弄斧了。四均值模糊的程式碼和效果
先放上均值模糊的程式碼void boxblur(Mat input ,Mat &out, int x, int y)
{
// accept only char type matrices
CV_Assert(input.depth() != sizeof(uchar));
out.create(input.size(),input.type());
int nChannels = input.channels();
int nRows = input.rows;
int nCols = input.cols;
int size = x * y;
float kernel = 1.0/size;
int i,j;
uchar* p;
uchar* q;
uchar R,G,B;
for( i = x; i < nRows - x; ++i)
{
q = out.ptr<uchar>(i);
for ( j = y; j < nCols - y; ++j)
{
float sumR = 0;
float sumG = 0;
float sumB = 0;
for (int k =0; k<x;k++)
{
p = input.ptr<uchar>(i-x+k);
for(int l = 0; l < y;l++)
{
sumB += input.at<uchar>(i - x + k,(j + l - y)*nChannels) * kernel;//p[(l + j -y)*nChannels ] * kernel;
sumG += input.at<uchar>(i - x + k,(j + l - y)*nChannels + 1) * kernel;//p[(l + j -y)*nChannels + 1] * kernel;
sumR += input.at<uchar>(i - x + k,(j + l - y)*nChannels + 2) * kernel;//p[(l + j -y)*nChannels + 2] * kernel;
}
}
q[j*nChannels] = sumB;
q[j*nChannels+1] = sumG;
q[j*nChannels+2] = sumR;
}
}
}
紅色部分是我想直接用at,而不用指標,但是效率低的厲害。
下圖是用指標的相差了20倍。。。可見指標雖然萬惡,但是確實是個好東西。
由於size(4,4)圖太小看不清, 實際用的是8
原始 | opencv | 本文 |
五高斯模糊的程式碼和效果
程式碼如下:void gaussblur(Mat input ,Mat &out, int x, int y) { float sigma = 1.5; Mat kernel; float pi = 3.1415926; kernel.create(x ,y ,CV_32F); float mx = x/2.0; float my = y/2.0;
//這裡有問題,後面做修正。
for (int i =0; i< x;i++)
{
for (int j =0; j<y;j++)
{
kernel.at<float>(i,j) = exp(-1 * ((i - mx) * (i - mx) +(j - my) * (j-my) )/( 2 * sigma * sigma))/(2 * pi * sigma *sigma) ;
}
}
int nChannels = input.channels();
int nRows = input.rows;
int nCols = input.cols;
out.create(input.size(),input.type());
uchar* p;
uchar* q;
float* s;
for(int i = x; i < nRows - x; ++i)
{
q = out.ptr<uchar>(i);
for (int j = y; j < nCols - y; ++j)
{
float sumR = 0;
float sumG = 0;
float sumB = 0;
for (int k =0; k<x;k++)
{
p = input.ptr<uchar>(i-x+k);
s = kernel.ptr<float>(k);
for(int l = 0; l < y;l++)
{
sumB += p[(l + j -y)*nChannels ] * s[l];//input.at<uchar>(i - x + k,(j + l - y)*nChannels) * kernel;//
sumG += p[(l + j -y)*nChannels + 1] *s[l];//input.at<uchar>(i - x + k,(j + l - y)*nChannels + 1) * kernel;//
sumR += p[(l + j -y)*nChannels + 2] * s[l];//input.at<uchar>(i - x + k,(j + l - y)*nChannels + 2) * kernel;
}
}
q[j*nChannels] = sumB;
q[j*nChannels+1] = sumG;
q[j*nChannels+2] = sumR;
}
}
}
效率如下:
效果圖如下: 本文沒有考慮邊界的情況,所以都是灰色的,可以考慮一下如何處理邊界。
原始 | opencv | 本文 |
上面程式碼有兩處問題: 第一是在size比較小的時候,這些點的概率之和不等於1,會導致圖片出問題。修正如下:
float sum = 0;
for (int i =0; i< x;i++)
{
for (int j =0; j<y;j++)
{
sum+= kernel.at<float>(i,j) = exp(-1 * ((i - mx) * (i - mx) +(j - my) * (j-my) )/( 2 * sigma * sigma))/(2 * pi * sigma *sigma) ;
}
}
for (int i =0; i< x;i++)
{
for (int j =0; j<y;j++)
{
kernel.at<float>(i,j) = kernel.at<float>(i,j)/ sum ;
}
}
第二個問題是本文中sigma 是個固定值,實際上它是個可變值,具體怎麼計算,我沒有搞清楚,可以檢視opencv的原始碼,下面文章有參考價值 更新一下參考opencv裡面的可以這樣計算 sigma = 0.3*((ksize-1)*0.5 - 1) + 0.8 .
修改程式之後發現和原始的高斯函式基本一致,希望廣大朋友們多多評論,本人水平有限,很多地方有紕漏,希望能夠共同提高。