###前提・実現したいこと
unsigned short型の画像を読み込み、検出フィルター、大津の2値化、白黒反転、ラベリング、ラベルの面積・円形度の計算を経て2値化した画像とラベルを色付けしたものを出力するプログラムを書いているのですが、
roundnessという関数の一つ目のfor文の途中で強制終了してしまいます。
エラー文は以下の通りです。
また、ステップオーバーで1文づつ確認していったところ、そこでエラーは出ず、
2値化した画像を書き込もうとしたときに、
image_write_unchar(outname, w, h, binary);
の中で
「ヒープが壊れています」
とエラーが出て、また*fpを参照すると
「メモリが読み取れません」
と表示されます。
また、freeで配列を解放した時にも同じエラーが出ます。
どこかで配列の扱い方が間違っているのだとは思いますが、どこが間違っているのか私にはわかりません。
お力を貸していただけないでしょうか。
よろしくお願いします。
###発生している問題・エラーメッセージ
①コマンドプロンプトで実行した場合
②ステップオーバー(デバッグモード)で実行した場合
①Unhandled exception at 0x0F5B205E (msvcr120d.dll) in fjt8.exe: 0xC0000005: Access violation reading location 0x40319E42. ②ハンドルされない例外が 0x77769D11 (ntdll.dll) で発生しました(fjt8.exe 内): 0xC0000374: ヒープは壊れています。 (パラメーター: 0x7779D8D0)。
###該当のソースコード
c++
1void removefilter(unsigned char *a, int w, int h){ 2 int i, j, k, l; 3 int *s; //ラベルの面積 4 s = (int *)calloc(labelcnt, sizeof(int *)); 5 6 printf("labelcnt = %d\n", labelcnt); 7 8 for (k = 0; k < labelcnt; k++){ //面積を計算 9 for (i = 0; i < h; i++){ 10 for (j = 0; j < w; j++){ 11 if (a[i*w + j] == k){ //もし注目座標のラベルがkなら 12 s[k]++; 13 } 14 15 } 16 } 17 } 18 s[0] = 0; 19 for (k = 0; k < labelcnt; k++){ //面積の出力 20 printf("ラベル%dの面積 = %d\n", k, s[k]); 21 } 22 printf("面積が極端に小さい、また極端に大きいラベルを削除します(100以下または3000以上)\n"); 23 for (k = 0; k < labelcnt; k++){ 24 if (s[k] < 100 || 3000 < s[k]){ //もし面積が極端に小さい、また極端に大きいなら 25 for (i = 0; i < h; i++){ 26 for (j = 0; j < w; j++){ 27 if (a[i*w + j] == k){ //もし該当するラベルの座標なら 28 a[i*w + j] = 0; //ラベルを取り消す 29 } 30 31 } 32 } 33 } 34 } 35 printf("削除工程を経て残ったものを表示します\n"); 36 initarray(s, labelcnt); 37 for (k = 1; k < labelcnt; k++){ //もう一度面積を計算(残ったもの) 38 for (i = 0; i < h; i++){ 39 for (j = 0; j < w; j++){ 40 if (a[i*w + j] == k){ 41 s[k]++; 42 } 43 44 } 45 } 46 } 47 s[0] = 0; 48 for (k = 0; k < labelcnt; k++){ //改めて面積の出力 49 if (s[k] != 0){ 50 printf("ラベル%dの面積 = %d\n", k, s[k]); 51 } 52 } 53 54 printf("これで面積の値が極端なものを削除することができました\n"); 55 printf("次に、円形度による判定を行います。\n"); 56 57 roundness(a, w, h, s, labelcnt); 58 printf("面積の初期化\n"); 59 initarray(s, labelcnt); 60 printf("面積の再計算\n"); 61 for (k = 0; k < labelcnt; k++){ //もう一度面積を計算(残ったもの) 62 for (i = 0; i < h; i++){ 63 for (j = 0; j < w; j++){ 64 if (a[i*w + j] == k){ 65 s[k]++; 66 } 67 68 } 69 } 70 } 71 s[0] = 0; 72 for (k = 0; k < labelcnt; k++){ //面積の出力 73 if (s[k] != 0){ 74 printf("ラベル%dの面積 = %d\n", k, s[k]); 75 } 76 77 } 78 printf("残ったラベルは以上です。\n"); 79 80 free(s); 81 82} 83void roundness(unsigned char *a, int w, int h, int *s, int labelcnt){ 84 int i, j, k, l; 85 86 double *r; //ラベルの仮想の円の半径 87 r = (double *)calloc(labelcnt, sizeof(double *)); 88 89 printf("円形度を求めるために仮想的な半径を求めます。\n"); 90 for (k = 0; k < labelcnt; k++){ 91 if (s[k] != 0){ 92 r[k] = sqrt((double)s[k] / pi); //r*r*pi = sより 93 printf("%d:r = %lf, s = %d\n", k, r[k],s[k]); 94 } 95 } 96 printf("次に、図形の中心となる座標を求めます。\n"); 97 int max_x = 0; 98 int min_x = 1024; 99 int max_y = 0; 100 int min_y = 1024; 101 int x[100],y[100]; //ラベルの中心の座標 102 initarray(x, 100); 103 initarray(y, 100); 104 105 printf("探索開始\n"); 106 for (k = 0; k < labelcnt; k++){ 107 if (s[k] != 0){ 108 max_x = 0; 109 min_x = 1024; 110 max_y = 0; 111 min_y = 1024; 112 //printf("ラベル%d:面積あり,%d\n", k,s[k]); 113 for (i = 0; i < h; i++){ 114 for (j = 0; j < w; j++){ 115 if (a[i*w + j] == k){ //もし注目座標のラベルがkなら 116 if (j > max_x){ 117 max_x = j; 118 } 119 if (j < min_x){ 120 min_x = j; 121 } 122 123 if (i > max_y){ 124 max_y = i; 125 } 126 if (i < min_y){ 127 min_y = i; 128 } 129 } 130 } 131 } 132 //printf("ラベル%d:探索終了\n", k); 133 x[k] = min_x + (max_x - min_x) / 2; 134 y[k] = min_y + (max_y - min_y) / 2; 135 printf("label %d: (x,y) = (%d,%d)\n", k, x[k], y[k]); //中心座標の出力 136 //終わったら次のラベルへ 137 } 138 } 139 printf("探索終了\n"); 140 141 printf("仮想の円と実際のラベルが一致している面積を求め、円形度を求める\n"); 142 143 int match_s[100]; 144 initarray(match_s, 100); 145 146 for (k = 0; k < labelcnt; k++){ 147 if (s[k] != 0){ 148 for (i = 0; i < h; i++){ 149 for (j = 0; j < w; j++){ 150 if ((double)(abs(j - x[k])*abs(j - x[k]) + abs(i - y[k])*abs(i - y[k])) < r[k] * r[k]){ //もし注目画素の座標が仮想の円の中なら 151 if (a[i*w + j] == k){ //注目画素の座標がラベルを持っている(=一致しているなら) 152 match_s[k]++; 153 } 154 } 155 } 156 } 157 printf("label %dの一致した面積: %d\n 元の面積: %d\n", k, match_s[k], s[k]); 158 } 159 } 160 printf("各ラベルの円形度を表示します。\n"); 161 for (k = 0; k < labelcnt; k++){ 162 if (s[k] != 0){ 163 printf("label %dの円形度: %lf\n", k, (double)match_s[k] / (double)s[k]); 164 } 165 } 166 printf("円形度が0.8以下のものを削除します\n"); 167 for (k = 0; k < labelcnt; k++){ 168 if (((double)match_s[k] / (double)s[k]) < 0.8){ //もし円形度が0.8以下なら 169 for (i = 0; i < h; i++){ 170 for (j = 0; j < w; j++){ 171 if (a[i*w + j] == k){ //もし該当するラベルの座標なら 172 a[i*w + j] = 0; //ラベルを取り消す 173 } 174 175 } 176 } 177 } 178 } 179 printf("円形度の値によるラベルの削除終了\n"); 180 181 free(r); 182 183 printf("free\n"); 184 185 186} 187void image_write_unchar(char *filename, int w, int h, unsigned char *im) 188{ 189 printf("output %s\n", filename); 190 191 FILE *fp; 192 if ((fp = fopen(filename, "wb")) == NULL){ 193 printf("File Open Error Occured!\n"); 194 exit(-1); 195 } 196 fwrite((unsigned char *)im, sizeof(unsigned char), w * h, fp); fclose(fp); 197 198 printf("output completed\n"); 199}
###試したこと
配列を宣言するときにmallocとcalloc、静的確保と動的確保、両方試してみました。
###補足情報(言語/FW/ツール等のバージョンなど)
そこのプログラムを実行すると変数:labelcntは88になります。
また上に乗せたソースはエラーが発生した関数のみとなります。

バッドをするには、ログインかつ
こちらの条件を満たす必要があります。