OpenCV计算机视觉开发入门与实践<二十三>:图像平滑之非线性滤波

1. 中值滤波

摘要 :本文介绍 OpenCV 中两种常用的空域平滑滤波方法------中值滤波与双边滤波。中值滤波通过取邻域灰度中值去除椒盐噪声,适合消除孤立噪点;双边滤波在加权平均中同时考虑空间距离与灰度差异,能够在降噪的同时较好地保留图像边缘。文中分别给出 medianBlur() 与 bilateralFilter() 的接口说明及完整 C++ 示例代码。

  中值滤波用像素点领域灰度值的中值来代替该像素点的灰度值,也就是说用一片区域的中间值来代替所有值,这可以除去最大值和最小值。中值滤波对除去斑点噪声和椒盐噪声很有用,缺点是中值滤波花费的时间在均值滤波的5倍以上。

  中值平滑也有核,但并不进行卷积计算,而是对核中所有像素值排序得到中间值,用该中间值来代替锚点值。中值滤波在数字图像处理中属于空域平滑滤波的内容。

  在OpenCV中,利用medianBlur()来进行中值平滑,其声明如下:

cpp 复制代码
void cv::medianBlur ( InputArray src, OutputArray dst, int ksize );

  其中参数src表示输入图像,图像为1、3、4通道的图像,当模板尺寸为3或5时,图像深度只能为CV_8U、CV_16U、CV_32F中的一个。对于较大孔径尺寸的图片,图像深度只能是CV_8U。dst表示输出图像,尺寸和类型与输入图像一致,可以使用Mat::Clone以原图像为模板来初始化输出图像。ksize表示滤波模板的尺寸大小,必须是大于1的奇数,如

3、5、7......

【例6.3】实现中值滤波

在代码中,我们对图片进行了孔径为7的中值滤波。

cpp 复制代码
#include "opencv2/core/core.hpp"
#include "opencv2/highgui/highgui.hpp"
#include "opencv2/imgproc/imgproc.hpp"

using namespace cv;
int main()
{
	Mat image = imread("lady.png");	// 载入原图
	namedWindow("src");	//创建窗口
	namedWindow("median filtering");//命名窗口
	//显示原图
	imshow("src", image);
	//进行中值滤波操作
	Mat out;
	medianBlur(image, out, 7);//输入,输出,孔径为7
	//显示效果图
	imshow("median filtering", out);//显示中值滤波效果图
	waitKey(0);
}

2. 双边滤波

  当前介绍的滤波器都是为了平滑图像,问题是有些时候这些滤波器不仅削弱了噪声,还把边缘也给磨掉了。为了避免这样的情形(至少在一定程度上),我们可以使用双边滤波。类似于高斯滤波器,双边滤波器也给每一个邻域像素分配一个加权系数。这些加权系数包含两部分:第一部分的加权方式与高斯滤波一样,第二部分的权重取决于该邻域像素与当前像素的灰度差值。

  双边滤波是一种非线性滤波器,它可以达到保持边缘、降噪平滑的效果。和其他滤波原理一样,双边滤波也采用加权平均的方法,用周边像素亮度值的加权平均代表某个像素的强度,所用的加权平均基于高斯分布。最重要的是,在计算中心像素的时候,双边滤波的权重不仅考虑了像素的欧氏距离(如普通的高斯低通滤波,只考虑了位置对中心像素的

影响),还考虑了像素范围域中的辐射差异(如卷积核中像素与中心像素之间的相似程

度、颜色强度、深度距离等)。

  与高斯滤波相比,双边滤波能够更好地保存图像的边缘信息。其原理为一个与空间距离相关的高斯函数与一个与灰度距离相关的高斯函数相乘。

  下面来看一个例子,使用4种不同的滤波器读取一幅图像,并显示平滑图像。

【例6.4】使用4种不同的滤波器读取并显示平滑图像

cpp 复制代码
#include <iostream>
#include <iostream>
#include "opencv2/imgproc.hpp"
#include "opencv2/imgcodecs.hpp"
#include "opencv2/highgui.hpp"
using namespace std;
using namespace cv;
int DELAY_CAPTION = 1500;
int DELAY_BLUR = 100;
int MAX_KERNEL_LENGTH = 31;
Mat src; Mat dst;
char window_name[] = "Smoothing Demo";
int display_caption(const char* caption);
int display_dst(int delay);

int main(int argc, char** argv)
{
	namedWindow(window_name, WINDOW_AUTOSIZE);
	const char* filename = argc >= 2 ? argv[1] : "lena.png";
	src = imread(samples::findFile(filename), IMREAD_COLOR);
	if (src.empty())
	{
		printf(" Error opening image\n");
		printf(" Usage:\n %s [image_name-- default lena.jpg] \n", argv[0]);
		return EXIT_FAILURE;
	}

	if (display_caption("Original Image") != 0)
	{
		return 0;
	}

	dst = src.clone();
	if (display_dst(DELAY_CAPTION) != 0)
	{
		return 0;
	}

	if (display_caption("Homogeneous Blur") != 0)
	{
		return 0;
	}

	for (int i = 1; i < MAX_KERNEL_LENGTH; i = i + 2)
	{
		blur(src, dst, Size(i, i), Point(-1, -1));
		if (display_dst(DELAY_BLUR) != 0)
		{
			return 0;
		}
	}

	if (display_caption("Gaussian Blur") != 0)
	{
		return 0;
	}

	for (int i = 1; i < MAX_KERNEL_LENGTH; i = i + 2)
	{
		GaussianBlur(src, dst, Size(i, i), 0, 0);
		if (display_dst(DELAY_BLUR) != 0)
		{
			return 0;
		}
	}

	if (display_caption("Median Blur") != 0)
	{
		return 0;
	}

	for (int i = 1; i < MAX_KERNEL_LENGTH; i = i + 2)
	{
		medianBlur(src, dst, i);
		if (display_dst(DELAY_BLUR) != 0)
		{
			return 0;
		}
	}

	if (display_caption("Bilateral Blur") != 0)
	{
		return 0;
	}

	for (int i = 1; i < MAX_KERNEL_LENGTH; i = i + 2)
	{
		bilateralFilter(src, dst, i, i * 2, i / 2);
		if (display_dst(DELAY_BLUR) != 0)
		{
			return 0;
		}
	}

	display_caption("Done!");

	return 0;
}
int display_caption(const char* caption)
{
	dst = Mat::zeros(src.size(), src.type());
	putText(dst, caption, Point(src.cols / 4, src.rows / 2), FONT_HERSHEY_COMPLEX, 1,
		Scalar(255, 255, 255));
	return display_dst(DELAY_CAPTION);
}

int display_dst(int delay)
{
	imshow(window_name, dst);
	int c = waitKey(delay);
	if (c >= 0) { return -1; }
	return 0;
}
相关推荐
All for pursuit.2 小时前
【位运算-1】338.比特位计数
数据结构·c++·算法·leetcode
库拉镜像AI牛牛2 小时前
工作室标准化出片体系:知漫剧小说转漫剧落地应用
人工智能
正在走向自律2 小时前
AI数据分析与可视化:从基础到应用实践
服务器·人工智能·python·机器学习·数据分析·pandas
小师兄吃牛肉3 小时前
C语言中的nullptr有必要吗
c语言·c++·算法
空堂与归3 小时前
Hinton 首篇 RSI 论文:AI 自我进化怎么闭环?
人工智能·ai
2601_956743683 小时前
上海GEO营销工程实践:知识库构建、AI内容生产、官网承接与监测优化闭环评估
人工智能·ai·geo·上海
盟接之桥3 小时前
当大模型遇见线束制造:不是通用AI,而是行业AI
大数据·网络·人工智能·安全·制造
WL学习笔记3 小时前
日期类(C++)
开发语言·c++·日期类实现
归秋1423 小时前
2026 企业 AI 办公工具选型指南:从评估框架到产品适配
大数据·运维·人工智能
冬奇Lab3 小时前
开源项目第229期:e2e — 用自然语言写 E2E 测试,还能把 Agent 跑过的操作录成‘回放缓存‘免模型调用
人工智能·测试