本節爲opencv數字圖像處理(8):頻率域濾波的第五小節,使用頻率域濾波器進行圖像的平滑與銳化,主要包括:理想低通/高通濾波器,巴特沃斯低通/高通濾波器、高斯低通/高通濾波器、頻率域拉普拉斯算子、高頻強調濾波器以及同態濾波的介紹和C++實現。
1. 使用低通濾波器進行圖像平滑
考慮圖像中的邊緣與其他尖銳的灰度轉變對其傅里葉變換的高頻內容有貢獻,因此在頻率域平滑圖像可通過高頻分量的衰減來達到,即低通濾波器。比較典型的低通濾波器即理想低通濾波器、布特沃斯低通濾波器和高斯濾波器,對圖像的平滑/模糊程度也是由高到底。其中布特沃斯濾波器有一個參數,成爲濾波器的階數,階數值越高,越接近理想濾波器,反之更像高斯濾波器。
1.1. 理想低通濾波器
在以原點爲圓心,以爲半徑的圓內,無衰減地通過所有頻率而在該圓外切斷所有頻率的二維低通濾波器,成爲理想低通濾波器(ILPF),它由下面的函數來確定:
其中是一個正常數,是頻率域中點與頻率矩形中心的距離,即:
如下圖所示,從左到右分別是一個理想低通濾波器變換函數的透視圖、以圖像形式顯示的濾波器和濾波器徑向橫截面。
使用一個理想低通濾波器進行圖像平滑結果與C++代碼如下:
C++代碼核心部分如下,將代碼插入文章底部的框架代碼中指定位置即可:
//1.理想低通濾波
cv::Mat idealBlur(padded.size(), CV_32FC2);
double D0 = 60;
for (int i = 0; i < padded.rows; i++) {
float* p = idealBlur.ptr<float>(i);
for (int j = 0; j < padded.cols; j++) {
double d = sqrt(pow((i - padded.rows / 2), 2) + pow((j - padded.cols / 2), 2));//分子,計算pow必須爲float型
if (d <= D0) {
p[2 * j + 1] = 1;
p[2 * j] = 1;
}
else {
p[2 * j] = 0;
p[2 * j + 1] = 0;
}
}
}
multiply(complexImg, idealBlur, idealBlur);
cv::idft(idealBlur, idealBlur);
cv::split(idealBlur, plane);
1.2. 巴特沃斯低通濾波器
截止頻率位於距原點處的階巴特沃斯低通濾波器BLPF的傳遞函數的定義爲:
下圖顯示了BLPF函數的透視圖、圖像顯示和徑向剖面圖:
BLPF傳遞函數並沒有在通過頻率和濾除頻率之間給出明顯截止的尖銳的不連續性,使用巴特沃斯低通濾波器的效果與C++代碼如下:
C++代碼核心部分如下,將代碼插入文章底部的框架代碼中指定位置即可:
//2.巴特沃斯低通濾波
cv::Mat butterworthBlur(padded.size(), CV_32FC2);
double D0 = 60;
int n = 1;
for (int i = 0; i < padded.rows; i++) {
float* p = butterworthBlur.ptr<float>(i);
for (int j = 0; j < padded.cols; j++) {
double d = sqrt(pow((i - padded.rows / 2), 2) + pow((j - padded.cols / 2), 2));//分子,計算pow必須爲float型
p[2*j] = 1.0 / (1 + pow(d / D0, 2 * n));
p[2*j+1] = 1.0 / (1 + pow(d / D0, 2 * n));
}
}
multiply(complexImg, butterworthBlur, butterworthBlur);
cv::idft(butterworthBlur, butterworthBlur);
cv::split(butterworthBlur, plane);
BLPF用於平滑處理,如圖像由於量化不足產生僞輪廓時,常可用低通濾波進行平滑以改進圖像質量。通常,BLPF的平滑效果好於ILPF,當n的階數較低時(n=1,2),沒有振鈴現象,當階數較高時會產生明顯的振鈴現象。
1.3. 高斯低通濾波器
高斯低通濾波器的傳遞函數如下所示:
其中是截止頻率,當時,GLPF下降到其最大值0.607處。GLPF的傅里葉反變換也是高斯的,這意味這空間高斯濾波器將沒有振鈴。下圖從左到右依次是GLPF函數的透視圖、圖像顯示和徑向剖面圖。
使用高斯低通濾波器平滑圖像效果如下:
C++代碼核心部分如下,將代碼插入文章底部的框架代碼中指定位置即可:
//3.高斯低通濾波
cv::Mat gaussianBlur(padded.size(), CV_32FC2);
float D0 = 2 * 1000 ;
for (int i = 0; i < padded.rows; i++)
{
float* p = gaussianBlur.ptr<float>(i);
for (int j = 0; j < padded.cols; j++)
{
float d = pow(i - padded.rows / 2, 2) + pow(j - padded.cols / 2, 2);
p[2 * j] = expf(-d / D0);
p[2 * j + 1] = expf(-d / D0);
}
}
multiply(complexImg, gaussianBlur, gaussianBlur);
cv::idft(gaussianBlur, gaussianBlur);
cv::split(gaussianBlur, plane);
2. 使用高通濾波器進行圖像銳化
因爲圖像的邊緣和其他灰度的急劇變化與高頻分量有關,所以圖像銳化可以通過高通濾波來實現,高通濾波會衰減傅立葉變換中的低頻分量而不會擾亂高頻信息,一個高通濾波器是從給定的低通濾波器用下式得到:
2.1. 理想高通濾波器
一個二維理想高通濾波器IHPF定義爲:
下圖從左到右依次表示典型理想高通濾波器的透視圖、圖像表示和剖面圖:
下圖顯示的是典型理想高通濾波器的空間表示及通過濾波器中心的對應灰度剖面圖:
效果和代碼如下:
C++代碼核心部分如下,將代碼插入文章底部的框架代碼中指定位置即可:
//4.理想高通濾波
cv::Mat idealBlur(padded.size(), CV_32FC2);
double D0 = 20;
for (int i = 0; i < padded.rows; i++) {
float* p = idealBlur.ptr<float>(i);
for (int j = 0; j < padded.cols; j++) {
double d = sqrt(pow((i - padded.rows / 2), 2) + pow((j - padded.cols / 2), 2));//分子,計算pow必須爲float型
if (d <= D0) {
p[2 * j + 1] = 0;
p[2 * j] = 0;
}
else {
p[2 * j] = 1;
p[2 * j + 1] = 1;
}
}
}
multiply(complexImg, idealBlur, idealBlur);
cv::idft(idealBlur, idealBlur);
cv::split(idealBlur, plane);
2.2. 巴特沃斯高通濾波器
截止頻率爲的階巴特沃斯高通濾波器BHPF定義爲:
下圖從左到右依次表示典型理想高通濾波器的透視圖、圖像表示和剖面圖:
下圖顯示的是典型理想高通濾波器的空間表示及通過濾波器中心的對應灰度剖面圖:
效果和C++代碼如下:
C++代碼核心部分如下,將代碼插入文章底部的框架代碼中指定位置即可:
//5.巴特沃斯高通濾波
cv::Mat butterworthBlur(padded.size(), CV_32FC2);
double D0 = 20;
int n = 1;
for (int i = 0; i < padded.rows; i++) {
float* p = butterworthBlur.ptr<float>(i);
for (int j = 0; j < padded.cols; j++) {
double d = sqrt(pow((i - padded.rows / 2), 2) + pow((j - padded.cols / 2), 2));//分子,計算pow必須爲float型
p[2*j] = 1.0 / (1 + pow(D0 / d, 2 * n));
p[2*j+1] = 1.0 / (1 + pow(D0 / d, 2 * n));
}
}
multiply(complexImg, butterworthBlur, butterworthBlur);
cv::idft(butterworthBlur, butterworthBlur);
cv::split(butterworthBlur, plane);
2.3. 高斯高通濾波器
截止頻率處在距頻率矩形中心距離爲的高斯高通濾波器GHPF的傳遞函數如下:
下圖從左到右依次表示典型理想高通濾波器的透視圖、圖像表示和剖面圖:
下圖顯示的是典型理想高通濾波器的空間表示及通過濾波器中心的對應灰度剖面圖:
效果和代碼如下所示:
C++代碼核心部分如下,將代碼插入文章底部的框架代碼中指定位置即可:
//6.高斯高通濾波
cv::Mat gaussianBlur(padded.size(), CV_32FC2);
float D0 = 2 * 10 * 10;
for (int i = 0; i < padded.rows; i++)
{
float* p = gaussianBlur.ptr<float>(i);
for (int j = 0; j < padded.cols; j++)
{
float d = pow(i - padded.rows / 2, 2) + pow(j - padded.cols / 2, 2);
p[2 * j] = 1 - expf(-d / D0);
p[2 * j + 1] = 1 - expf(-d / D0);
}
}
multiply(complexImg, gaussianBlur, gaussianBlur);
cv::idft(gaussianBlur, gaussianBlur);
cv::split(gaussianBlur, plane);
2.4. 頻率域的拉普拉斯算子
拉普拉斯算子使用如下濾波器在頻率與實現:
或者說關於頻率矩形的中心,使用如下濾波器:
然後拉普拉斯圖像由下式得到:
增強的話可用下式實現:
這裏因爲是負的,所以。頻率域中上式可彙總爲下面的式子:
效果圖與C++實現如下:
C++代碼核心部分如下,將代碼插入文章底部的框架代碼中指定位置即可:
//7.頻率域拉普拉斯算子
cv::Mat Laplace(padded.size(), CV_32FC2);
for (int i = 0; i < padded.rows; i++)
{
float* p = Laplace.ptr<float>(i);
for (int j = 0; j < padded.cols; j++)
{
float d = pow(i - padded.rows / 2, 2) + pow(j - padded.cols / 2, 2);
p[2 * j] = 1 + 4 * pow(CV_PI, 2) * d;
p[2 * j + 1] = 1 + 4 * pow(CV_PI, 2) * d;
}
}
multiply(complexImg, Laplace, Laplace);
cv::idft(Laplace, Laplace);
cv::split(Laplace, plane);
2.5. 鈍化模板、高提升濾波和高頻強調濾波
鈍化模板技術在頻率域:
高提升濾波在頻率域:
其中是一個低通濾波器,是的傅里葉變換,是平滑後的圖像。然後,根據下式:
該表達式定義了時的鈍化模板和時的高提升濾波器。我們可以用涉及低通濾波器的頻率域計算來表達上式:
對應地,高通:
其中,方括號中的表達式稱爲高頻強調濾波器。之前提到高通濾波器將直流項設爲0,但是高頻強調濾波不存在這一問題,更一般地,高頻強調濾波的公式如下:
給出了控制距原點的偏移量,控制高頻的貢獻。
書中給出了一個例子,從左上到右下,圖中分別表示原圖、高斯高通濾波器、基於高斯濾波的高頻強調濾波器以及直方圖均衡化後的結果。高頻強調濾波
代碼比較簡單,結合上面的高斯高通濾波實現,比較簡單不再重複, 上面的例子取,有效的保留了灰度緩慢變化的區域。
2.6. 同態濾波
照射-反射模型可用於開發一種頻率域處理過程,該過程同時壓縮灰度範圍和增強對比度來改善一幅圖像的表觀,一幅圖像可表示爲其照射分量和反射分量的乘積:
但是傅里葉變換的乘積並不等於乘積的傅立葉變換,即:
但是我們可以定義:
則有:
即:
使用一個濾波器對進行濾波:
空間域濾波後的圖像:
根據定義有:
和
所以,濾波後空間域的圖像可以寫爲:
最後,因爲是通過取輸入圖像的自然對數形成的,可通過濾波後取指數來形成輸出圖像:
步驟總結如下:
該方法是以同態系統的一類系統的特殊情況爲基礎,方法的關鍵在於照射分量和反射分量的分離。圖像的照射分量通常由慢的空間變化來表徵,而反射分量往往引起突變,特別是在不同物體的連接部分。這樣的特性導致圖像取對數後的傅立葉變換的低頻分量與照射相聯繫,而高頻成分與反射相聯繫,雖然只是不強的聯繫。
同態濾波函數如下:
其中如果那麼如下圖所示的濾波器趨向於衰減低頻/照射分量的貢獻,而增強高頻/反射分量的貢獻,常數控制函數坡度的銳利度,在之間過渡,類似於高頻強調濾波:
該濾波器實現起來也比較簡單,不再重複。書中給出了一個同臺濾波的例子如下所示,其中:
文中提到的代碼框架:
#if 1
#include "opencv2/opencv.hpp"
int main()
{
cv::Mat input = cv::imread("2.JPG", cv::IMREAD_GRAYSCALE);
cv::imshow("step0_ori", input);
int w = cv::getOptimalDFTSize(input.cols);
int h = cv::getOptimalDFTSize(input.rows);
cv::Mat padded;
cv::copyMakeBorder(input, padded, 0, h - input.rows, 0, w - input.cols,
cv::BORDER_CONSTANT, cv::Scalar::all(0));
padded.convertTo(padded, CV_32FC1);
cv::imshow("step1_padded", padded);
for (int i = 0; i < padded.rows; i++)
{
float* ptr = padded.ptr<float>(i);
for (int j = 0; j < padded.cols; j++)
ptr[j] *= pow(-1, i + j);
}
cv::imshow("step2_center", padded);
cv::Mat plane[] = { padded,cv::Mat::zeros(padded.size(),CV_32F) };
cv::Mat complexImg;
cv::merge(plane, 2, complexImg);
cv::dft(complexImg, complexImg);
cv::split(complexImg, plane);
cv::magnitude(plane[0], plane[1], plane[0]);
plane[0] += cv::Scalar::all(1);
cv::log(plane[0], plane[0]);
cv::normalize(plane[0], plane[0], 1, 0, cv::NORM_MINMAX);
cv::imshow("dft", plane[0]);
/***************************************************************************/
//插入
/***************************************************************************/
cv::magnitude(plane[0], plane[1], plane[0]);
cv::normalize(plane[0], plane[0], 1, 0, cv::NORM_MINMAX);
cv::imshow("lpf", plane[0]);
cv::waitKey();
return 0;
}
#endif
歡迎掃描二維碼關注微信公衆號 深度學習與數學 [每天獲取免費的大數據、AI等相關的學習資源、經典和最新的深度學習相關的論文研讀,算法和其他互聯網技能的學習,概率論、線性代數等高等數學知識的回顧]