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)

其中,

//Filters.h

#ifndef FILTERS_H
#define FILTERS_H #include "opencv2/imgproc.hpp"
#include "opencv2/highgui.hpp"
#include "opencv2/core.hpp" #include <iostream>
#include <cmath> //Bilateral Filtering
//sigmaD == sigmaSpace, sigmaR == sigmaColor
cv::Mat BilateralFilter(cv::Mat inputImg, int filterSize, double sigmaD, double sigmaR); cv::Mat fastBilateralFilter(cv::Mat inputImg, int filterSize, double sigmaD, double sigmaR); #endif // ! FILTERS_H
//Filters.cpp

#include "Filters.h"

double SpaceFactor(int x1, int y1, int x2, int y2, double sigmaD) {
double absX = pow(abs(x1 - x2), );
double absY = pow(abs(y1 - y2), ); return exp(-(absX + absY) / ( * pow(sigmaD, )));
} double ColorFactor(int x, int y, double sigmaR) {
double distance = abs(x - y) / sigmaR;
return exp(-0.5 * pow(distance, ));
} cv::Mat BilateralFilter(cv::Mat inputImg, int filterSize, double sigmaD, double sigmaR) {
int len; //must be odd number
cv::Mat gray; // must be 1-channel image
cv::Mat LabImage; // if channels == 3 if (filterSize % != || filterSize <= ) {
std::cerr << "Filter Size must be a positive odd number!" << std::endl;
return inputImg;
}
len = filterSize / ; if (inputImg.channels() >= ) {
cv::cvtColor(inputImg, LabImage, cv::COLOR_BGR2Lab);
gray = cv::Mat::zeros(LabImage.size(), CV_8UC1);
for (int i = ; i < LabImage.rows; i++) {
for (int j = ; j < LabImage.cols; j++) {
gray.ptr<uchar>(i)[j] = LabImage.ptr<uchar>(i, j)[];
}
}
}
else if(inputImg.channels() == ){
inputImg.copyTo(gray);
}
else {
std::cerr << "the count of input image's channel can not be 2!" << std::endl;
return inputImg;
} cv::Mat resultGrayImg = cv::Mat::zeros(gray.size(), CV_8UC1);
for (int i = ; i < gray.rows; i++) {
for (int j = ; j < gray.cols; j++) {
double k = ;
double f = ;
for (int r = i - len; r <= i + len; r++) {
for (int c = j - len; c <= j + len; c++) {
if (r < || c < || r >= gray.rows || c >= gray.cols)
continue;
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);
k += SpaceFactor(i, j, r, c, sigmaD) * ColorFactor(gray.ptr<uchar>(i)[j], gray.ptr<uchar>(r)[c], sigmaD);
}
}
int value = f / k;
if (value < ) value = ;
else if (value > ) value = ; resultGrayImg.ptr<uchar>(i)[j] = (uchar)value;
}
} cv::Mat resultImg;
if (inputImg.channels() >= ) {
for (int i = ; i < LabImage.rows; i++) {
for (int j = ; j < LabImage.cols; j++) {
LabImage.ptr<uchar>(i, j)[] = resultGrayImg.ptr<uchar>(i)[j];
}
}
cv::cvtColor(LabImage, resultImg, cv::COLOR_Lab2BGR);
}
else {
resultGrayImg.copyTo(resultImg);
} return resultImg;
} cv::Mat fastBilateralFilter(cv::Mat inputImg, int filterSize, double sigmaD, double sigmaR) {
int len; //must be odd number
cv::Mat gray; // must be 1-channel image
cv::Mat LabImage; // if channels == 3 if (filterSize % != || filterSize <= ) {
std::cerr << "Filter Size must be a positive odd number!" << std::endl;
return inputImg;
}
len = filterSize / ; if (inputImg.channels() >= ) {
cv::cvtColor(inputImg, LabImage, cv::COLOR_BGR2Lab);
gray = cv::Mat::zeros(LabImage.size(), CV_8UC1);
for (int i = ; i < LabImage.rows; i++) {
for (int j = ; j < LabImage.cols; j++) {
gray.ptr<uchar>(i)[j] = LabImage.ptr<uchar>(i, j)[];
}
}
}
else if (inputImg.channels() == ) {
inputImg.copyTo(gray);
}
else {
std::cerr << "the count of input image's channel can not be 2!" << std::endl;
return inputImg;
} cv::Mat resultGrayImg = cv::Mat::zeros(gray.size(), CV_8UC1);
for (int i = ; i < gray.rows; i++) {
for (int j = ; j < gray.cols; j++) {
double k = ;
double f = ;
double sum = ;
for (int r = i - len; r <= i + len; r++) {
if (r < || r >= gray.rows)
continue;
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);
k += SpaceFactor(i, j, r, j, sigmaD) * ColorFactor(gray.ptr<uchar>(i)[j], gray.ptr<uchar>(r)[j], sigmaD);
}
sum = f / k;
f = k = 0.0;
for (int c = j - len; c <= j + len; c++) {
if (c < || c >= gray.cols)
continue;
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);
k += SpaceFactor(i, j, i, c, sigmaD) * ColorFactor(gray.ptr<uchar>(i)[j], gray.ptr<uchar>(i)[c], sigmaD);
}
int value = (sum + f / k) / ;
if (value < ) value = ;
else if (value > ) value = ; resultGrayImg.ptr<uchar>(i)[j] = (uchar)value;
}
} cv::Mat resultImg;
if (inputImg.channels() >= ) {
for (int i = ; i < LabImage.rows; i++) {
for (int j = ; j < LabImage.cols; j++) {
LabImage.ptr<uchar>(i, j)[] = resultGrayImg.ptr<uchar>(i)[j];
}
}
cv::cvtColor(LabImage, resultImg, cv::COLOR_Lab2BGR);
}
else {
resultGrayImg.copyTo(resultImg);
} return resultImg;
}
//main.cpp

#include <iostream>
#include <time.h> #include "Filters.h" using namespace std; int main() {
cv::Mat img = cv::imread("Capture.jpg", cv::IMREAD_UNCHANGED);
clock_t begin_time = clock();
cv::Mat result = BilateralFilter(img, , 12.5, );
std::cout << float(clock() - begin_time) / CLOCKS_PER_SEC << std:: endl;
cv::imshow("original", result);
cv::waitKey();
cv::imwrite("original.jpg", result); begin_time = clock();
result = fastBilateralFilter(img, , 12.5, );
std::cout << float(clock() - begin_time) / CLOCKS_PER_SEC << std::endl;
cv::imshow("fast", result);
cv::waitKey();
cv::imwrite("fast.jpg", result); begin_time = clock();
cv::bilateralFilter(img, result, , , 12.5);
std::cout << float(clock() - begin_time) / CLOCKS_PER_SEC << std::endl;
cv::imshow("opencv", result);
cv::waitKey();
cv::imwrite("opencv.jpg", result); system("pause");
return ;
}

运行结果:

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. Redmine 数据库连接错误

    /******************************************************************** * Redmine 数据库连接错误 * 说明: * Open ...

  2. Palindromic Squares

    链接 分析:求出b进制以后在判是否为回文 /* ID:wanghan PROB:palsquare LANG:C++ */ #include "iostream" #include ...

  3. 【POI 2006】 Tet-Tetris-3D

    [题目链接] 点击打开链接 [算法] 二维线段树(树套树) 注意标记永久化 [代码] #include<bits/stdc++.h> using namespace std; #defin ...

  4. nc之二:nc命令详解

    NetCat,在网络工具中有“瑞士军刀”美誉,其有Windows和Linux的版本.因为它短小精悍(1.84版本也不过25k,旧版本或缩减版甚至更小).功能实用,被设计为一个简单.可靠的网络工具,可通 ...

  5. B - Soldier and Badges

    Time Limit:3000MS     Memory Limit:262144KB     64bit IO Format:%I64d & %I64u Description Colone ...

  6. SCUT - 48 - 飞行员的配对方案 - 费用流

    https://scut.online/p/48 一道二分图匹配,跑费用流就可以过了(其实最大流都可以了). #include<bits/stdc++.h> #define MAXN_ 5 ...

  7. Python基础:一起来面向对象 (二) 之搜索引擎

    实例 搜索引擎 一个搜索引擎由搜索器.索引器.检索器和用户接口四个部分组成 搜索器就是爬虫(scrawler),爬出的内容送给索引器生成索引(Index)存储在内部数据库.用户通过用户接口发出询问(q ...

  8. HTTP请求头中的那些东西

    一.HTTP请求头是什么? HTTP请求头,HTTP客户程序(例如浏览器),向服务器发送请求的时候必须指明请求类型(一般是GET或者POST).如有必要,客户程序还可以选择发送其他的请求头. 二.HT ...

  9. OpenCV认识之发展历史

    OpenCV认识之发展历史刚接触OpenCV,据说是专门用于机器视觉,机器人图形图像处理等,但对OpenCV的历史还不是特别了解,今天上网查好多资料,记录在此,OpenCV的全称是:Open Sour ...

  10. 两边是线 ,中间是文字 的CSS写法 而且还是自适应的