图象锐化
建议先查看图像平滑
锐化处理的主要目的是突出图像中的细节或者增强被模糊了的细节,这种模糊不是由于错误操作,就是特殊图像获取方法的固有影响。图像均值滤波器可以使图像变模糊,是因为均值处理与积分相类似,因此可以对其进行逆运算(如微分运算)就可以使图像变得清晰。
常常采用基于一阶或二阶微分的锐化滤波器实现图像的锐化处理。
一阶微分
一阶微分是通过梯度法来实现的。对于图像f(i,j),它在点(i,j)处的梯度是一个矢量,定义为:
利用差分法近似上述公式,得到:
为了便于编程和提高运算,可进一步简化为:
利用差分运算时,图像的第一行和第一列的像素的梯度无法求得,一般用后一行或后一列的梯度值近似代替。微分运算可以增强图像高频分量(边缘等细节),但是仅仅微分处理后的图像非常暗,因此既要增强图像边缘,又要保持目标物体的内部灰度不变,常采用给边缘规定一个特定的灰度级的方法来完成梯度锐化处理。公式为:
La为一指定的灰度值,它将边界的灰度值统一化,这样可以使其边界更加清晰明显。该方法基本上不破坏图像的背景,又可找到边缘,并根据需要增强边缘。
基于二阶微分的锐化滤波器
基于二阶微分的锐化滤波器,即拉普拉斯增强算子。一个二元图像函数f(x, y)的拉普拉斯变换定义为:
由于拉普拉斯是一种微分算子,它的应用强调图像中灰度的突变及降低灰度慢变化的区域,这将产生一幅把图像中的浅灰色边线和突变点叠加到暗背景中的图像。将原始图像和拉普拉斯图像叠加在一起的简单方法可以保护拉普拉斯锐化处理的效果,同时又能复原背景信息。这种方法可表示为:
OpenCV实现
对去噪后的图像进行锐化,分别采用一阶微分和二阶微分,比较锐化效果。
一阶微分
罗伯特交叉算子
// 梯度锐化函数
// -1 1
// -1
// 1
Mat GradientSharpening(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) {
int a, b, c;
if (i < src.rows - 1 && j < src.cols - 1) {
//罗伯特交叉算子
a = abs(src.at<Vec3b>(i + 1, j )[0] - src.at<Vec3b>(i, j)[0]) + abs(src.at<Vec3b>(i , j + 1)[0] - src.at<Vec3b>(i, j)[0]);
b = abs(src.at<Vec3b>(i + 1, j )[1] - src.at<Vec3b>(i, j)[1]) + abs(src.at<Vec3b>(i , j + 1)[1] - src.at<Vec3b>(i, j)[1]);
c = abs(src.at<Vec3b>(i + 1, j )[2] - src.at<Vec3b>(i, j)[2]) + abs(src.at<Vec3b>(i , j + 1)[2] - src.at<Vec3b>(i, j)[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];
}
//颜色值 超过255,为255
if (a > 255 || b > 255 || b > 255) {
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;
}
}
return dst;
}
二阶微分
// 拉普拉斯锐化函数
// 0 -1 0
// -1 4 -1
// 0 -1 0
Mat LaplacianSharpening(const Mat& src, Mat& dst) {
if (!src.data) return src;
Mat img(src.size(), src.type());
for (int i = 0; i < src.rows; ++i)
for (int j = 0; j < src.cols; ++j) {
int a, b, c;
if (i > 1 && j > 1 && i < src.rows - 1 && j < src.cols - 1) {
//5 是因为直接加上了原来的颜色值
a = abs(4 * src.at<Vec3b>(i, j)[0] - src.at<Vec3b>(i - 1, j)[0] - src.at<Vec3b>(i + 1, j)[0] - src.at<Vec3b>(i, j - 1)[0] - src.at<Vec3b>(i, j + 1)[0] );
b = abs(4 * src.at<Vec3b>(i, j)[1] - src.at<Vec3b>(i - 1, j)[1] - src.at<Vec3b>(i + 1, j)[1] - src.at<Vec3b>(i, j - 1)[1] - src.at<Vec3b>(i, j + 1)[1] );
c = abs(4 * src.at<Vec3b>(i, j)[2] - src.at<Vec3b>(i - 1, j)[2] - src.at<Vec3b>(i + 1, j)[2] - src.at<Vec3b>(i, j - 1)[2] - src.at<Vec3b>(i, j + 1)[2] );
a += src.at<Vec3b>(i, j)[0];
b += src.at<Vec3b>(i, j)[1];
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 ) {
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;
}
}
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;
}
// 梯度锐化函数
Mat GradientSharpening(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) {
int a, b, c;
if (i < src.rows - 1 && j < src.cols - 1) {
//罗伯特交叉算子
a = abs(src.at<Vec3b>(i + 1, j )[0] - src.at<Vec3b>(i, j)[0]) + abs(src.at<Vec3b>(i , j + 1)[0] - src.at<Vec3b>(i, j)[0]);
b = abs(src.at<Vec3b>(i + 1, j )[1] - src.at<Vec3b>(i, j)[1]) + abs(src.at<Vec3b>(i , j + 1)[1] - src.at<Vec3b>(i, j)[1]);
c = abs(src.at<Vec3b>(i + 1, j )[2] - src.at<Vec3b>(i, j)[2]) + abs(src.at<Vec3b>(i , j + 1)[2] - src.at<Vec3b>(i, j)[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];
}
//颜色值 超过255,为255
if (a > 255 || b > 255 || b > 255) {
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;
}
}
return dst;
}
// 拉普拉斯锐化函数
// 0 -1 0
// -1 4 -1
// 0 -1 0
Mat LaplacianSharpening(const Mat& src, Mat& dst) {
if (!src.data) return src;
Mat img(src.size(), src.type());
for (int i = 0; i < src.rows; ++i)
for (int j = 0; j < src.cols; ++j) {
int a, b, c;
if (i > 1 && j > 1 && i < src.rows - 1 && j < src.cols - 1) {
//5 是因为直接加上了原来的颜色值
a = abs(4 * src.at<Vec3b>(i, j)[0] - src.at<Vec3b>(i - 1, j)[0] - src.at<Vec3b>(i + 1, j)[0] - src.at<Vec3b>(i, j - 1)[0] - src.at<Vec3b>(i, j + 1)[0] );
b = abs(4 * src.at<Vec3b>(i, j)[1] - src.at<Vec3b>(i - 1, j)[1] - src.at<Vec3b>(i + 1, j)[1] - src.at<Vec3b>(i, j - 1)[1] - src.at<Vec3b>(i, j + 1)[1] );
c = abs(4 * src.at<Vec3b>(i, j)[2] - src.at<Vec3b>(i - 1, j)[2] - src.at<Vec3b>(i + 1, j)[2] - src.at<Vec3b>(i, j - 1)[2] - src.at<Vec3b>(i, j + 1)[2] );
a += src.at<Vec3b>(i, j)[0];
b += src.at<Vec3b>(i, j)[1];
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 ) {
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;
}
}
return dst;
}
int main()
{
Mat src = imread("F:/雪野Solye/所有课程/大三下课程/数字图像与艺术分析/img/噪声图像.bmp");
Mat averageFilter;
Mat medianFilter;
Mat gradientSharpening;
Mat laplacianSharpening;
averageFilter.create(src.rows, src.cols, src.type());
medianFilter.create(src.rows, src.cols, src.type());
gradientSharpening.create(src.rows, src.cols, src.type());
laplacianSharpening.create(src.rows, src.cols, src.type());
imshow("原图", src);
imshow("均值滤波", AverageFilter(src, averageFilter));
imshow("中值滤波", MedianFilter(src,medianFilter));
imshow("梯度锐化", GradientSharpening(medianFilter, gradientSharpening));
imshow("拉普拉斯增强算子锐化", LaplacianSharpening(medianFilter, laplacianSharpening));
return waitKey(0);
}