图像滤波
基本的图像滤波包括两类:图像平滑与图像锐化。
一、图像平滑
图像平滑是一种可以减少和抑制图像噪声的实用数字图像处理技术。
1、均值滤波
对于图像中的某个像素点的值,其均值滤波后的值为该像素邻域所有像素及自身的均值,模板为:
2、高斯滤波
二维高斯函数为:
因此,(2k+1)×(2k+1)高斯平滑模板可以表示为:
如常见的3×3高斯模板为:
3、中值滤波
对于图像中的某个像素点的值,其中值滤波后的值为该像素邻域所有像素及自身的像素值的中值,中值滤波的一种经典应用是消除椒盐噪声。
二、图像锐化
图像锐化的目的是将模糊的图像变得更加清晰。
(一)基于一阶导数的图像增强
其中:
对于二维离散函数,上式可近似为:
实际应用中,常被采用的是另一种近似梯度-Robert交叉梯度,即:
1、Robert交叉梯度
2、Sobel梯度
其中,w1和w2分别为对水平边缘有较大响应的竖直梯度和对竖直方向有较大响应的水平梯度。另外,还有对45°和135°方向响应的模板:
(一)基于二阶导数的图像增强——拉普拉斯算子
二维函数二阶微分为:
对于离散的二维图像,上述微分可近似为:
从而有:
因此,对应的模板为:
等同于:
三、基于模板的滤波程序
程序设计思路:
遍历目标图像中的每个像素点,对于目标图像中某个坐标(x1, y1)处的点有:
对于原图像,如果x0+i<0或y0+j<0或x0+i≥W或y0+j≥H则可以选择不同的填充方法:
①直接补0;②选择最近点填充;③收缩处理范围
实现代码:
/*****************************************************************************
函数名 : ImgFilter
功能 : 图像滤波
算法实现 : <可选项>
参数说明 : tSrcImg 原图像[in]
ptDstImg 目标图像[out]
au8TempMat 模板[in]
u8TempH 模板高度/行数[in]
u8TempW 模板宽度/列数[in]
返回值说明 : 无
其他说明 : 无
******************************************************************************/
void ImgFilter(MyImage tSrcImg, MyImage *ptDstImg, f32 *au8TempMat, u8 u8TempH, u8 u8TempW)
{
/*原图像高、宽、通道数*/
l32 l32SrcImgHeight = tSrcImg.l32ImgH;
l32 l32SrcImgWidth = tSrcImg.l32ImgW;
l32 l32ImgChs = tSrcImg.l32ImgChs;
/*目标图像高、宽(等于原图像)*/
l32 l32DstImgHeight = l32SrcImgHeight;
l32 l32DstImgWidth = l32SrcImgWidth;
MyImageInit(ptDstImg, l32DstImgHeight, l32DstImgWidth, l32ImgChs);
for (l32 l32DstImgHeightIdx = 0; l32DstImgHeightIdx < l32DstImgHeight; l32DstImgHeightIdx++)
{
for (l32 l32DstImgWidthIdx = 0; l32DstImgWidthIdx < l32DstImgWidth; l32DstImgWidthIdx++)
{
for (l32 l32ImgChsIdx = 0; l32ImgChsIdx < l32ImgChs; l32ImgChsIdx++)
{
l32 l32DstImgPixelPos = l32DstImgHeightIdx * l32DstImgWidth * l32ImgChs + \
l32DstImgWidthIdx * l32ImgChs + l32ImgChsIdx; //目标图像像素在内存中的位置
l32 l32MatMulResult = 0;//目标图像像素值
for (u8 u8MatHeightIdx = 0; u8MatHeightIdx < u8TempH; u8MatHeightIdx++)
{
for (u8 u8MatWidthIdx = 0; u8MatWidthIdx < u8TempW; u8MatWidthIdx++)
{
l32 l32SrcImgHeightIdx = l32DstImgHeightIdx + u8MatHeightIdx - u8(u8TempH / 2);
l32 l32SrcImgWidthIdx = l32DstImgWidthIdx + u8MatWidthIdx - u8(u8TempW / 2);
if (l32SrcImgHeightIdx < 0 || l32SrcImgHeightIdx >= l32SrcImgHeight || l32SrcImgWidthIdx < 0 || l32SrcImgWidthIdx >= l32SrcImgWidth)
{
l32MatMulResult += 0; //边缘填充0
}
else
{
l32 l32SrcImgPixelPos = l32SrcImgHeightIdx * l32SrcImgWidth * l32ImgChs + \
l32SrcImgWidthIdx * l32ImgChs + l32ImgChsIdx; //原图像像素在内存中的位置
l32MatMulResult += au8TempMat[u8MatHeightIdx * u8TempW + u8MatWidthIdx] * tSrcImg.pu8Data[l32SrcImgPixelPos];
}
}
}
if (l32MatMulResult < 0)
{
l32MatMulResult = 0;
}
if (l32MatMulResult > 255)
{
l32MatMulResult = 255;
}
ptDstImg->pu8Data[l32DstImgPixelPos] = u8(l32MatMulResult);
}
}
}
}
四、中值滤波程序
程序设计思路:
遍历目标图像中的每个像素点,对于目标图像中某个坐标(x1, y1)处的点,对其8邻域及其自身像素值排序,取中值作为Pdst(x1, y1)。
实现代码:
/*****************************************************************************
函数名 : ImgMedianFilter
功能 : 图像中值滤波
算法实现 : <可选项>
参数说明 : tSrcImg 原图像[in]
ptDstImg 目标图像[out]
u8TempH 窗体区域高[in]
u8TempW 窗体区域宽[in]
返回值说明 : 无
其他说明 : 无
******************************************************************************/
void ImgMedianFilter(MyImage tSrcImg, MyImage *ptDstImg, u8 u8AreaH, u8 u8AreaW)
{
/*原图像高、宽、通道数*/
l32 l32SrcImgHeight = tSrcImg.l32ImgH;
l32 l32SrcImgWidth = tSrcImg.l32ImgW;
l32 l32ImgChs = tSrcImg.l32ImgChs;
/*目标图像高、宽(等于原图像)*/
l32 l32DstImgHeight = l32SrcImgHeight;
l32 l32DstImgWidth = l32SrcImgWidth;
u8 u8ArrSize = u8AreaH * u8AreaW;
u8 *pu8NghbPixel = (u8 *)malloc(u8ArrSize * sizeof(u8));
u8 *u8pStart = pu8NghbPixel;
MyImageInit(ptDstImg, l32DstImgHeight, l32DstImgWidth, l32ImgChs);
for (l32 l32DstImgHeightIdx = 0; l32DstImgHeightIdx < l32DstImgHeight; l32DstImgHeightIdx++)
{
for (l32 l32DstImgWidthIdx = 0; l32DstImgWidthIdx < l32DstImgWidth; l32DstImgWidthIdx++)
{
for (l32 l32ImgChsIdx = 0; l32ImgChsIdx < l32ImgChs; l32ImgChsIdx++)
{
l32 l32DstImgPixelPos = l32DstImgHeightIdx * l32DstImgWidth * l32ImgChs + \
l32DstImgWidthIdx * l32ImgChs + l32ImgChsIdx; //目标图像像素在内存中的位置
l32 l32MatMulResult = 0;//目标图像像素值
for (u8 u8MatHeightIdx = 0; u8MatHeightIdx < u8AreaH; u8MatHeightIdx++)
{
for (u8 u8MatWidthIdx = 0; u8MatWidthIdx < u8AreaW; u8MatWidthIdx++)
{
l32 l32SrcImgHeightIdx = l32DstImgHeightIdx + u8MatHeightIdx - u8(u8AreaH / 2);
l32 l32SrcImgWidthIdx = l32DstImgWidthIdx + u8MatWidthIdx - u8(u8AreaW / 2);
l32 l32SrcImgPixelPos = l32SrcImgHeightIdx * l32SrcImgWidth * l32ImgChs + \
l32SrcImgWidthIdx * l32ImgChs + l32ImgChsIdx; //原图像像素在内存中的位置
if (l32SrcImgHeightIdx < 0 || l32SrcImgHeightIdx >= l32SrcImgHeight || l32SrcImgWidthIdx < 0 || l32SrcImgWidthIdx >= l32SrcImgWidth)
{
//*pu8NghbPixel = 0; //边缘填充0
pu8NghbPixel[u8MatHeightIdx * u8AreaW + u8MatWidthIdx] = 0;
}
else
{
//*pu8NghbPixel = tSrcImg.pu8Data[l32SrcImgPixelPos];
pu8NghbPixel[u8MatHeightIdx * u8AreaW + u8MatWidthIdx] = tSrcImg.pu8Data[l32SrcImgPixelPos];
}
//pu8NghbPixel++;
}
}
for (u8 u8ArrIdx1 = 0; u8ArrIdx1 < u8ArrSize-1; u8ArrIdx1++)
{
for (u8 u8ArrIdx2 = u8ArrSize - 1; u8ArrIdx2 > u8ArrIdx1; u8ArrIdx2--)
{
u8 u8Temp;
if (pu8NghbPixel[u8ArrIdx2] > pu8NghbPixel[u8ArrIdx2 - 1])
{
u8Temp = pu8NghbPixel[u8ArrIdx2];
pu8NghbPixel[u8ArrIdx2] = pu8NghbPixel[u8ArrIdx2 - 1];
pu8NghbPixel[u8ArrIdx2 - 1] = u8Temp;
}
}
}
if (u8ArrSize % 2 == 0)
ptDstImg->pu8Data[l32DstImgPixelPos] = (pu8NghbPixel[u8ArrSize / 2 - 1] + pu8NghbPixel[u8ArrSize / 2]) / 2;
else
ptDstImg->pu8Data[l32DstImgPixelPos] = pu8NghbPixel[(u8ArrSize - 1) / 2];
}
}
}
free(pu8NghbPixel);
}