有许多实现中值滤波的方法,本文用的是非常暴力的方法:这里以一个彩色图像为例,遍历所有非边界上的像素,每找到一个像素(r,g,b三个元素的数组),就将它(0)及周围 3x3 邻域的所有像素(1-8)的r,g,b(9个r,9个g,9个b)三种值分别做插入排序取中值(你也可以用直方图估算中值的方法做)返回给输出图像。因此此方法仅供了解中值滤波基本原理,生产环境请直接使用OpenCV自带的函数medianBlur。如图:
代码:
#include <iostream>
#include <string>
#include <opencv2/opencv.hpp>
using namespace std;
using namespace cv;
int insertSortAndReturnMedian(int arr[], int n){
for(int i = 1; i < n; i++) {
int e = arr[i];
int j;
for(j = i; j >= 1 && e < arr[j-1]; j--){
arr[j] = arr[j - 1];
}
arr[j] = e;
}
if (n % 2 == 1) {
return arr[n / 2];
} else {
return (arr[n / 2 - 1] + arr[n / 2]) / 2;
}
}
int main() {
string imagePath = "../cup.jpg";
Mat image = imread(imagePath);
resize(image, image, Size(600, 900));
Mat dstImg(image.rows, image.cols, CV_8UC3);
for (int i = 0; i < image.rows; ++i) {
for (int j = 0; j < image.cols; ++j) {
// 边界像素3x3的邻域不足9个,就不取中值了
if(i == 0 || j == 0) {
dstImg.at<Vec3b>(i,j)[0] = image.at<Vec3b>(i,j)[0];
dstImg.at<Vec3b>(i,j)[1] = image.at<Vec3b>(i,j)[1];
dstImg.at<Vec3b>(i,j)[2] = image.at<Vec3b>(i,j)[2];
} else {
// 3x3邻域中值滤波
int pb[9];
pb[0] = image.at<Vec3b>(i,j)[0];
pb[1] = image.at<Vec3b>(i,j + 1)[0];
pb[2] = image.at<Vec3b>(i - 1,j + 1)[0];
pb[3] = image.at<Vec3b>(i - 1,j)[0];
pb[4] = image.at<Vec3b>(i - 1,j - 1)[0];
pb[5] = image.at<Vec3b>(i,j - 1)[0];
pb[6] = image.at<Vec3b>(i + 1,j - 1)[0];
pb[7] = image.at<Vec3b>(i + 1,j)[0];
pb[8] = image.at<Vec3b>(i + 1,j + 1)[0];
int pg[9];
pg[0] = image.at<Vec3b>(i,j)[1];
pg[1] = image.at<Vec3b>(i,j + 1)[1];
pg[2] = image.at<Vec3b>(i - 1,j + 1)[1];
pg[3] = image.at<Vec3b>(i - 1,j)[1];
pg[4] = image.at<Vec3b>(i - 1,j - 1)[1];
pg[5] = image.at<Vec3b>(i,j - 1)[1];
pg[6] = image.at<Vec3b>(i + 1,j - 1)[1];
pg[7] = image.at<Vec3b>(i + 1,j)[1];
pg[8] = image.at<Vec3b>(i + 1,j + 1)[1];
int pr[9];
pr[0] = image.at<Vec3b>(i,j)[2];
pr[1] = image.at<Vec3b>(i,j + 1)[2];
pr[2] = image.at<Vec3b>(i - 1,j + 1)[2];
pr[3] = image.at<Vec3b>(i - 1,j)[2];
pr[4] = image.at<Vec3b>(i - 1,j - 1)[2];
pr[5] = image.at<Vec3b>(i,j - 1)[2];
pr[6] = image.at<Vec3b>(i + 1,j - 1)[2];
pr[7] = image.at<Vec3b>(i + 1,j)[2];
pr[8] = image.at<Vec3b>(i + 1,j + 1)[2];
dstImg.at<Vec3b>(i,j)[0] = insertSortAndReturnMedian(pb, 9);
dstImg.at<Vec3b>(i,j)[1] = insertSortAndReturnMedian(pg, 9);
dstImg.at<Vec3b>(i,j)[2] = insertSortAndReturnMedian(pr, 9);
}
}
}
namedWindow("MedianBlur",WINDOW_AUTOSIZE);
imshow("MedianBlur",dstImg);
waitKey(0);
destroyAllWindows();
return 0;
}
原图:
中值滤波后的目标图:
终于打完了,以上还有更好的优化方式,
取中值方式:https://www.sciencedirect.com/science/article/pii/S0022000073800339
最后我只有一句话想说: