Opencv计算机视觉编程攻略-第六节 图像滤波
滤波是信号和图像处理中的一种基本操作。它的目的是选择性地提取图像中某些方面的内容,这些内容在特定应用环境下传达了重要信息。滤波可去除图像中的噪声,提取有用的视觉特征,对图像重新采样,等等。
1. 低通滤波器
cv::blur 函数将每个像素的值替换成该像素邻域的平均值(邻域是矩形的),从而使图像更加平滑。这个低通滤波器的用法如下所示:
cv::blur(image,result, cv::Size(5,5)); // 滤波器尺寸
cv::GaussianBlur(image, result, cv::Size(5,5), 1.5); // 控制高斯曲线形状的参数
这种滤波器也称为块滤波器(box filter),为了让效果更加明显,这里使用尺寸为5×5 的滤
波器。blur是均值平滑,在平滑窗口依据距离设置权重,可以使用GaussianBlur
2. 用滤波器进行缩减像素采样
需要调整图像精度(重新采样)的情况屡见不鲜,降低图像精度的过程称为缩减像素采(downsampling),提升图像精度的过程称为提升像素采样(upsampling)。这些算法的难点在于要尽可能地保持图像质量。为此,人们通常采用低通滤波器来实现算,通过将高频进行抑制,使得在下采样时保持整体平整性:
// 首先去除高频成分
cv::GaussianBlur(image,image,cv::Size(11,11),2.0);
// 只保留每4 个像素中的1 个
cv::Mat reduced(image.rows/4,image.cols/4,CV_8U);
for (int i=0; i<reduced.rows; i++)
for (int j=0; j<reduced.cols; j++)
reduced.at<uchar>(i,j)= image.at<uchar>(i*4,j*4);
//也可以使用内置的方法
cv::Mat reducedImage; // 用于存储缩小后的图像
cv::pyrDown(image,reducedImage); // 图像尺寸缩小一半
// resize
cv::Mat resizedImage; // 用于存储缩放后的图像
cv::resize(image, resizedImage,cv::Size(image.cols/4,image.rows/4)); // 行和列均缩小为原来的1/4
你也可以指定缩放比例。在参数中提供一个空的图像实例,然后提供缩放比例:
cv::resize(image, resizedImage,cv::Size(), 1.0/4.0, 1.0/4.0); // 缩小为原来的1/4
resize在计算插入点像素时,可以参考周围的像素进行计算,
3. 中值滤波器
中值滤波器函数的方法与调用其他滤波器差不多:
cv::medianBlur(image, result, 5);
// 最后一个参数是滤波器尺寸
中值滤波器有利于保留边缘的尖锐度,但它会洗去均质区域中的纹理(例如背景中的树木)。因为中值滤波器具有良好的视觉效果,因此照片编辑软件常用它创建特效。可用彩色图像来测试,看它如何生成类似卡通的图像,同理有取最大值,取最小值等等。
4. 用定向滤波器检测边缘
这些滤波器通过移除或减弱高频成分,取得模糊图像的效果。执行一种反向的变换,即放大图像中的高频成分,再使用高通滤波器进行边缘检测。
// 计算Sobel 滤波器的范数
cv::Sobel(image,sobelX,CV_16S,1,0);
cv::Sobel(image,sobelY,CV_16S,0,1);
cv::Mat sobel;
// 计算L1 范数
sobel= abs(sobelX)+abs(sobelY);
// 找到Sobel 最大值
double sobmin, sobmax;
cv::minMaxLoc(sobel,&sobmin,&sobmax);
// 转换成8 位图像
// sobelImage = -alpha*sobel + 255
cv::Mat sobelImage;
sobel.convertTo(sobelImage,CV_8U,-255./sobmax,255);
5. 计算拉普拉斯算子
拉普拉斯算子也是一种基于图像导数运算的高通线性滤波器,它通过计算二阶导数来度量图像函数的曲率。
与Sobel 算子相比,拉普拉斯算子在计算时可以使用更大的内核,并且对图像噪声更加敏感,因此是更理想的选择(除非要重点考虑计算效率)。因为这些更大的内核是用高斯函数的二阶导数计算的,因此这个算子也常称为高斯拉普拉斯算子(Laplacian of Gaussian,LoG)。注意,拉普拉斯算子内核的值的累加和总是0。这保证在强度值恒定的区域中,拉普拉斯算子将变为0。因为拉普拉斯算子度量的是图像函数的曲率,所以它在平坦区域中应该等于0。
// 计算拉普拉斯算子
cv::Laplacian(image,laplace,CV_32F,aperture);