八領域邊界追蹤演算法
八領域邊界追蹤 C語言
其中_Binary為輸入的bmp二值化影象,_TracingPtr為輪廓空間點(型別為結構體)
typedef struct Contours
{
int height;
int width;
int stateFlag;
} contour;
void edgeTracing( const unsigned char* _Binary, contour** _TracingPtr, const int _Width, const int _Height )
{
unsigned char* _Mark = NULL;//標記矩陣
int direction[8][2] = { 0,-1, -1,-1, -1,0, -1,1, 0,1, 1,1, 1,0, 1,-1 };//方向陣列
int i = 0, j = 0;//行、列計數
int start_I = 0, start_J = 0;//輪廓的起始點
int rec_I = 0, rec_J = 0;//待檢測輪廓點座標
int mov_I = 0, mov_J = 0;//待檢測輪廓點周圍8領域逆時針旋轉點
int tmp_I = 0, tmp_J = 0;//臨時點儲存
int point_Count = 0;//輪廓點計數
int direc_Count = 0;//方向轉次數計數
int rot_Direct = 0;//方向陣列計數
int stepWidth = (_Width + 3) & ~3;//灰度圖行步長
int contour_Succe_Flag = 0;//輪廓尋找成功標誌位
int contour_Point_Now = 0;//現已開闢輪廓空間點數量
int contour_Point_Add = 0;//需要增加的輪廓空間點數量
contour* ptr_Contour_First = NULL;//輪廓點陣列首地址
contour_Point_Now = 4 * (_Width+_Height);
contour_Point_Add = _Width + _Height;
*_TracingPtr = ( contour *)malloc( contour_Point_Now * sizeof( contour) );//為儲存輪廓點建立記憶體塊
ptr_Contour_First = *_TracingPtr;
_Mark = ( unsigned char*)malloc( stepWidth*_Height );//輪廓標記矩陣
memset(_Mark, 0, stepWidth*_Height);//輪廓標記矩陣清零
for ( i = 0; i < _Height; i ++ )
{
for ( j = 1; j < _Width; j ++ )
{
if ( 255 == _Binary[ i*stepWidth + j - 1] && 0 == _Binary[ i*stepWidth + j] && 0 == _Mark[i*stepWidth + j] )
{
direc_Count = 0;//方向計數置零
rot_Direct = 0;//旋轉方向計數置零
start_I = i;//儲存每個輪廓的起始點
start_J = j;
rec_I = i;//儲存第一個b點的行座標
rec_J = j;//儲存第一個b點的列座標
mov_I = i;//儲存第一個c點的行座標
mov_J = j-1;//儲存第一個c點的列座標
while ( direc_Count < 8 && mov_I > 0 && mov_I < _Height && mov_J > 0 && mov_J < _Width )
{
direc_Count ++;
rot_Direct ++;//順時針方向轉45°
if ( 8 == rot_Direct) rot_Direct = 0;//使方向迴圈且不溢位
mov_I = rec_I + direction[rot_Direct][0];//轉完之後c點的行座標
mov_J = rec_J + direction[rot_Direct][1];//轉完之後c點的列座標
if ( 0 == _Binary[ mov_I*stepWidth + mov_J]
&& mov_I > 0 && mov_I < _Height
&& mov_J > 0 && mov_J < _Width
&& ( start_I != mov_I || start_J != mov_J ) )
{
if ( 0 == rot_Direct ) rot_Direct = 7;//方向回到上一個角度
else rot_Direct --;
tmp_I = rec_I;//記錄變換前b點行座標
tmp_J = rec_J;//記錄變換前b點列座標
rec_I = mov_I;//新的c點座標賦值給b點
rec_J = mov_J;
mov_I = tmp_I + direction[rot_Direct][0];//將上一個c點座標賦值給新c點座標
mov_J = tmp_J + direction[rot_Direct][1];
direc_Count = 0;//方向次數計數清零
if ( rec_I > mov_I )//計算現在c點相對b點的方位
rot_Direct = 2;
else if ( rec_I < mov_I )
rot_Direct = 6;
else if ( rec_J > mov_J )
rot_Direct = 0;
else if ( rec_J < mov_J )
rot_Direct = 4;
}
else if ( start_I == mov_I && start_J == mov_J )
{
//如果等於起始點,則重新遍歷該輪廓,標記輪廓並儲存輪廓點
if ( point_Count > contour_Point_Now-1 )
{
//若輪廓空間點超出範圍,則加入額外輪廓空間點
ptr_Contour_First = ( contour *)malloc( contour_Point_Now * sizeof( contour) );
memcpy( ptr_Contour_First, *_TracingPtr, contour_Point_Now * sizeof( contour) );
*_TracingPtr = ( contour *)malloc( (contour_Point_Now + contour_Point_Add) * sizeof( contour) );
memcpy( *_TracingPtr, ptr_Contour_First, contour_Point_Now * sizeof( contour) );
contour_Point_Now += contour_Point_Add;
free( ptr_Contour_First);
ptr_Contour_First = NULL;
ptr_Contour_First = *_TracingPtr;
}
ptr_Contour_First[ point_Count].height = start_I;//儲存起始點
ptr_Contour_First[ point_Count].width = start_J;
ptr_Contour_First[ point_Count].stateFlag = 1;//狀態標誌位stateFlag:
//1為起始點,0為普通邊緣點,2為結束點
_Mark[ start_I*stepWidth + start_J] = 255;//標記為已搜尋過的點
direc_Count = 0;//方向計數置零
rot_Direct = 0;//旋轉方向計數置零
rec_I = start_I;//儲存b點的行座標
rec_J = start_J;//儲存b點的列座標
mov_I = start_I;//儲存 c點的行座標
mov_J = start_J-1;//儲存c點的列座標
while ( direc_Count < 8 && mov_I > 0 && mov_I < _Height && mov_J > 0 && mov_J < _Width )
{
direc_Count ++;
rot_Direct ++;//順時針方向轉45°
if ( 8 == rot_Direct) rot_Direct = 0;//使方向迴圈且不溢位
mov_I = rec_I + direction[rot_Direct][0];//轉完之後c點的行座標
mov_J = rec_J + direction[rot_Direct][1];//轉完之後c點的列座標
if ( 0 == _Binary[ mov_I*stepWidth + mov_J]
&& mov_I > 0 && mov_I < _Height
&& mov_J > 0 && mov_J < _Width
&& ( start_I != mov_I || start_J != mov_J ) )
{
if ( 0 == rot_Direct ) rot_Direct = 7;//方向回到上一個角度
else rot_Direct --;
tmp_I = rec_I;//記錄變換前b點行座標
tmp_J = rec_J;//記錄變換前b點列座標
rec_I = mov_I;//新的c點座標賦值給b點
rec_J = mov_J;
mov_I = tmp_I + direction[rot_Direct][0];//將上一個c點座標賦值給新c點座標
mov_J = tmp_J + direction[rot_Direct][1];
direc_Count = 0;//方向次數計數清零
if ( rec_I > mov_I )//計算現在c點相對b點的方位
rot_Direct = 2;
else if ( rec_I < mov_I )
rot_Direct = 6;
else if ( rec_J > mov_J )
rot_Direct = 0;
else if ( rec_J < mov_J )
rot_Direct = 4;
point_Count ++;//壓入新點之前,輪廓計數自加
if ( point_Count > contour_Point_Now-1 )
{
//若輪廓空間點超出範圍,則加入額外輪廓空間點
ptr_Contour_First = ( contour *)malloc( contour_Point_Now * sizeof( contour) );
memcpy( ptr_Contour_First, *_TracingPtr, contour_Point_Now * sizeof( contour) );
*_TracingPtr = ( contour *)malloc( (contour_Point_Now + contour_Point_Add) * sizeof( contour) );
memcpy( *_TracingPtr, ptr_Contour_First, contour_Point_Now * sizeof( contour) );
contour_Point_Now += contour_Point_Add;
free( ptr_Contour_First);
ptr_Contour_First = NULL;
ptr_Contour_First = *_TracingPtr;
}
ptr_Contour_First[ point_Count].height = rec_I;//儲存新輪廓點
ptr_Contour_First[ point_Count].width = rec_J;
ptr_Contour_First[ point_Count].stateFlag = 0;//狀態標誌位stateFlag:
//1為起始點,0為普通邊緣點,2為結束點
_Mark[ rec_I*stepWidth + rec_J] = 255;//標記為已搜尋過的點
}
else if ( start_I == mov_I && start_J == mov_J )
{
//如果等於起始點,則把之前最後一個點改為終點,跳出開始新的搜尋
ptr_Contour_First[ point_Count].stateFlag = 2;//狀態標誌位stateFlag:
//1為起始點,0為普通邊緣點,2為結束點
contour_Succe_Flag = 1;//輪廓完整,標誌位置一
point_Count ++;//為下一個輪廓開闢一個新點
break;
}
}
}
if ( contour_Succe_Flag )//如果一個輪廓搜尋並儲存成功,則開始找新的起始點
{
contour_Succe_Flag = 0;//輪廓搜尋成功標誌位置零
break;
}
}
}
}
}
ptr_Contour_First[0].stateFlag = point_Count;//將輪廓點數量儲存在第一個空間點的狀態位
}
相關文章
- 4連通域邊界填充演算法和8連通域邊界填充演算法C++演算法C++
- 時至今日,深度學習領域有哪些值得追蹤的前沿研究?深度學習
- 追蹤演算法KCF體驗演算法
- SQL追蹤和事件追蹤SQL事件
- 索尼最新專利技術曝光:可用於VR領域的手部追蹤技術VR
- Maya 2024:塑造奇幻領域,視覺創新無邊界 mac/win版視覺Mac
- 區塊鏈在企業、遊戲以及大麻追蹤等領域的應用 -inc42區塊鏈遊戲
- 整個IT界可分為13塊大領域
- 《超越邊界》
- 日誌追蹤
- 程式碼追蹤
- 二分查詢左邊界,右邊界,>=,>,<=,<
- KDD 2024|港大黃超團隊深度解析大模型在圖機器學習領域的「未知邊界」大模型機器學習
- [業界方案] 用SOFATracer學習分散式追蹤系統Opentracing分散式
- [業界方案]用Jaeger來學習分散式追蹤系統Opentracing分散式
- 微服務邊界微服務
- C++進階:STL演算法9--邊界C++演算法
- OpenTelemetry分散式追蹤分散式
- 區塊鏈在糧食浪費、羊絨追蹤和假冒問題等領域的應用 - inc42區塊鏈
- 微服務追蹤SQL(支援Isto管控下的gorm查詢追蹤)微服務SQLGoORM
- 技術的邊界
- 如何追蹤laravel動態Laravel
- 如何追蹤Java動態Java
- 如何追蹤vue動態Vue
- 如何追蹤Go動態Go
- 追蹤解析 Disruptor 原始碼原始碼
- Debug追蹤eclipseEclipse
- 路由追蹤命令詳解路由
- oracle追蹤誤操作DDLOracle
- go的鏈路追蹤Go
- 【AutoCAD .NET】如何在無邊界Hatch上選擇邊界點?
- 搭建資料追蹤系統
- 使用 CSS 追蹤使用者CSS
- 如何追蹤Python動態Python
- 如何追蹤laravel動態<二>Laravel
- 追蹤解析 ThreadPoolExecutor 原始碼thread原始碼
- Tockler for Mac時間追蹤工具Mac
- Spring Cloud 鏈路追蹤SpringCloud