Bilateral Filtering for Gray and Color Images

双边滤波器:保留边界的平滑滤波器。 在局部上,就是在灰度值差异不大的区域平滑,在灰度值差异比较大的边界地区保留边界。所以双边滤波器作用于每个像素的同时,必然会受到领域像素点的距离、灰度值差的权重影响。

已知低通滤波可以表示为:

range filter可以表示为:(range filter 试选定一个数值范围,再做滤波的一个操作)

所以,双边滤波器的定义是:

其中,k(x)是归一化(normalize)函数,

( f 表示原图像,h 表示处理后的图像 x 表示 h 中某个像素点位置,ξ 表示 f 中x位置像素点的邻域像素,f(ξ)表示该像素点的灰度值,c表示低通滤波, s表示range filter)

其中,

  1. //Filters.h
  2.  
  3. #ifndef FILTERS_H
  4. #define FILTERS_H
  5.  
  6. #include "opencv2/imgproc.hpp"
  7. #include "opencv2/highgui.hpp"
  8. #include "opencv2/core.hpp"
  9.  
  10. #include <iostream>
  11. #include <cmath>
  12.  
  13. //Bilateral Filtering
  14. //sigmaD == sigmaSpace, sigmaR == sigmaColor
  15. cv::Mat BilateralFilter(cv::Mat inputImg, int filterSize, double sigmaD, double sigmaR);
  16.  
  17. cv::Mat fastBilateralFilter(cv::Mat inputImg, int filterSize, double sigmaD, double sigmaR);
  18.  
  19. #endif // ! FILTERS_H
  1. //Filters.cpp
  2.  
  3. #include "Filters.h"
  4.  
  5. double SpaceFactor(int x1, int y1, int x2, int y2, double sigmaD) {
  6. double absX = pow(abs(x1 - x2), );
  7. double absY = pow(abs(y1 - y2), );
  8.  
  9. return exp(-(absX + absY) / ( * pow(sigmaD, )));
  10. }
  11.  
  12. double ColorFactor(int x, int y, double sigmaR) {
  13. double distance = abs(x - y) / sigmaR;
  14. return exp(-0.5 * pow(distance, ));
  15. }
  16.  
  17. cv::Mat BilateralFilter(cv::Mat inputImg, int filterSize, double sigmaD, double sigmaR) {
  18. int len; //must be odd number
  19. cv::Mat gray; // must be 1-channel image
  20. cv::Mat LabImage; // if channels == 3
  21.  
  22. if (filterSize % != || filterSize <= ) {
  23. std::cerr << "Filter Size must be a positive odd number!" << std::endl;
  24. return inputImg;
  25. }
  26. len = filterSize / ;
  27.  
  28. if (inputImg.channels() >= ) {
  29. cv::cvtColor(inputImg, LabImage, cv::COLOR_BGR2Lab);
  30. gray = cv::Mat::zeros(LabImage.size(), CV_8UC1);
  31. for (int i = ; i < LabImage.rows; i++) {
  32. for (int j = ; j < LabImage.cols; j++) {
  33. gray.ptr<uchar>(i)[j] = LabImage.ptr<uchar>(i, j)[];
  34. }
  35. }
  36. }
  37. else if(inputImg.channels() == ){
  38. inputImg.copyTo(gray);
  39. }
  40. else {
  41. std::cerr << "the count of input image's channel can not be 2!" << std::endl;
  42. return inputImg;
  43. }
  44.  
  45. cv::Mat resultGrayImg = cv::Mat::zeros(gray.size(), CV_8UC1);
  46. for (int i = ; i < gray.rows; i++) {
  47. for (int j = ; j < gray.cols; j++) {
  48. double k = ;
  49. double f = ;
  50. for (int r = i - len; r <= i + len; r++) {
  51. for (int c = j - len; c <= j + len; c++) {
  52. if (r < || c < || r >= gray.rows || c >= gray.cols)
  53. continue;
  54. f = f + gray.ptr<uchar>(r)[c] * SpaceFactor(i, j, r, c, sigmaD) * ColorFactor(gray.ptr<uchar>(i)[j], gray.ptr<uchar>(r)[c], sigmaD);
  55. k += SpaceFactor(i, j, r, c, sigmaD) * ColorFactor(gray.ptr<uchar>(i)[j], gray.ptr<uchar>(r)[c], sigmaD);
  56. }
  57. }
  58. int value = f / k;
  59. if (value < ) value = ;
  60. else if (value > ) value = ;
  61.  
  62. resultGrayImg.ptr<uchar>(i)[j] = (uchar)value;
  63. }
  64. }
  65.  
  66. cv::Mat resultImg;
  67. if (inputImg.channels() >= ) {
  68. for (int i = ; i < LabImage.rows; i++) {
  69. for (int j = ; j < LabImage.cols; j++) {
  70. LabImage.ptr<uchar>(i, j)[] = resultGrayImg.ptr<uchar>(i)[j];
  71. }
  72. }
  73. cv::cvtColor(LabImage, resultImg, cv::COLOR_Lab2BGR);
  74. }
  75. else {
  76. resultGrayImg.copyTo(resultImg);
  77. }
  78.  
  79. return resultImg;
  80. }
  81.  
  82. cv::Mat fastBilateralFilter(cv::Mat inputImg, int filterSize, double sigmaD, double sigmaR) {
  83. int len; //must be odd number
  84. cv::Mat gray; // must be 1-channel image
  85. cv::Mat LabImage; // if channels == 3
  86.  
  87. if (filterSize % != || filterSize <= ) {
  88. std::cerr << "Filter Size must be a positive odd number!" << std::endl;
  89. return inputImg;
  90. }
  91. len = filterSize / ;
  92.  
  93. if (inputImg.channels() >= ) {
  94. cv::cvtColor(inputImg, LabImage, cv::COLOR_BGR2Lab);
  95. gray = cv::Mat::zeros(LabImage.size(), CV_8UC1);
  96. for (int i = ; i < LabImage.rows; i++) {
  97. for (int j = ; j < LabImage.cols; j++) {
  98. gray.ptr<uchar>(i)[j] = LabImage.ptr<uchar>(i, j)[];
  99. }
  100. }
  101. }
  102. else if (inputImg.channels() == ) {
  103. inputImg.copyTo(gray);
  104. }
  105. else {
  106. std::cerr << "the count of input image's channel can not be 2!" << std::endl;
  107. return inputImg;
  108. }
  109.  
  110. cv::Mat resultGrayImg = cv::Mat::zeros(gray.size(), CV_8UC1);
  111. for (int i = ; i < gray.rows; i++) {
  112. for (int j = ; j < gray.cols; j++) {
  113. double k = ;
  114. double f = ;
  115. double sum = ;
  116. for (int r = i - len; r <= i + len; r++) {
  117. if (r < || r >= gray.rows)
  118. continue;
  119. f = f + gray.ptr<uchar>(r)[j] * SpaceFactor(i, j, r, j, sigmaD) * ColorFactor(gray.ptr<uchar>(i)[j], gray.ptr<uchar>(r)[j], sigmaD);
  120. k += SpaceFactor(i, j, r, j, sigmaD) * ColorFactor(gray.ptr<uchar>(i)[j], gray.ptr<uchar>(r)[j], sigmaD);
  121. }
  122. sum = f / k;
  123. f = k = 0.0;
  124. for (int c = j - len; c <= j + len; c++) {
  125. if (c < || c >= gray.cols)
  126. continue;
  127. f = f + gray.ptr<uchar>(i)[c] * SpaceFactor(i, j, i, c, sigmaD) * ColorFactor(gray.ptr<uchar>(i)[j], gray.ptr<uchar>(i)[c], sigmaD);
  128. k += SpaceFactor(i, j, i, c, sigmaD) * ColorFactor(gray.ptr<uchar>(i)[j], gray.ptr<uchar>(i)[c], sigmaD);
  129. }
  130. int value = (sum + f / k) / ;
  131. if (value < ) value = ;
  132. else if (value > ) value = ;
  133.  
  134. resultGrayImg.ptr<uchar>(i)[j] = (uchar)value;
  135. }
  136. }
  137.  
  138. cv::Mat resultImg;
  139. if (inputImg.channels() >= ) {
  140. for (int i = ; i < LabImage.rows; i++) {
  141. for (int j = ; j < LabImage.cols; j++) {
  142. LabImage.ptr<uchar>(i, j)[] = resultGrayImg.ptr<uchar>(i)[j];
  143. }
  144. }
  145. cv::cvtColor(LabImage, resultImg, cv::COLOR_Lab2BGR);
  146. }
  147. else {
  148. resultGrayImg.copyTo(resultImg);
  149. }
  150.  
  151. return resultImg;
  152. }
  1. //main.cpp
  2.  
  3. #include <iostream>
  4. #include <time.h>
  5.  
  6. #include "Filters.h"
  7.  
  8. using namespace std;
  9.  
  10. int main() {
  11. cv::Mat img = cv::imread("Capture.jpg", cv::IMREAD_UNCHANGED);
  12. clock_t begin_time = clock();
  13. cv::Mat result = BilateralFilter(img, , 12.5, );
  14. std::cout << float(clock() - begin_time) / CLOCKS_PER_SEC << std:: endl;
  15. cv::imshow("original", result);
  16. cv::waitKey();
  17. cv::imwrite("original.jpg", result);
  18.  
  19. begin_time = clock();
  20. result = fastBilateralFilter(img, , 12.5, );
  21. std::cout << float(clock() - begin_time) / CLOCKS_PER_SEC << std::endl;
  22. cv::imshow("fast", result);
  23. cv::waitKey();
  24. cv::imwrite("fast.jpg", result);
  25.  
  26. begin_time = clock();
  27. cv::bilateralFilter(img, result, , , 12.5);
  28. std::cout << float(clock() - begin_time) / CLOCKS_PER_SEC << std::endl;
  29. cv::imshow("opencv", result);
  30. cv::waitKey();
  31. cv::imwrite("opencv.jpg", result);
  32.  
  33. system("pause");
  34. return ;
  35. }

运行结果:

46.889s  5.694s  0.202s

二维算子降成两个一维算子之后,速度加快了一些,但是还是不如opencv的快,效果也比它差一些(No more reinventing the wheel...)

从左至右:“小雀斑”帅气原图、BilateralFilter处理结果、fastBilateralFilter处理结果、opencv接口处理结果

   

【C++】双边滤波器(bilateral filter)的更多相关文章

  1. 【VS开发】【图像处理】双边滤波器bilateral filter

    目录(?)[-] 简介 原理 代码实现 1 Spatial Weight 2 Similarity Weight 3 Color Filtering 在SSAO中的使用 1. 简介 图像平滑是一个重要 ...

  2. Bilateral Filter

    最近在看图像风格化的论文的时候,频繁遇到 Bilateral Filter.google 一波后,发现并不是什么不得了的东西,但它的思想却很有借鉴意义. 简介 Bilateral Filter,中文又 ...

  3. 三维网格去噪算法(bilateral filter)

    受图像双边滤波算法的启发,[Fleishman et al. 2003]和[Jones et al. 2003]分别提出了利用双边滤波算法对噪声网格进行光顺去噪的算法,两篇文章都被收录于当年的SIGG ...

  4. vs2015+opencv3.3.1 实现 c++ 双边滤波器(Bilateral Filter)

    #include <opencv2\highgui\highgui.hpp> #include <iostream> #include<vector> using ...

  5. 卡尔曼滤波器 Kalman Filter (转载)

    在学习卡尔曼滤波器之前,首先看看为什么叫“卡尔曼”.跟其他著名的理论(例如傅立叶变换,泰勒级数等等)一样,卡尔曼也是一个人的名字,而跟他们不同的是,他是个现代人! 卡 尔曼全名Rudolf Emil ...

  6. [转]计算机视觉之跟踪算法——相关滤波器Correlation Filter

    https://blog.csdn.net/victoriaw/article/details/62416759 ASEF相关滤波器: Average of Synthetic Exact Filte ...

  7. 灰度图像--图像增强 双边滤波 Bilateral Filtering

    学习DIP第31天 转载请标明本文出处:http://blog.csdn.net/tonyshengtan,欢迎大家转载,发现博客被某些论坛转载后,图像无法正常显示,无法正常表达本人观点,对此表示很不 ...

  8. 测试卡尔曼滤波器(Kalman Filter)

    真实的温度测试数据,通过加热棒加热一盆水测得的真实数据,X轴是时间秒,Y轴是温度: 1)滤波前 2)滤波后(p=10, q=0.0001, r=0.05, kGain=0;) 2)滤波后(p=10, ...

  9. Atitit   图像处理 平滑 也称 模糊, 归一化块滤波、高斯滤波、中值滤波、双边滤波)

    Atitit   图像处理 平滑 也称 模糊, 归一化块滤波.高斯滤波.中值滤波.双边滤波) 是一项简单且使用频率很高的图像处理方法 用途 去噪 去雾 各种线性滤波器对图像进行平滑处理,相关OpenC ...

随机推荐

  1. codeforces 459E E. Pashmak and Graph(dp+sort)

    题目链接: E. Pashmak and Graph time limit per test 1 second memory limit per test 256 megabytes input st ...

  2. 关于GitHub的DNS基础设施,你了解吗?

    在 GitHub,我们最近从头改进了 DNS.这包括了我们如何与外部 DNS 提供商交互以及我们如何在内部向我们的主机提供记录.为此,我们必须设计和构建一个新的 DNS 基础设施,它可以随着 GitH ...

  3. node npm 总结

    是nodejs的软件包管理器,用于node插件管理 npm install <name> [-g] [--save -dev] name:安装模块的名称 -g:全局安装 --save:将保 ...

  4. 【推荐】 体验SubSonic

    SubSonic简介 SubSonic配置 利用sonic.exe来生成代码 通过Substage来生成代码 简单操作示例 1.SubSonic简介 一句讲完就是:SubSonic就是一个ORM开源框 ...

  5. C++ 指针p1 p2,p1-p2 与*p1-*p2的区别

    p1-p2 指 指针的地址值相减,计算两个指针之间的偏移量 *p1-*p2 指 指针指向的内存地址里面存的数值相减

  6. ubuntu的NAT方式上网配置

    vm菜单栏虚拟机--->设置---->网络适配器---->勾选NAT方式 vi /etc/network/interfaces修改配置文件如下: auto loiface lo in ...

  7. 算法练习--LeetCode--54. Spiral Matrix 100%

      Spiral MatrixMedium Given a matrix of m x n elements (m rows, n columns), return all elements of t ...

  8. 51nod 1103【鸽巢原理】

    思路: 这道题嘛有些弯还是要转的,比如你说让你搞n的倍数,你别老老实实照她的意思去啊,倍数可以除法,取膜 . 因为n个数我们可以求前缀和然后取膜,对n取膜的话有0-n-1种情况,所以方案一定是有的,说 ...

  9. sublime text3 注册码

    —– BEGIN LICENSE —– TwitterInc 200 User License EA7E-890007 1D77F72E 390CDD93 4DCBA022 FAF60790 61AA ...

  10. 编译boost asio http/server 方法

    这段时间学习boost 的asio 编程,想编译asio自带的http/server的程序,无奈在网上根本找不到方法,只能自己摸索学习. 登陆boost asio 的example 目录,(我 boo ...