配列の不正アクセスについて

フォーラム(掲示板)ルール
フォーラム(掲示板)ルールはこちら  ※コードを貼り付ける場合は [code][/code] で囲って下さい。詳しくはこちら
maxwell
記事: 6
登録日時: 8年前

配列の不正アクセスについて

#1

投稿記事 by maxwell » 8年前

C言語やプログラムを書くのが不得手な初心者です。

今回opencvを用いて画像を読み込み、画像処理の実装部分は自力で書いているという状況です。

http://imagingsolution.blog107.fc2.com/ ... y-193.html

こちらのサイトに書いてあるアルゴリズムを参考にプログラムを一通り書き終え、
デバッグを行ったところ
****初回の例外が発生しました: 0xC0000005: 場所 ******* を書き込み中にアクセス違反が発生しました。
というエラーが、画素の端の例外処理を行っている部分で置きました。
具体的にはあとで記述する
ur = labelmatrix[y - 1][x + 1];
のところが不正アクセスを行っている(?)らしいのですが自分としては考えうる例外の分岐を書いたつもりでまったく解決法が思いつきません。
もしよろしければ教えてもらえないでしょうか。

コード:

void labeling(void)
{

    IplImage *binaryImage;
	start = clock(); //処理時間計測開始

	binaryImage = cvLoadImage("../result/binary.jpg", CV_LOAD_IMAGE_ANYCOLOR | CV_LOAD_IMAGE_ANYDEPTH);
	if (binaryImage == NULL)
	{
		printf("画像が見つかりませんでした\n");
		exit(-1);
	}



	uchar * bImg = (uchar*)binaryImage->imageData;
	int bStep = binaryImage->widthStep;

	int i;
	int ur, up, ul, lt; //右上、上、左上、左の変数

	int min = 0; //ラベルの最小値
	int labeltable[HEIGHT*WIDTH / 4]; //ルックアップテーブル
	int labelcount = 0; //ラベル番号
	int comp[4] = {}; //最小判定の入れ物

	int **labelmatrix; //ラベル配列の確保

	labelmatrix = (int **)malloc(sizeof(int*)*HEIGHT);
	if (labelmatrix == NULL){
		printf("配列が確保できませんでした\n");
		exit(1);
	}
	for (y = 0; y < HEIGHT; y++)
	{
		labelmatrix[y] = (int*)malloc(sizeof(int)*WIDTH);
	}

	for (y = 0; y < HEIGHT; y++){ //配列の中身の初期化
		for (x = 0; x < WIDTH; x++){
			labelmatrix[y][x] = 0;
		}
	}


	int area[HEIGHT*WIDTH / 4] = {};
	int check = 0;

	for (i = 1; i < (HEIGHT*WIDTH / 4); i++){ //ルックアップテーブルの作製
		labeltable[i] = i;
	}



	for (y = 0; y < HEIGHT; y++)
	{
		for (x = 0; x < WIDTH; x++)
		{
			if ((uchar)bImg[bStep*y + x] > 200)//もし白なら
			{
				//例外処理 端っこ

				if (x == 0 && y > 1) //左端(原点除く)
				{
					ul = 0; lt = 0;
				}
				else if (y == 0 && x > 1) //上端(原点除く)
				{
					ur = 0; up = 0; ul = 0;
				}

				else if (y == 0 && x == 0) //原点
				{
					ur = 0; up = 0; ul = 0; lt = 0;
				}
				else if (y > 1 && x == WIDTH - 1) //右端(右上除く)
				{
					ur = 0;
				}
				else
				{
					ur = labelmatrix[y - 1][x + 1];
					up = labelmatrix[y - 1][x];
					ul = labelmatrix[y - 1][x - 1];
					lt = labelmatrix[y][x - 1];
				}



				if (ur == 0 && up == 0 && ul == 0 && lt == 0) //右上、上、左上、左のラベル番号が0なら
				{

					labelcount++;	//ラベルをインクリメント
					labelmatrix[y][x] = labelcount;	//ラベル表に書き込む
					
					area[labelcount]++; //ラベル番号の面積を加算
				}




				else if (ur != 0 || up != 0 || ul != 0 || lt != 0) //一つでも0以外があれば
				{
					if (ur != 0) //0以外であれば最小を代入、その後0以外があれば比較して更新していく
					{									//同時に面積も加算しているが、のちにラベル番号を更新した際に加減する


						min = labelmatrix[y - 1][x + 1]; //一番最初なのでとりあえず最小値とする

						check++;						//最小が代入されたかチェック

						comp[0] = labelmatrix[y - 1][x + 1]; //比較用配列に代入

						area[labelmatrix[y - 1][x + 1]]++; //面積加算

					}

					if (up != 0)
					{

						if (check != 0)					//最小が代入されていたら比較
						{
							if (labelmatrix[y - 1][x] < min)
								min = labelmatrix[y - 1][x];

						}
						else                            //代入されていなかったら代入

						{
							min = labelmatrix[y - 1][x];
							check++;
						}
						comp[1] = labelmatrix[y - 1][x]; //比較用配列に代入

						area[labelmatrix[y - 1][x]]++; //同じラベルの面積を加算
					}

					if (ul != 0)
					{


						if (check != 0){
							if (labelmatrix[y - 1][x - 1] < min)
								min = labelmatrix[y - 1][x - 1];
						}
						else
						{
							min = labelmatrix[y - 1][x - 1];

							check++;
						}

						comp[2] = labelmatrix[y - 1][x - 1]; //比較用配列に代入

						area[labelmatrix[y - 1][x - 1]]++; //面積加算
					}

					if (lt != 0)
					{
						if (check != 0)
						{
							if (labelmatrix[y][x - 1] < min)
								min = labelmatrix[y][x - 1];

						}
						else
						{
							min = labelmatrix[y][x - 1];
						}

						comp[3] = labelmatrix[y][x - 1]; //比較用配列に代入

						area[labelmatrix[y][x - 1]]++; //面積加算
					}

					check = 0; //チェックを初期化


					for (y = 0; y < 4; y++)
					{
						if (comp[y] != 0) //中身が0でなければ
							labeltable[comp[y]] = min; //ルックアップテーブルの更新

						comp[y] = 0; //比較用配列の初期化
					}

					labelmatrix[y][x] = min; //ラベルを代入
				}
			}

		}
	}

	for (y = 0; y < HEIGHT; y++)
	{
		for (x = 0; x < WIDTH; x++)
		{
			if (labelmatrix[y][x] != labeltable[labelmatrix[y][x]])
			{
				area[labelmatrix[y][x]]--; //面積引いて

				do{
					labelmatrix[y][x] = labeltable[labelmatrix[y][x]];

				} while (labelmatrix[y][x] != labeltable[labelmatrix[y][x]]);  //ルックアップテーブルの番号とラベル番号が一致するまでループ

				area[labelmatrix[y][x]]++; //面積足して
			}
		}
	}

	for (x = 0; x < labelcount; x++)
	{
		if (area[x] != 0)
			printf("ラベル番号%dの面積は\t%d\n", x, area[x]);
	}


	for (y = 0; y < HEIGHT; y++)  //ラベル配列の開放
		free(labelmatrix[y]);
	free(labelmatrix);
	end = clock();

	printf("処理時間は%d\n", end - start);
}

Egg

Re: 配列の不正アクセスについて

#2

投稿記事 by Egg » 8年前

コード:

// 例外処理 端っこ
if (x == 0 && y > 1) // 左端 (原点除く
{
    /* 記述 */
}
else if (y == 0 && x > 1) // 上端 (原点除く
{
    /* 記述 */
}
else if (y == 0 && x == 0) // 原点
{
    /* 記述 */
}
else if (y > 0 && x == WIDTH - 1) // 右端(右上除く
{
    /* 記述 */
}
else 
{
    // ここでエラー
    ur = labelmatrix[y - 1][x + 1];
}
条件を図示してみました。
塗りつぶしている部分が条件で弾いている部分です。

コード:

■□■■■■■■
□□□□□□□□
■□□□□□□■
■□□□□□□■
■□□□□□□■
■□□□□□□■
■□□□□□□■
■□□□□□□■
1行目の左から2番目は x = 1, y = 0です。
labelmatrix[-1][2]です。

複数の条件式を記述する際に書き方が一貫していないと、このようなミスが発生します。
更にいうと書き方に問題があったとしても、頭の中で考えずnotepadでもExcel何でもいいので図示していればミスを防げたと思います。
該当部分をコメント化して、もう一度条件を組みなおすことをお勧めします。

※注意
これはあくまで配列の不正アクセスへの回答であり、ラベリング処理のアルゴリズムに対する正しい回答ではありません。

maxwell
記事: 6
登録日時: 8年前

Re: 配列の不正アクセスについて

#3

投稿記事 by maxwell » 8年前

Eggさん 回答ありがとうございます。
一応ノートに書いてどうすればいいのか考えていたんですけど抜けていました・・・。
今後気をつけます、ありがとうございました。

Egg

Re: 配列の不正アクセスについて

#4

投稿記事 by Egg » 8年前

もし解決されたなら解決にチェックいれて
正しいコードを記載してくださいね。

そうすることで他の初心者さんが助かることもありますので。

maxwell
記事: 6
登録日時: 8年前

Re: 配列の不正アクセスについて

#5

投稿記事 by maxwell » 8年前

Eggさんの助言の通り、条件の書く順番を統一(y, xの順)し、抜けていた範囲(y=1, x=1)を修正したのですが、
再びデバッグするとur=labelmatrix[y-1][x+1]の部分で不正アクセスのエラーが出てしまいました。
よろしければまたご教示お願いしたいです。

以下が自分で修正したコードです。

コード:

	//例外処理 端っこ

				if (y == 0 && x == 0) //原点
				{
					ur = 0; up = 0; ul = 0; lt = 0;
				}
				else if (y > 0 && x == 0) //左端(原点除く)
				{
					ul = 0; lt = 0;
				}
				else if (y == 0 && x > 0) //上端(原点除く)
				{
					ur = 0; up = 0; ul = 0;
				}
				else if (y > 0 && x == WIDTH - 1) //右端(右上除く)
				{
					ur = 0;
				}
				else if (y > 0 && x > 0 && x < (WIDTH-1))
				{
					ur = labelmatrix[y - 1][x + 1];
					up = labelmatrix[y - 1][x];
					ul = labelmatrix[y - 1][x - 1];
					lt = labelmatrix[y][x - 1];
				}


アバター
みけCAT
記事: 6734
登録日時: 14年前
住所: 千葉県
連絡を取る:

Re: 配列の不正アクセスについて

#6

投稿記事 by みけCAT » 8年前

まずxやyの値などを(printfまたはデバッガで)出力し、どのような条件で落ちているかを確かめましょう。
複雑な問題?マシンの性能を上げてOpenMPで殴ればいい!(死亡フラグ)

maxwell
記事: 6
登録日時: 8年前

Re: 配列の不正アクセスについて

#7

投稿記事 by maxwell » 8年前

for文の前にブレークポイントを作り1行ずつデバッグしていったら自己解決しました。

まず

コード:

//例外処理 端っこ
 
                if (x == 0 && y > 1) //左端(原点除く)
                {
                    ul = 0; lt = 0;
                }
                else if (y == 0 && x > 1) //上端(原点除く)
                {
                    ur = 0; up = 0; ul = 0;
                }
 
                else if (y == 0 && x == 0) //原点
                {
                    ur = 0; up = 0; ul = 0; lt = 0;
                }
                else if (y > 1 && x == WIDTH - 1) //右端(右上除く)
                {
                    ur = 0;
                }
                else
                {
                    ur = labelmatrix[y - 1][x + 1];
                    up = labelmatrix[y - 1][x];
                    ul = labelmatrix[y - 1][x - 1];
                    lt = labelmatrix[y][x - 1];
                }
 
 
 
の部分を、条件式の書式の統一、y=1, x=1のときも入れる修正をした上で
どの条件のときもur,up,ul,ltを代入しなければいけないことに気づき、

コード:

//例外処理 端っこ

				if (y == 0 && x == 0) //原点
				{
					ur = 0;
					up = 0; 
					ul = 0; 
					lt = 0;
				}
				else if (y != 0 && x == 0) //左端(原点除く)
				{
					ur = labelmatrix[y - 1][x + 1]; 
					up = labelmatrix[y - 1][x];
					ul = 0; 
					lt = 0;
				}
				else if (y == 0 && x != 0) //上端(原点除く)
				{
					ur = 0; 
					up = 0; 
					ul = 0;
					lt = labelmatrix[y][x - 1];
				}
				else if (y != 0 && x == WIDTH - 1) //右端(右上除く)
				{
					ur = 0;
					up = labelmatrix[y - 1][x];
					ul = labelmatrix[y - 1][x - 1];
					lt = labelmatrix[y][x - 1];
				}
				else if (y != 0 && x != 0 && x != (WIDTH-1))
				{
					ur = labelmatrix[y - 1][x + 1];
					up = labelmatrix[y - 1][x];
					ul = labelmatrix[y - 1][x - 1];
					lt = labelmatrix[y][x - 1];
				}

と修正しました。

また下の部分で新しく変数を宣言するのを面倒臭がってyを再利用したために、きちんとラスター走査が行えていませんでした。
他の部分でもなぜかyやxを再利用していたのですべて他の変数に置き換えたところ無事動きました。
ありがとうございました。

コード:

  for (y = 0; y < 4; y++)
                    {
                        if (comp[y] != 0) //中身が0でなければ
                            labeltable[comp[y]] = min; //ルックアップテーブルの更新
 
                        comp[y] = 0; //比較用配列の初期化
                    }

閉鎖

“C言語何でも質問掲示板” へ戻る