- ベストアンサー
openCVでの白黒画像読み込みに関する質問
- openCVで白黒画像を読み込む際に、ピクセルの値が255(白)になってしまい困っています。
- 原因を特定するため、画像の読み込みや変換などの処理を試していますが、うまくいかない状況です。
- 初歩的な質問かもしれませんが、どのように解決すれば良いかアドバイスをいただけると助かります。
- みんなの回答 (2)
- 専門家の回答
質問者が選んだベストアンサー
> out_img->imageData[out_img->widthStep * 6 + 6 * 3] = 0; > out_img->imageData[out_img->widthStep * 6 + 6 * 3 + 1] = 0; > out_img->imageData[out_img->widthStep * 6 + 6 * 3 + 2] = 0; これでは座標(6,6)であり、6x6の画像(x=0~5,y=0~5)に存在しない点です > なぜか上のsrc_img_grayでは黒がゼロにはならない JPEGで保存しているようですが、JPEGは非可逆圧縮を使っています。 不可逆とは、元に戻らない、という意味です。 「見た目が似ていれば、ちょっとくらい色が違っていてもいい」という考えで、高圧縮率を実現しています。 元の色が黒(0)だったら、JPEG保存したものを読み出したときに「だいたい黒(1とか2とか)」になってればいい、というものです。 そのまま扱いたいのなら、PNG等の可逆圧縮やBMP等の非圧縮形式を使いましょう。 > uchar iro = tmp_img->imageData[tmp_img->widthStep * y + x * 3]; なぜ x *3 になっているのですか? 前にも言いましたが、配列や画像の範囲について注意が足りません。 まずは、imageDataに直接アクセスするのではなく、 cvSet2D/cvGet2D やcvSetReal2D/cvGetReal2D で x,y を指定するようにしては。 imageDataを使いたいのなら、C言語の配列とポインタをしっかり学習してマスターしてからにしましょう。
その他の回答 (1)
- kmee
- ベストアンサー率55% (1857/3366)
imgData の中は、次のようにデータが並んでいます 0 * widthStep から X=0,Y=0のデータ X=1,Y=0のデータ ... X=x,Y=0のデータ ... X=width-1,Y=0のデータ 1 * widthStep から X=0,Y=1のデータ X=1,Y=1のデータ ... X=x,Y=1のデータ ... X=width-1,Y=1のデータ y * widthStep から ... X=x,Y=yのデータ ... y * widthStep から ... X=x,Y=yのデータ ... (height-1)*widthStepから ... X=width-1,Y=height-1のデータ 各座標データは次のようになっています チャンネル1のデータ チャンネル2のデータ(2チャンネル以上のとき) チャンネル3のデータ(3チャンネル以上のとき) チャンネル4のデータ(4チャンネル以上のとき) 各チャンネルのデータは IPL_DEPTH_* で示されるバイト数だけ使われます。 IPL_DEPTH_8U なら1バイト IPL_DEPTH_32F なら4バイト 以上のことから、座標(x,y)のチャンネルch のデータは imageData[ y * widhtStep + 1データあたりのバイト数 * ( x * 総チャンネル数 + (ch -1)) ] から始まる 「1データあたりのバイト数」のデータ、ということになります で out_img = cvLoadImage("C:...\shiro.jpg", CV_LOAD_IMAGE_COLOR); だと、おそらく IPL_DEPTH_8U(1バイト), チャンネル数3になっているはずです。 これだと out_img->imageData[out_img->widthStep * y + x * 3] = 0; // 3チャンネルのうちのチャンネル1: B out_img->imageData[out_img->widthStep * y + x * 3 + 1] = 0; // 3チャンネルのうちのチャンネル2: G out_img->imageData[out_img->widthStep * y + x * 3 + 2] = 0; // 3チャンネルのうちのチャンネル3: R となります。 /* 元の画像が 6x6 なら、 x=6,y=6という座標は存在しません。 */ /* よって out_img->widthStep * 6 + 6 * 3 は間違いです */ ですが cvCreateImage(cvGetSize(src_img), IPL_DEPTH_8U, 1) だと、IPL_DEPTH_8U(1バイト), チャンネル数1 です。 imageData[ y * widhtStep + 1データあたりのバイト数 * ( x * 総チャンネル数 + (ch -1)) ] にあてはめれば imageData[ y * widhtStep + 1 * ( x * 1 + (1 -1)) ] です。 前にも言ったと思いますが、C言語では、配列の範囲外かどうかのチェックはしません。 例え範囲外でも、とにかくそのアドレスをアクセスしに行きます。 ちゃんと正しい範囲かどうかを管理するのは、プログラム制作者の仕事です。 そこが不完全なら、まずは、チェックしてくれるSet/Getを使って「正しい処理」をするプログラムを作ることから始めてはどうでしょうか。
お礼
いろいろとこのように丁寧なアドバイスをくださったのにきちんとお礼を書き込んでいませんでした。 申し訳ありません。 今でも「何ビットの画像だっけ」と迷うので、このコメントを読み返して知識を確実にしていきます。 本当にありがとうございました!
お礼
kmee様 すぐに回答くださってありがとうございます。 いろいろと今回もミスを教えてくださって助かりました。 pngにしてみたところゼロになりました。 画像の拡張子にも注意します。 できればぜひ、もうひとつ教えていただきたいのですが なぜimageDataの場合、「*3」は不要なのでしょうか? いくら2値にしたとはいえ、配列はRGBなので 3番目の値=画素値、だと理解していました。 cvSet2Dなどを使用してみますが、 なぜimageDataでRGB画像の場合に「*3」ではNGなのか 自分で調べた結果の理解ですので、 恥ずかしいのですが混乱しています。 もし教えていただけると嬉しいです。 よろしくお願い致します。