【C++】图像处理中的滤波算法(四)

简介: 总结一下图像处理中常用的几种滤波算法,包括中值、均值、高斯、双边、引导滤波这五种,主要用于图像平滑去噪方面。滤波算法的基本思路,就是采用周边像素,加权平均计算一个新的像素,来缓减噪声对当前像素的影响。

引导滤波

导向图滤波(Guided Filter)是一种能使视频平滑化的非线性滤波器,通过一张引导图G,对目标图像P(输入图像)进行滤波处理,使得最后的输出图像大体上与目标图像P相似,但是纹理部分与引导图G相似。应用有两个:保边图像平滑,抠图。

引导滤波是由何凯明等人于2010年发表在ECCV的文章《Guided Image Filtering》中提出的,后续于2013年发表了改进算法快速引导滤波的实现。它与双边滤波最大的相似之处,就是同样具有保持边缘特性。该模型认为,某函数上一点与其邻近部分的点成线性关系,一个复杂的函数就可以用很多局部的线性函数来表示,当需要求该函数上某一点的值时,只需计算所有包含该点的线性函数的值并做平均即可。这种模型,在表示非解析函数上,非常有用。

在滤波效果上,引导滤波和双边滤波差不多,在一些细节上,引导滤波较好。引导滤波最大的优势在于,可以写出时间复杂度与窗口大小无关的算法,因此在使用大窗口处理图片时,其效率更高。

e07f0fdb38694349bbe45e70907bebcf.png

引导图像I,原图P,公式如下:

dfb873163b9548508b7952a07f8f348f.jpg

引导滤波算法,目前opencv没有提供API,伪代码如下:

40166d864f51495484f06dad4f22f38e.png

实现这种算法的关键思想是盒式滤波(box filter),而且必须是通过积分图来实现的盒式滤波,否则不可能与窗口大小无关,好在OpenCV的boxFilter函数满足这个要求。与均值滤波不同的是,方框滤波不会计算像素的均值。在均值滤波中,滤波结果的像素值是任意一个点的邻域平均值,等于各邻域像素值之和除以邻域面积。而在方框滤波中,可以自由选择是否对均值滤波的结果进行归一化,即可以自由选择滤波结果是邻域像素值之和的平均值,还是邻域像素值之和。

CV_EXPORTS_WvoidboxFilter(InputArraysrc,OutputArraydst, intddepth, 
Sizeksize, Pointanchor=Point(-1,-1), boolnormalize=true, 
intborderType=BORDER_DEFAULT) 

165089fb93d242f48a2bfe29fc910924.png

c0bdb56d27c6427aba38608de3db0caa.png

C++实现:

#include <iostream>#include <opencv2/core.hpp>#include <opencv2/highgui.hpp>#include <opencv2/imgproc.hpp>////   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)//   -local window radius : r//   -regularization parameter : eps/cv::MatGuidedFilter(cv::Mat&I, cv::Mat&p, intr, doubleeps){
intwsize=2*r+1;
//数据类型转换I.convertTo(I, CV_64F, 1.0/255.0);
p.convertTo(p, CV_64F, 1.0/255.0);
//meanI=fmean(I)cv::Matmean_I;
cv::boxFilter(I, mean_I, -1, cv::Size(wsize, wsize), cv::Point(-1, -1), true, cv::BORDER_REFLECT);//盒子滤波//meanP=fmean(P)cv::Matmean_p;
cv::boxFilter(p, mean_p, -1, cv::Size(wsize, wsize), cv::Point(-1, -1), true, cv::BORDER_REFLECT);//盒子滤波//corrI=fmean(I.*I)cv::Matmean_II;
mean_II=I.mul(I);
cv::boxFilter(mean_II, mean_II, -1, cv::Size(wsize, wsize), cv::Point(-1, -1), true, cv::BORDER_REFLECT);//盒子滤波//corrIp=fmean(I.*p)cv::Matmean_Ip;
mean_Ip=I.mul(p);
cv::boxFilter(mean_Ip, mean_Ip, -1, cv::Size(wsize, wsize), cv::Point(-1, -1), true, cv::BORDER_REFLECT);//盒子滤波//varI=corrI-meanI.*meanIcv::Matvar_I, mean_mul_I;
mean_mul_I=mean_I.mul(mean_I);
cv::subtract(mean_II, mean_mul_I, var_I);
//covIp=corrIp-meanI.*meanpcv::Matcov_Ip;
cv::subtract(mean_Ip, mean_I.mul(mean_p), cov_Ip);
//a=conIp./(varI+eps)//b=meanp-a.*meanIcv::Mata, b;
cv::divide(cov_Ip, (var_I+eps),a);
cv::subtract(mean_p, a.mul(mean_I), b);
//meana=fmean(a)//meanb=fmean(b)cv::Matmean_a, mean_b;
cv::boxFilter(a, mean_a, -1, cv::Size(wsize, wsize), cv::Point(-1, -1), true, cv::BORDER_REFLECT);//盒子滤波cv::boxFilter(b, mean_b, -1, cv::Size(wsize, wsize), cv::Point(-1, -1), true, cv::BORDER_REFLECT);//盒子滤波//q=meana.*I+meanbcv::Matq;
q=mean_a.mul(I) +mean_b;
//数据类型转换I.convertTo(I, CV_8U, 255);
p.convertTo(p, CV_8U, 255);
q.convertTo(q, CV_8U, 255);
returnq;
}
intmain(){
cv::Matsrc=cv::imread("I:\\Learning-and-Practice\\2019Change\\Image process algorithm\\Img\\woman.jpg");
if (src.empty()){
return-1;
    }
//if (src.channels() > 1)  //  cv::cvtColor(src, src, CV_RGB2GRAY);//自编GuidedFilter测试doublet2= (double)cv::getTickCount(); //测时间cv::Matdst1, src_input, I;
src.copyTo(src_input);
if (src.channels() >1)
cv::cvtColor(src, I, CV_RGB2GRAY); //若引导图为彩色图,则转为灰度图std::vector<cv::Mat>p,q;
if (src.channels() >1){             //输入为彩色图cv::split(src_input, p);
for (inti=0; i<src.channels(); ++i){
dst1=GuidedFilter(I, p[i], 9, 0.1*0.1);
q.push_back(dst1);
        }
cv::merge(q, dst1);
    }
else{                               //输入为灰度图src.copyTo(I);
dst1=GuidedFilter(I, src_input, 9, 0.1*0.1);
    }
t2= (double)cv::getTickCount() -t2;
doubletime2= (t2*1000.) / ((double)cv::getTickFrequency());
std::cout<<"MyGuidedFilter_process="<<time2<<" ms. "<<std::endl<<std::endl;
cv::namedWindow("GuidedImg", CV_WINDOW_NORMAL);
cv::imshow("GuidedImg", I);
cv::namedWindow("src", CV_WINDOW_NORMAL);
cv::imshow("src", src);
cv::namedWindow("GuidedFilter_box", CV_WINDOW_NORMAL);
cv::imshow("GuidedFilter_box", dst1);
cv::waitKey(0);
}
目录
相关文章
|
2月前
|
算法 测试技术 C++
【动态规划算法】蓝桥杯填充问题(C/C++)
【动态规划算法】蓝桥杯填充问题(C/C++)
|
2月前
|
存储 算法 C++
高精度算法(加、减、乘、除,使用c++实现)
高精度算法(加、减、乘、除,使用c++实现)
670 0
高精度算法(加、减、乘、除,使用c++实现)
|
2月前
|
算法 数据处理 C++
c++ STL划分算法;partition()、partition_copy()、stable_partition()、partition_point()详解
这些算法是C++ STL中处理和组织数据的强大工具,能够高效地实现复杂的数据处理逻辑。理解它们的差异和应用场景,将有助于编写更加高效和清晰的C++代码。
45 0
|
2月前
|
存储 算法 决策智能
【算法】博弈论(C/C++)
【算法】博弈论(C/C++)
|
2月前
|
存储 算法 C++
【算法】哈希映射(C/C++)
【算法】哈希映射(C/C++)
|
2月前
|
机器学习/深度学习 人工智能 算法
【算法】最长公共子序列(C/C++)
【算法】最长公共子序列(C/C++)
|
2月前
|
人工智能 算法 BI
一篇带你速通差分算法(C/C++)
一篇带你速通差分算法(C/C++)
|
2月前
|
人工智能 算法 C++
一篇带你速通前缀和算法(C/C++)
一篇带你速通前缀和算法(C/C++)
|
2月前
|
存储 算法 C++
弗洛伊德(Floyd)算法(C/C++)
弗洛伊德(Floyd)算法(C/C++)
|
2月前
|
存储 算法 程序员
迪杰斯特拉(Dijkstra)算法(C/C++)
迪杰斯特拉(Dijkstra)算法(C/C++)