ページ 1 / 1
動的な三次元配列で画像のRGBを取得
Posted: 2011年2月25日(金) 22:00
by 六氏
画像(bmp)を読み込み、そのRGBデータを配列に入れる処理を以下のように作りました。
xとyにはint型で数字が入っています。
unsigned char header[54],rgb[x][y][3];
fr=fopen("gazou.bmp","rb");
fread(header,1,54,fr);
fread(rgb,1,x*y*3,fr);
rgb[0][0][1]などでRGBの取得が成功したので、rgbを動的な三次元配列として確保したあとにfreadしたいと思っています。
そこで以下のように作ってみたところ、メイクは成功するのですが※の部分で止まってしまいます。
unsigned char header[54];
unsigned char*** rgb;
rgb=(unsigned char***)malloc(sizeof(unsigned char**)*x);
for(i=0;i<x;++i){
rgb=(unsigned char**)malloc(sizeof(unsigned char*)*y);
for(j=0;j<y;++j){
rgb[j]=(unsigned char*)malloc(sizeof(unsigned char)*3);
}
}
fr=fopen("gazou.bmp","rb");
fread(header,1,54,fr);
fread(rgb,1,x*y*3,fr);
for (i=0;i<x;i++) {
for (j=0;j<y;j++) {
free(rgb[j]);※
}
free(rgb);
}
free(rgb);
本やHPにあった二次元配列の作り方を参考にして作ってみたのですが何か根本的な勘違いをしているのでしょうか?
お教えいただけると幸いです。
Re: 動的な三次元配列で画像のRGBを取得
Posted: 2011年2月25日(金) 23:06
by h2so5
この動的確保の方法ですと、三次元配列のメモリ上の位置が1次元的に連続していないので
fread(rgb,1,x*y*3,fr);
をした時点でデータが壊れています。
rgb=(unsigned char*)malloc(sizeof(unsigned char)*x*y*3);
のように確保するべきだと思います。
Re: 動的な三次元配列で画像のRGBを取得
Posted: 2011年2月25日(金) 23:07
by bitter_fox
六氏 さんが書きました:rgbを動的な三次元配列として確保したあとにfreadしたいと思っています。
そこで以下のように作ってみたところ、メイクは成功するのですが※の部分で止まってしまいます。
コード:
fr=fopen("gazou.bmp","rb");
fread(header,1,54,fr);
fread(rgb,1,x*y*3,fr);
for (i=0;i<x;i++) {
for (j=0;j<y;j++) {
free(rgb[i][j]);※
}
free(rgb[i]);
}
free(rgb);
本当にfreeで止まってしまっていますか?
個人的にはfreadの方が問題がありそうな気がするのですが・・・
[hr][追記]
それからコードを載せる際にはcodeタグで囲っていただきますようにお願いします。
Re: 動的な三次元配列で画像のRGBを取得
Posted: 2011年2月26日(土) 00:43
by 六氏
>>h2so5さん
rgb=(unsigned char*)malloc(sizeof(unsigned char)*x*y*3);
だとx*y*3に相当する一次元の配列が出来るということだと思うのですが、取得したいものは[0,255,0],[255,0,0],[0,0,255]のようになっているので・・・
>>bitter_fox
間違いなく最初のfreeまでは処理が進んでいます。
freadをコメントアウトすると止まららないので、freadでデータが壊れても無視して進み、freeで解放するときに壊れたデータで止まっているのだと思います。
codeタグのご指摘ありがとうございます。次回から必ず使うようにします。
Re: 動的な三次元配列で画像のRGBを取得
Posted: 2011年2月26日(土) 01:20
by kimuchi
コード:
unsigned char header[54];
unsigned char* rgb;
rgb=(unsigned char*)calloc(x*y,sizeof(unsigned char*)*3);
fr=fopen("gazou.bmp","rb");
fread(header,1,54,fr);
for(i=0;i<x*y;++i){
fread(rgb,1,3,fr);
rgb++;
}
free(rgb);
取得したいものは[0,255,0],[255,0,0],[0,0,255]のようになっているので・・・
上のサンプルは、
callocを使って3バイトのメモリを「x*y」個確保してファイルから3バイトずつ読み込ませています。
これでうまくいきそうですが・・・いかがでしょう?
Re: 動的な三次元配列で画像のRGBを取得
Posted: 2011年2月26日(土) 01:42
by bitter_fox
六氏 さんが書きました:
間違いなく最初のfreeまでは処理が進んでいます。
freadをコメントアウトすると止まららないので、freadでデータが壊れても無視して進み、freeで解放するときに壊れたデータで止まっているのだと思います。
確かにh2so5さんが仰られた
h2so5 さんが書きました:
この動的確保の方法ですと、三次元配列のメモリ上の位置が1次元的に連続していないので
fread(rgb,1,x*y*3,fr);
をした時点でデータが壊れています。
が原因のようですね。
細かく見ると
コード:
rgb=(unsigned char***)malloc(sizeof(unsigned char**)*x);
を実行したときのrgb[0]の値を0x00004000として。(注:以下の値はすべて仮定の値です)
その次の
コード:
for(i=0;i<x;++i){
rgb[i]=(unsigned char**)malloc(sizeof(unsigned char*)*y);
で、
rgb[0]の時に0x00005000が入ったとします。
そこで
コード:
fread(rgb,1,x*y*3,fr);
とした場合は、
rgb[0]の0x00004000を先頭にしてファイルの内容をx*y*3バイト分書き込んでしまいます。(この時にx*y*3バイトは最初に確保した範囲を当然超えているのでヒープ領域を破壊する恐れもあります。)
で、書き込んだ結果
*(0x00004000) = 0xff (←ここは画像データの値
...
となり、次のfreeのところはどうなるかというと
free(*(0x00004000))がfree(0xff)となって解放してはいけない領域を解放しようとしてエラーになってしまったのだと思います。
ですので、freadのところを各ピクセルごとに読み込むように変えて実行してみてください。
コード:
fr=fopen("gazou.bmp","rb");
fread(header,1,54,fr);
for (i = 0; i < x; i++) // xが縦というのは少々おかしいですが縦
{
for (j = 0; j < y; j++) // yが横というのも同じく変ですが横
{
fread(rgb[i][j],1,3,fr);
}
}
for (i=0;i<x;i++) {
for (j=0;j<y;j++) {
free(rgb[i][j]);※
}
free(rgb[i]);
}
free(rgb);
Re: 動的な三次元配列で画像のRGBを取得
Posted: 2011年2月26日(土) 02:44
by 六氏
kimuchiさんとbitter_foxさんのコードを見ながら考えてみたところ、上手く出来ました。
止まってしまう原因も理解でき、何を勘違いしていたのかもわかったのでとても勉強になりました。
ありがとうございました。
Re: 動的な三次元配列で画像のRGBを取得
Posted: 2011年2月26日(土) 11:36
by Dixq (管理人)
> rgb=(unsigned char*)malloc(sizeof(unsigned char)*x*y*3);
> だとx*y*3に相当する一次元の配列が出来るということだと思うのですが、取得したいものは[0,255,0],[255,0,0],[0,0,255]のようになっているので・・・
解決されたようですが、補足です。
二次元配列も結局は一次元配列と同じことですよ。
例えば
int arr[2][3];
と確保すると
* * * * * *
このように横6つの
連続した領域が確保され、例えばarr[1][0]と示せば4つめの要素を示せるだけです。
逆に言えば配列要素が連続していない二次元配列において、arr[1][0]を示すと要素ではないものを指してしまいます。
今回、
コード:
rgb=(unsigned char***)malloc(sizeof(unsigned char**)*x);
for(i=0;i<x;++i){
rgb[i]=(unsigned char**)malloc(sizeof(unsigned char*)*y);
for(j=0;j<y;++j){
rgb[i][j]=(unsigned char*)malloc(sizeof(unsigned char)*3);
}
}
このように要素が全て別々に作られているので、アドレスが連続しているとは限りません。
よって、期待しない要素を示してしまっていたのだと思います。