C言語で4近傍距離を用いた距離変換をするプログラムを作成しました。
入力画像は2値画像です。
自分独自の解釈で作成したもので、実際に細かく検証していないので、このコードではうまく求められないものもあるかもしれないですがそれは内緒です。
解説を細かく書こうかなあ、とも思いましたが、めんどくさくなったので書きません。
もし、気になることがあったら、コメントお願いします。需要があれば解説も書きたいと思います。
/*4近傍距離を求める関数*/
/*求める手順。
1.行を左から見ていき、画素値「1」の連続回数を記録
2.行を右から見ていき、画素値「1」の連続回数を記録、1.の結果と比べ小さい法を採用
3、列でも同様に調べる。
4.縦横のみの最短の値がわかる。
5.すべての画素の上下左右をチェックし、隣の画素との値の差が1より大きいものがあった場合、値を調整し、差が1以内にする・
バグ回避のため、4辺の画素値はすべてゼロとする。
*/
void kinbou4(Image *img1,ImageF *img2,int *gmax){
Size s;
int x, y;
int point=0;//1の連続回数を記録する変数
s.x = img1->s.x;
s.y = img1->s.y;
*gmax=0;
for( y=0; y<s.y; y++ ){
for( x=0; x<s.x; x++ ){
img2->val[x][y] = (float)img1->val[x][y]; //img2に全要素を一旦代入
}
}
for(y=0;y<s.y;y++){ //左右の辺の画素値をゼロにする
img2->val[0][y]=0;
img2->val[s.x-1][y]=0;
}
for(x=0;x<s.x;x++){ //上下の辺の画素値をゼロにする。
img2->val[x][0] = 0;
img2->val[x][s.y-1] = 0;
}
/*
1.行を左から見ていき、画素値「1」の連続回数を記録
2.行を右から見ていき、画素値「1」の連続回数を記録、1.の結果と比べ小さい法を採用*/
for(int y=1;y<s.y-1;y++){
for(int x=1;x<s.x-1;x++){//左から見る場合
if(img1->val[x][y]==0){
point=0; //ポイントをゼロにリセット
}
if(img1->val[x][y]==1){
point++;
img2->val[x][y]=point;
}
}
for(int x=s.x-2;x>0;x--){
if(img1->val[x][y]==0){ //
point=0;
}
if(img1->val[x][y]==1){
point++;
if(img2->val[x][y]>=point){ //valの値がpointより大きいとき
img2->val[x][y]=point;
}
else{
//img2valの値のほうが小さい場合はimg2valの値はそのまま。
}
}
}
}
/*
1.列を上から見ていき、画素値「1」の連続回数を記録
2.列を下から見ていき、画素値「1」の連続回数を記録、1.の結果と比べ小さい法を採用*/
for(int x=1;x<s.x-1;x++){
for(int y=1;y<s.y-1;y++){//左から見る場合
if(img1->val[x][y]==0){
point=0; //ポイントをゼロにリセット
}
if(img1->val[x][y]==1){
point++;
if(img2->val[x][y]>=point){ //valの値がpointより大きいとき
img2->val[x][y]=point;
}
else{
}
}
}
for(int y=s.y-2;y>0;y--){
if(img1->val[x][y]==0){ //
point=0;
}
if(img1->val[x][y]==1){
point++;
if(img2->val[x][y]>=point){ //valの値がpointより大きいとき
img2->val[x][y]=point;
}
else{
//img2valの値のほうが小さい場合はimg2valの値はそのまま。
}
}
}
}
/*5.すべての画素の上下左右をチェックし、隣の画素との値の差が1より大きいものがあった場合、値を調整し、差が1以内にする*/
for(int x=1;x<s.x-2;x++){
for(int y=1;y<s.y-2;y++){
if(img2->val[x][y]!=0){
/*上*/
if(img2->val[x][y] - img2->val[x][y-1]>=2 || img2->val[x][y] - img2->val[x][y-1]<=-2){ //差が2以上の場合
if(img2->val[x][y]>img2->val[x][y-1]){//上の値よりも自分の値が小さい場合は
img2->val[x][y]=img2->val[x][y-1]+1; //上の値+1をしている。
}
}
/*下*/
if(img2->val[x][y] - img2->val[x][y+1]>=2 || img2->val[x][y] - img2->val[x][y+1]<=-2){ //差が2以上の場合
if(img2->val[x][y]>img2->val[x][y+1]){
img2->val[x][y]=img2->val[x][y+1]+1; //下の値+1をしている。
}
}
/*左*/
if(img2->val[x][y] - img2->val[x-1][y]>=2 || img2->val[x][y] - img2->val[x-1][y]<=-2){ //差が2以上の場合
if(img2->val[x][y]>img2->val[x-1][y]){
img2->val[x][y]=img2->val[x][y-1]+1; //左の値+1をしている。
}
}
/*右*/
if(img2->val[x][y] - img2->val[x+1][y]>=2 || img2->val[x][y] - img2->val[x+1][y]<=-2){ //差が2以上の場合
if(img2->val[x][y]>img2->val[x+1][y]){
img2->val[x][y]=img2->val[x+1][y]+1; //右の値+1をしている。
}
}
}
}
}
for( y=0; y<img1->s.y; y++ ){
for( x=0; x<img1->s.x; x++ ){
if(img2->val[x][y] > *gmax){ //最大画素値の計算
*gmax = img2->val[x][y];
}
}
}
}