Rso's Jotter

日々の開発の知見のメモやその他雑記

輪郭線追跡

輪郭線追跡プログラム

/*	輪郭線追跡プログラム 8連結
 * 前提:画像の最外周は画素が存在しないこと(存在すると実行時エラー)
 *  ドーナツ型の図形もおそらく対応
 * 画像は擬似配列を用いている(1が画素とする)
 */

#include<iostream>

#define SIZE 20
#define WHITE 0
#define BLACK 1
#define CHECK -1

using namespace std;

void output(void);	//擬似画像表示関数
int OutlineTrace();//輪郭線追跡
int TraceAround(int,int,int);//画像の周囲をラベル付けする

struct Point{	//座標を格納する構造体
	int x;
	int y;
};


int gaso[SIZE][SIZE] =		{0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
							 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
							 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
							 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
							 0,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,
							 0,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,
							 0,0,0,1,1,1,1,1,1,1,0,1,1,1,1,1,1,1,0,0,
							 0,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,
							 0,0,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,
							 0,0,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,0,
							 0,0,0,0,0,0,1,1,1,1,1,1,1,1,1,1,1,0,0,0,
							 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
							 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,
							 0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,
							 0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,
							 0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,
							 0,0,1,1,1,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,
							 0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,
							 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
							 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
};



int main()
{
	output();
	OutlineTrace();
	output();
	
}

void output()	//擬似画像の出力
{
	for(int i = 0 ; i < SIZE ; i++){
		for(int j = 0 ; j < SIZE ; j++){
			if(gaso[i][j] == WHITE)
				cout << "○";
			else if(gaso[i][j] == BLACK)
				cout << "●";
			else
				cout << "▲";
		}
		cout << endl;
	}
	cout << endl;

}

int OutlineTrace(){
	for(int i = 0 ; i < SIZE ; i++){
		for(int j = 0 ; j < SIZE ; j++){
			if(gaso[i][j] == BLACK){	//BLACKがあれば周りを走査
//				cout << "画素" << i << "," << j << "からトレース開始" <<  endl;
				TraceAround(i,j,0);
//				output();
			}
			 if(gaso[i][j] == CHECK){	//CHECK済みであれば次のWHITEまで読み飛ばし
				while(gaso[i][j] != WHITE){
					j++;
				}
			}
		}
	}

	return 0;
}

//画像の周りをトレース
/*
	Pを取り囲む要素		Pの周囲の座標
	p3 p2 p1			P+offset[3] P+offset[2] P+offset[1]
	p4 P  p0			P+offset[4]     P		P+offset[0]
	p5 p6 p7			P+offset[5] P+offset[6] P+offset[7]

	画素を発見した位置(direction)と探索を開始する位置(sd)には
		sd = (direction + 5) % 8
	の関係がある
  */


int TraceAround(int y,int x,int direction){
	const Point offset[8] = {	{1,0},{1,-1},	//8近傍の相対位置(オフセット)
								{0,-1},{-1,-1},
								{-1,0},{-1,1},
								{0,1},{1,1}
	};
	int startx = x,starty = y;	//開始地点を保存
//	gaso[y][x] = CHECK;
	
	do{	
		int sd = (direction + 5) % 8;		//探索を開始する方向(SearchDirection)
			for(int i = 0;i < 8; ++i){		//ここでもし周りに何も見つからなかったら無限ループになるので後で修正
				int arroundx = x + offset[(sd + i) % 8].x;
				int arroundy = y + offset[(sd + i) % 8].y;

				if(gaso[arroundy][arroundx] != WHITE){
					y = arroundy;
					x = arroundx;
					gaso[y][x] = CHECK;
//					cout << "画素" << y << "," << x << "をチェック" << endl;
					direction = (sd + i) % 8;
					break;
				}
		}
	}while(startx != x || starty != y);	//開始地点に戻ってくるまでループ

	return 0;
}