大家好,欢迎来到IT知识分享网。
1、引言
均值滤波、方框滤波、高斯滤波,都是线性滤波方式。由于线性滤波的结果是所有像素值的线性组合,因此含有噪声的像素也会被考虑进去,噪声不会被消除,而是以更柔和的方式存在。这时使用非线性滤波效果可能会更好。中值滤波是一种非线性滤波方式,不再采用加权求均值的方式计算滤波结果,基本原理是把数字图像或数字序列中一点的值用该点的一个邻域中各点值的中值代替,让周围的像素值接近的真实值,从而消除孤立的噪声点。
优缺点:中值滤波可以有效的去除斑点和椒盐噪声。但是效率低,其运算时间 为均值滤波的五倍以上
2、中值滤波过程
首先我们先取一个nxn的滤波核,该核是一个空核,核中不在有权重等数字,把滤波核放在图像上滑动,每滑动到一个位置,就把核覆盖下的所有像素值进行排序,然后取排序后中间的像素值替换被核中心覆盖下的原图像像素值。下面演示下滤波过程。
3、opencv中值滤波函数使用
void cv::medianBlur(InputArray src, OutputArray dst, int ksize )
4、滤波核根据图像自适应调整大小
我们在调用medianBlur时需要手动传入一个滤波核大小,下面的一个demo介绍了核的大小根据局部邻域的均值和标准差进行自适应调整:
#include <opencv2/opencv.hpp> cv::Mat adaptiveMedianBlur(const cv::Mat& src, int maxWindowSize) {
cv::Mat result = src.clone(); int numChannels = src.channels(); for (int y = maxWindowSize / 2; y < src.rows - maxWindowSize / 2; ++y) {
for (int x = maxWindowSize / 2; x < src.cols - maxWindowSize / 2; ++x) {
int windowSize = 3; // 初始核大小 while (windowSize <= maxWindowSize) {
// 提取局部邻域 cv::Mat region = src(cv::Range(y - windowSize / 2, y + windowSize / 2 + 1), cv::Range(x - windowSize / 2, x + windowSize / 2 + 1)); // 计算标准差 cv::Scalar mean, stddev; cv::meanStdDev(region, mean, stddev); // 中值滤波 if (numChannels == 1 && src.at<uchar>(y, x) < mean[0] + stddev[0] * 0.5) {
// 单通道图像中值滤波 cv::Mat subRegion = result(cv::Range(y - windowSize / 2, y + windowSize / 2 + 1), cv::Range(x - windowSize / 2, x + windowSize / 2 + 1)); cv::medianBlur(region, subRegion, windowSize); break; } else if (numChannels == 3 && src.at<cv::Vec3b>(y, x)[0] < mean[0] + stddev[0] * 0.5 && src.at<cv::Vec3b>(y, x)[1] < mean[1] + stddev[1] * 0.5 && src.at<cv::Vec3b>(y, x)[2] < mean[2] + stddev[2] * 0.5) {
// 三通道图像中值滤波 cv::Mat subRegion = result(cv::Range(y - windowSize / 2, y + windowSize / 2 + 1), cv::Range(x - windowSize / 2, x + windowSize / 2 + 1)); cv::medianBlur(region, subRegion, windowSize); break; } else {
// 增大核大小 windowSize += 2; if (windowSize > maxWindowSize) {
break; } } } } } return result; } int main() {
// 读取图像 cv::Mat image = cv::imread("input_image.jpg", cv::IMREAD_GRAYSCALE); // 应用自适应中值滤波 cv::Mat result = adaptiveMedianBlur(image, 11); // 显示原始图像和处理后的图像 cv::imshow("Original Image", image); cv::imshow("Adaptive Median Blur Image", result); cv::waitKey(0); cv::destroyAllWindows(); return 0; }
加上标准差的一半的目的是提高容错性,使得判断更加灵活。这个设计的理念是在图像中的一些相对较暗的区域或包含细节的区域,由于灰度值的波动,可能出现一些像素的值略低于整体平均值。通过引入标准差的一半,可以允许更大的变化范围,从而更好地适应图像的局部特征。当然也可以把标准差的一半换成一个固定的值,具体可以根据实验来调整。
下面是带三通道的情况:
cv::Mat adaptiveMedianBlur1(const cv::Mat& src, int maxWindowSize) {
cv::Mat result = src.clone(); int numChannels = src.channels(); for (int y = maxWindowSize / 2; y < src.rows - maxWindowSize / 2; ++y) {
for (int x = maxWindowSize / 2; x < src.cols - maxWindowSize / 2; ++x) {
int windowSize = 3; // 初始核大小 while (windowSize <= maxWindowSize) {
// 提取局部邻域 cv::Mat region = src(cv::Range(y - windowSize / 2, y + windowSize / 2 + 1), cv::Range(x - windowSize / 2, x + windowSize / 2 + 1)); // 计算标准差 cv::Scalar mean, stddev; cv::meanStdDev(region, mean, stddev); // 中值滤波 if (numChannels == 1 && src.at<uchar>(y, x) < mean[0] + stddev[0] * 0.5) {
// 单通道图像中值滤波 cv::Mat subRegion = result(cv::Range(y - windowSize / 2, y + windowSize / 2 + 1), cv::Range(x - windowSize / 2, x + windowSize / 2 + 1)); cv::medianBlur(region, subRegion, windowSize); break; } else if (numChannels == 3 && src.at<cv::Vec3b>(y, x)[0] < mean[0] + stddev[0] * 0.5 && src.at<cv::Vec3b>(y, x)[1] < mean[1] + stddev[1] * 0.5 && src.at<cv::Vec3b>(y, x)[2] < mean[2] + stddev[2] * 0.5) {
// 三通道图像中值滤波 cv::Mat subRegion = result(cv::Range(y - windowSize / 2, y + windowSize / 2 + 1), cv::Range(x - windowSize / 2, x + windowSize / 2 + 1)); cv::medianBlur(region, subRegion, windowSize); break; } else {
// 增大核大小 windowSize += 2; if (windowSize > maxWindowSize) {
break; } } } } } return result; }
免责声明:本站所有文章内容,图片,视频等均是来源于用户投稿和互联网及文摘转载整编而成,不代表本站观点,不承担相关法律责任。其著作权各归其原作者或其出版社所有。如发现本站有涉嫌抄袭侵权/违法违规的内容,侵犯到您的权益,请在线联系站长,一经查实,本站将立刻删除。 本文来自网络,若有侵权,请联系删除,如若转载,请注明出处:https://haidsoft.com/137263.html