前提・実現したいこと
C言語によるラベリング処理について質問です。現在、あるpgmファイルを読み込み、それを2値化し、pbmファイルとして出力したものを、4連結でラベリング処理し、連結成分の個数をカウントするプログラムを作っています。
pgmファイルを読み込み、それを2値化し、pbmファイルとして出力するところまでは、うまくいっているのですが、4連結でラベリング処理し、連結成分の個数をカウントする部分がよくわかりません。最後のループでラベリング番号を振った配列を表示しているのですが、テスト用の画像をみてもせいぜい、10もないぐらいだと思うのですが、かなり大きな桁が表示されます。また、ルックアップテーブルをどのように詰めれば良いのかわからずじまいです。ご教授よろしくお願いいたします。テスト用の画像は以下のをpgmファイルにして使用しています。
該当のソースコード
C
1#include<stdio.h> 2#include<string.h> 3#include<stdlib.h> 4 5 6int main(void){ 7 8 FILE *fp, *output; 9 int h, w, m, v, i, j; 10 char type[10]; 11 int stage[256]={}; 12 13 //pgmファイルがNULLだった場合の処理 14 if ((fp = fopen("test.pgm", "rb"))== NULL){ 15 printf("画像が開けません\n"); 16 exit(1); 17 } 18 19 20 fgets(type,10,fp); //画像形式の読み込み 21 fscanf(fp, "%d", &w); //画像の幅 22 fscanf(fp, "%d", &h); //画像の高さ 23 fscanf(fp, "%d", &m); //画像の輝度の階調 24 25 //上記4つの画像情報を出力 26 printf("type=%sw=%d, h=%d, m=%d, ", type, w, h, m); 27 28 //以下for文で1画素ずつ輝度をカウントし、ヒストグラムの元となる 29 //それぞれの輝度値の合計を出力 30 for (i = 0; i <w; i++){ 31 for (j = 0; j <h; j++){ 32 if((v = getc(fp)) != EOF) { 33 stage[v]++; 34 } else { 35 } 36 } 37 } 38 fclose(fp); 39 40 //以下輝度0から輝度の合計をしていき、ある割合になった時、閾値を決定する 41 double pixel;//画素数を保存 42 double pixel_sum;//輝度値から加算して知った画素数を保存 43 double pixel_average;//画素数比率の保存 44 double pixel_before;//直前の画素数比率の保存 45 int number;//閾値の保存 46 47 pixel=w*h;//画素数を計算 48 printf("pixel=%.f\n", pixel); 49 50 for(i=0;i<256;i++){ 51 pixel_sum=pixel_sum+stage[i]; 52 pixel_average=pixel_sum/pixel; 53 if(pixel_average>=0.7){ 54 printf("輝度値=%d 比率=%.4f\n",i-1,pixel_before);//閾値の1つ前の割合を出力 55 printf("輝度値=%d 比率=%.4f\n",i,pixel_average);//閾値の割合を出力 56 printf("閾値=%d\n",i );//閾値を出力 57 number=i;//閾値を保存 58 break; 59 } 60 pixel_before=pixel_average;//求めた割合を1つ前の割合として保存 61 } 62 63 //以下、決定した閾値から2値化画像を出力、2値化画像を2次元配列として格納 64 //4連結、8連結のラベリング処理を行う 65 output = fopen("test.pbm", "w");//白黒画像であるPBMファイルに出力 66 fp = fopen("test.pgm", "rb"); 67 fgets(type,10,fp); //画像形式の読み込み 68 fscanf(fp, "%d", &w); //画像の幅 69 fscanf(fp, "%d", &h); //画像の高さ 70 fscanf(fp, "%d", &m); //画像の輝度の階調 71 72 fprintf(output, "P1\n%d %d\n", w, h);//マジックナンバーはP1、アスキー形式 73 74 int image[w][h];//2値化画像を2次元配列として格納 75 76 for (i = 0; i <h; i++){//imageの初期化 77 for (j = 0; j <w; j++){ 78 image[w][h]=0; 79 } 80 } 81 82 for (i = 0; i <h; i++){ 83 for (j = 0; j <w; j++){ 84 if((v = getc(fp)) != EOF) { 85 if(v>=number){//画素を読み込んだ時、閾値以上か以下かを判定 86 fprintf(output, "0 ");//閾値以上の場合白として出力 87 image[j][i]=0; 88 }else{ 89 fprintf(output, "1 ");//閾値未満の場合黒として出力 90 image[j][i]=1; 91 } 92 } else { 93 } 94 } 95 fprintf(output, "\n"); 96 } 97 98 fclose(fp); 99 fclose(output); 100 101 int image_4[w][h];//4連結用配列 102 int image_8[w][h];//8連結用配列 103 int count_4[(w*h)/2][2];//4連結用ラベリング配列 104 int count_8[(w*h)/2][2];//8連結用ラベリング配列 105 int l4=1,l8=1;//4連結、8連結用の連結成分カウント変数 106 int min=0;//検査時の最小値を保存 107 108 for (i=1;i<(w*h)/2;i++){ 109 count_4[i][0]=i; 110 count_4[i][1]=0; 111 count_8[i][0]=i; 112 count_8[i][1]=i; 113 } 114 115 for (i = 0; i <h; i++){//image_4の初期化 116 for (j = 0; j <w; j++){ 117 image_4[w][h]=0; 118 } 119 } 120 121 122 for (i = 0; i <h; i++){//4連結用 123 for (j = 0; j <w; j++){ 124 if(image[j][i]==1){//対象画素が1,以下は4連結用 125 if(i==0&&j==0){//画素の一番始まり(左上角) 126 image_4[0][0]=l4; 127 l4++; 128 } 129 130 else if(i==0){//対象画素が一番上の辺にあたる場所にある 131 if(image_4[j-1][0]!=0){ 132 image_4[j][0]=image_4[j-1][0]; 133 }else{ 134 image_4[j][0]=l4; 135 l4++; 136 } 137 138 }else if(j==0){//対象画像が一番左の辺に当たる場所にある 139 if(image_4[j][i-1]!=0){ 140 image_4[j][i]=image_4[j][i-1]; 141 }else{ 142 image_4[j][i]=l4; 143 l4++; 144 } 145 146 }else{//上記に当てはまらない全ての画素 147 if(image_4[j-1][i]!=0||image_4[j][i-1]!=0){//左マスまたは上のマスが0ではない 148 149 if(image_4[j-1][i]==image_4[j][i-1]){//左と上のマスが同じラベル番号 150 image_4[j][i]=image_4[j-1][i]; 151 152 }else if((image_4[j-1][i]!=0)&&((image_4[j][i-1]==0)||(image_4[j-1][i]<image_4[j][i-1]))){ 153 //左のラベル番号が0ではなくかつ、左のラベル番号の方が小さい 154 image_4[j][i]=image_4[j-1][i]; 155 count_4[image_4[j][i-1]][1]=image_4[j-1][i]; 156 157 }else{//上のラベル番号が0ではなくかつ、上のラベル番号の方が小さい 158 if((image_4[j][i-1]!=0)&&((image_4[j-1][i]==0)||(image_4[j][i-1]<image_4[j-1][i]))){ 159 image_4[j][i]=image_4[j][i-1]; 160 count_4[image_4[j-1][i]][1]=image_4[j][i-1]; 161 } 162 } 163 164 }else{ 165 image_4[j][i]=l4; 166 l4++; 167 } 168 } 169 } 170 } 171 } 172 173for (i = 0; i <h; i++){ 174 for (j = 0; j <w; j++){ 175 printf("%d ", image_4[j][i]); 176 } 177 printf("\n"); 178} 179for(i=1;i<(w*h)/2;i++){ 180 if(count_4[i][1]!=0) 181 printf("%d %d\n",count_4[i][0],count_4[i][1] ); 182 183} 184 185 186//printf("4連結の連結成分の個数=%d\n",max4); 187return 0; 188 189} 190
試したこと
最後のループでラベリング番号を振った配列を表示し、正しくラベリング番号が振られているかどうかを調べた。
補足情報(FW/ツールのバージョンなど)
ここにより詳細な情報を記載してください。
回答3件
あなたの回答
tips
プレビュー