- 浏览: 280672 次
- 性别:
- 来自: 济南
文章分类
最新评论
邻域滤波(卷积)
邻域算子值利用给定像素周围像素的值决定此像素的最终输出。如图左边图像与中间图像卷积禅城右边图像。目标图像中绿色的像素由原图像中蓝色标记的像素计算得到。
通用线性邻域滤波是一种常用的邻域算子,输入像素加权得到输出像素:
其中权重核 为“滤波系数 ”。上面的式子可以简记为:
【方框滤波】
最简单的线性滤波是移动平均或方框滤波,用
窗口中的像素值平均后输出,核函数为:
其实等价于图像与全部元素值为1的核函数进行卷积再进行尺度缩放。
代码
OpenCV中的 blur函数是进行标准方框滤波:
void cv::blur( InputArray src, OutputArray dst, Size ksize, Point anchor, int borderType ) { boxFilter( src, dst, -1, ksize, anchor, true, borderType ); }而boxFilter函数源码如下:
cv::Ptr<cv::FilterEngine> cv::createBoxFilter( int srcType, int dstType, Size ksize, Point anchor, bool normalize, int borderType ) { int sdepth = CV_MAT_DEPTH(srcType); int cn = CV_MAT_CN(srcType), sumType = CV_64F; if( sdepth <= CV_32S && (!normalize || ksize.width*ksize.height <= (sdepth == CV_8U ? (1<<23) : sdepth == CV_16U ? (1 << 15) : (1 << 16))) ) sumType = CV_32S; sumType = CV_MAKETYPE( sumType, cn ); Ptr<BaseRowFilter> rowFilter = getRowSumFilter(srcType, sumType, ksize.width, anchor.x ); Ptr<BaseColumnFilter> columnFilter = getColumnSumFilter(sumType, dstType, ksize.height, anchor.y, normalize ? 1./(ksize.width*ksize.height) : 1); return Ptr<FilterEngine>(new FilterEngine(Ptr<BaseFilter>(0), rowFilter, columnFilter, srcType, dstType, sumType, borderType )); }这里 blur 和 boxFilter 的区别是,blur是标准化后的 boxFilter,即boxFilter的核函数:
其中,
blur( src, dst, Size( 1, 1 ), Point(-1,-1)); blur( src, dst, Size( 4, 4 ), Point(-1,-1)); blur( src, dst, Size( 8, 8 ), Point(-1,-1)); blur( src, dst, Size( 16, 16 ), Point(-1,-1));
实验结果
下图是对一幅图像分别用1*1,4*4,8*8,16*16标准方框滤波后的图像:
【高斯滤波】
高斯滤波器是一类根据高斯函数的形状来选择权值的线性平滑滤波器。它对去除服从正态分布的噪声很有效。
常用的零均值离散高斯滤波器函数:
常用的零均值离散高斯滤波器函数:
2D图像中表示为:
代码
/****************************************************************************************\ Gaussian Blur \****************************************************************************************/ cv::Mat cv::getGaussianKernel( int n, double sigma, int ktype ) { const int SMALL_GAUSSIAN_SIZE = 7; static const float small_gaussian_tab[][SMALL_GAUSSIAN_SIZE] = { {1.f}, {0.25f, 0.5f, 0.25f}, {0.0625f, 0.25f, 0.375f, 0.25f, 0.0625f}, {0.03125f, 0.109375f, 0.21875f, 0.28125f, 0.21875f, 0.109375f, 0.03125f} }; const float* fixed_kernel = n % 2 == 1 && n <= SMALL_GAUSSIAN_SIZE && sigma <= 0 ? small_gaussian_tab[n>>1] : 0; CV_Assert( ktype == CV_32F || ktype == CV_64F ); Mat kernel(n, 1, ktype); float* cf = (float*)kernel.data; double* cd = (double*)kernel.data; double sigmaX = sigma > 0 ? sigma : ((n-1)*0.5 - 1)*0.3 + 0.8; double scale2X = -0.5/(sigmaX*sigmaX); double sum = 0; int i; for( i = 0; i < n; i++ ) { double x = i - (n-1)*0.5; double t = fixed_kernel ? (double)fixed_kernel[i] : std::exp(scale2X*x*x); if( ktype == CV_32F ) { cf[i] = (float)t; sum += cf[i]; } else { cd[i] = t; sum += cd[i]; } } sum = 1./sum; for( i = 0; i < n; i++ ) { if( ktype == CV_32F ) cf[i] = (float)(cf[i]*sum); else cd[i] *= sum; } return kernel; } cv::Ptr<cv::FilterEngine> cv::createGaussianFilter( int type, Size ksize, double sigma1, double sigma2, int borderType ) { int depth = CV_MAT_DEPTH(type); if( sigma2 <= 0 ) sigma2 = sigma1; // automatic detection of kernel size from sigma if( ksize.width <= 0 && sigma1 > 0 ) ksize.width = cvRound(sigma1*(depth == CV_8U ? 3 : 4)*2 + 1)|1; if( ksize.height <= 0 && sigma2 > 0 ) ksize.height = cvRound(sigma2*(depth == CV_8U ? 3 : 4)*2 + 1)|1; CV_Assert( ksize.width > 0 && ksize.width % 2 == 1 && ksize.height > 0 && ksize.height % 2 == 1 ); sigma1 = std::max( sigma1, 0. ); sigma2 = std::max( sigma2, 0. ); Mat kx = getGaussianKernel( ksize.width, sigma1, std::max(depth, CV_32F) ); Mat ky; if( ksize.height == ksize.width && std::abs(sigma1 - sigma2) < DBL_EPSILON ) ky = kx; else ky = getGaussianKernel( ksize.height, sigma2, std::max(depth, CV_32F) ); return createSeparableLinearFilter( type, type, kx, ky, Point(-1,-1), 0, borderType ); } void cv::GaussianBlur( InputArray _src, OutputArray _dst, Size ksize, double sigma1, double sigma2, int borderType ) { Mat src = _src.getMat(); _dst.create( src.size(), src.type() ); Mat dst = _dst.getMat(); if( borderType != BORDER_CONSTANT ) { if( src.rows == 1 ) ksize.height = 1; if( src.cols == 1 ) ksize.width = 1; } if( ksize.width == 1 && ksize.height == 1 ) { src.copyTo(dst); return; } #ifdef HAVE_TEGRA_OPTIMIZATION if(sigma1 == 0 && sigma2 == 0 && tegra::gaussian(src, dst, ksize, borderType)) return; #endif Ptr<FilterEngine> f = createGaussianFilter( src.type(), ksize, sigma1, sigma2, borderType ); f->apply( src, dst ); }
实验结果
下图是对一幅图像分别用1*1,3*3,5*5,9*9标准方框滤波后的图像:
非线性滤波
线性滤波易于构造,且易于从频率响应的角度分析,但如果噪声是散粒噪声而非高斯噪声时线性滤波不能去除噪声。如图像突然出现很大的值,线性滤波只是转换为柔和但仍可见的散粒。这时需要非线性滤波。
简单的非线性滤波有 中值滤波 , -截尾均值滤波 ,定义域滤波 和值域滤波 。
中值滤波选择每个邻域像素的中值输出; -截尾均值滤波是指去掉百分率为 的最小值和最大值;定义域滤波中沿着边界的数字是像素的距离;值域就是去掉值域外的像素值。
中值滤波代码
medianBlur ( src, dst, i );
中值滤波实验
下图是对一幅图像分别用3*3,5*5,7*7,9*9(这里必须是奇数)标准方框滤波后的图像:
【双边滤波】
双边滤波的思想是抑制与中心像素值差别太大的像素,输出像素值依赖于邻域像素值的加权合:
权重系数 取决于定义域核
和依赖于数据的值域核
的乘积。相乘后会产生依赖于数据的双边权重函数:
双边滤波源码
/****************************************************************************************\ Bilateral Filtering \****************************************************************************************/ namespace cv { static void bilateralFilter_8u( const Mat& src, Mat& dst, int d, double sigma_color, double sigma_space, int borderType ) { int cn = src.channels(); int i, j, k, maxk, radius; Size size = src.size(); CV_Assert( (src.type() == CV_8UC1 || src.type() == CV_8UC3) && src.type() == dst.type() && src.size() == dst.size() && src.data != dst.data ); if( sigma_color <= 0 ) sigma_color = 1; if( sigma_space <= 0 ) sigma_space = 1; double gauss_color_coeff = -0.5/(sigma_color*sigma_color); double gauss_space_coeff = -0.5/(sigma_space*sigma_space); if( d <= 0 ) radius = cvRound(sigma_space*1.5); else radius = d/2; radius = MAX(radius, 1); d = radius*2 + 1; Mat temp; copyMakeBorder( src, temp, radius, radius, radius, radius, borderType ); vector<float> _color_weight(cn*256); vector<float> _space_weight(d*d); vector<int> _space_ofs(d*d); float* color_weight = &_color_weight[0]; float* space_weight = &_space_weight[0]; int* space_ofs = &_space_ofs[0]; // initialize color-related bilateral filter coefficients for( i = 0; i < 256*cn; i++ ) color_weight[i] = (float)std::exp(i*i*gauss_color_coeff); // initialize space-related bilateral filter coefficients for( i = -radius, maxk = 0; i <= radius; i++ ) for( j = -radius; j <= radius; j++ ) { double r = std::sqrt((double)i*i + (double)j*j); if( r > radius ) continue; space_weight[maxk] = (float)std::exp(r*r*gauss_space_coeff); space_ofs[maxk++] = (int)(i*temp.step + j*cn); } for( i = 0; i < size.height; i++ ) { const uchar* sptr = temp.data + (i+radius)*temp.step + radius*cn; uchar* dptr = dst.data + i*dst.step; if( cn == 1 ) { for( j = 0; j < size.width; j++ ) { float sum = 0, wsum = 0; int val0 = sptr[j]; for( k = 0; k < maxk; k++ ) { int val = sptr[j + space_ofs[k]]; float w = space_weight[k]*color_weight[std::abs(val - val0)]; sum += val*w; wsum += w; } // overflow is not possible here => there is no need to use CV_CAST_8U dptr[j] = (uchar)cvRound(sum/wsum); } } else { assert( cn == 3 ); for( j = 0; j < size.width*3; j += 3 ) { float sum_b = 0, sum_g = 0, sum_r = 0, wsum = 0; int b0 = sptr[j], g0 = sptr[j+1], r0 = sptr[j+2]; for( k = 0; k < maxk; k++ ) { const uchar* sptr_k = sptr + j + space_ofs[k]; int b = sptr_k[0], g = sptr_k[1], r = sptr_k[2]; float w = space_weight[k]*color_weight[std::abs(b - b0) + std::abs(g - g0) + std::abs(r - r0)]; sum_b += b*w; sum_g += g*w; sum_r += r*w; wsum += w; } wsum = 1.f/wsum; b0 = cvRound(sum_b*wsum); g0 = cvRound(sum_g*wsum); r0 = cvRound(sum_r*wsum); dptr[j] = (uchar)b0; dptr[j+1] = (uchar)g0; dptr[j+2] = (uchar)r0; } } } }
双边滤波调用
bilateralFilter(InputArray src, OutputArray dst, int d, double sigmaColor, double sigmaSpace, int borderType=BORDER_DEFAULT );d 表示滤波时像素邻域直径,d为负时由 sigaColor计算得到;d>5时不能实时处理。
sigmaColor、sigmaSpace非别表示颜色空间和坐标空间的滤波系数sigma。可以简单的赋值为相同的值。<10时几乎没有效果;>150时为油画的效果。
borderType可以不指定。
双边滤波实验
用sigma为10,150,240,480时效果如下:
参考文献:
Richard Szeliski 《Computer Vision: Algorithms and Applications》
http://homepages.inf.ed.ac.uk/rbf/CVonline/LOCAL_COPIES/MANDUCHI1/Bilateral_Filtering.html
《The OpenCV Tutorials》 Release 2.4.2
《The OpenCV Reference Manual 》 Release 2.4.2
转载请注明出处:http://blog.csdn.net/xiaowei_cqu/article/details/7785365
发表评论
-
unity基础开发----物体位移和旋转实用代码
2013-11-21 22:46 1270using UnityEngine; using Syst ... -
Android中View绘制优化之一---- 优化布局层次
2012-09-04 23:00 1074... -
Android中View绘制优化二一---- 使用<include />标签复用布局文件
2012-09-08 13:54 1055... -
Android中View绘制优化之三---- 优化View
2012-09-13 21:00 1083... -
兰林任务管理应用程序雏形版以及概要说明
2012-09-15 21:54 880... -
Android中measure过程、WRAP_CONTENT详解以及xml布局文件解析流程浅析(上)
2012-10-10 18:14 1167... -
Android中measure过程、WRAP_CONTENT详解以及xml布局文件解析流程浅析(下)
2012-10-17 20:05 862... -
Android中文件选择器的实现
2012-11-30 08:59 1173... -
【编译原理】使用Lex将C/C++文件输出为HTML文件
2012-07-20 09:37 107008年9月入学,12年7月毕业,结束了我在软件学院愉快丰富的大 ... -
【编译原理】正则表达式
2012-07-21 21:49 230408年9月入学,12年7月毕业,结束了我在软件学院愉快丰富的大 ... -
【OpenCV】访问Mat图像中每个像素的值
2012-07-22 07:10 1171今天百度搜资料还搜到了自己的。。。《访问图像中每个像素的值 ... -
【编译原理】用Yacc做语法分析
2012-07-23 05:47 177408年9月入学,12年7月毕 ... -
【UML】UML几种图的绘制
2012-07-24 09:49 99008年9月入学,12年7月毕业,结束了我在软件学院愉快丰富的大 ... -
【数据结构】排序算法:希尔、归并、快速、堆排序
2012-07-28 06:15 102508年9月入学,12年7月毕 ... -
【OpenCV】角点检测:Harris角点及Shi-Tomasi角点检测
2012-07-31 13:25 1546角点 特征检测与匹配 ... -
【UML】案例分析:机场运作系统
2012-08-01 17:22 313308年9月入学,12年7月毕 ... -
【OpenCV】边缘检测:Sobel、拉普拉斯算子
2012-08-04 13:41 1547边缘 边缘(edge)是指图像局部强度变化最显著的部分。主要 ... -
【OpenCV】Canny 边缘检测
2012-08-08 10:17 1997Canny 边缘检测算法 1986 ... -
【UML】案例分析:新型超市购物自助系统
2012-08-19 01:13 129608年9月入学,12年7月毕业,结束了我在软件学院愉快丰富的大 ... -
【数据结构】二叉树、AVL树
2012-08-21 00:30 109908年9月入学,12年7月毕业,结束了我在软件学院愉快丰富的大 ...
相关推荐
本项目基于OpenCV库,使用C++语言,在Visual Studio 2015环境下,实现了线性滤波和非线性滤波的多种算法,包括方框滤波、均值滤波、高斯滤波、中值滤波以及双边滤波。 1. **线性滤波**: - 方框滤波(Box Filter)...
本项目涉及的核心知识点是图像滤波技术,包括方框滤波、高斯滤波、中值滤波和双边滤波。这些滤波器在图像处理中扮演着重要角色,主要用于去除噪声、平滑图像或者突出图像的某些特性。 1. **方框滤波**:方框滤波是...
在OpenCV中,这些滤波操作可以通过相应的函数实现,例如`cv::boxFilter`用于方框滤波,`cv::blur`对应均值滤波,`cv::GaussianBlur`实现高斯滤波,`cv::medianBlur`执行中值滤波,而`cv::bilateralFilter`则是双边...
【OpenCV入门教程之八】线性邻域滤波专场主要介绍了三种常见的图像滤波方法:方框滤波、均值滤波与高斯滤波。这些滤波技术主要用于图像平滑处理,以减少噪声和失真,尤其在降低图像分辨率时效果显著。 **一、平滑...
本文将详细介绍四种常用的图像平滑方法:均值滤波、方框滤波、高斯滤波以及中值滤波,并结合Python和OpenCV库进行实践。 1. **图像平滑**: - 图像平滑的主要目标是消除图像中的噪声,提高图像质量。噪声通常由...
本主题将深入探讨如何利用C#实现图形处理,包括图像的平滑、去噪、打开图像,以及高斯滤波、均值滤波、中值滤波、灰度转换和小波分析等技术。 首先,我们要了解图像处理的基础概念。图像通常由像素矩阵组成,每个...
3. **中值滤波**:中值滤波是一种非常有效的去噪方法,特别是对于椒盐噪声。它不是取区域内像素的平均值,而是取中值,即排序后位于中间的像素值。这可以保护图像的边缘,因为边缘通常由连续的像素值构成,而在噪声...
本文将详细介绍五种常见的图像平滑方法:均值滤波、方框滤波、高斯滤波、中值滤波和双边滤波。 ### 均值滤波 #### 1. 算法原理 均值滤波是一种简单的线性滤波方法,它通过计算窗口内所有像素的平均值来代替中心...
在"图像滤波处理.rar"这个压缩包中,我们关注的是OpenCV库中实现的四种基本滤波方法:中值滤波、双边滤波、高斯滤波,以及自定义编程实现的这三种滤波器。以下是对这些滤波方法的详细解释: 1. **中值滤波**: ...
本主题将深入探讨四种基本的滤波方法:均值滤波、方框滤波、高斯滤波和中值滤波,并通过Python实现进行对比。此外,还会涉及到线性变换、边缘检测以及Canny算法在实际应用中的作用。 1. **均值滤波**: 均值滤波是...
在OpenCV中,这些滤波操作可以通过相应的函数实现,如`cv2.filter2D()`进行自定义滤波,`cv2.blur()`、`cv2.GaussianBlur()`、`cv2.medianBlur()`和`cv2.bilateralFilter()`分别对应均值滤波、高斯滤波、中值滤波和...
【OpenCV入门教程之九】主要讲解了非线性滤波技术,特别是中值滤波和双边滤波在图像处理中的应用。非线性滤波与线性滤波不同,它在处理某些特定类型的噪声时能展现出更好的效果。本文由毛星云(浅墨)撰写,他是一位...
2. 中值滤波:主要用于去除椒盐噪声,它将每个像素替换为其邻域内像素值的中位数,对边缘保持较好,但对高斯噪声效果不佳。 3. 灰度形态学滤波:基于数学形态学的操作,如膨胀、腐蚀、开运算和闭运算,可以有效地...
- **中值滤波**:不采用平均值,而是取邻域内像素值的中位数,特别适用于去除椒盐噪声。 ### 4. 应用场景 邻域滤波广泛应用于各种图像处理任务,如: - **降噪**:通过平滑处理消除图像中的噪声。 - **图像平滑**...
本项目包含三种类型的滤波算法的C++实现:中值滤波、高斯滤波和平滑滤波,这些都是图像处理中的基础且重要的操作。 **中值滤波**是一种非线性的去噪方法,它在每个像素点处用该点邻域内像素值的中值来代替原像素值...
本项目是基于OpenCV实现的二维图像加噪与去噪的C++程序,涵盖了多种滤波技术,如方框滤波、均值滤波、高斯滤波、中值滤波和双边滤波。 1. **高斯噪声**:在图像中添加高斯噪声是一种常见的模拟真实世界噪声的方式。...
`OpenCV`的`cv2.bilateralFilter`函数实现了双边滤波,参数包括滤波半径、高斯空间权重的标准差以及高斯颜色权重的标准差。 在Project1这个项目中,你将有机会实践这些理论,通过Python代码处理测试图片,观察不同...
OpenCV(开源计算机视觉库)是一个强大的图像处理和计算机视觉库,它包含了各种滤波算法,其中中值滤波是一种常用的去噪技术。本篇将深入解析OpenCV中实现中值滤波的源代码,以及如何利用SSE2指令优化算法以提升运行...
如下图,左图带有椒盐噪声,右图为使用中值滤波处理后的图片。 图像滤波的目的有两个:一是抽出对象的特征作为图像识别的特征模式;另一个是为适应图像处理的要求,消除图像数字化时所混入的噪声。 python +opencv...