形态学运算
1、腐蚀与膨胀
腐蚀与膨胀是针对二值化图像而言的。
腐蚀:使用(2k+1)*(2k+1)的模板S对图像A进行腐蚀,当S移动至A中某点z时,如果S能完全包含在A中(设S为所有值都是255的模板,而A的(2k+1)*(2k+1)邻域以及z点值也都是255,那么就说S能完全包含在A中),那么由这样的点z构成的图像即为S对A的腐蚀图像。
膨胀:使用(2k+1)*(2k+1)的模板S'对图像A进行膨胀,当S'移动至A中某点z时,如果S'与A的(2k+1)*(2k+1)邻域以及z点值有重叠,那么由这样的点z构成的图像即为S'对A的膨胀图像。
实现代码:
/*****************************************************************************
函数名 : ImgErodeDilate
功能 : 腐蚀膨胀
算法实现 : <可选项>
参数说明 : tSrcImg 原图像[in]
ptDstImg 目标图像[out]
u8TempH 窗体区域高[in]
u8TempW 窗体区域宽[in]
u8OpMode 运算模式[in]
返回值说明 : 无
其他说明 : 无
******************************************************************************/
void ImgErodeDilate(MyImage tSrcImg, MyImage *ptDstImg, u8 u8AreaH, u8 u8AreaW, u8 u8OpMode)
{
/*原图像高、宽、通道数*/
l32 l32SrcImgHeight = tSrcImg.l32ImgH;
l32 l32SrcImgWidth = tSrcImg.l32ImgW;
/*目标图像高、宽(等于原图像)*/
l32 l32DstImgHeight = l32SrcImgHeight;
l32 l32DstImgWidth = l32SrcImgWidth;
MyImageInit(ptDstImg, l32DstImgHeight, l32DstImgWidth, 1);
for (l32 l32DstImgHeightIdx = 0; l32DstImgHeightIdx < l32DstImgHeight; l32DstImgHeightIdx++)
{
for (l32 l32DstImgWidthIdx = 0; l32DstImgWidthIdx < l32DstImgWidth; l32DstImgWidthIdx++)
{
u8 u8IsErode = 1;
u8 u8IsDilate = 0;
l32 l32DstImgPixelPos = l32DstImgHeightIdx * l32DstImgWidth + l32DstImgWidthIdx; //目标图像像素在内存中的位置
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 + l32SrcImgWidthIdx; //原图像像素在内存中的位置
if (l32SrcImgHeightIdx >= 0 && l32SrcImgHeightIdx < l32SrcImgHeight && l32SrcImgWidthIdx >= 0 && l32SrcImgWidthIdx < l32SrcImgWidth)
{
switch (u8OpMode)
{
case MORP_ERODE:
if (tSrcImg.pu8Data[l32SrcImgPixelPos] != 255)
u8IsErode = 0;
break;
case MORP_DILATE:
if (tSrcImg.pu8Data[l32SrcImgPixelPos] == 255)
u8IsDilate = 1;
break;
default:break;
}
}
}
}
switch (u8OpMode)
{
case MORP_ERODE:
if (u8IsErode)
ptDstImg->pu8Data[l32DstImgPixelPos] = 255;
break;
case MORP_DILATE:
if (u8IsDilate)
ptDstImg->pu8Data[l32DstImgPixelPos] = 255;
break;
default:break;
}
}
}
}
2、开运算与闭运算
开运算是先腐蚀再膨胀,而闭运算是先膨胀再腐蚀。
实现代码:
/*****************************************************************************
函数名 : ImgOpenClose
功能 : 开闭运算
算法实现 : <可选项>
参数说明 : tSrcImg 原图像[in]
ptDstImg 目标图像[out]
u8TempH 窗体区域高[in]
u8TempW 窗体区域宽[in]
u8OpMode 运算模式[in]
返回值说明 : 无
其他说明 : 无
******************************************************************************/
void ImgOpenClose(MyImage tSrcImg, MyImage *ptDstImg, u8 u8AreaH, u8 u8AreaW, u8 u8OpMode)
{
MyImage tImgErode, tImgDilate;
switch (u8OpMode)
{
case MORP_OPEN:
ImgErodeDilate(tSrcImg, &tImgErode, u8AreaH, u8AreaW, MORP_ERODE);
ImgErodeDilate(tImgErode, ptDstImg, u8AreaH, u8AreaW, MORP_DILATE);
break;
case MORP_CLOSE:
ImgErodeDilate(tSrcImg, &tImgDilate, u8AreaH, u8AreaW, MORP_DILATE);
ImgErodeDilate(tImgDilate, ptDstImg, u8AreaH, u8AreaW, MORP_ERODE);
default:break;
}
}
3、细化