teratail header banner
teratail header banner
質問するログイン新規登録

回答編集履歴

2

説明の誤字を修正

2020/06/28 11:36

投稿

e-watt
e-watt

スコア84

answer CHANGED
@@ -1,6 +1,10 @@
1
1
  回答が長くなってしまったので、「詰め直し」は別に回答します。
2
- こちらは全般的な参考に、ということで
2
+ こちらは全般的な参考に、ということで
3
+ なお、コンパイル前に先頭付近のマクロ NEIGHBOR により、4連結、8連結のどちらかを選んで実行できます。
3
4
  ```C
5
+ #define NEIGHBOR 4 /*連結数:4か8*/
6
+ ```
7
+ ```C
4
8
  /*
5
9
  ・マクロの使い方など、かなり行儀が悪い部分がありますがご了承ください。
6
10
  */

1

コードを少々修正し、説明を別枠で行うことを追記

2020/06/28 11:35

投稿

e-watt
e-watt

スコア84

answer CHANGED
@@ -1,19 +1,16 @@
1
- 肝心の「ルックアップテーブルの詰め直し」で「なぜ」「何を」やっているかの説明が未記入ですがとりあえずコードだけ這っておきます。
2
- 説明は追ってします。
1
+ 回答が長くなってしまったので、「詰め直し」は別に回答します。
3
-
2
+ こちらは府全般的な参考に、ということで
4
3
  ```C
5
4
  /*
6
5
  ・マクロの使い方など、かなり行儀が悪い部分がありますがご了承ください。
7
- ・変数名などかなりいじってしまいました。悪しからず
8
- ・インデントなども雑です。すみません
9
6
  */
10
7
  #include<stdio.h>
11
8
  #include<string.h>
12
9
  #include<stdlib.h>
13
10
 
14
- #define NEIGHBOR 4 /*連結数4か8で指定*/
11
+ #define NEIGHBOR 4 /*連結数:4か8*/
15
12
 
16
- /* デバッ:画像っぽいものをなんとなく表示 */
13
+ /* デバッ用 */
17
14
  static void showIntMatrix(const char* name, const int* array, int width, int height, int line) {
18
15
  printf("%s: %dWx%dh @%d\n", name, width, height, line);
19
16
  for (int i = 0; i < height; i++){
@@ -32,17 +29,17 @@
32
29
  #define showLabeledImage() showIntMatrix("Labels", &labeled_image[0][0], w, h, __LINE__)
33
30
 
34
31
 
35
- /*デバッグ用:配列の要素を横一列に表示*/
32
+ /*デバッグ用*/
36
33
  static void showIntArray(const char* caption, const char* name, const int* array, int N) {
37
- printf("%s:\n", caption);
34
+ printf("%s:\n%s ", caption, name);
38
35
  for (int i=1; i<=N; i++){
39
36
  printf("%2d ", array[i]);
40
37
  }
41
38
  printf("\n");
42
39
  }
43
- #define showDST(expr) showIntArray(expr, "dst", dst, ((w*h)+1)/2)
40
+ #define showDST(expr) showIntArray(expr, "Dst", dst, ((t)+1)/2)
44
41
  #define PartN (14)
45
- #define showPartOfDST(expr) showIntArray(expr, "dst", dst, PartN) /*全部出すと冗長なので先頭付近のみ表示*/
42
+ #define showPartOfDST(expr) showIntArray(expr, "Dst", dst, PartN) /*全部出すと冗長なので先頭付近のみ表示*/
46
43
 
47
44
 
48
45
  int main(void){
@@ -63,7 +60,7 @@
63
60
  fscanf(fp, "%d", &w); //画像の幅
64
61
  fscanf(fp, "%d", &h); //画像の高さ
65
62
  fscanf(fp, "%d", &m); //画像の輝度の階調
66
- fgets(junk,10,fp); // 改行を読み飛ばす
63
+ fgets(junk,10,fp); //改行を読み飛ばす
67
64
  printf("J[%s]len(%d)\n", junk, strlen(junk));
68
65
 
69
66
  //上記4つの画像情報を出力
@@ -125,9 +122,9 @@
125
122
  /* いや、8連結はやらないよ。*/
126
123
  output = fopen("test.pbm", "w");//白黒画像であるPBMファイルに出力
127
124
  fp = fopen("test.pgm", "rb");
128
- fgets(junk,10,fp); // ヘッダを読み飛ばす
125
+ fgets(junk,10,fp); //ヘッダを読み飛ばす
129
- fgets(junk,10,fp); // ヘッダを読み飛ばす
126
+ fgets(junk,10,fp); //ヘッダを読み飛ばす
130
- fgets(junk,10,fp); // ヘッダを読み飛ばす
127
+ fgets(junk,10,fp); //ヘッダを読み飛ばす
131
128
 
132
129
 
133
130
  fprintf(output, "P1\n%d %d\n", w, h);//マジックナンバーはP1、アスキー形式
@@ -165,13 +162,13 @@
165
162
 
166
163
  int labeled_image[w][h];//4連結用配列
167
164
  int Label=0; //ラベル番号
168
- int NL = ((w*h)+1)/2; // ラベルの最大数
165
+ int NL = ((w*h)+1)/2; //ラベルの最大数
169
166
  int dst[NL+1];//ラベリング配列 ; Srcは書き換えないし連番だから、Dstしか用意しないぜ
170
167
 
171
168
  for (i=1;i<=NL;i++){
172
- dst[i] = i; // [1]から[((w*h)+1)/2]にその値を入れるぜ;
169
+ dst[i] = i; //[1]から[((w*h)+1)/2]にその値を入れるぜ;
173
- // ただし質問者様は要素数と末尾の処理を間違ってるっぽい
170
+ //ただし質問者様は要素数と末尾の処理を間違ってるっぽい
174
- // + 領域数の最大値は、市松模様に塗り分けられた時の ceil(W*H/2) 3x3マスだと5個まであり
171
+ //+ 領域数の最大値は、市松模様に塗り分けられた時の ceil(W*H/2) 3x3マスだと5個まであり
175
172
  }
176
173
  //初期化を忘れずに
177
174
  for (i = 0; i <h; i++){//
@@ -184,7 +181,7 @@
184
181
  #define _TL_ printf("%d at %d,%d L=%d \n", Label, j, i, __LINE__ );
185
182
  #define _Tm_ printf("%d at %d,%d L=%d \n", min, j, i, __LINE__ );
186
183
 
187
- /* (x,y)のラベル番号を与える。画像の範囲外に対してゼロを与える */
184
+ /* (x,y)のラベル番号を与える。画像の範囲外に対してゼロを与える */
188
185
  #define getLabel(x,y) ((0<=(x)&&(x)<w && 0<=(y)) ? labeled_image[x][y] : 0)
189
186
 
190
187
  /*ゼロでなくminより小さい値であればそれを与える*/
@@ -193,10 +190,10 @@
193
190
  for (i = 0; i <h; i++){
194
191
  for (j = 0; j <w; j++){
195
192
  if(image[j][i]==1){ //対象画素が1
196
- int up_m = getLabel(j, i-1); // 上 4/8連結で共通
193
+ int up_m = getLabel(j, i-1); //上 4/8連結で共通
197
- int left = getLabel(j-1, i); // 左 4/8連結で共通
194
+ int left = getLabel(j-1, i); //左 4/8連結で共通
198
195
  #if NEIGHBOR == 4 //4連結
199
- if (up_m == 0 && left == 0) { // コメントは8連結側を参照されたし
196
+ if (up_m == 0 && left == 0) { //コメントは8連結側を参照されたし
200
197
  labeled_image[j][i] = ++Label;
201
198
  //_TL_
202
199
  }else{
@@ -204,18 +201,18 @@
204
201
  min = nonzeroMin(up_m, min);
205
202
  min = nonzeroMin(left, min);
206
203
  labeled_image[j][i] = min;
207
- dst[up_m] = nonzeroMin(dst[up_m], min); // 双方ゼロではないので実は普通のmin(a,b)でよい
204
+ dst[up_m] = nonzeroMin(dst[up_m], min); //双方ゼロではないので実は普通のmin(a,b)でよい
208
205
  dst[left] = nonzeroMin(dst[left], min);
209
206
  _Tm_
210
207
  }
211
208
  #elif NEIGHBOR == 8
212
- int up_l = getLabel(j-1, i-1); // 左上
209
+ int up_l = getLabel(j-1, i-1); //左上
213
- int up_r = getLabel(j+1, i-1); // 右上
210
+ int up_r = getLabel(j+1, i-1); //右上
214
211
 
215
- // 『』内は参照ページの記述の引用;なるべく書いてある通りに作るぜ
212
+ //『』内は参照ページの記述の引用;なるべく書いてある通りに作るぜ
216
- // 『左上、上、右上、左の画素のラベル番号を参照し、全て0(ゼロ)の場合は』
213
+ //『左上、上、右上、左の画素のラベル番号を参照し、全て0(ゼロ)の場合は』
217
214
  if (up_l == 0 && up_m == 0 && up_r == 0 && left == 0) {
218
- labeled_image[j][i] = ++Label; // 『最後に割り振った番号+1のラベル番号を割り振ります。』
215
+ labeled_image[j][i] = ++Label; //『最後に割り振った番号+1のラベル番号を割り振ります。』
219
216
  _TL_
220
217
  }else{
221
218
  //『参照した画素のラベル番号が複数存在した場合は、』
@@ -226,9 +223,9 @@
226
223
  min = nonzeroMin(up_m, min);
227
224
  min = nonzeroMin(up_r, min);
228
225
  min = nonzeroMin(left, min);
229
- labeled_image[j][i] = min; // (0以外の)『最小の番号を割り振ります。』
226
+ labeled_image[j][i] = min; //(0以外の)『最小の番号を割り振ります。』
230
227
  _Tm_
231
- // 『用いなかったラベル番号のルックアップテーブルの番号を最小の番号に書き換えます。』
228
+ //『用いなかったラベル番号のルックアップテーブルの番号を最小の番号に書き換えます。』
232
229
  /* ループ内でdst[0] は未使用だ(参照しない)からチェックせずにガンガン上書きするぜ*/
233
230
  /* 用いたところもどうせminで同じ値だから気にせず上書きするぜ*/
234
231
  dst[up_l] = nonzeroMin(dst[up_l], min);
@@ -241,7 +238,7 @@
241
238
  #endif
242
239
  }
243
240
  }
244
- showLabeledImage(); // 一行操作するごとに表示する…と、解説ページと似た感じの出力に
241
+ showLabeledImage(); //一行操作するごとに表示する…と、解説ページと似た感じの出力に
245
242
  }
246
243
 
247
244
  printf("RAW result (%dx%d):\n", h, w);
@@ -249,25 +246,24 @@
249
246
 
250
247
  showPartOfDST("DST before");
251
248
 
252
- /* ルックアップテーブルの詰め替え;思いのほか面倒;もっといいやり方はありそう */
249
+ /* ルックアップテーブルの詰め替え */
253
250
 
254
- int conv[NL+1]; //
251
+ int conv[NL+1]; //
255
252
  for (i=1;i<=NL;i++){
256
- conv[i] = -1; // すべて「未定」にする
253
+ conv[i] = -1; //すべて「未定」にする
257
254
  }
258
255
  conv[0] = 0;
259
256
  dst[0] = 0;
260
257
 
261
- //再帰的結合 ;
258
+ //再帰的結合; ←これは回答者の勝手な命名で、専門用語ではない
262
- for (i=1;i<=NL;i++){
263
- for (j=1;j<=NL;j++){
259
+ for (j=1;j<=NL;j++){
264
- while (dst[j] != dst[ dst[j] ])
260
+ while (dst[j] != dst[ dst[j] ])
265
- dst[j] = dst[ dst[j] ];
261
+ dst[j] = dst[ dst[j] ];
266
- }
262
+ }
267
- }
263
+
268
264
  showPartOfDST("recursed");
269
265
 
270
- // 番号を圧縮; 説明しないとわからんと思う
266
+ //番号を圧縮; 説明しないとわからんと思う
271
267
  int seqn = 1;
272
268
  for (i=1;i<=13;i++){
273
269
  int dstQ = dst[i];
@@ -288,18 +284,17 @@
288
284
  showPartOfDST("after:");
289
285
  /* ルックアップテーブルの詰め替え;ここまで */
290
286
 
291
- // ルックアップテーブルに従い結果を書き換え
287
+ //ルックアップテーブルに従い結果を書き換え
292
- // 上でさんざんdst[0]に好き放題したが、ここでは参照しうるので本来の値を入れる
293
288
  dst[0] = 0;
294
289
  for (i = 0; i <h; i++){
295
290
  for (j = 0; j <w; j++){
296
291
  labeled_image[j][i] = dst[ labeled_image[j][i] ];
297
292
  }
298
293
  }
299
- // 最終結果を表示
294
+ //最終結果を表示
300
295
  showLabeledImage();
301
296
 
302
- printf("%d連結の連結成分の個数=%d\n", NEIGHBOR, dst[Label]); /*使われたラベルの値(最大値)の圧縮結果が領域の数*/
297
+ printf("%d連結の連結成分の個数=%d?\n", NEIGHBOR, dst[Label]); /*使われたラベルの値(最大値)の圧縮結果が領域の数…とは限らなそう*/
303
298
 
304
299
  return 0;
305
300
  }