一. 應用場景!
使用過Genesis的朋友都知道,它可以提取你點擊單圖元中心<提取圖元輪廓計算中心點>!
二.
由于工作需要,去年在師傅的知道下寫了一個單圖元輪廓提取算法!
三. 原理
提取輪廓即需要找出單圖元最外(內)層連續不間斷的點!
故我們需要一個起始點,即從你點擊的單圖元出發,向左(←↑→↓, 4個方向皆可,只需改變算子的起始點)遍歷至第一個與點擊點不用色調的點,此點極為最外層輪廓的起始點,然后以你所選方向為算子起始項,進行順時針(逆時針)遍歷,直到遍歷點與起始點重合,說明輪廓提取完畢!
四.
本例中我采用向左順時針遍歷,剩余的7種就交給聰明的你了!
1)準備算子結構
1 | 2 | 3 |
0 | * | 4 |
7 | 6 | 5 |
typedef struct DOTS_ARR // 采用屏幕坐標,Y軸向下!
{
INT32 OffsetX; // 相對中心點X向的偏移量
INT32 OffsetY; // 相對中心點Y向的偏移量
INT32 NextDotIndex; // 此點為目標點,下次遍歷位置索引
}DOTS_ARR;
2)未優化算子
DOTS_ARR DotsArr[] =?
{
-1, ?0, 5,
-1, -1, 6,
0, -1, 7, // 上圖中當前計算點的正上方2號點,若此點為最新提取的輪廓點,則下一點應為此點相對位置7開始遍歷,原因如下:
1, -1, 0,
1, ?0, 1,
1, ?1, 2,
0, ?1, 3,
-1, ?1, 4,
};
為了保證不遺漏,我們必須采取順時針(逆時針)遍歷當前點周圍所有點(以上次遍歷成功2號點為例)
1 | 2 | 3 |
0(1) | *(2) | 4(3) |
7(0) | 6(*) | 5(4) |
()括號中為以上以中心點為相對位置的坐標
看到上圖,聰明的朋友一定會說7不是最好的位置,1才是,應為0,7在上次的遍歷中已經被排除了(you are right)!
故最優算子如下
DOTS_ARR DotsArr[] =?
{
-1, ?0, 5,
-1, -1, 7,
0, -1, 1,
1, -1, 1,
1, ?0, 3,
1, ?1, 3,
0, ?1, 5,
-1, ?1, 5,
};
五. Demo
關鍵的算子已經序數完了,那么我用一個簡單的Demo來實踐一下!
1)先上一個提取后的效果圖
2)簡單的列幾處關鍵代碼:
1.創建一個簡單窗口類單獨用來繪制
?m_MyView.CreateEx(NULL, AfxRegisterWndClass(CS_HREDRAW,NULL,(HBRUSH)::GetStockObject(WHITE_BRUSH),NULL), L"CPaintView Window", WS_CHILD, m_MyViewRect, this, 0);
if (NULL == m_MyView)
{
TRACE(_T("Error:(%s.%d) CreateEx Failed!\r\n"), __FUNCTION__, __LINE__);
}?
2.在窗口顯示之前,加載我們的位圖
if (bShow)// Show
{
m_hMemDC = CreateCompatibleDC(NULL);
HBITMAP hBitmap = LoadBitmapW(AfxGetInstanceHandle(), MAKEINTRESOURCE(IDB_BITMAP_START));
BITMAP bmp;
GetObject(hBitmap, sizeof(BITMAP), &bmp);
m_BitmapSize.cx = bmp.bmWidth;
m_BitmapSize.cy = bmp.bmHeight;
m_hOldBitmap = (HBITMAP)SelectObject(m_hMemDC, hBitmap);
}
else// Close
{
HBITMAP hBitmap = (HBITMAP)SelectObject(m_hMemDC, m_hOldBitmap);
DeleteObject(m_hOldBitmap);
DeleteDC(m_hMemDC);
}
注意:一定要刪除GDI對象,做到萬浪叢中過,滴水不沾身,否則會造成GDI泄漏(進程中GDI對象達到9999個,此進程會奔潰)
3.在圖元上打擊做按鈕時,提取輪廓!
#pragma region Get Contour Centerm_VectorContourPoint.clear();CDC *lpCDC = GetDC();HDC hClientDC = lpCDC->GetSafeHdc();RECT ContourRect = {};POINT ptStart = {};POINT ptErgod = {point.x, point.y};COLORREF iColorValue = GetPixel(hClientDC, point.x, point.y);while (iColorValue == GetPixel(hClientDC, ptErgod.x , ptErgod.y)){ptErgod.x--;}if (-1 == ptErgod.x){return;}ptErgod.x++;memcpy(&ptStart, &ptErgod, sizeof(POINT));ContourRect.left = ptStart.x;ContourRect.right = ptStart.x;ContourRect.top = ptStart.y;ContourRect.bottom = ptStart.y;INT32 Count = 0;INT32 FlagIndex = 0;do {for (INT32 i = 0; i < DotsArrCount; i++){if (iColorValue == GetPixel(hClientDC, ptErgod.x + DotsArr[FlagIndex].OffsetX, ptErgod.y + DotsArr[FlagIndex].OffsetY)){Count++;ptErgod.x += DotsArr[FlagIndex].OffsetX;ptErgod.y += DotsArr[FlagIndex].OffsetY;FlagIndex = DotsArr[FlagIndex].NextDotIndex;m_VectorContourPoint.push_back(ptErgod);break;}FlagIndex++;if (FlagIndex == DotsArrCount){FlagIndex = 0;}}ContourRect.left = (ptErgod.x < ContourRect.left) ? ptErgod.x : ContourRect.left;ContourRect.right = (ptErgod.x > ContourRect.right) ? ptErgod.x : ContourRect.right;ContourRect.top = (ptErgod.y < ContourRect.top) ? ptErgod.y : ContourRect.top;ContourRect.bottom = (ptErgod.y > ContourRect.bottom) ? ptErgod.y : ContourRect.bottom;} while (ptStart.x != ptErgod.x || ptStart.y != ptErgod.y);TRACE("Count is %d\r\n", Count);m_ptCenter.x = (ContourRect.left + ContourRect.right) >> 1;m_ptCenter.y = (ContourRect.top + ContourRect.bottom) >> 1;ReleaseDC(lpCDC);Invalidate(TRUE);
#pragma endregion
4)簡單動態顯示我們提取成果
BitBlt(dc.GetSafeHdc(), 0, 0, m_BitmapSize.cx, m_BitmapSize.cy, m_hMemDC, 0, 0, SRCCOPY);for (vector<POINT>::iterator itPoint = m_VectorContourPoint.begin(); itPoint != m_VectorContourPoint.end(); itPoint++){if (itPoint == m_VectorContourPoint.begin()){MoveToEx(dc.GetSafeHdc(), (*itPoint).x + m_BitmapSize.cx, (*itPoint).y, NULL);}else{Sleep(1);LineTo(dc.GetSafeHdc(), itPoint->x + m_BitmapSize.cx, itPoint->y);}}
5)完成,運行過程中截圖,運行完成即為之前貼出的預覽圖!
六.總結
師傅告訴我:圖像算法的處理要長期的積累,自己去悟,多思考,當遇到一個新的算法需求,結合自己的經驗積累,就能快速得到處理方法!
有興趣的朋友可以不使用Demo中Getpixel(),而是直接處理位圖數據塊,這樣輪廓提取的效率會更高!
這也是我去年學到第一個算法處理的,在這一年中,自己也積累了一些簡單的圖像處理算法:如灰度淡化(抽點),多圖元骨架提取等!
最后希望圖像處理大神不嗇指出demo中的不足以及需要優化之處,謝謝!
七)Demo源碼下載地址
http://download.csdn.net/detail/u012158162/9590647