• 扩散修复是一种常见的小面积图像篡改手段,考虑到扩散修复引入的模糊效应,提出了一种梯度导向滤波增强的图像扩散修复取证算法。因伪造图像在未修复区域结构纹理清晰,而模糊效应会导致修复区域纹理发生一定的改变,...
• 作者提出了一种新的梯度域引导图像滤波器，通过将明确的一阶边缘感知约束结合到现有的引导图像滤波器中。 matlab代码实现 转载至：...


作者提出了一种新的梯度域引导图像滤波器，通过将明确的一阶边缘感知约束结合到现有的引导图像滤波器中。

matlab代码实现
转载至：https://blog.csdn.net/majinlei121/article/details/50717777

%主程序function q = gradient_guidedfilter(I, p, eps)
%   GUIDEDFILTER   O(1) time implementation of guided filter.
%
%   - guidance image: I (should be a gray-scale/single channel image)
%   - filtering input image: p (should be a gray-scale/single channel image)
%   - regularization parameter: eps

r=16;
[hei, wid] = size(I);
N = boxfilter(ones(hei, wid), r); % the size of each local patch; N=(2r+1)^2 except for boundary pixels.

mean_I = boxfilter(I, r) ./ N;
mean_p = boxfilter(p, r) ./ N;
mean_Ip = boxfilter(I.*p, r) ./ N;
cov_Ip = mean_Ip - mean_I .* mean_p; % this is the covariance of (I, p) in each local patch.

mean_II = boxfilter(I.*I, r) ./ N;
var_I = mean_II - mean_I .* mean_I;

%weight
epsilon=(0.001*(max(p(:))-min(p(:))))^2;
r1=1;

N1 = boxfilter(ones(hei, wid), r1); % the size of each local patch; N=(2r+1)^2 except for boundary pixels.
mean_I1 = boxfilter(I, r1) ./ N1;
mean_II1 = boxfilter(I.*I, r1) ./ N1;
var_I1 = mean_II1 - mean_I1 .* mean_I1;

chi_I=sqrt(abs(var_I1.*var_I));
weight=(chi_I+epsilon)/(mean(chi_I(:))+epsilon);

gamma = (4/(mean(chi_I(:))-min(chi_I(:))))*(chi_I-mean(chi_I(:)));
gamma = 1 - 1./(1 + exp(gamma));

%result
a = (cov_Ip + (eps./weight).*gamma) ./ (var_I + (eps./weight));
b = mean_p - a .* mean_I;

mean_a = boxfilter(a, r) ./ N;
mean_b = boxfilter(b, r) ./ N;

q = mean_a .* I + mean_b;
end
%子程序boxfilter()

[cpp] view plain copy
function imDst = boxfilter(imSrc, r)

%   BOXFILTER   O(1) time box filtering using cumulative sum
%
%   - Definition imDst(x, y)=sum(sum(imSrc(x-r:x+r,y-r:y+r)));
%   - Running time independent of r;
%   - Equivalent to the function: colfilt(imSrc, [2*r+1, 2*r+1], 'sliding', @sum);
%   - But much faster.

[hei, wid] = size(imSrc);
imDst = zeros(size(imSrc));

%cumulative sum over Y axis
imCum = cumsum(imSrc, 1);
%difference over Y axis
imDst(1:r+1, :) = imCum(1+r:2*r+1, :);
imDst(r+2:hei-r, :) = imCum(2*r+2:hei, :) - imCum(1:hei-2*r-1, :);
imDst(hei-r+1:hei, :) = repmat(imCum(hei, :), [r, 1]) - imCum(hei-2*r:hei-r-1, :);

%cumulative sum over X axis
imCum = cumsum(imDst, 2);
%difference over X axis
imDst(:, 1:r+1) = imCum(:, 1+r:2*r+1);
imDst(:, r+2:wid-r) = imCum(:, 2*r+2:wid) - imCum(:, 1:wid-2*r-1);
imDst(:, wid-r+1:wid) = repmat(imCum(:, wid), [1, r]) - imCum(:, wid-2*r:wid-r-1);
end

%运行程序

clear
I = double(imread('D:\数字图像处理\研究方向\Filter Smooth\images\tulips.png')) / 255;% if size(I,3)==3%     I=rgb2gray(I);% end
p = I;r=16;eps = 0.8^2; % try eps=0.1^2, 0.2^2, 0.4^2
q_guide(:,:,1)=guidedfilter(I(:,:,1), p(:,:,1), r, eps);q_guide(:,:,2)=guidedfilter(I(:,:,2), p(:,:,2), r, eps);q_guide(:,:,3)=guidedfilter(I(:,:,3), p(:,:,3), r, eps);
figure;imshow([I,q_guide,q]);title('原图，引导滤波，改进引导滤波 eps=0.8^2');


展开全文
• 基本原理 导向滤波（Guided Fliter）显式地利用 guidance image ...除了速度优势以外，导向滤波的一个很好的性能就是可以保持梯度，这是bilateral做不到的，因为会有梯度翻转现象。（Preserves edges, but not gradient
基本原理
导向滤波（Guided Fliter）显式地利用 guidance image 计算输出图像，其中 guidance image 可以是输入图像本身或者其他图像。导向滤波比起双边滤波来说在边界附近效果较好；另外，它还具有 O(N) 的线性时间的速度优势。细节请查阅论文《Guided Image Filtering》

基本原理如下：

其中，p为输入图像，I 为导向图，q 为输出图像。在这里我们认为输出图像可以看成导向图I 的一个局部线性变换，其中k是局部化的窗口的中点，因此属于窗口 ωk 的pixel，都可以用导向图对应的pixel通过（ak,bk）的系数进行变换计算出来。同时，我们认为输入图像 p 是由 q 加上我们不希望的噪声或纹理得到的，因此有p = q + n 。
接下来就是解出这样的系数，使得p和q的差别尽量小，而且还可以保持局部线性模型。这里利用了带有正则项的 linear ridge regression（岭回归）

求解以上方程得到a和b在局部的值，对于一个要求的pixel可能含在多个window中，因此平均后得到：

最后得到的算法为：

示例演示
头文件GuidedFilter.h
#pragma once

#include <opencv2\opencv.hpp>

/*
输入：
guidedImg　　----引导图像,单通道或者三通道
inputImg　　----输入待滤波图像，单通道或者三通道
r　　　　　　----滤波窗口半径
eps　　　　　----截断值eps

输出：
outputImg　　----引导图滤波后图像
*/

class GuidedFilter
{
public:
GuidedFilter();
~GuidedFilter();

private:

cv::Mat runGuidedFilter_Gray(cv::Mat I, cv::Mat P, int type, int radius, double eps);
cv::Mat runGuidedFilter_Color(cv::Mat I, cv::Mat P, int type, int radius, double eps);

public:
cv::Mat myGuidedFilter_GrayGuided(cv::Mat guidedImg, cv::Mat inputImg, int radius, double eps);
cv::Mat myGuidedFilter_ColorGuided(cv::Mat guidedImg, cv::Mat inputImg, int radius, double eps);

};

源文件GuidedFilter.cpp
#include "guidedFilter.h"
#include <iostream>
#include <string>

using namespace std;
using namespace cv;

GuidedFilter::GuidedFilter()
{
}

GuidedFilter::~GuidedFilter()
{
}

//引导图为灰度图像
cv::Mat GuidedFilter::runGuidedFilter_Gray(cv::Mat I, cv::Mat P, int type, int radius, double eps)
{
//求I*I, I*P
cv::Mat  I2, IP;
multiply(I, I, I2);
multiply(I, P, IP);
//求均值
cv::Mat meanI, meanP, meanI2, meanIP;
cv::boxFilter(I, meanI, type, winSize);
cv::boxFilter(P, meanP, type, winSize);
cv::boxFilter(I2, meanI2, type, winSize);
cv::boxFilter(IP, meanIP, type, winSize);
//求方差/协方差
cv::Mat varI, covIP;
varI = meanI2 - meanI.mul(meanI);
covIP = meanIP - meanI.mul(meanP);
//求系数a, b
cv::Mat a, b;
varI += eps;
cv::divide(covIP, varI, a);
b = meanP - a.mul(meanI);
//a、b窗口内求平均
cv::Mat meanA, meanB;
cv::boxFilter(a, meanA, type, winSize);
cv::boxFilter(b, meanB, type, winSize);
//输出
cv::Mat output;
output = meanA.mul(I) + meanB;
return output;
}

//引导图I为灰度图像，输入图像P为单通道或者三通道图像
cv::Mat GuidedFilter::myGuidedFilter_GrayGuided(cv::Mat guidedImg, cv::Mat inputImg, int radius, double eps)
{
CV_Assert(guidedImg.channels() == 1);
CV_Assert(inputImg.channels() == 1 || inputImg.channels() == 3);
CV_Assert(guidedImg.rows == inputImg.rows && guidedImg.cols == inputImg.cols);
int type = CV_64FC1;
cv::Mat I, P, output;
inputImg.convertTo(P, type);
guidedImg.convertTo(I, type);

//判断输入图像是单通道还是三通道
int channel = inputImg.channels();
switch (channel)
{
case 1:
output = runGuidedFilter_Gray(I, P, type, radius, eps);
break;
case 3:
{
cv::Mat bgr[3], bgrFilter[3];
cv::split(P, bgr);
for (int chan = 0; chan < channel; chan++)
{
bgrFilter[chan] = runGuidedFilter_Gray(I, bgr[chan], type, radius, eps);
}
cv::merge(bgrFilter, channel, output);
break;
}
default:
cout << "err! input image channel should be 1 or 3! " << endl;
break;
}

return output;
}

//引导图I为三通道图像
cv::Mat GuidedFilter::runGuidedFilter_Color(cv::Mat I, cv::Mat P, int type, int radius, double eps)
{
int channel = I.channels();
int H = I.rows;
int W = I.cols;

cv::Mat bgr[3], meanI[3];
//引导图各通道的均值
split(I, bgr);
for (int chan = 0; chan < channel; chan++)
{
boxFilter(bgr[chan], meanI[chan], type, winSize);
}
//输入图像均值
cv::Mat meanP;
boxFilter(P, meanP, type, winSize);
//引导图各通道与输入图像相乘并求均值
cv::Mat meanIP[3], IP;
for (int chan = 0; chan < channel; chan++)
{
multiply(bgr[chan], P, IP);
boxFilter(IP, meanIP[chan], type, winSize);
}
//引导图各通道与输入图协方差
cv::Mat covIP[3], meanImulP;
for (int chan = 0; chan < channel; chan++)
{
multiply(meanI[chan], meanP, meanImulP);
covIP[chan] = meanIP[chan] - meanImulP;
}

//求引导图协方差矩阵
cv::Mat varI[9], tmp, mean2Tmp, meanTmp2;
int varIdx = 0;
for (int i = 0; i < channel; i++)
{
for (int j = 0; j < channel; j++)
{
multiply(bgr[i], bgr[j], tmp);
boxFilter(tmp, meanTmp2, type, winSize);//mean(I*I)
multiply(meanI[i], meanI[j], mean2Tmp);//meanI*meanI
varI[varIdx] = meanTmp2 - mean2Tmp;
varIdx++;
}
}
//求a，三通道
cv::Mat a[3];
for (int chan = 0; chan < channel; chan++)
{
a[chan] = cv::Mat::zeros(I.size(), type);
}
cv::Mat epsEye = cv::Mat::eye(3, 3, type);
epsEye *= eps;
//公式(19)
for (int y = 0; y < H; y++)
{
double* vData[9];
for (int v = 0; v < 9; v++)
{
vData[v] = (double*)varI[v].ptr<double>(y);
}
double* cData[3];
for (int c = 0; c < 3; c++)
{
cData[c] = (double *)covIP[c].ptr<double>(y);
}
for (int c = 0; c < 3; c++)
{
}
for (int x = 0; x < W; x++)
{
cv::Mat sigma = (cv::Mat_<double>(3, 3) <<
vData[0][x], vData[1][x], vData[2][x],
vData[3][x], vData[4][x], vData[5][x],
vData[6][x], vData[7][x], vData[8][x]
);
sigma += epsEye;
cv::Mat cov_Ip_13 = (cv::Mat_<double>(3, 1) <<
cData[0][x], cData[1][x], cData[2][x]);
cv::Mat tmpA = sigma.inv()*cov_Ip_13;
double* tmpData = tmpA.ptr<double>(0);
for (int c = 0; c < 3; c++)
{
}
}
}

//求b
cv::Mat b = meanP - a[0].mul(meanI[0]) - a[1].mul(meanI[1]) - a[2].mul(meanI[2]);
//b的均值
cv::Mat meanB;
boxFilter(b, meanB, type, winSize);
//a的均值
cv::Mat meanA[3];
for (int c = 0; c < channel; c++)
{
boxFilter(a[c], meanA[c], type, winSize);
}
cv::Mat output = (meanA[0].mul(bgr[0]) + meanA[1].mul(bgr[1]) + meanA[2].mul(bgr[2])) + meanB;

return output;
}

//引导图I为三通道图像，输入图像P为单通道或者三通道图像
cv::Mat GuidedFilter::myGuidedFilter_ColorGuided(cv::Mat guidedImg, cv::Mat inputImg, int radius, double eps)
{
CV_Assert(guidedImg.channels() == 3);
CV_Assert(inputImg.channels() == 1 || inputImg.channels() == 3);
CV_Assert(guidedImg.cols == inputImg.cols && guidedImg.rows == inputImg.rows);
int type = CV_64F;
int channel = inputImg.channels();
cv::Mat I, P, output;
guidedImg.convertTo(I, type);
inputImg.convertTo(P, type);

//判断输入图像是单通道还是三通道
switch (channel)
{
case 1:
output = runGuidedFilter_Color(I, P, type, radius, eps);
break;
case 3:
{
cv::Mat bgr[3], bgrFilter[3];
cv::split(P, bgr);
for (int chan = 0; chan < channel; chan++)
{
bgrFilter[chan] = runGuidedFilter_Color(I, bgr[chan], type, radius, eps);
}
cv::merge(bgrFilter, channel, output);
break;
}
default:
cout << "err! input image channel should be 1 or 3! " << endl;
break;
}

output.convertTo(output, CV_8U);
return output;
}

主函数
#include <opencv2\opencv.hpp>
#include "guidedFilter.h"
#include <iostream>

using namespace std;
using namespace cv;

int main(int argc, char** argv)
{
//if (argc != 2)
//{
//    cout << "Usage: opencv_test <image path>" << endl;
//    return -1;
//}

//char *imgName = argv[1];
char *imgName = "C:\\Users\\VINNO\\Desktop\\src\\cat.jpg";
Mat inputImg;

if (!inputImg.data)
{
cout << "No image data" << endl;
return -1;
}
Mat grayImg , guidedImg;
inputImg.copyTo(guidedImg);

GuidedFilter filter;
grayImg = filter.myGuidedFilter_ColorGuided(inputImg, guidedImg, 80, 0.001);
imwrite("./result.jpg", grayImg);
imshow("", grayImg);
waitKey(0);

return 0;
}

参考资料
[1] K. He, J. Sun, and X. Tang. Guided image filtering. In ECCV, pages 1–14. 2010.
[2] K. He, J. Sun, and X. Tang. Guided image filtering. TPAMI, 35(6):1397–1409, 2013
[3] He K, Sun J. Fast Guided Filter[J]. Computer Science, 2015.


展开全文
• 导向滤波  下引用 https://blog.csdn.net/baimafujinji/article/details/74750283 的一段话来说明导向滤波的作用：  无论是简单平滑，还是高斯平滑，它们都有一个共同的弱点，即它们都属于各向同性滤波。...
滤波系列：

均值滤波

中值滤波
高斯滤波
双边滤波
导向滤波

下引用 https://blog.csdn.net/baimafujinji/article/details/74750283 的一段话来说明导向滤波的作用：

无论是简单平滑，还是高斯平滑，它们都有一个共同的弱点，即它们都属于各向同性滤波。我们都知道，一幅自然的图像可以被看成是有（过渡平缓的，也就是梯度较小）区域和（过渡尖锐的，也就是梯度较大）边缘（也包括图像的纹理、细节等）共同组成的。噪声是影响图像质量的不利因素，我们希望将其滤除。噪声的特点通常是以其为中心的各个方向上梯度都较大而且相差不多。边缘则不同，边缘相比于区域也会出现梯度的越变，但是边缘只有在其法向方向上才会出现较大的梯度，而在切向方向上梯度较小。

因此，对于各向同性滤波（例如简单平滑或高斯平滑）而言，它们对待噪声和边缘信息都采取一直的态度。结果，噪声被磨平的同时，图像中具有重要地位的边缘、纹理和细节也同时被抹平了。这是我们所不希望看到的。研究人员已经提出了很多Edge-perserving的图像降噪（平滑）算法，例如双边滤波、自适应（维纳）平滑滤波（请参见文献【1】）、基于PM方程的各向异性滤波以及基于TV-norm的降噪算法等。本文将考虑在文献【2】中提出的另外一种Edge-perserving的图像滤波（平滑）算法——导向滤波（Guided Filter）。当然，通过阅读文献【2】，我们也知道导向滤波的应用不止有Edge-perserving的图像平滑，还包括图像去雾、图像Matting等等。

下给出处理流程图：

从图中也可以看出，导向滤波的输入为两个，一个是真实的输入p，另一个是引导输入I。输出为q，是p和I共同作用的产物。

实现代码：

#include<opencv2/core/core.hpp>
#include<opencv2/imgproc/imgproc.hpp>
#include<opencv2/highgui/highgui.hpp>
#include<iostream>
using namespace std;
using namespace cv;
//导向滤波器
Mat guidedfilter(Mat &srcImage, Mat &srcClone, int r, double eps)
{
//转换源图像信息
srcImage.convertTo(srcImage, CV_64FC1);
srcClone.convertTo(srcClone, CV_64FC1);
int nRows = srcImage.rows;
int nCols = srcImage.cols;
Mat boxResult;
//步骤一：计算均值
boxFilter(Mat::ones(nRows, nCols, srcImage.type()),
boxResult, CV_64FC1, Size(r, r));
//生成导向均值mean_I
Mat mean_I;
boxFilter(srcImage, mean_I, CV_64FC1, Size(r, r));
//生成原始均值mean_p
Mat mean_p;
boxFilter(srcClone, mean_p, CV_64FC1, Size(r, r));
//生成互相关均值mean_Ip
Mat mean_Ip;
boxFilter(srcImage.mul(srcClone), mean_Ip,
CV_64FC1, Size(r, r));
Mat cov_Ip = mean_Ip - mean_I.mul(mean_p);
//生成自相关均值mean_II
Mat mean_II;
//应用盒滤波器计算相关的值
boxFilter(srcImage.mul(srcImage), mean_II,
CV_64FC1, Size(r, r));
//步骤二：计算相关系数
Mat var_I = mean_II - mean_I.mul(mean_I);
Mat var_Ip = mean_Ip - mean_I.mul(mean_p);
//步骤三：计算参数系数a,b
Mat a = cov_Ip / (var_I + eps);
Mat b = mean_p - a.mul(mean_I);
//步骤四：计算系数a\b的均值
Mat mean_a;
boxFilter(a, mean_a, CV_64FC1, Size(r, r));
mean_a = mean_a / boxResult;
Mat mean_b;
boxFilter(b, mean_b, CV_64FC1, Size(r, r));
mean_b = mean_b / boxResult;
//步骤五：生成输出矩阵
Mat resultMat = mean_a.mul(srcImage) + mean_b;
return resultMat;
}
void main()
{
if (!srcImage.data){
cout << "falied to read" << endl;
system("pause");
return;
}
imshow("srcImage", srcImage);
//通道分离
vector<Mat> vSrcImage, vResultImage;
split(srcImage, vSrcImage);
Mat resultMat;
for (int i = 0; i < 3; i++){
//分通道转换成浮点型
Mat tempImage;
vSrcImage[i].convertTo(tempImage, CV_64FC1, 1.0 / 255.0);
Mat p = tempImage.clone();
//分别进行导向滤波
Mat resultImage = guidedfilter(tempImage, p, 10, 0.01);
vResultImage.push_back(resultImage);
}
//通道结果合并
merge(vResultImage, resultMat);
imshow("resultMat", resultMat);
waitKey(0);
}

实现效果：


展开全文
• 无论是简单平滑，还是高斯平滑，它们都有一个共同的弱点，即它们都属于各向同性滤波。一幅自然的图像可以被看成是有（过渡平缓的，也就是梯度较小）区域和（过渡尖锐的，也就是梯度较大）边缘（也包括图像的纹理、...
无论是简单平滑，还是高斯平滑，它们都有一个共同的弱点，即它们都属于各向同性滤波。一幅自然的图像可以被看成是有（过渡平缓的，也就是梯度较小）区域和（过渡尖锐的，也就是梯度较大）边缘（也包括图像的纹理、细节等）共同组成的。
噪声是影响图像质量的不利因素，我们希望将其滤除。
噪声的特点通常是以其为中心的各个方向上梯度都较大而且相差不多。
边缘则不同，边缘相比于区域也会出现梯度的越变，但是边缘只有在其法向方向上才会出现较大的梯度，而在切向方向上梯度较小。
因此，对于各向同性滤波（例如简单平滑或高斯平滑）而言，它们对待噪声和边缘信息都采取一直的态度。结果，噪声被磨平的同时，图像中具有重要地位的边缘、纹理和细节也同时被抹平了。这是我们所不希望看到的。
Edge-perserving的图像降噪（平滑）算法：
双边滤波、自适应（维纳）平滑滤波（请参见文献【1】）
基于PM方程的各向异性滤波以及基于TV-norm的降噪算法等
本文将考虑在文献【2】中提出的另外一种Edge-perserving的图像滤波（平滑）算法——导向滤波（Guided Filter）。
导向滤波的应用不止有Edge-perserving的图像平滑，还包括图像去雾、图像Matting等等。


展开全文
• 本文素材主要来自何凯明的导向滤波，需要更精细的理解可以拜读原文 1.优点 ———————————————————— 噪声和边缘的区别，噪声一般周围的像素梯度变化较大，并且以其为中心，向四周的梯度大体相似...
• 前言 在图像处理上，导向滤波器（Guided Image Filter）是一种能使图像平滑化的非线性滤波器。...双边滤波器因为数学模型的缘故，在某些时候会发生梯度反转（gradient reverse）的状况，出现图像有损；
• 系统分析了滚动导向滤波的参数,根据参数变化的规律提出一种基于滚动导向滤波的混合多尺度分解方法,并基于此方法将红外与可见光图像分解到基本层、小尺度层和大尺度层。在基本层上使用像素能量与梯度能量相结合的融合...
• 现在从一个最简单的情形来开始我们的讨论。...我们都知道，一幅自然的图像可以被看成是有（过渡平缓的，也就是梯度较小）区域和（过渡尖锐的，也就是梯度较大）边缘（也包括图像的纹理、细节等）共同组成的。...
• 引导滤波（导向滤波）的目的是，保持双边滤波的优势（有效保持边缘，非迭代计算），而克服双边滤波的缺点（设计一种时间复杂度为 O(1) 的快速滤波器，而且在主要边缘附近没有梯度的变形） 引导滤波（导向滤波）不仅...
•  引导滤波（导向滤波）的目的是，保持双边滤波的优势（有效保持边缘，非迭代计算），而克服双边滤波的缺点（设计一种时间复杂度为 O(1) 的快速滤波器，而且在主要边缘附近没有梯度的变形）。 本次实验采取的方法是...
• 采用导向信息，对cost volume滤波，保存边缘信息的平滑，计算时采用了GPU，速度为25FPS cost包括两个因子：1.色彩差异；2.梯度差异 ...2.导向滤波（见blog） 3.互为参考图，纠正错误dispartiy值 结果图：
• 局部预处理可以分为二种，一种是平滑，一种是梯度算子。...常见的有基于二维离散卷积的高斯平滑、均值平滑、基于统计学习方法的中值平滑，具备保持边缘的双边滤波、导向滤波等。 OpenCV提供函数cv2.filte...
• 在代价聚合阶段,使用基于自适应支持域的导向滤波;在视差细化阶段,提出一套基于自适应支持域的多步细化方法,通过该方法得到最终的视差图。实验结果表明,视差细化后全部区域的平均误差和方均根误差平均减少43.7%和38%,...
• 4.5.1 导向滤波.. 166 4.5.2 图像污点修复 169 4.5.3 旋转文本图像矫正. 172 4.6 小结. 178 第5 章进阶篇——边缘检测技术.. 179 5.1 边缘检测基础. 180 5.1.1 边缘检测概念 180 5.1.2 梯度算子.. 180 5.1.3 一阶...