图像平滑
下一篇图像锐化。
众所周知,实际获得的图像在形成、传输、接收和处理的过程中,不可避免地存在着外部和内部的噪声干扰。噪声恶化了图像质量,使图像模糊,给分析带来困难。因此,去除噪声,恢复原始图像时图像处理中的一个重要内容。消除图像噪声的工作称之为图像平滑或滤波。
图像平滑方法包括空域法和频域法两大类。在空域法中,图像平滑常用的方法是采用均值滤波或中值滤波。
均值滤波
对于均值滤波,它是采用一个有奇数点的滑动窗口在图像上滑动,将窗口中心点对应的图像像素点的灰度值用窗口内的各个点的灰度值的平均值代替,在取均值过程中,如果窗口规定了各个像素点所占的权重,也就是各个像素点的系数,则称为加权均值滤波。
中值滤波
对于中值滤波,窗口中心点所对应像素的灰度值用窗口内所有像素的中间值代替。实现均值或中值滤波时,可以定义一个n*n的模板数组。另外,读者需要注意一点,在用窗口扫描图像过程中,对于图像四个边缘的像素点,可以不处理;也可以用灰度值为"0"的像素点扩展图像的边缘。
OpenCV实现
编程实现车牌图像的去噪,分别采用均值滤波器和中值滤波器进行处理,比较两种滤波器效果。
原图:
结果图:
均值滤波器
首先需要求出传入像素点的九宫格像素值的均值。
//求均值
uchar getAverage(Mat src,int i, int j,int way) {
uchar newData;
newData = (
src.at<Vec3b>(i-1, j)[way] + src.at<Vec3b>(i - 1, j)[way] + src.at<Vec3b>(i - 1, j+1)[way] +
src.at<Vec3b>(i, j - 1)[way] +src.at<Vec3b>(i , j)[way] + src.at<Vec3b>(i, j + 1)[way] +
src.at<Vec3b>(i + 1, j - 1)[way] + src.at<Vec3b>(i+1, j )[way] + src.at<Vec3b>(i + 1, j+1)[way]
) / 9;
return newData;
}
然后遍历像素点进行更新,注意边框上的像素因为不满足九宫格,会直接赋值原来的像素值。
//均值滤波
Mat AverageFilter(const Mat& src, Mat& dst) {
if (!src.data) return src;
for (int i = 0; i < src.rows; ++i)
for (int j = 0; j < src.cols; ++j) {
if (i >= 1 && j >= 1 && i < src.rows - 1 && j < src.cols - 1) {
dst.at<Vec3b>(i, j)[0] = getAverage(src, i, j, 0);
dst.at<Vec3b>(i, j)[1] = getAverage(src, i, j, 1);
dst.at<Vec3b>(i, j)[2] = getAverage(src, i, j, 2);
}
else {
dst.at<Vec3b>(i, j)[0] = src.at<Vec3b>(i, j)[0];
dst.at<Vec3b>(i, j)[1] = src.at<Vec3b>(i, j)[1];
dst.at<Vec3b>(i, j)[2] = src.at<Vec3b>(i, j)[2];
}
}
return dst;
}
中值滤波器
需要求出传入像素点的九宫格像素值的中值。
//求中值
uchar getMedian(Mat src, int a, int b, int way) {
uchar newArray[9];
newArray[0] = src.at<Vec3b>(a - 1, b - 1)[way];
newArray[1] = src.at<Vec3b>(a - 1, b )[way];
newArray[2] = src.at<Vec3b>(a - 1, b + 1)[way];
newArray[3] = src.at<Vec3b>(a , b -1)[way];
newArray[4] = src.at<Vec3b>(a , b )[way];
newArray[5] = src.at<Vec3b>(a , b + 1)[way];
newArray[6] = src.at<Vec3b>(a + 1, b -1)[way];
newArray[7] = src.at<Vec3b>(a + 1, b)[way];
newArray[8] = src.at<Vec3b>(a + 1, b+1)[way];
int len = (int)sizeof(newArray) / sizeof(uchar);
uchar temp;
for (int i = 0; i < len - 1; i++)
for (int j = 0; j < len - 1 - i; j++)
if (newArray[j] > newArray[j + 1])
{
temp = newArray[j];
newArray[j] = newArray[j + 1];
newArray[j + 1] = temp;
}
return newArray[4];
}
然后遍历像素点进行更新,注意边框上的像素因为不满足九宫格,会直接赋值原来的像素值。
//中值滤波
Mat MedianFilter(const Mat& src, Mat& dst) {
if (!src.data) return src;
for (int i = 0; i < src.rows; ++i) {
for (int j = 0; j < src.cols; ++j) {
if (i >= 1 && j >= 1 && i < src.rows - 1 && j < src.cols - 1) {
dst.at<Vec3b>(i, j)[0] = getMedian(src, i, j, 0);
dst.at<Vec3b>(i, j)[1] = getMedian(src, i, j, 1);
dst.at<Vec3b>(i, j)[2] = getMedian(src, i, j, 2);
}
else {
dst.at<Vec3b>(i, j)[0] = src.at<Vec3b>(i, j)[0];
dst.at<Vec3b>(i, j)[1] = src.at<Vec3b>(i, j)[1];
dst.at<Vec3b>(i, j)[2] = src.at<Vec3b>(i, j)[2];
}
}
}
return dst;
}
所有代码
#include<opencv2\opencv.hpp>
#include<iostream>
using namespace cv;
using namespace std;
//2021.4.25
//Solye
//求均值
uchar getAverage(Mat src,int i, int j,int way) {
uchar newData;
newData = (
src.at<Vec3b>(i-1, j)[way] + src.at<Vec3b>(i - 1, j)[way] + src.at<Vec3b>(i - 1, j+1)[way] +
src.at<Vec3b>(i, j - 1)[way] +src.at<Vec3b>(i , j)[way] + src.at<Vec3b>(i, j + 1)[way] +
src.at<Vec3b>(i + 1, j - 1)[way] + src.at<Vec3b>(i+1, j )[way] + src.at<Vec3b>(i + 1, j+1)[way]
) / 9;
return newData;
}
//均值滤波
Mat AverageFilter(const Mat& src, Mat& dst) {
if (!src.data) return src;
for (int i = 0; i < src.rows; ++i)
for (int j = 0; j < src.cols; ++j) {
if (i >= 1 && j >= 1 && i < src.rows - 1 && j < src.cols - 1) {
dst.at<Vec3b>(i, j)[0] = getAverage(src, i, j, 0);
dst.at<Vec3b>(i, j)[1] = getAverage(src, i, j, 1);
dst.at<Vec3b>(i, j)[2] = getAverage(src, i, j, 2);
}
else {
dst.at<Vec3b>(i, j)[0] = src.at<Vec3b>(i, j)[0];
dst.at<Vec3b>(i, j)[1] = src.at<Vec3b>(i, j)[1];
dst.at<Vec3b>(i, j)[2] = src.at<Vec3b>(i, j)[2];
}
}
return dst;
}
//求中值
uchar getMedian(Mat src, int a, int b, int way) {
uchar newArray[9];
newArray[0] = src.at<Vec3b>(a - 1, b - 1)[way];
newArray[1] = src.at<Vec3b>(a - 1, b )[way];
newArray[2] = src.at<Vec3b>(a - 1, b + 1)[way];
newArray[3] = src.at<Vec3b>(a , b -1)[way];
newArray[4] = src.at<Vec3b>(a , b )[way];
newArray[5] = src.at<Vec3b>(a , b + 1)[way];
newArray[6] = src.at<Vec3b>(a + 1, b -1)[way];
newArray[7] = src.at<Vec3b>(a + 1, b)[way];
newArray[8] = src.at<Vec3b>(a + 1, b+1)[way];
int len = (int)sizeof(newArray) / sizeof(uchar);
uchar temp;
for (int i = 0; i < len - 1; i++)
for (int j = 0; j < len - 1 - i; j++)
if (newArray[j] > newArray[j + 1])
{
temp = newArray[j];
newArray[j] = newArray[j + 1];
newArray[j + 1] = temp;
}
return newArray[4];
}
//中值滤波
Mat MedianFilter(const Mat& src, Mat& dst) {
if (!src.data) return src;
for (int i = 0; i < src.rows; ++i) {
for (int j = 0; j < src.cols; ++j) {
if (i >= 1 && j >= 1 && i < src.rows - 1 && j < src.cols - 1) {
dst.at<Vec3b>(i, j)[0] = getMedian(src, i, j, 0);
dst.at<Vec3b>(i, j)[1] = getMedian(src, i, j, 1);
dst.at<Vec3b>(i, j)[2] = getMedian(src, i, j, 2);
}
else {
dst.at<Vec3b>(i, j)[0] = src.at<Vec3b>(i, j)[0];
dst.at<Vec3b>(i, j)[1] = src.at<Vec3b>(i, j)[1];
dst.at<Vec3b>(i, j)[2] = src.at<Vec3b>(i, j)[2];
}
}
}
return dst;
}
int main()
{
Mat src = imread("XXXXXXXXXX.bmp");
Mat averageFilter;
Mat medianFilter;
averageFilter.create(src.rows, src.cols, src.type());
medianFilter.create(src.rows, src.cols, src.type());
imshow("原图", src);
imshow("均值滤波", AverageFilter(src, averageFilter));
imshow("中值滤波", MedianFilter(src,medianFilter));
waitKey();
}
下一篇 图像锐化
图像锐化。
https://blog.csdn.net/weixin_44394801/article/details/116132496