好久没更博客了。去年年底跳了槽,转回了工业检测领域,忙于找工作和开发新算法,同时担心泄露技术秘密,所以一直没有更新博客。刚过去的三个月试用期里开发了两个原创算法,一个已经申请专利(涉及工业品区域边界轮廓提取),一个正准备申请(涉及复杂纹理下的圆孔提取),也算是值得骄傲的一件事了。待专利授权下来后,我可以给大家讲一讲这两个新算法,目前就暂且保密啦。言归正传,下面给大家分享一个个人编写的一些基础算法的代码。

引导滤波和边窗滤波都是近几年出现的快速高效好用的滤波器。引导滤波器可以让输入图像学习引导图像的纹理信息,具有O(N)的计算复杂度,当引导图像就是输入图像本身时,引导滤波还能起到保边滤波的作用。边窗滤波则是采用半窗口甚至1/4窗口内的像素值滤波来代替常规的全窗口滤波,通过选择枚举的8个半窗口与1/4窗口滤波器滤波结果中与原始值最接近的一个来作为当前点滤波结果,可以有效避免在边缘处因为全窗口跨越两个截然不同的区域所造成的边缘扩散问题,达到保边效果,方法非常简单直观,效果却出类拔萃。这种重视捕捉直觉并将其抽象出来的算法开发思想值得我们学习。这里本人分享一下本人实现的这两种滤波器的代码以帮助大家避免不必要的重复劳动(国内太缺乏优质博客与开源精神了)。其中,引导滤波只实现了单通道版,三通道版需要用到协方差,这个工作就留给各位读者了(头文件读者自己添加吧)。

guidedFilter代码:

Mat guidedFilter(const cv::Mat& inputImg, const cv::Mat& guideImg, int iBoxFiltRadius, float eps)
{Mat inputImgF, guideImgF;inputImg.convertTo(inputImgF, CV_32F);guideImg.convertTo(guideImgF, CV_32F);Mat productImg = inputImgF.mul(guideImgF);Mat onesImg = Mat::ones(inputImgF.size(), CV_32F);Mat bfOnesImg, bfInputImg, bfGuideImg, bfProductImg, bfSqureGuideImg;boxFilter(onesImg, bfOnesImg, CV_32F, Size(2 * iBoxFiltRadius + 1, 2 * iBoxFiltRadius + 1), Point(-1, -1), false);boxFilter(inputImgF, bfInputImg, CV_32F, Size(2 * iBoxFiltRadius + 1, 2 * iBoxFiltRadius + 1), Point(-1, -1), false);boxFilter(guideImgF, bfGuideImg, CV_32F, Size(2 * iBoxFiltRadius + 1, 2 * iBoxFiltRadius + 1), Point(-1, -1), false);boxFilter(productImg, bfProductImg, CV_32F, Size(2 * iBoxFiltRadius + 1, 2 * iBoxFiltRadius + 1), Point(-1, -1), false);boxFilter(guideImgF.mul(guideImgF), bfSqureGuideImg, CV_32F, Size(2 * iBoxFiltRadius + 1, 2 * iBoxFiltRadius + 1), Point(-1, -1), false);divide(bfInputImg, bfOnesImg, bfInputImg);divide(bfGuideImg, bfOnesImg, bfGuideImg);divide(bfProductImg, bfOnesImg, bfProductImg);divide(bfSqureGuideImg, bfOnesImg, bfSqureGuideImg);//mean(I*G)-mean(I)*mean(G)及mean(G*G)-mean(G)*mean(G)Mat varIG = bfProductImg - bfInputImg.mul(bfGuideImg);Mat varG = bfSqureGuideImg - bfGuideImg.mul(bfGuideImg);//a=VarIG/(VarI+eps); b=mean(inputImgF)-a*mean(guideImgF)Mat a, b;divide(varIG, varG + eps, a);b = bfInputImg - a.mul(bfGuideImg);Mat bfA, bfB;boxFilter(a, bfA, CV_32F, Size(2 * iBoxFiltRadius + 1, 2 * iBoxFiltRadius + 1), Point(-1, -1), false);boxFilter(b, bfB, CV_32F, Size(2 * iBoxFiltRadius + 1, 2 * iBoxFiltRadius + 1), Point(-1, -1), false);divide(bfA, bfOnesImg, bfA);divide(bfB, bfOnesImg, bfB);Mat filtedImg = bfA.mul(guideImgF) + bfB;if (inputImg.type() == CV_32F){return filtedImg;}else{Mat outputImg;filtedImg.convertTo(outputImg, inputImg.type());return outputImg;}
}

sideWindowBoxFilter代码:

void SideWindowBoxFilter(Mat& srcImg, Mat& dstImg, int r = 4, int interation = 1)
{int channels = srcImg.channels();int height = srcImg.rows;int width = srcImg.cols;Mat disImg = Mat::zeros(Size(width, height), CV_32F);Mat disImgArr[8] = { disImg.clone(),disImg.clone(),disImg.clone(),disImg.clone(),disImg.clone(),disImg.clone(),disImg.clone(),disImg.clone() };vector<Mat> vecChannels;if (channels > 1){split(srcImg, vecChannels);}else{vecChannels.push_back(srcImg.clone());}vector<Mat> vecDstChannels;//构造滤波器Mat kU = Mat::zeros(2 * r + 1, 1, CV_32F);kU(Range(0, r + 1), Range(0, 1)) = 1;Mat kD = Mat::zeros(2 * r + 1, 1, CV_32F);kD(Range(r, 2 * r + 1), Range(0, 1)) = 1;Mat kL = Mat::zeros(1, 2 * r + 1, CV_32F);kL(Range(0, 1), Range(0, r + 1)) = 1;Mat kR = Mat::zeros(1, 2 * r + 1, CV_32F);kR(Range(0, 1), Range(r, 2 * r + 1)) = 1;Mat AllOneKerUD = Mat::ones(2 * r + 1, 1, CV_32F);Mat AllOneKerLR = Mat::ones(1, 2 * r + 1, CV_32F);Mat filtedImg0, filtedImg1, filtedImg2, filtedImg3, filtedImg4, filtedImg5, filtedImg6, filtedImg7;Mat filtedImgArr[8] = { disImg.clone(),disImg.clone(),disImg.clone(),disImg.clone(),disImg.clone(),disImg.clone(),disImg.clone(),disImg.clone() };for (int ch = 0; ch < channels; ch++){Mat chImg = vecChannels[ch];if (chImg.type() != CV_32F){chImg.convertTo(chImg, CV_32F);}Mat padChImg;copyMakeBorder(chImg, padChImg, r, r, r, r, BORDER_REPLICATE);for (int iter = 0; iter < interation; iter++){sepFilter2D(padChImg, filtedImg0, CV_32F, kL, kU, Point(-1, -1), 0, BORDER_CONSTANT);filtedImgArr[0] = filtedImg0 / ((r + 1)*(r + 1));disImgArr[0] = abs(filtedImgArr[0] - padChImg);sepFilter2D(padChImg, filtedImg1, CV_32F, kL, kD, Point(-1, -1), 0, BORDER_CONSTANT);filtedImgArr[1] = filtedImg1 / ((r + 1)*(r + 1));disImgArr[1] = abs(filtedImgArr[1] - padChImg);sepFilter2D(padChImg, filtedImg2, CV_32F, kR, kU, Point(-1, -1), 0, BORDER_CONSTANT);filtedImgArr[2] = filtedImg2 / ((r + 1)*(r + 1));disImgArr[2] = abs(filtedImgArr[2] - padChImg);sepFilter2D(padChImg, filtedImg3, CV_32F, kR, kD, Point(-1, -1), 0, BORDER_CONSTANT);filtedImgArr[3] = filtedImg3 / ((r + 1)*(r + 1));disImgArr[3] = abs(filtedImgArr[3] - padChImg);sepFilter2D(padChImg, filtedImg4, CV_32F, AllOneKerLR, kU, Point(-1, -1), 0, BORDER_CONSTANT);filtedImgArr[4] = filtedImg4 / ((r + 1)*(2 * r + 1));disImgArr[4] = abs(filtedImgArr[4] - padChImg);sepFilter2D(padChImg, filtedImg5, CV_32F, AllOneKerLR, kD, Point(-1, -1), 0, BORDER_CONSTANT);filtedImgArr[5] = filtedImg5 / ((r + 1)*(2 * r + 1));disImgArr[5] = abs(filtedImgArr[5] - padChImg);sepFilter2D(padChImg, filtedImg6, CV_32F, kL, AllOneKerUD, Point(-1, -1), 0, BORDER_CONSTANT);filtedImgArr[6] = filtedImg6 / ((r + 1)*(2 * r + 1));disImgArr[6] = abs(filtedImgArr[6] - padChImg);sepFilter2D(padChImg, filtedImg7, CV_32F, kR, AllOneKerUD, Point(-1, -1), 0, BORDER_CONSTANT);filtedImgArr[7] = filtedImg7 / ((r + 1)*(2 * r + 1));disImgArr[7] = abs(filtedImgArr[7] - padChImg);for (int row = 0; row < padChImg.rows; row++){for (int col = 0; col < padChImg.cols; col++){int idxMin = 0;float minVal = FLT_MAX;for (int k = 0; k < 8; k++){if (disImgArr[k].at<float>(row, col) < minVal){minVal = disImgArr[k].at<float>(row, col);idxMin = k;}}padChImg.at<float>(row, col) = filtedImgArr[idxMin].at<float>(row, col);}}}padChImg(Range(r, padChImg.rows - r), Range(r, padChImg.cols - r)).copyTo(chImg);if (vecChannels[ch].type() != CV_32F){chImg.convertTo(chImg, vecChannels[ch].type());}vecDstChannels.push_back(chImg);}if (channels > 1){merge(vecDstChannels, dstImg);}else{dstImg = vecDstChannels[0];}
}

输入图像:

灰度图:

引导滤波处理结果(半径:60,eps:0.001*255^2):

处理前后差值图像(放大了30倍):

可以看到,头发丝、衣服边缘等锐利边缘改变得很少,较平滑的区域和小尺度纹理改变得较多,符合保边滤波的要求。

边窗滤波结果(半径:9):

保边滤波效果显而易见。

引导滤波(guidedFilter)与边窗盒式滤波(sideWindowBoxFilter)的C++与OpenCV实现相关推荐

  1. 导向滤波算法 java_一种基于双通道先验和侧窗导向滤波的单幅图像去雾方法与流程...

    本发明属于计算机图像处理的领域,用于图像或者视频去雾等相关领域:具体涉及一种基于双通道先验和侧窗导向滤波的单幅图像去雾方法. 背景技术: 图像采集过程中,由于雾天的影响,使得景物的能见度大幅降低,再加 ...

  2. 引导滤波GuidedFilter

    何恺明读博士提出基于暗通道采用引导滤波去雾算法获CVPR2009最佳论文,现在应用面很广.很广:能够克服双边滤波的梯度翻转现象,在滤波后图像的细节上更优,主要美颜算法差不多都用这个. 先贴伪代码: 实 ...

  3. 盒式滤波_如何数字化/备份盒式磁带和其他旧媒体

    盒式滤波 If you have some old cassette tapes lying around, it's a good idea to digitize and back them up ...

  4. 快速导向滤波 matlab,导向滤波小结:从导向滤波(guided filter)到快速导向滤波(fast guide filter)的原理,应用及opencv实现代码...

    http://blog.csdn.net/kuweicai/article/details/78385871 1. 导向滤波简介 导向滤波是何凯明在学生时代提出的一个保边滤波(edge-preserv ...

  5. 导向滤波小结:从导向滤波(guided filter)到快速导向滤波(fast guide filter)的原理,应用及opencv实现代码

    1. 导向滤波简介 导向滤波是何凯明在学生时代提出的一个保边滤波(edge-preserving smoothing)算法.何凯明在cv圈应该算是名人了,学生时代关于图像去雾的研究就以第一作者的身份获 ...

  6. 三种经典图像滤波方法介绍——双边滤波(Bilateral filter)、导向滤波(Guided Fliter)、滚动导向滤波(RollingGuidedFilter)

    文章目录 一.前言 二.双边滤波(Bilateral filter) 2.1 双边滤波的理论介绍及公式推导 2.2 双边滤波的matlab程序实现 三.导向滤波(Guided Fliter) 3.1 ...

  7. opencv python 高斯滤波_OpenCV 学习:8 高斯滤波GaussianBlur

    1 什么是高斯滤波? 高斯滤波是一种线性平滑滤波,适用于消除高斯噪声,广泛应用于图像处理的减噪过程.[1]通俗的讲,高斯滤波就是对整幅图像进行加权平均的过程,每一个像素点的值,都由其本身和邻域内的其他 ...

  8. 图像处理:图像复原与重建之逆滤波、维纳滤波、约束最小二乘滤波——Matlab实现

    参考资料: 陷波滤波器-matlab实现 http://blog.sina.com.cn/s/blog_ebd29d830102wdzw.html 图像复原之约束最小二乘方滤波 https://blo ...

  9. 第5章 Python 数字图像处理(DIP) - 图像复原与重建12 - 空间滤波 - 使用频率域滤波降低周期噪声 - 陷波滤波、最优陷波滤波

    标题 使用频率域滤波降低周期噪声 陷波滤波深入介绍 最优陷波滤波 本章陷波滤波器有部分得出的结果不佳,如果有更好的解决方案,请赐教,不胜感激. 使用频率域滤波降低周期噪声 陷波滤波深入介绍 零相移滤波 ...

最新文章

  1. python数据结构与算法:队列与双端队列
  2. python好学嘛-Python对于没有计算机基础知识的人来说,好学吗?
  3. 一文讲透 “进程、线程、协程”
  4. java xheditor 上传图片_xhEditor粘贴图片自动上传到服务器(Java版)
  5. 底层实现红黑树_图解:红黑树
  6. vue页面渲染(请求返回的后端)data,文本换行与显示bug 的分析与解决提示
  7. [Winodows Phone 7控件详解]Silverlight toolkit for Windows Phone 7.1控件-3
  8. erlang四大behaviour简述
  9. IntelliJ IDEA 快捷键 Windows
  10. 【啊哈!算法】算法6:只有五行的Floyd最短路算法
  11. node http创建正向代理_Node.JS实战20:用execFile执行外部程序
  12. win7计算机系统减肥,怎样给win7瘦身 win7瘦身攻略
  13. jquery-重要的方法和注意事项
  14. jdk8中新增的日期处理类LocalDate,LocalTime,LocalDateTime,ZoneId,ZonedDateTime详解
  15. R 添加使用mac字体
  16. alta公司1553b板卡编程相关
  17. XMind: ZEN 快捷键超强盘点
  18. HDU4847-Wow! Such Doge!
  19. DP1332E NFC刷卡芯片内置mcu
  20. 2022年百度竞价推广效果不好了?怎么做?

热门文章

  1. iOS开发之直播App流程介绍
  2. 【论文精读】Shape-optimizing hybrid warping for image stitching
  3. 计算机网络实验指导书谢希仁,计算机网络(谢希仁)实验指导书.doc
  4. MPU6050 MPU6500 MPU9250 使用心得
  5. 用java编写一个魔塔地图生成器
  6. 白话 垃圾回收之对象优先在Eden分配
  7. 一条命令将windows下多个ts文件合并为一个ts文件
  8. 用go语言撸一个简易版的区块链
  9. 滴滴前端高频react面试题总结
  10. 我的PhoneGap安装配置经历