🎄teratailクリスマスプレゼントキャンペーン2024🎄』開催中!

\teratail特別グッズやAmazonギフトカード最大2,000円分が当たる!/

詳細はこちら
C

C言語は、1972年にAT&Tベル研究所の、デニス・リッチーが主体となって作成したプログラミング言語です。 B言語の後継言語として開発されたことからC言語と命名。そのため、表記法などはB言語やALGOLに近いとされています。 Cの拡張版であるC++言語とともに、現在世界中でもっとも普及されているプログラミング言語です。

Q&A

解決済

4回答

3909閲覧

C言語でラベリングをしたい。

0126tami

総合スコア60

C

C言語は、1972年にAT&Tベル研究所の、デニス・リッチーが主体となって作成したプログラミング言語です。 B言語の後継言語として開発されたことからC言語と命名。そのため、表記法などはB言語やALGOLに近いとされています。 Cの拡張版であるC++言語とともに、現在世界中でもっとも普及されているプログラミング言語です。

0グッド

0クリップ

投稿2019/10/31 09:14

C言語を使ってラベリングしようとしています。
lavel.txtはこれです
1 1 0 0 0 0 0
1 1 0 0 0 1 0
0 0 0 1 1 1 1
1 0 0 0 0 0 0
0 0 0 0 1 1 1

ラベリング
1 1 0 0 0 0 0
1 1 0 0 0 2 0
0 0 0 2 2 2 2
3 0 0 0 0 0 0
0 0 0 0 4 4 4

この1のかたまりになっているところを1、2、3、4という風にラベル付けしたいです。
元々のlabel.txtはnum配列に格納されており、新しくラベリングしたものはnum2
に格納したいです。
tikaku関数では対象となるマスの左上、真上、右上、真左。という風に隣り合っている場所が全て0になる以外はラベリングされた値を返す。というような関数を作りたいです。

関数やらnum2配列がごちゃごちゃしてうまくいかないのですがアドバイスをいただけると嬉しいです。

c

1#include <stdio.h> 2#include <stdlib.h> 3 4int tikaku(int a[5][7],int x,int y){ 5 int i=x,j=y; 6 7 8 9 10 11 if(!(a[i-1][j-1]==0&&a[i-1][j-1]=='NULL')){ 12return a[i-1][j-1]; 13 }else if(!(a[i-1][j]==0&&a[i-1][j]=='NULL')){ 14 return a[i-1][j]; 15 }else if(!(a[i-1][j+1]==0&&a[i-1][j+1]=='NULL')){ 16 17 return a[i-1][j+1]; 18 }else if(!(a[i][j-1]==0&&a[i][j-1]=='NULL')){ 19 return a[i][j-1]; 20 } 21 return a[i][j]; 22} 23 24 25 26int main(void) { 27 FILE *fp; // FILE型構造体 28 static char fname[] = "label.txt"; 29 int i,j,n,f1; 30 int num[5][7]; 31 int num2[5][7]; 32 33 34 //テキストファイルの数値を表示し配列に格納 35 fp = fopen(fname, "r"); // ファイルを開く。失敗するとNULLを返す。 36 if(fp == NULL) { 37 printf("%s file not open!\n", fname); 38 return -1; 39 } 40 for(i=0;i<5;i++){ 41 for(j=0;j<7;j++){ 42 fscanf(fp, "%d ", &f1); 43 num[i][j]=f1; 44 printf("%d ",num[i][j]); 45 } 46 printf("\n"); 47 } 48 printf("\n"); 49 50 fclose(fp); // ファイルを閉じる 51 52 53 54 n=1; 55 for(i=0;i<5;i++){ 56 for(j=0;j<7;j++){ 57 if(num[i][j]==0){ 58 num2[i][j]=0; 59 60 } else if(num[i][j]==1){ 61 62 63 num2[i][j]=n; 64 65 n=tikaku(num2,i,j); 66 num2[i][j]=n; 67 printf("%d ",num2[i][j]); 68 69 } 70 } 71 } 72 printf("\n"); 73 74 } 75 76 77 78 //for(i=0;i<5;i++){ 79 // for(j=0;j<7;j++){ 80 // printf("%d ",num2[i][j]); 81 // } 82 // printf("\n"); 83 // } 84 85 86 return 0; 87} 88 89

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

tatsu99

2019/10/31 12:18

1 0 1 0 1 0 1 0 0 0 0 0 0 0 1 0 1 0 1 0 1 0 0 0 0 0 0 0 1 0 1 0 1 0 1 上記のようなデータの場合、ラベル対象は10件以上ですが、その場合、ラベルはどうするのでしょうか? (9より大きいラベルをどうするのかという質問です)
fana

2019/11/01 01:34

num2[]の要素はintですから10以上になっても問題ないと思います. (領域に付与するラベルは「領域を区別できる何か」でさえあればどうでもよいと思います.)
tatsu99

2019/11/01 02:51

なるほど、結果を画面にきれいにだすことが目的ではないのですね。 10以上の場合、画面が乱れると思いましたが・・・・ 了解です。
guest

回答4

0

私なら隣接している範囲をチェックするのに再帰呼び出しで処理します。
こんな感じ(サンプルなのでファイル読み込みは省いています)

c

1#include <stdio.h> 2 3#define X 7 4#define Y 5 5 6void label(int pnum[Y][X], int x, int y, int cnt); 7 8int main(void) 9{ 10 int num[Y][X] = { 11 { 1,1,0,0,0,0,0 }, 12 { 1,1,0,0,0,1,0 }, 13 { 0,0,0,1,1,1,1 }, 14 { 1,0,0,0,0,0,0 }, 15 { 0,0,0,0,1,1,1 }, 16 }; 17 int num2[Y][X]; 18 int x, y; 19 int cnt; 20 21 // numをnum2にコピー。1は-1に置き換え。 22 for(y = 0; y < Y; y++){ 23 for(x = 0; x < X; x++){ 24 num2[y][x] = num[y][x] == 1? -1: 0; 25 } 26 } 27 28 // 左上から-1を探す 29 cnt = 1; 30 for(y = 0; y < Y; y++){ 31 for(x = 0; x < X; x++){ 32 if(num2[y][x] == -1){ 33 // -1が見つかったら隣接している-1をラベリングする 34 label(num2, x, y, cnt++); 35 } 36 } 37 } 38 39 // 結果表示 40 for(y = 0; y < Y; y++){ 41 for(x = 0; x < X; x++){ 42 printf("%d ", num2[y][x]); 43 } 44 printf("\n"); 45 } 46} 47 48// ラベリング関数(再帰) 49void label(int pnum[Y][X], int x, int y, int cnt) 50{ 51 // 終了チェック 52 if(x < 0 || x >= X) return; 53 if(y < 0 || y >= Y) return; 54 if(pnum[y][x] != -1) return; 55 56 // ラベリング 57 pnum[y][x] = cnt; 58 59 // 隣接要素をチェック 60 label(pnum, x - 1, y, cnt); 61 label(pnum, x + 1, y, cnt); 62 label(pnum, x, y - 1, cnt); 63 label(pnum, x, y + 1, cnt); 64} 65

投稿2019/11/01 00:40

ttyp03

総合スコア17000

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

fana

2019/11/01 01:42

「ラベリングという処理をしたいが,どうしたらいいかわからない」という質問では無く,画像のラベリングで有名なアルゴリズム(https://imagingsolution.blog.fc2.com/blog-entry-193.htmlとかの内容.最後の処理を「何とかして」とぼかして説明してないけど)を実装している中でうまくいかんので困っているという話だと思うのです… なので,質問者が取り組んでいるものとは全く別の処理アルゴリズムの実装を示すのは回答として妥当だろうか?とか思う…次第です…
ttyp03

2019/11/01 02:10

私は画像処理には詳しくないのでそこまで推測はできませんでした。 もしそうであるなら前提条件を書いて欲しいですが。。。 まあ役に立たなくても参考になればいいかなと。
tatsu99

2019/11/01 02:43

あなたのソースを実行すると 入力データが 1 1 0 0 0 0 1 1 1 0 0 0 1 0 0 0 0 1 1 1 1 1 0 0 0 0 0 0 0 0 0 0 1 1 1 のとき、結果は 1 1 0 0 0 0 2 1 1 0 0 0 3 0 0 0 0 3 3 3 3 4 0 0 0 0 0 0 0 0 0 0 5 5 5 となります。 正しくは 1 1 0 0 0 0 2 1 1 0 0 0 2 0 0 0 0 2 2 2 2 3 0 0 0 0 0 0 0 0 0 0 4 4 4 ではないでしょうか。 ななめの処理の考慮もれかと。
ttyp03

2019/11/01 02:51

ん?そうなんすか? 斜めも対象にするのか質問文からはよく判別できなかったので考慮してませんでした。 まあ、斜めが必要かどうかはわからないですが、例が悪いですよね。
fana

2019/11/01 03:12

(なんとなく高評価押す)
tatsu99

2019/11/01 04:09 編集

>tikaku関数では対象となるマスの左上、真上、右上、真左。という風に隣り合っている場所が全て0になる以外はラベリングされた値を返す。 ということから、斜めも対象になると考えます。(まあ、質問者本人からのコメントがあればはっきりするのですが・・・) 質問者があとで、このソースを参考にすることを考えると、斜めのケースも考慮したものを提供しておくと質問者にとってはうれしい回答になるかと思います。
Y.H.

2019/11/01 04:11

質問に > 対象となるマスの左上、真上、右上、真左 と条件あるのでこの回答で要件満たしてると思います。
ttyp03

2019/11/01 04:25

左上と右上、が書かれているのが気になりますね。 これを鵜呑みにするなら斜め方向も必要そうですが。 その割には下方向の条件がないのも気になります。 まあ仕様不明確ってことで、質問者からの追加情報を待ちたいと思います。
ttyp03

2019/11/01 04:27

あ、ちなみに斜め方向を考慮したコードを提示する予定はありません。 どうすればよいかはコード見れば一目瞭然だと思うので。 それくらいは自力でやってくれてもいいでしょう。 どうしてもわからないなら書きますが。
Y.H.

2019/11/01 04:28

あぁ自分でコピペしていながら誤読してました。左上と右上。
fana

2019/11/01 04:34

質問者は8近傍(つまり斜めも繋がる)のタイプ,この回答は4近傍のタイプ. 下方向の条件が無いのは, 着目画素の周辺8近傍のうちの既に走査済みの4画素(上の行の3個と左隣)との連続性だけをチェックする形の処理だから.そのため,1回の走査だけでは完了しない→後段でラベルの付け直し処理が必要.
0126tami

2019/11/07 05:56

下の考慮を忘れてしまっていました。 混乱させてしまいすみません。 ありがとうございます
guest

0

うまくいかない

だと漠然としているので,問題状況を明確に説明すると良いかと思います.

tikaku()内の

a[i-1][j-1]=='NULL'

という記述がとても怪しいです.何を意図しているのでしょうか?
とりあえず近隣を見る前に,その近隣が存在するか否かの範囲内外チェックをすべきです.

なお,このtikaku()を用いた処理でデータを1回走査しただけではうまくラベリングできないパターンが存在するハズです.
(その後で逆向きの走査が必要になるでしょう.)

投稿2019/10/31 09:51

fana

総合スコア11985

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

0

自己解決

たくさんの回答者様ご意見ありがとうございました。
私がラベリングをする上での例題がだいぶおかしかったのすみませんでした。
斜め左下の考慮を忘れてしまっていました。

結局学校の先生にソースコードを描いてもらって解決することができました。
一部載せておきます。

#include <stdio.h> #include "img.h" #define NBR 4 #define TBLSIZ 63 int nbrlbl(Img img, Img limg, int x, int y, int l[]) { int ml, i; int sx, sy; sx = img.sx; sy = img.sy; l[3] = x > 0 ? limg.d[0][y][x-1] : 0; if(y > 0) { l[1] = limg.d[0][y-1][x]; l[0] = x > 0 ? limg.d[0][y-1][x-1] : 0; l[2] = x < sx - 1 ? limg.d[0][y-1][x+1] : 0; } else { l[0] = l[1] = l[2] = 0; } ml = TBLSIZ; //printf("%d %d: %d ", x, y, ml); for(i = 0; i < NBR; i++) { if(l[i] > 0 && l[i] < ml) ml = l[i]; //printf(" %d ", l[i]); } if(ml == TBLSIZ) ml = 0; //printf(" min: %d\n", ml); return ml; } Img lbl(Img img) { Img limg; int nbrlbl(Img, Img, int, int, int []); int sx, sy; int x, y, i; int tbl[TBLSIZ], l[NBR], ml, ll; sx = img.sx; sy = img.sy; limg.sx = sx; limg.sy = sy; tbl[0] = 0; ll = 0; for(y = 0; y < sy; y++) { for(x = 0; x < sx; x++) { if(img.d[0][y][x] > 0) { ml = nbrlbl(img, limg, x, y, l); //printf("\t>>%d %d: %d\n", x, y, ml); if(ml == 0) { limg.d[0][y][x] = ++ll; tbl[ll] = ll; } else { limg.d[0][y][x] = ml; for(i = 0; i < NBR; i++) { if(l[i] > ml) { tbl[l[i]] = ml; } } } } else { limg.d[0][y][x] = 0; } } } /* For debug. for(i = 1; i <= ll; i++) { printf("(%3d %3d)\n", i, tbl[i]); } */ for(y = 0; y < sy; y++) { for(x = 0; x < sx; x++) { limg.d[0][y][x] = tbl[limg.d[0][y][x]]; } } return limg; }

投稿2019/11/07 05:40

編集2019/11/07 05:42
0126tami

総合スコア60

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

0

(とりあえず?) tikaku 関数が書ければ良いということでしょうか.

c

1int tikaku(int a[5][7],int i,int j){ 2 if(i>0 && j>0 && a[i-1][j-1]!=0){ //左上 3 return a[j-1][j-1]; 4 } 5 if(i>0 && a[i-1][j]!=0){ //上 6 return a[i-1][j]; 7 } 8 if(i>0 && j<7-1 && a[i-1][j+1]!=0){ //右上 9 return a[i-1][j+1]; 10 } 11 if(j>0 && a[i][j-1]!=0){ //左 12 return a[i][j-1]; 13 } 14 return a[i][j]; 15}

投稿2019/11/01 13:32

jimbe

総合スコア13202

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.36%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問