实验二 图像的空间域增强
实验项目名称:图像的空间域增强
实验项目性质:设计性实验
所属课程名称:数字图像分析与艺术化处理
实验计划学时:2
一、实验目的
- 进一步理解图像平滑和图像锐化等空间域增强方法的原理。
- 了解图像平滑和图像锐化的效果和作用。
- 掌握图像模板运算的流程。
二、实验主要仪器设备和材料
计算机,VS+OpenCV
三、实验原理
1、图像平滑
众所周知,实际获得的图像在形成、传输、接收和处理的过程中,不可避免地存在着外部和内部的噪声干扰。噪声恶化了图像质量,使图像模糊,给分析带来困难。因此,去除噪声,恢复原始图像时图像处理中的一个重要内容。消除图像噪声的工作称之为图像平滑或滤波。
图像平滑方法包括空域法和频域法两大类。在空域法中,图像平滑常用的方法是采用均值滤波或中值滤波。对于均值滤波,它是采用一个有奇数点的滑动窗口在图像上滑动,将窗口中心点对应的图像像素点的灰度值用窗口内的各个点的灰度值的平均值代替,在取均值过程中,如果窗口规定了各个像素点所占的权重,也就是各个像素点的系数,则称为加权均值滤波。对于中值滤波,窗口中心点所对应像素的灰度值用窗口内所有像素的中间值代替。实现均值或中值滤波时,可以定义一个n*n的模板数组。另外,读者需要注意一点,在用窗口扫描图像过程中,对于图像四个边缘的像素点,可以不处理;也可以用灰度值为"0"的像素点扩展图像的边缘。
2、图象锐化
锐化处理的主要目的是突出图像中的细节或者增强被模糊了的细节,这种模糊不是由于错误操作,就是特殊图像获取方法的固有影响。图像均值滤波器可以使图像变模糊,是因为均值处理与积分相类似,因此可以对其进行逆运算(如微分运算)就可以使图像变得清晰。
常常采用基于一阶或二阶微分的锐化滤波器实现图像的锐化处理。一阶微分是通过梯度法来实现的。对于图像f(i,j),它在点(i,j)处的梯度是一个矢量,定义为:
利用差分法近似上述公式,得到:
为了便于编程和提高运算,可进一步简化为:
利用差分运算时,图像的第一行和第一列的像素的梯度无法求得,一般用后一行或后一列的梯度值近似代替。微分运算可以增强图像高频分量(边缘等细节),但是仅仅微分处理后的图像非常暗,因此既要增强图像边缘,又要保持目标物体的内部灰度不变,常采用给边缘规定一个特定的灰度级的方法来完成梯度锐化处理。公式为:
La为一指定的灰度值,它将边界的灰度值统一化,这样可以使其边界更加清晰明显。该方法基本上不破坏图像的背景,又可找到边缘,并根据需要增强边缘。
基于二阶微分的锐化滤波器,即拉普拉斯增强算子。一个二元图像函数f(x, y)的拉普拉斯变换定义为:
由于拉普拉斯是一种微分算子,它的应用强调图像中灰度的突变及降低灰度慢变化的区域,这将产生一幅把图像中的浅灰色边线和突变点叠加到暗背景中的图像。将原始图像和拉普拉斯图像叠加在一起的简单方法可以保护拉普拉斯锐化处理的效果,同时又能复原背景信息。这种方法可表示为:
四、实验内容和要求
编程实现车牌图像的去噪和锐化处理。首先对图像去噪,分别采用均值滤波器和中值滤波器进行处理,比较两种滤波器效果;然后对去噪后的图像进行锐化,分别采用一阶微分和二阶微分,比较锐化效果。
五、实验设计思路
1.均值滤波器即把邻域内的平均值赋给中心元素。
2.中值滤波器即把邻域内的中值赋给中心元素。
3. 对去噪图像进行像素值进行一阶微分与二阶微分,得到锐化图像。
六、实验代码
#include <iostream>
#include <opencv2/opencv.hpp>
using namespace std;
using namespace cv;
//均值滤波函数
void AverFiltering(const Mat& src, Mat& dst) {
if (!src.data) return;
//at访问像素点
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] = (src.at<Vec3b>(i, j)[0] + src.at<Vec3b>(i - 1, j - 1)[0] + src.at<Vec3b>(i - 1, j)[0] + src.at<Vec3b>(i, j - 1)[0] +
src.at<Vec3b>(i - 1, j + 1)[0] + src.at<Vec3b>(i + 1, j - 1)[0] + src.at<Vec3b>(i + 1, j + 1)[0] + src.at<Vec3b>(i, j + 1)[0] +
src.at<Vec3b>(i + 1, j)[0]) / 9;
dst.at<Vec3b>(i, j)[1] = (src.at<Vec3b>(i, j)[1] + src.at<Vec3b>(i - 1, j - 1)[1] + src.at<Vec3b>(i - 1, j)[1] + src.at<Vec3b>(i, j - 1)[1] +
src.at<Vec3b>(i - 1, j + 1)[1] + src.at<Vec3b>(i + 1, j - 1)[1] + src.at<Vec3b>(i + 1, j + 1)[1] + src.at<Vec3b>(i, j + 1)[1] +
src.at<Vec3b>(i + 1, j)[1]) / 9;
dst.at<Vec3b>(i, j)[2] = (src.at<Vec3b>(i, j)[2] + src.at<Vec3b>(i - 1, j - 1)[2] + src.at<Vec3b>(i - 1, j)[2] + src.at<Vec3b>(i, j - 1)[2] +
src.at<Vec3b>(i - 1, j + 1)[2] + src.at<Vec3b>(i + 1, j - 1)[2] + src.at<Vec3b>(i + 1, j + 1)[2] + src.at<Vec3b>(i, j + 1)[2] +
src.at<Vec3b>(i + 1, j)[2]) / 9;
}
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];
}
}
}
//求九个数的中值
uchar Median(uchar n1, uchar n2, uchar n3, uchar n4, uchar n5,
uchar n6, uchar n7, uchar n8, uchar n9) {
uchar arr[9];
arr[0] = n1;
arr[1] = n2;
arr[2] = n3;
arr[3] = n4;
arr[4] = n5;
arr[5] = n6;
arr[6] = n7;
arr[7] = n8;
arr[8] = n9;
sort(arr, arr + 9);//指针
//for (int gap = 9 / 2; gap > 0; gap /= 2)//希尔排序
// for (int i = gap; i < 9; ++i)
// for (int j = i - gap; j >= 0 && arr[j] > arr[j + gap]; j -= gap)
// swap(arr[j], arr[j + gap]);
return arr[4];//返回中值
}
//中值滤波函数
void MedianFlitering(const Mat& src, Mat& dst) {
if (!src.data)return;
for (int i = 0; i < src.rows; ++i)
for (int j = 0; j < src.cols; ++j) {
if (i > 1 && i < src.rows - 1 && j > 1 && j < src.cols - 1) {
dst.at<Vec3b>(i, j)[0] = Median(src.at<Vec3b>(i, j)[0], src.at<Vec3b>(i + 1, j + 1)[0],
src.at<Vec3b>(i + 1, j)[0], src.at<Vec3b>(i, j + 1)[0], src.at<Vec3b>(i + 1, j - 1)[0],
src.at<Vec3b>(i - 1, j + 1)[0], src.at<Vec3b>(i - 1, j)[0], src.at<Vec3b>(i, j - 1)[0],
src.at<Vec3b>(i - 1, j - 1)[0]);
dst.at<Vec3b>(i, j)[1] = Median(src.at<Vec3b>(i, j)[1], src.at<Vec3b>(i + 1, j + 1)[1],
src.at<Vec3b>(i + 1, j)[1], src.at<Vec3b>(i, j + 1)[1], src.at<Vec3b>(i + 1, j - 1)[1],
src.at<Vec3b>(i - 1, j + 1)[1], src.at<Vec3b>(i - 1, j)[1], src.at<Vec3b>(i, j - 1)[1],
src.at<Vec3b>(i - 1, j - 1)[1]);
dst.at<Vec3b>(i, j)[2] = Median(src.at<Vec3b>(i, j)[2], src.at<Vec3b>(i + 1, j + 1)[2],
src.at<Vec3b>(i + 1, j)[2], src.at<Vec3b>(i, j + 1)[2], src.at<Vec3b>(i + 1, j - 1)[2],
src.at<Vec3b>(i - 1, j + 1)[2], src.at<Vec3b>(i - 1, j)[2], src.at<Vec3b>(i, j - 1)[2],
src.at<Vec3b>(i - 1, j - 1)[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];
}
}
}
// 梯度锐化函数
void DegreeSharpDeal(const Mat& src, Mat& dst) {
if (!src.data)return;
for (int i = 0; i < src.rows; ++i)
for (int j = 0; j < src.cols; ++j) {
float a, b, c;
if (i > 1 && j > 1) {
a = abs((float)src.at<Vec3b>(i, j)[0] - (float)src.at<Vec3b>(i - 1, j)[0]) + abs((float)src.at<Vec3b>(i, j)[0] - (float)src.at<Vec3b>(i, j - 1)[0]);
b = abs((float)src.at<Vec3b>(i, j)[1] - (float)src.at<Vec3b>(i - 1, j)[1]) + abs((float)src.at<Vec3b>(i, j)[1] - (float)src.at<Vec3b>(i, j - 1)[1]);
c = abs((float)src.at<Vec3b>(i, j)[2] - (float)src.at<Vec3b>(i - 1, j)[2]) + abs((float)src.at<Vec3b>(i, j)[2] - (float)src.at<Vec3b>(i, j - 1)[2]);
a = a + src.at<Vec3b>(i, j)[0];
b = b + src.at<Vec3b>(i, j)[1];
c = c + src.at<Vec3b>(i, j)[2];
}
else {//边缘赋值
a = src.at<Vec3b>(i, j)[0];
b = src.at<Vec3b>(i, j)[1];
c = src.at<Vec3b>(i, j)[2];
}
if (a > 255 || b > 255 || b > 255 || a < 0 || b < 0 || c < 0) {
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];
}
else {
dst.at<Vec3b>(i, j)[0] = a;
dst.at<Vec3b>(i, j)[1] = b;
dst.at<Vec3b>(i, j)[2] = c;
}
}
}
// 拉普拉斯锐化函数
void LaplacianSharpDeal(const Mat& src, Mat& dst) {
if (!src.data)return;
Mat img(src.size(), src.type());
for (int i = 0; i < src.rows; ++i)
for (int j = 0; j < src.cols; ++j) {
float a, b, c;
if (i > 1 && i < src.rows - 1 && j > 1 && j < src.cols - 1) {
a = 5 * (float)src.at<Vec3b>(i, j)[0] - (float)src.at<Vec3b>(i - 1, j)[0] - (float)src.at<Vec3b>(i, j - 1)[0] -
(float)src.at<Vec3b>(i, j + 1)[0] - (float)src.at<Vec3b>(i + 1, j)[0];
b = 5 * (float)src.at<Vec3b>(i, j)[1] - (float)src.at<Vec3b>(i - 1, j)[1] - (float)src.at<Vec3b>(i, j - 1)[1] -
(float)src.at<Vec3b>(i, j + 1)[1] - (float)src.at<Vec3b>(i + 1, j)[1];
c = 5 * (float)src.at<Vec3b>(i, j)[2] - (float)src.at<Vec3b>(i - 1, j)[2] - (float)src.at<Vec3b>(i, j - 1)[2] -
(float)src.at<Vec3b>(i, j + 1)[2] - (float)src.at<Vec3b>(i + 1, j)[2];
}
else {//边缘赋值
a = src.at<Vec3b>(i, j)[0];
b = src.at<Vec3b>(i, j)[1];
c = src.at<Vec3b>(i, j)[2];
}
if (a > 255 || b > 255 || b > 255 || a < 0 || b < 0 || c < 0) {
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];
}
else {
dst.at<Vec3b>(i, j)[0] = a;
dst.at<Vec3b>(i, j)[1] = b;
dst.at<Vec3b>(i, j)[2] = c;
}
}
}
void main() {
Mat image = imread("噪声图像.bmp");
Mat image1(image.size(), image.type());
Mat image2(image.size(), image.type());
Mat image3(image2.size(), image2.type());
Mat image4(image2.size(), image2.type());
AverFiltering(image, image1);
MedianFlitering(image, image2);
LaplacianSharpDeal(image2, image3);
DegreeSharpDeal(image2, image4);
imshow("原图像", image);
imshow("均值滤波", image1);
imshow("中值滤波", image2);
imshow("拉普拉斯锐化处理", image3);
imshow("梯度锐化处理", image4);
waitKey();
}
七、实验结果与心得体会
实验结果明显,在此图像中使用中值滤波器与二阶微分效果更好。本次实验,更好的巩固了对图像去噪以及锐化的原理,使得不在仅限于原理的理解,而是从实践中更好的学习。通过此次实验,对今后图像处理的学习有了较大的帮助。