- //---------------------------------------------------------------------------
-
- //
定义ARGB像素结构 - typedef
union - {
-
ARGB Color; -
struct -
{ -
BYTE Blue; -
BYTE Green; -
BYTE Red; -
BYTE Alpha; -
}; - }ARGBQuad,
*PARGBQuad; - //---------------------------------------------------------------------------
-
- //
获取二值图像data的字节图数据map,骨架像素是否为黑色 - VOID
GetDataMap(CONST BitmapData *data, BitmapData *map, BOOL blackPixel) - {
-
// 字节图边缘扩展1字节,便于处理data的边缘像素 -
map->Width = data->Width + 2; -
map->Height = data->Height + 2; -
map->Stride = map->Width; -
map->Scan0 = (void*)new char[map->Stride * map->Height + 1];// +1防最末字节越界 -
BYTE *ps = (BYTE*)data->Scan0; -
BYTE *pd0 = (BYTE*)map->Scan0; -
BYTE *pd = pd0 + map->Stride; -
BYTE *pt = pd; -
INT srcOffset = data->Stride - data->Width * sizeof(ARGBQuad); -
UINT x, y; -
-
// 如果骨架像素为黑色,获取异或字节图 -
if (blackPixel) -
{ -
for (y = 0; y < data->Height; y ++, ps += srcOffset) -
{ -
*pd ++ = *ps ^ 255; -
for (x = 0; x < data->Width; x ++, ps += sizeof(ARGBQuad)) -
*pd ++ = *ps ^ 255; -
*pd ++ = *(ps - sizeof(ARGBQuad)) ^ 255; -
} -
-
} -
// 否则,获取正常字节图 -
else -
{ -
for (y = 0; y < data->Height; y ++, *pd ++ = *(ps - sizeof(ARGBQuad)), ps += srcOffset) -
{ -
for (x = 0, *pd ++ = *ps; x < data->Width; x ++, *pd ++ = *ps, ps += sizeof(ARGBQuad)); -
} -
} -
ps = pd - map->Stride; -
for (x = 0; x < map->Width; x ++, *pd0 ++ = *pt ++, *pd ++ = *ps ++); - }
- //---------------------------------------------------------------------------
-
- //
按结构元素模板templet制作字节掩码数组masks - //
templet低3字节的低3位对应结构元素,如下面的结构元素: - //
水平 垂直 十字 方形 其它 - //
○ ○ ○ ○ ● ○ ○ ● ○ ● ● ● ○ ● ○ - //
● ● ● ○ ● ○ ● ● ● ● ● ● ● ● ● - //
○ ○ ○ ○ ● ○ ○ ● ○ ● ● ● ○ ● ● - //
用templet分别表示为:0x000700, 0x020202, 0x020702, 0x070707, 0x020703 - VOID
GetTempletMasks(DWORD templet, DWORD masks[]) - {
-
for (INT i = 2; i >= 0; i --, templet >>= 8) -
{ -
masks[i] = 0; -
for (UINT j = 4; j; j >>= 1) -
{ -
masks[i] <<= 8; -
if (templet & j) masks[i] |= 1; -
} -
} - }
- //---------------------------------------------------------------------------
-
- VOID
Erosion_Dilation(BitmapData *data, DWORD templet, BOOL blackPixel) - {
-
BitmapData map; -
GetDataMap(data, &map, blackPixel); -
-
PARGBQuad pd = (PARGBQuad)data->Scan0; -
BYTE *ps = (BYTE*)map.Scan0 + map.Stride; -
INT width = (INT)data->Width; -
INT height = (INT)data->Height; -
INT dstOffset = data->Stride - width * sizeof(ARGBQuad); -
INT value = blackPixel? 0 : 255; -
INT x, y; -
-
if (templet == 0x0700) // 水平结构元素单独处理,可提高处理速度 -
{ -
for (y = 0; y < height; y ++, (BYTE*)pd += dstOffset, ps += 2) -
{ -
for (x = 0; x < width; x ++, pd ++, ps ++) -
{ -
if (*(DWORD*)ps & 0x010101) -
pd->Blue = pd->Green = pd->Red = value; -
} -
} -
} -
else -
{ -
DWORD masks[3]; -
GetTempletMasks(templet, masks); -
-
for (y = 0; y < height; y ++, (BYTE*)pd += dstOffset, ps += 2) -
{ -
for (x = 0; x < width; x ++, pd ++, ps ++) -
{ -
if (*(DWORD*)(ps - map.Stride) & masks[0] || -
*(DWORD*)ps & masks[1] || -
*(DWORD*)(ps + map.Stride) & masks[2]) -
pd->Blue = pd->Green = pd->Red = value; -
} -
} -
} -
-
delete map.Scan0; - }
- //---------------------------------------------------------------------------
-
- //
二值图膨胀。参数:二值图数据,结构元素模板,是否黑色像素骨架 - FORCEINLINE
- VOID
Dilation(BitmapData *data, DWORD templet, BOOL blackPixel = TRUE) - {
-
Erosion_Dilation(data, templet, blackPixel); - }
- //---------------------------------------------------------------------------
-
- //
二值图腐蚀。参数:二值图数据,结构元素模板,是否黑色像素骨架 - FORCEINLINE
- VOID
Erosion(BitmapData *data, DWORD templet, BOOL blackPixel = TRUE) - {
-
Erosion_Dilation(data, templet, !blackPixel); - }
- //---------------------------------------------------------------------------
- //---------------------------------------------------------------------------
-
- VOID
_Dilation(BitmapData *data, BitmapData *map, DWORD templet) - {
-
PARGBQuad pd = (PARGBQuad)data->Scan0; -
BYTE *ps = (BYTE*)map->Scan0 + map->Stride; -
INT width = (INT)data->Width; -
INT height = (INT)data->Height; -
INT dstOffset = data->Stride - width * sizeof(ARGBQuad); -
INT x, y; -
-
if (templet == 0x0700) // 水平结构元素单独处理,可提高处理速度 -
{ -
for (y = 0; y < height; y ++, (BYTE*)pd += dstOffset, ps += 2) -
{ -
for (x = 0; x < width; x ++, pd ++, ps ++) -
if (*(DWORD*)ps & 0x010101) -
pd->Color &= 0xff000000; -
} -
} -
else -
{ -
DWORD masks[3]; -
GetTempletMasks(templet, masks); -
-
for (y = 0; y < height; y ++, (BYTE*)pd += dstOffset, ps += 2) -
{ -
for (x = 0; x < width; x ++, pd ++, ps ++) -
if (*(DWORD*)(ps - map->Stride) & masks[0] || -
*(DWORD*)ps & masks[1] || -
*(DWORD*)(ps + map->Stride) & masks[2]) -
pd->Color &= 0xff000000; -
} -
} - }
- //---------------------------------------------------------------------------
-
- VOID
_Erosion(BitmapData *data, BitmapData *map, DWORD templet) - {
-
PARGBQuad pd = (PARGBQuad)data->Scan0; -
BYTE *ps = (BYTE*)map->Scan0 + map->Stride; -
INT width = (INT)data->Width; -
INT height = (INT)data->Height; -
INT dstOffset = data->Stride - width * sizeof(ARGBQuad); -
INT x, y; -
-
if (templet == 0x0700) // 水平结构元素单独处理,可提高处理速度 -
{ -
for (y = 0; y < height; y ++, (BYTE*)pd += dstOffset, ps += 2) -
{ -
for (x = 0; x < width; x ++, pd ++, ps ++) -
if (*(DWORD*)ps & 0x010101) -
pd->Color |= 0x00ffffff; -
} -
} -
else -
{ -
DWORD masks[3]; -
GetTempletMasks(templet, masks); -
-
for (y = 0; y < height; y ++, (BYTE*)pd += dstOffset, ps += 2) -
{ -
for (x = 0; x < width; x ++, pd ++, ps ++) -
if (*(DWORD*)(ps - map->Stride) & masks[0] || -
*(DWORD*)ps & masks[1] || -
*(DWORD*)(ps + map->Stride) & masks[2]) -
pd->Color |= 0x00ffffff; -
} -
} - }
- //---------------------------------------------------------------------------
-
- //
二值图膨胀。参数:二值图数据,结构元素模板,是否黑色像素骨架 - VOID
Dilation(BitmapData *data, DWORD templet, BOOL blackPixel = TRUE) - {
-
BitmapData map; -
GetDataMap(data, &map, blackPixel); -
if (blackPixel) -
_Dilation(data, &map, templet); -
else -
_Erosion(data, &map, templet); -
delete map.Scan0; - }
- //---------------------------------------------------------------------------
-
- //
二值图腐蚀。参数:二值图数据,结构元素模板,是否黑色像素骨架 - VOID
Erosion(BitmapData *data, DWORD templet, BOOL blackPixel = TRUE) - {
-
Dilation(data, templet, !blackPixel); - }
- //---------------------------------------------------------------------------
- //---------------------------------------------------------------------------
-
- //
图像数据data灰度同时二值化,threshold阀值 - VOID
GrayAnd2Values(BitmapData *data, BYTE threshold) - {
-
PARGBQuad p = (PARGBQuad)data->Scan0; -
INT offset = data->Stride - data->Width * sizeof(ARGBQuad); -
-
for (UINT y = 0; y < data->Height; y ++, (BYTE*)p += offset) -
{ -
for (UINT x = 0; x < data->Width; x ++, p ++) -
{ -
if (((p->Blue * 29 + p->Green * 150 + p->Red * 77 + 128) >> 8) < threshold) -
p->Color &= 0xff000000; -
else -
p->Color |= 0x00ffffff; -
-
} -
} - }
- //---------------------------------------------------------------------------
-
- //
锁定GDI+位位图扫描线到data - FORCEINLINE
- VOID
LockBitmap(Gdiplus::Bitmap *bmp, BitmapData *data) - {
-
Gdiplus::Rect r(0, 0, bmp->GetWidth(), bmp->GetHeight()); -
bmp->LockBits(&r, ImageLockModeRead | ImageLockModeWrite, -
PixelFormat32bppARGB, data); - }
- //---------------------------------------------------------------------------
-
- //
GDI+位图扫描线解锁 - FORCEINLINE
- VOID
UnlockBitmap(Gdiplus::Bitmap *bmp, BitmapData *data) - {
-
bmp->UnlockBits(data); - }
- //---------------------------------------------------------------------------
-
- void
__fastcall TForm1::Button1Click(TObject *Sender) - {
-
Gdiplus::Bitmap *bmp = new Gdiplus::Bitmap(L"d:\\source1.jpg"); -
Gdiplus::Graphics *g = new Gdiplus::Graphics(Canvas->Handle); -
g->DrawImage(bmp, 0, 0); -
BitmapData data; -
LockBitmap(bmp, &data); -
-
GrayAnd2Values(&data, 128); -
Erosion(&data, 0x020702); -
Dilation(&data, 0x020702); -
-
UnlockBitmap(bmp, &data); -
g->DrawImage(bmp, data.Width, 0); -
delete g; -
delete bmp; - }
- //---------------------------------------------------------------------------