博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
导向滤波之图像融合(C++版) Image Fusion with Guided Filtering
阅读量:3904 次
发布时间:2019-05-23

本文共 8750 字,大约阅读时间需要 29 分钟。

导向滤波之图像融合(C++版) Image Fusion with Guided Filtering

本次代码效果图。

代码效果展示

关于这篇IEEE上高被引的论文的算法还原工作如下:

论文主页
首先关于这篇论文的思路分析,就是通过各种滤波之间的组合,筛选出两张图中各自细节丰富的那一部分,从而经行不同权值的融合,实现双重曝光的融合。如下图所示分为ABC三个步骤。
论文图片
下面按照步骤经行详细操作:
首先A步:
一、对原图I1和I2进行均值滤波,由此得到基层(Base layer) B1和B2。
B1B2
二、用原图I1和I2减去基层B1和B2得到细节层(Detali layer)D1和D2。
D1D2
三、对原图I1和I2进行拉普拉斯滤波,由此得到显著分布图(Saliency map)S1和S2。
S1S2
四、对S1和S2的每个像素点比较,选出对应像素点最大值得到S_max。
S_MAX
五、用S1和S2分别和S_max经行比较,若相等则为1,不等则为0,得到权重分布图(Weight map)P1和P2。
P1P2
六、用原图I为导向,权重图P为被引导图,进行导向滤波,第一次滤波核为9,正则化参数为0.03,得到提炼的权重分布图(Refined weight mapWb1和Wb2),第二次滤波核为5,正则化参数为0.003,得到提炼的权重分布图(Refined weight mapWd1和Wd2)
WBWD
七、将Wb1和Wb2相加得到Wb_max,Wd1和Wd2相加得到Wd_max。再将他们全部除以Wb_max得到归一化的Wb1、Wb2、Wd1、Wd2。
归一化
八、B1 x Wb1+ B2 x Wb2得到B_bar,D1 x Wd1+ D2 x Wd2得到D_bar
B_barD_bar
九、输出图像九等于B_bar+D_bar。
输出图像
输出图像和原图像比较:
比较图
代码先不说,这篇论文我也是给予很高的厚望,但是最后发现,这种方法对于曝光度差别很大的图片效果很不错,但是一旦曝光度差异不大,那么就会出现亮区暗区过渡区间的色彩严重失真。影响观感。最后我仔细端详论文中这两幅图我发现,高曝光那个图,周围的颜色很单一,就是墙的颜色,低曝光那个图中间看似色彩丰富,但是恰恰这一点,让你发现不了里面的是真,妙啊真的妙。
过渡边缘色彩失真
后我自己尝试使用提取图像的光照分量,对光照分量进行单独的引导滤波融合后再与原来的图像融合。细节存在,但是颜色失真。想法失败。失真图片

#include
#include
#include
using namespace std;using namespace cv;//--------------------------------------------------------------//函数名:guidedFilter_oneChannel//函数功能:用于单通道图像(灰度图)的引导滤波函数;//参数:Mat srcImg:输入图像,为单通道图像;//参数:Mat guideImg:引导图像,为单通道图像,尺寸与输入图像一致;//参数:Mat dstImg:输出图像,尺寸、通道数与输入图像吻合;//参数:const int rad:滤波器大小,应该保证为奇数,默认值为9;//参数:const double eps :防止a过大的正则化参数,bool guidedFilter_oneChannel(Mat srcImg, Mat guideImg, Mat dstImg, const int rad = 9, const double eps = 0.01){
//--------------确保输入参数正确----------- {
if (!srcImg.data || srcImg.channels() != 1) {
cout << "输入图像错误,请重新输入图像" << endl; return false; } if (!guideImg.data || guideImg.channels() != 1) {
cout << "输入引导图像错误,请重新输入图像" << endl; return false; } if (guideImg.cols != srcImg.cols || guideImg.rows != srcImg.rows) {
cout << "输入图像与引导图像尺寸不匹配,请重新确认" << endl; return false; } if (dstImg.cols != srcImg.cols || dstImg.rows != srcImg.rows || dstImg.channels() != 1) {
cout << "参数输出图像错误,请重新确认" << endl; return false; } if (rad % 2 != 1) {
cout << "参数“rad”应为奇数,请修改" << endl; return false; } } //--------------转换数值类型,并归一化------------- srcImg.convertTo(srcImg, CV_32FC1, 1.0 / 255.0); guideImg.convertTo(guideImg, CV_32FC1, 1.0 / 255.0); //--------------求引导图像和输入图像的均值图 Mat mean_srcImg, mean_guideImg; boxFilter(srcImg, mean_srcImg, CV_32FC1, Size(rad, rad)); boxFilter(guideImg, mean_guideImg, CV_32FC1, Size(rad, rad)); Mat mean_guideImg_square, mean_guideImg_srcImg; boxFilter(guideImg.mul(guideImg), mean_guideImg_square, CV_32FC1, Size(rad, rad)); boxFilter(guideImg.mul(srcImg), mean_guideImg_srcImg, CV_32FC1, Size(rad, rad)); Mat var_guideImg = mean_guideImg_square - mean_guideImg.mul(mean_guideImg); Mat cov_guideImg_srcImg = mean_guideImg_srcImg - mean_guideImg.mul(mean_srcImg); Mat aImg = cov_guideImg_srcImg / (var_guideImg + eps); Mat bImg = mean_srcImg - aImg.mul(mean_guideImg); Mat mean_aImg, mean_bImg; boxFilter(aImg, mean_aImg, CV_32FC1, Size(rad, rad)); boxFilter(bImg, mean_bImg, CV_32FC1, Size(rad, rad)); dstImg = (mean_aImg.mul(guideImg) + mean_bImg); //dstImg.convertTo(dstImg, CV_8UC1, 255);//加这句最后返回的是CV_8UC1的图像 return true;}//--------------------------------------------------------------//函数名:guidedFilter_threeChannel//函数功能:用于三通道图像(RGB彩色图)的引导滤波函数;//参数:Mat srcImg:输入图像,为三通道图像;//参数:Mat guideImg:引导图像,为三通道图像,尺寸与输入图像一致;//参数:Mat dstImg:输出图像,尺寸、通道数与输入图像吻合;//参数:const int rad:滤波器大小,应该保证为奇数,默认值为9;//参数:const double eps :防止a过大的正则化参数,bool guidedFilter_threeChannel(Mat srcImg, Mat guideImg, Mat dstImg, const int rad = 9, const double eps = 0.01){
//----------------确保输入参数正确------------- {
if (!srcImg.data || srcImg.channels() != 3) {
cout << "输入图像错误,请重新输入图像" << endl; return false; } if (!guideImg.data || guideImg.channels() != 3) {
cout << "输入引导图像错误,请重新输入图像" << endl; return false; } if (guideImg.cols != srcImg.cols || guideImg.rows != srcImg.rows) {
cout << "输入图像与引导图像尺寸不匹配,请重新确认" << endl; return false; } if (rad % 2 != 1) {
cout << "参数“rad”应为奇数,请修改" << endl; return false; } } vector
src_vec, guide_vec, dst_vec; split(srcImg, src_vec); split(guideImg, guide_vec); for (int i = 0; i < 3; i++) {
Mat tempImg = Mat::zeros(srcImg.rows, srcImg.cols, CV_32FC1); guidedFilter_oneChannel(src_vec[i], guide_vec[i], tempImg, rad, eps); dst_vec.push_back(tempImg); } merge(dst_vec, dstImg); return true;}//根据2013年论文"Image Fusion with Guided Filtering"引导滤波的图像融合//double_exposure_HDR//函数名:double_exposure_HDR//函数功能:用于同一场景的不同曝光融合//参数:Mat Mat I1:输入的短曝光图像光照分量//参数:Mat Mat I2:输入的长曝光图像光照分量//返回:Mat 融合图像Mat double_exposure_HDR(Mat I1, Mat I2){
//论文中的A步Two-Scale Image Decomposition(双尺度分解)**************************************************** Mat B1, B2; //average filtering得到基础层base layer blur(I1, B1, Size(3,3)); blur(I2, B2, Size(3,3)); //imshow("短曝光基础层", B1); //imshow("长曝光基础层", B2); //相减得到细节层detail layer Mat D1, D2; D1 = I1 - B1; D2 = I2 - B2; //imshow("短曝光细节层", D1); //imshow("长曝光细节层", D2); //论文中的B步Weight Map Construction With Guided Filtering(构建权重图)********************************* Mat H1; Mat H2; //对原图来一次拉普拉斯滤波 Laplacian(I1, H1,0.3); Laplacian(I2, H2,0.3); //排除负值 H1 = abs(H1); H2 = abs(H2); //imshow("短曝光拉普拉斯滤波", H1); //imshow("长曝光拉普拉斯滤波", H2); //高斯滤波一次 Mat S1, S2; GaussianBlur(H1, S1, Size(11, 11), 9); GaussianBlur(H2, S2, Size(11, 11), 9); //imshow("短曝光显著像素分布图Saliency map", S1); //imshow("长曝光显著像素分布图Saliency map", S2); //再去根据论文的像素显著性 和 空间连续性 求权重图 P1 P2 Mat P1; Mat P2; P1 = Mat(I1.rows, I1.cols, CV_8UC3); P2 = Mat(I1.rows, I1.cols, CV_8UC3); //再求之前要求一个总的显著分布图s_max Mat S_max; S_max = Mat(I1.rows, I1.cols, CV_8UC3); for (int k = 0; k < I1.channels(); k++) {
for (int j = 0; j < I1.cols; j++) {
for (int i = 0; i < I1.rows; i++) {
S_max.at
(i, j)[k] = ((S1.at
(i, j)[k] > S2.at
(i, j)[k]) ? S1.at
(i, j)[k] : S2.at
(i, j)[k]); } } } //imshow("最大显著分布图", S_max); //下面求那两个权重分布图P1,P2 for (int k = 0; k < I1.channels(); k++) { for (int j = 0; j < I1.cols; j++) { for (int i = 0; i < I1.rows; i++) { P1.at
(i, j)[k] = (S1.at
(i, j)[k] == S_max.at
(i, j)[k]) ? 1 : 0; P2.at
(i, j)[k]= (S2.at
(i, j)[k] == S_max.at
(i, j)[k]) ? 1 : 0; } } } //imshow("短曝光权重分布图weight map", P1*255);//乘以255是为了可视化,白色代表1黑色代表0 //imshow("长曝光权重分布图weight map", P2*255);//乘以255是为了可视化,白色代表1黑色代表0 //这样我们就得到了关于各个源图像的粗略权重值。 //但是由于多个图像间容易产生噪声,并可能存在不完全对齐等问题,很容易造成融合后的图像有伪影等。 //因此在基于空间连续性的思想下,需要对得到的权重图进行导向滤波。 Mat Wb1, Wb2; Wb1 = Mat(I1.rows, I1.cols, CV_32FC3); Wb2 = Mat(I1.rows, I1.cols, CV_32FC3); guidedFilter_threeChannel(P1, I1, Wb1,9, 0.03); guidedFilter_threeChannel(P2, I2, Wb2,9, 0.03); //imshow("短曝光提炼权重分布图refined weight map Wb1", Wb1*255);//乘以255是为了可视化 //imshow("长曝光提炼权重分布图redined weight map Wb2", Wb2*255);//乘以255是为了可视化 Mat Wd1, Wd2; Wd1 = Mat(I1.rows, I1.cols, CV_32FC3); Wd2 = Mat(I1.rows, I1.cols, CV_32FC3); guidedFilter_threeChannel(P1, I1, Wd1, 5, 0.003); guidedFilter_threeChannel(P2, I2, Wd2, 5, 0.003); //imshow("短曝光提炼权重分布图refined weight map Wd1", Wd1*255);//乘以255是为了可视化 //imshow("长曝光提炼权重分布图redined weight map Wd2", Wd2*255);//乘以255是为了可视化 //得到A步骤中四个图对应的四个权重图 //论文中的C步Two-Scale Image Reconstruction(融合重建)**************************************************** Mat Wb_max, Wd_max; Wb_max = Mat(I1.rows, I1.cols, CV_32FC3); Wd_max = Mat(I1.rows, I1.cols, CV_32FC3); Wb_max = Wb1 + Wb2; Wd_max = Wd1 + Wd2; //归一化 for (int k = 0; k < I1.channels(); k++) { for (int j = 0; j < I1.cols; j++) { for (int i = 0; i < I1.rows; i++) { Wb1.at
(i, j)[k] /= Wb_max.at
(i, j)[k]; Wb2.at
(i, j)[k] /= Wb_max.at
(i, j)[k]; Wd1.at
(i, j)[k] /= Wd_max.at
(i, j)[k]; Wd2.at
(i, j)[k] /= Wd_max.at
(i, j)[k]; } } } //imshow("归一化短曝光提炼权重分布图Wb1", Wb1*255); //imshow("归一化长曝光提炼权重分布图Wb2", Wb2*255); //imshow("归一化短曝光提炼权重分布图Wd1", Wd1*255); //imshow("归一化长曝光提炼权重分布图Wd2", Wd2*255); Mat B_bar, D_bar; B_bar = Mat(I1.rows, I1.cols, CV_8UC3); D_bar = Mat(I1.rows, I1.cols, CV_8UC3); for (int k = 0; k < I1.channels(); k++) { for (int j = 0; j < I1.cols; j++) { for (int i = 0; i < I1.rows; i++) { B_bar.at
(i, j)[k] = B1.at
(i, j)[k] * Wb1.at
(i, j)[k] + B2.at
(i, j)[k] * Wb2.at
(i, j)[k]; D_bar.at
(i, j)[k] = D1.at
(i, j)[k] * Wd1.at
(i, j)[k] + D2.at
(i, j)[k] * Wd2.at
(i, j)[k]; } } } //融合输出 Mat out; out = B_bar + D_bar; //imshow("B_bar", B_bar); //imshow("D_bar", D_bar); return out;}int main() { Mat src_UE = imread("C:\\Users\\hl\\Desktop\\I1.jpg", IMREAD_COLOR); Mat src_OE = imread("C:\\Users\\hl\\Desktop\\I2.jpg", IMREAD_COLOR); Mat out; out=double_exposure_HDR(src_UE,src_OE); imshow("过曝光", src_OE); imshow("欠曝光", src_UE); imshow("引导滤波后", out); waitKey(); return 0;}

https://blog.csdn.net/u013921430/article/details/99695647

声明:关于导向滤波C++函数模块部分借鉴了不用先生 2019-08-18 10:28:05的一篇【图像处理】引导滤波(guided image filtering)

你可能感兴趣的文章
Django short url
查看>>
Tech Blog
查看>>
Logon System Design
查看>>
Python yield
查看>>
Sina API OAuth
查看>>
Python supervisor
查看>>
dict & set
查看>>
Common Multiple and Least Common Multiple(LCM)
查看>>
Greatest Common Divisor (GCD) - Euclidean algorithm
查看>>
Regular Expression Python
查看>>
大数据处理
查看>>
Mapreduce 通俗版
查看>>
MapReduce Inverted index
查看>>
MapReduce Intro
查看>>
Mapreduce Patterns, Algorithms, and use cases
查看>>
Hadoop interview
查看>>
数据处理问题
查看>>
BloomFilter
查看>>
Bloom Filter - Math deduce
查看>>
Bit Byte Megabyte Gigabyte
查看>>