概述
https://blog.csdn.net/cyf15238622067/article/details/86657370 文中介紹的入射分量和反射分量模型,可開發一種頻域處理過程,通過壓縮灰度範圍和增強對比度來改善一幅圖像的外觀。
頻譜域同態濾波
圖像可以表示爲照度和反射率的乘積:
f(x,y) = i(x,y)r(x,y)
現在定義:
則有:
或
式中 分別是 的傅里葉變換。
然後用H(u,v)對Z(u,v)濾波
S(u,v)=H(u,v)Z(u,v) = H(u,v) + H(u,v)
在空間域中:
由定義:
可以用下列表達式來表達:
最後因爲z(x,y)是通過取輸入圖像的自然對數形成的,可以通過取濾波後結果的指數反處理輸出圖像。
其中 i0是圖像的照射, r0是圖像的反射成分。
剛剛推導的濾波方法總結如下圖:
該方法的關鍵在於入射分量和反射分量的分離;然後對其分別進行濾波操作;
圖像的入射分量通常由慢的空間變化來表徵;而反射分量往往引起突變,特別是在不同物體的連接部分。
這些特性導致圖像取對數後傅里葉變換低頻成分與照射聯繫,而高頻部分與反射聯繫。雖然聯繫是粗略的近似,但他們用在圖像濾波中是有益的。
使用同態濾波器可以更好的控制入射分量和反射分量。這種控制需要指定一個濾波器函數H(u,v);可用不同的方法影響傅里葉變換的高頻和低頻。下圖是濾波器的剖面圖
如果rH ,rL選定,而rL<1,rH>1;那麼濾波器函數趨向於衰減低頻(照射)的貢獻,增強高頻(反射)的貢獻。最終結果是同時進行動態範圍的壓縮和對比度的增強。
上述剖面圖可用高斯的變換形式表示:
D(u,v)是頻率域中心(u,v)與頻率矩形中心的距離。
常數c控制函數邊坡的銳利度,它在rL 和rH之間過度。
例子:全身PET掃描圖像,有點模糊,支配動態顯示範圍的高灰度“熱點”使得低灰度特徵很朦朧。
使用高斯同態濾波處理,令 rL=0.25,rH=2,c=1,D0=80
代碼實現:
#include<opencv2/opencv.hpp>
#include<iostream>
using namespace std;
using namespace cv;
cv::Mat image_add_border( cv::Mat &src )
{
int w=2*src.cols;
int h=2*src.rows;
std::cout << "src: " << src.cols << "*" << src.rows << std::endl;
cv::Mat padded;
copyMakeBorder( src, padded, 0, h-src.rows, 0, w-src.cols,
cv::BORDER_CONSTANT, cv::Scalar::all(0));
// padded.convertTo(padded,CV_32FC1);
std::cout << "opt: " << padded.cols << "*" << padded.rows << std::endl;
return padded;
}
//transform to center 中心化
void center_transform( cv::Mat &src )
{
for(int i=0; i<src.rows; i++){
float *p = src.ptr<float>(i);
for(int j=0; j<src.cols; j++){
p[j] = p[j] * pow(-1, i+j);
}
}
}
//對角線交換內容
void zero_to_center(cv::Mat &freq_plane)
{
// freq_plane = freq_plane(Rect(0, 0, freq_plane.cols & -2, freq_plane.rows & -2));
//這裏爲什麼&上-2具體查看opencv文檔
//其實是爲了把行和列變成偶數 -2的二進制是11111111.......10 最後一位是0
int cx=freq_plane.cols/2;int cy=freq_plane.rows/2;//以下的操作是移動圖像 (零頻移到中心)
cv::Mat part1_r(freq_plane, cv::Rect(0,0,cx,cy)); //元素座標表示爲(cx,cy)
cv::Mat part2_r(freq_plane, cv::Rect(cx,0,cx,cy));
cv::Mat part3_r(freq_plane, cv::Rect(0,cy,cx,cy));
cv::Mat part4_r(freq_plane, cv::Rect(cx,cy,cx,cy));
cv::Mat tmp;
part1_r.copyTo(tmp); //左上與右下交換位置(實部)
part4_r.copyTo(part1_r);
tmp.copyTo(part4_r);
part2_r.copyTo(tmp); //右上與左下交換位置(實部)
part3_r.copyTo(part2_r);
tmp.copyTo(part3_r);
}
void show_spectrum( cv::Mat &complexI )
{
cv::Mat temp[] = {cv::Mat::zeros(complexI.size(),CV_32FC1),
cv::Mat::zeros(complexI.size(),CV_32FC1)};
//顯示頻譜圖
cv::split(complexI, temp);
cv::Mat aa;
cv::magnitude(temp[0], temp[1], aa);
// zero_to_center(aa);
cv::divide(aa, aa.cols*aa.rows, aa);
cv::imshow("src_img_spectrum",aa);
}
//頻率域濾波
cv::Mat frequency_filter(cv::Mat &padded,cv::Mat &blur)
{
cv::Mat plane[]={padded, cv::Mat::zeros(padded.size(), CV_32FC1)};
cv::Mat complexIm;
cv::merge(plane,2,complexIm);
cv::dft(complexIm,complexIm);//fourior transform
show_spectrum(complexIm);
cv::Mat dst_plane[2];
cv::multiply(complexIm, blur, complexIm);
// mulSpectrums(complexIm, blur, complexIm, 0);
cv::idft(complexIm, complexIm, DFT_INVERSE); //idft
cv::split(complexIm, dst_plane);
// cv::magnitude(dst_plane[0],dst_plane[1],dst_plane[0]); //求幅值(模)
center_transform(dst_plane[0]); //center transform
return dst_plane[0];
}
//高斯同態濾波器
cv::Mat gaussian_homo_kernel( cv::Mat &scr, float rh, float rl, float c, float D0 )
{
cv::Mat gaussian_high_pass(scr.size(),CV_32FC2);
int row_num = scr.rows;
int col_num = scr.cols;
float r = rh -rl;
float d0 = 2 * D0 * D0;
for(int i=0; i<row_num; i++ ){
float *p = gaussian_high_pass.ptr<float>(i);
for(int j=0; j<col_num; j++ ){
float d = pow((i - row_num/2),2) + pow((j - col_num/2),2);
p[2*j] = r*(1 - expf(-1*c*(d/d0))) + rl;
p[2*j+1] = r*(1 - expf(-1*c*(d/d0))) + rl;
}
}
cv::Mat temp[] = { cv::Mat::zeros(scr.size(), CV_32FC1),
cv::Mat::zeros(scr.size(), CV_32FC1) };
cv::split(gaussian_high_pass, temp);
std::string name = "濾波器d0=" + std::to_string(D0);
cv::Mat show;
cv::normalize(temp[0], show, 1, 0, CV_MINMAX);
cv::imshow(name, show);
return gaussian_high_pass;
}
Mat homofilter( Mat image_in, float rh, float rl, float c, float D0 )
{
image_in.convertTo(image_in,CV_32FC1);
log(image_in+1, image_in);
Mat padded = image_add_border(image_in);
center_transform(padded);
Mat blur = gaussian_homo_kernel(padded, rh, rl, c, D0 );
Mat dst = frequency_filter(padded, blur);
cv::normalize(dst, dst, 5, 0, CV_MINMAX); //歸一化5-0,因爲e^6 = 387 e^5 = 143,避免溢出
exp(dst,dst);
dst = dst - 1;
return dst;
}
int main() {
Mat src = imread("462.tif", 0);
resize(src, src, Size(), 0.5, 0.5);
imshow("原圖像", src);
Mat dst = homofilter(src,2, 0.25, 1, 80 );
dst = dst(Rect(0,0,src.cols, src.rows));
cv::normalize(dst, dst, 255, 0, CV_MINMAX);
dst.convertTo(dst, CV_8U);
imshow("同態濾波", dst);
waitKey(0);
}