基于opencv,C++实现中值滤波器
目的:去除图像的椒盐噪声
原理:它将每一像素点的灰度值设置为该点某邻域窗口内的所有像素点灰度值的中值
伪代码:
输入:原图像、目标图像、核的半径
(1).判断原图像是否为空,空则直接返回
(2).判断核的半径是否为奇数
(3).原图像边界填充,目标图像清空
(4).中值滤波
①.新建一个半径*半径大小的二维数组
②.获取核大小的原图像的值,写入数组
③.数组进行排序
④.将中值写入目标图像
源代码
// ConsoleApplication1.cpp : 此文件包含 "main" 函数。程序执行将在此处开始并结束。
//#include <iostream>
#include <opencv2/opencv.hpp>
#include <opencv2/highgui.hpp>
#include <opencv2/core.hpp>
#include <opencv2/imgproc.hpp>
#include <vector>
#include <algorithm>using namespace cv;
using namespace std;// 冒泡排序
void Sort(int* a, int n) //把数组a递增排序
{//for (int gap = n / 2; gap > 0; gap /= 2)//希尔排序// for (int i = gap; i < n; ++i)// for (int j = i - gap; j >= 0 && a[j] > a[j + gap]; j -= gap)// swap(a[j], a[j + gap]);for (int i = 0; i < n; i++) {for (int j = i + 1; j < n; j++){if (a[i] > a[j]) {int tmp = a[i];a[i] = a[j];a[j] = tmp;}}}}// 中值滤波
void MedianFilter(cv::Mat &srcImg, cv::Mat& dstImg, int ksize)
{// 判断原图像是否为空if (srcImg.empty()) {return;}// 判断核的大小是否为奇数CV_Assert(ksize % 2 == 1);// 获取通道数int channels = srcImg.channels();// 清空目标图像,对原图像进行边界填充Mat tmp;dstImg = dstImg.zeros(srcImg.size(), srcImg.type());int *kernel = new int[ksize*ksize];copyMakeBorder(srcImg, tmp, ksize / 2, ksize / 2, ksize / 2, ksize / 2, BORDER_REPLICATE);for (int i = ksize / 2; i < srcImg.rows + ksize / 2; i++) //对填充后的图像从有图像区域开始滤波{for (int j = ksize / 2; j < srcImg.cols + ksize / 2; j++){for (int c = 0; c < channels; c++){// 将核大小的图像填入数组for (int m = 0; m < ksize*ksize; m++) {if (tmp.channels() == 1) {kernel[m] = tmp.ptr<uchar>(i - ksize / 2 + m / ksize, j - ksize / 2 + m % ksize)[c];}else if (tmp.channels() == 3) {kernel[m] = tmp.ptr<Vec3b>(i - ksize / 2 + m / ksize, j - ksize / 2 + m % ksize)->val[c];}else{delete[]kernel;return;}}// 排序 Sort(kernel, ksize*ksize);// 将中值写入目标图像if (tmp.channels() == 1) {dstImg.ptr<uchar>(i - ksize / 2, j - ksize / 2)[c] = kernel[(ksize*ksize) / 2];}else if (tmp.channels() == 3) {dstImg.ptr<Vec3b>(i - ksize / 2, j - ksize / 2)->val[c] = kernel[(ksize*ksize) / 2];}}}}delete[]kernel;}int main() {Mat image = imread("C:/Users/vmyf16/Desktop/1.jpg");if (image.empty()) {return -1;}Mat image2, image3;double t1 = (double)cv::getTickCount()/1000;MedianFilter(image, image2,3);t1 = (double)cv::getTickCount()/1000 - t1;std::cout << "自定义:" << t1 << std::endl;double t2 = (double)cv::getTickCount()/1000;medianBlur(image, image3, 3);t2 = (double)cv::getTickCount()/1000 - t2;std::cout << "opencv:" << t2 << std::endl;imshow("原图", image);imshow("自定义中值滤波处理后", image2);imshow("openCV自带的中值滤波", image3);waitKey(0);return 0;
}
结果图
原图:
效果图:
明显看出:opencv的算法还是挺快的,自己写的就当练练手。