#include //戻り値 #define SUCCESS 0 #define TOO_MUCH_POINT -1 #define NO_POINT -2 //trace 関数 //追跡対象の1ピクセル外側を追跡します //輪郭の1ピクセル外側の座標が格納されていく事になります //image :画像 //iWidth :画像の横幅 //iHeight :画像の高さ //BackColor :背景色 //lpPoints :輪郭の座標を格納します //nPoints :lpPoints 配列の要素の個数 //*nCount :座標の個数を格納します //xStart :追跡を開始する x 座標 //yStart :追跡を開始する y 座標 //戻り値 :0(=SUCCESS 正常) / -1(=TOO_MUCH_POINT 異常) int trace(LPDWORD image,int iWidth,int iHeight,DWORD BackColor, LPPOINT lpPoints,int nPoints,int *nCount,int xStart,int yStart) { int x=xStart; int y=yStart; int n=0; //座標の個数 int vec=9; DWORD from,to; while(1){ if(n!=0 && x==xStart && y==yStart){ //終点に達した *nCount=n; return SUCCESS; //正常 } if(n>=nPoints){ //終点に達せずバッファが満杯 *nCount=n; return TOO_MUCH_POINT; //無限ループに陥った可能性が高い } switch(vec){ //優先順位を付けてチェックする(闇雲に調べると無限ループに陥る可能性が高い) case 6: //右中が輪郭? from=((x+1)<0 || iWidth<=(x+1) || y<0 || iHeight<=y)?BackColor:image[x+1+y*iWidth]; to=((x+1)<0 || iWidth<=(x+1) || (y+1)<0 || iHeight<=(y+1))?BackColor:image[x+1+(y+1)*iWidth]; if(from==BackColor && to!=BackColor){ x=x+1; y=y; lpPoints[n].x=x; lpPoints[n].y=(iHeight-1)-y; n++; vec=7; continue; } case 3: //右上が輪郭? from=((x+1)<0 || iWidth<=(x+1) || (y+1)<0 || iHeight<=(y+1))?BackColor:image[x+1+(y+1)*iWidth]; to=(x<0 || iWidth<=x || (y+1)<0 || iHeight<=(y+1))?BackColor:image[x+(y+1)*iWidth]; if(from==BackColor && to!=BackColor){ x=x+1; y=y+1; lpPoints[n].x=x; lpPoints[n].y=(iHeight-1)-y; n++; vec=8; continue; } case 2: //中上が輪郭? from=(x<0 || iWidth<=x || (y+1)<0 || iHeight<=(y+1))?BackColor:image[x+(y+1)*iWidth]; to=((x-1)<0 || iWidth<=(x-1) || (y+1)<0 || iHeight<=(y+1))?BackColor:image[x-1+(y+1)*iWidth]; if(from==BackColor && to!=BackColor){ x=x; y=y+1; lpPoints[n].x=x; lpPoints[n].y=(iHeight-1)-y; n++; vec=9; continue; } case 1: //左上が輪郭? from=((x-1)<0 || iWidth<=(x-1) || (y+1)<0 || iHeight<=(y+1))?BackColor:image[x-1+(y+1)*iWidth]; to=((x-1)<0 || iWidth<=(x-1) || y<0 || iHeight<=y)?BackColor:image[x-1+y*iWidth]; if(from==BackColor && to!=BackColor){ x=x-1; y=y+1; lpPoints[n].x=x; lpPoints[n].y=(iHeight-1)-y; n++; vec=6; continue; } case 4: //左中が輪郭? from=((x-1)<0 || iWidth<=(x-1) || y<0 || iHeight<=y)?BackColor:image[x-1+y*iWidth]; to=((x-1)<0 || iWidth<=(x-1) || (y-1)<0 || iHeight<=(y-1))?BackColor:image[x-1+(y-1)*iWidth]; if(from==BackColor && to!=BackColor){ x=x-1; y=y; lpPoints[n].x=x; lpPoints[n].y=(iHeight-1)-y; n++; vec=3; continue; } case 7: //左下が輪郭? from=((x-1)<0 || iWidth<=(x-1) || (y-1)<0 || iHeight<=(y-1))?BackColor:image[x-1+(y-1)*iWidth]; to=(x<0 || iWidth<=x || (y-1)<0 || iHeight<=(y-1))?BackColor:image[x+(y-1)*iWidth]; if(from==BackColor && to!=BackColor){ x=x-1; y=y-1; lpPoints[n].x=x; lpPoints[n].y=(iHeight-1)-y; n++; vec=2; continue; } case 8: //中下が輪郭? from=(x<0 || iWidth<=x || (y-1)<0 || iHeight<=(y-1))?BackColor:image[x+(y-1)*iWidth]; to=((x+1)<0 || iWidth<=(x+1) || (y-1)<0 || iHeight<=(y-1))?BackColor:image[x+1+(y-1)*iWidth]; if(from==BackColor && to!=BackColor){ x=x; y=y-1; lpPoints[n].x=x; lpPoints[n].y=(iHeight-1)-y; n++; vec=1; continue; } case 9: //右下が輪郭? from=((x+1)<0 || iWidth<=(x+1) || (y-1)<0 || iHeight<=(y-1))?BackColor:image[x+1+(y-1)*iWidth]; to=((x+1)<0 || iWidth<=(x+1) || y<0 || iHeight<=y)?BackColor:image[x+1+y*iWidth]; if(from==BackColor && to!=BackColor){ x=x+1; y=y-1; lpPoints[n].x=x; lpPoints[n].y=(iHeight-1)-y; n++; vec=4; continue; } vec=6; //一番上へ } } } //GetOutline 関数 //対象の外側の輪郭のみを取得します //複数の対象の輪郭を取得することはできません //image :画像 //iWidth :画像の横幅 //iHeight :画像の高さ //BackColor :背景色 //*lpPoints :輪郭の座標を格納します //nPoints :lpPoints 配列の要素の個数 //*nCount :座標の個数を格納します //戻り値 :0(=SUCCESS 正常) / -1(=TOO_MUCH_POINT 異常) / -2(=NO_POINT 異常) int GetOutline(LPDWORD image,int iWidth,int iHeight,DWORD BackColor, POINT *lpPoints,int nPoints,int *nCount) { for(int y=0;y