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
#include
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
for(int j=0; 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
for(int j=0; j
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);
}