こんにちはゲストさん。会員登録(無料)して質問・回答してみよう!

締切り済みの質問

ラベリング処理プログラム

画像のラベリング処理プログラムを作っているんですが
どうもうまく実行できません。よければ教えていただけないでしょうか。
#include<stdio.h>
#include<stdlib.h>

int column, row;
unsigned char val[4] = {0,0,0,0};
unsigned char tmp[255];
int pos_y[4] = {-1, 0, 1, 0};
int pos_x[4] = {0, 1, 0, -1};
int i, j, x, y, label, level, label1;
int label_count = 1;
unsigned char *in, *out;

void labeling_main();
void labeling_search();

void labeling_main()
{
for(i = 0; i < y; i++){
for(j = 0; j < x; j++){
printf("aaa\n");
if(out[i * x + j] == 255){
printf("bbb\n");
fflush(stdout);
out[i * x + j] = label_count;
labeling_search(label_count, i, j);
label_count++;
}
}
}
}

void labeling_search(int label_count, int x, int y)
{
for(i = 0; i < 4; i++){
if(out[(pos_y[i] + y) * x + (pos_x[i] + x)] == 255){
out[(pos_y[i] + y) * x + (pos_x[i] + x)] = label_count;
labeling_search(label_count,(pos_y[i]+y),(pos_x[i]+x));
}
}
printf("ccc\n");
}

int main(int argc, char *argv[])
{
int result;
int head, Magic;
unsigned char *image, *in, *out, *res, *ros;
FILE *fin, *fout;

if(argc!=3){
printf("Usage : %s input output\n",argv[0]);
exit(1);
}
fin = fopen(argv[1],"rb");

/* -------------------- ヘッダ取得ここから -------------------- */
fgets(tmp,255,fin);
if(tmp[0]!='P') return 0;
sscanf(tmp,"P%d",&Magic);
if(Magic < 1 || Magic > 6) return 0;
do fgets(tmp,255,fin); while(tmp[0]=='#');
sscanf(tmp,"%d %d",&x,&y);
if(x < 1 || y < 1) return 0;
fgets(tmp,255,fin);
sscanf(tmp,"%d",&level);

/* ヘッダの確認 */
printf("P%d\n",Magic);
printf("%d %d\n",x,y);
printf("%d\n",level);

/* 画素の読み込み */
in = (unsigned char *)malloc(sizeof(unsigned char) *x*y);
fread(in,sizeof(unsigned char),x*y,fin);

fout = fopen(argv[2],"wb");
fprintf(fout,"P%d\n",Magic);
fprintf(fout,"# My new PGM\n");
fprintf(fout,"%d %d\n",x, y);
fprintf(fout,"%d\n",level);
fwrite(out, sizeof(unsigned char),x*y, fout);

out = (unsigned char *)malloc(sizeof(unsigned char) *x*y);

//2値画像
for (i = 0; i < y; i++) {
for (j = 0; j < x; j++){
if(in[i * x + j] > 120){
out[i * x + j] = 0;
}else if(in[i * x + j] <= 120){
out[i * x + j] = 255;
}
}
}

labeling_main();
printf("Max label number:%d\n",label_count);

free(in);
free(out);
fclose(fin);
fclose(fout);
}
コンパイルは通るのですが実行するとlabeling_mainの
if文でセグメンテーションが出てしまいます。

投稿日時 - 2012-12-13 12:36:19

QNo.7842984

すぐに回答ほしいです

このQ&Aは役に立ちましたか?

0人が「このQ&Aが役に立った」と投票しています

回答(4)

labeling_search()の引数のxとyも間違えていますね.
他のグローバル変数の意見等を反映したものが下のコード.
ただし再帰はループに変えないと,小さい画像でもすぐスタックがあふれるでしょう.
エラー処理もさぼってます.
あとはご自分で.

#include<stdio.h>
#include<stdlib.h>
#include<limits.h>

#define GRAY_MAP 5

typedef struct PGM {
int magic;
int width;
int height;
int level;
unsigned char *image;
} PGM;

typedef enum Result {
ERROR,
SUCCESS
} Result;

enum {
BACK = 0,
FORE = UCHAR_MAX
};

#define is_in_image(pgm, x, y) \
(((x) >= 0) && ((y) >= 0) && ((x) < (pgm)->width) && ((y) < (pgm)->height))

static void labeling_search(PGM *pgm, int label_count, int x, int y)
{
int pos_y[4] = { -1, 0, 1, 0 };
int pos_x[4] = { 0, 1, 0, -1 };
int pos[4] = {
pgm->width * pos_y[0] + pos_x[0],
pgm->width * pos_y[1] + pos_x[1],
pgm->width * pos_y[2] + pos_x[2],
pgm->width * pos_y[3] + pos_x[3]
};

unsigned char *p = pgm->image + (pgm->width * y) + x;
int i;

for (i = 0; i < 4; i++) {
if (is_in_image(pgm, x, y) && (p[pos[i]] == FORE)) {
p[pos[i]] = label_count;
labeling_search(pgm, label_count, x + pos_x[i], y + pos_y[i]);
}
}
return;
}

static int labeling_main(PGM *pgm)
{
int label_count = 1;
unsigned char *p;
int x, y;

p = pgm->image;
for (y = 0; y < pgm->height; y++) {
for (x = 0; x < pgm->width; x++) {
if (*p == FORE) {
*p = label_count;
labeling_search(pgm, label_count, x, y);
label_count++;
}
p++;
}
}
return label_count;
}

static Result pgm_read(PGM *pgm, char *filename)
{
const int TMP_SIZE = 255;
size_t size;
char tmp[TMP_SIZE];
FILE *fin;

fin = fopen(filename, "rb");
if (fin == NULL) { return ERROR; }

fgets(tmp, TMP_SIZE, fin);
if (tmp[0] != 'P') { fclose(fin); return ERROR; }

sscanf(tmp,"P%d", &(pgm->magic));
if (pgm->magic != GRAY_MAP) { fclose(fin); return ERROR; }

while (fgets(tmp, TMP_SIZE, fin) != NULL) {
if (tmp[0] != '#') {
break;
}
}

sscanf(tmp,"%d %d", &(pgm->width), &(pgm->height));
if ((pgm->width < 1) || (pgm->height < 1)) {
fclose(fin); return ERROR;
}
fgets(tmp, TMP_SIZE, fin);
sscanf(tmp, "%d", &(pgm->level));

size = pgm->width * pgm->height;
pgm->image = malloc(sizeof(unsigned char) * size);
if (pgm->image == NULL) { fclose(fin); return ERROR; }

fread(pgm->image, sizeof(unsigned char), size, fin);
fclose(fin);
return SUCCESS;
}

static Result pgm_write(PGM *pgm, char *filename)
{
FILE *fout;

fout = fopen(filename, "wb");
if (fout == NULL) { return ERROR; }

fprintf(fout, "P%d\n", pgm->magic);
fprintf(fout, "# My new PGM\n");
fprintf(fout, "%d %d\n", pgm->width, pgm->height);
fprintf(fout, "%d\n", pgm->level);

fwrite(pgm->image, sizeof(unsigned char), pgm->width * pgm->height, fout);
fclose(fout);
return SUCCESS;
}

static void pgm_binarize(PGM *pgm, int thresh)
{
unsigned char *p;
int x, y;

p = pgm->image;
for (y = 0; y < pgm->height; y++) {
for (x = 0; x < pgm->width; x++) {
*p = (*p > thresh) ? BACK : FORE;
p++;
}
}
return;
}

int main(int argc, char *argv[])
{
const int THRESH = 120;
int label_count;
Result r;
PGM pgm;

if (argc != 3) {
printf("Usage : %s input output\n",argv[0]);
exit(1);
}

r = pgm_read(&pgm, argv[1]);
if (r == ERROR) {
printf("error\n");
exit(1);
}

pgm_binarize(&pgm, THRESH);

label_count = labeling_main(&pgm);
printf("Max label number:%d\n",label_count);

r = pgm_write(&pgm, argv[2]);
if (r == ERROR) {
printf("error\n");
exit(1);
}

free(pgm.image);
return EXIT_SUCCESS;
}

投稿日時 - 2012-12-14 02:27:17

ANo.3

◯「グローバル変数の間違った使い方」の見本みたいなプログラムになっています
i=10,j=15でlabeling_searchを実行したらどうなると思います?

◯0,0に対象があったとしたらlabeling_search(1,0,0)で実行することになるかと思います
このとき
(pos_y[i] + y) * x + (pos_x[i] + x)

はいくつになると思います?


◯グローバル変数x,yで画像の幅、高さにしているようですが、labeling_search関数では、仮引数x,yで座標を表しています
out[(pos_y[i] + y) * x + (pos_x[i] + x)]
xは画像幅にはなってません


labeling_mainで問題を起こしそうなにのは上のような点



他にも
PGMのバイナリ8ビットしか対応してないのに、P1等でも読み込もうとする
間違いじゃないけど、doに{}が無いのが気持ち悪い

投稿日時 - 2012-12-13 13:38:41

ANo.2

Wr5

>コンパイルは通るのですが実行するとlabeling_mainの
>if文でセグメンテーションが出てしまいます。

本当にその場所…ですか?
ちゃんと追ってはいませんが、
labeling_search()の
>if(out[(pos_y[i] + y) * x + (pos_x[i] + x)] == 255){
>out[(pos_y[i] + y) * x + (pos_x[i] + x)] = label_count;
辺りが範囲外に行きそうな気が……。

あとは……labeling_main()からlabeling_search()をコールして戻って来た時点で、y座標を走査しているカウンタ変数のiが期待外の値(具体的には3)になっていることが「保証されて」ます。
グローバル変数は便利ですよね?
# 意図しない箇所で書き換えできますから…ね。
# 書き換えたくなくてももれなく書き換え可能ですから。

>fwrite(out, sizeof(unsigned char),x*y, fout);
>out = (unsigned char *)malloc(sizeof(unsigned char) *x*y);

ここのfwrite()でセグメンテーション違反になるギャンブルも楽しめるようです。
# fwrite()の時点ではポインタ変数outが挿している箇所は「不定」です。
# malloc()の後なら不定値ではないかも知れませんが、「メモリの内容」不定値です。

投稿日時 - 2012-12-13 13:09:47

お礼

ありがとうございます。

投稿日時 - 2012-12-13 13:40:03

ANo.1

メモリくらい割当ててあげようよ.

投稿日時 - 2012-12-13 12:50:56

あなたにオススメの質問