日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

提取单图元轮廓

發布時間:2023/12/18 编程问答 25 豆豆
生活随笔 收集整理的這篇文章主要介紹了 提取单图元轮廓 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

一. 應用場景!

使用過Genesis的朋友都知道,它可以提取你點擊單圖元中心<提取圖元輪廓計算中心點>!


二.

由于工作需要,去年在師傅的知道下寫了一個單圖元輪廓提取算法!


三. 原理

提取輪廓即需要找出單圖元最外(內)層連續不間斷的點!

故我們需要一個起始點,即從你點擊的單圖元出發,向左(←↑→↓, 4個方向皆可,只需改變算子的起始點)遍歷至第一個與點擊點不用色調的點,此點極為最外層輪廓的起始點,然后以你所選方向為算子起始項,進行順時針(逆時針)遍歷,直到遍歷點與起始點重合,說明輪廓提取完畢!


四.

本例中我采用向左順時針遍歷,剩余的7種就交給聰明的你了!


1)準備算子結構

123
0*4
765


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號點為例)

123
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);
i
f (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




創作挑戰賽新人創作獎勵來咯,堅持創作打卡瓜分現金大獎

總結

以上是生活随笔為你收集整理的提取单图元轮廓的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。