プロが教えるわが家の防犯対策術!

はじめての投稿です。よろしくお願いします。
ただいまC++でBMPファイル処理の勉強をしています。わからないところがBMPファイル(480×640)を読み込みその画像の輝度を配列(480×640)でテキストファイルに書き込みたいのですが、途中から配列がずれてしまいます。
各ピクセルからRGB値を読み込み輝度yを求めてるのですが、最初にBMPファイルのヘッダーを読み込んでしまってるんでしょうか?どなたかご教授お願いします。プラットフォームはWin32です。
以下にソースコードを載せます。

#include <stdio.h>
#include <stdlib.h>
#include <windows.h>
#pragma warning( disable : 4996 )
#pragma warning( disable : 4244 )
#pragma warning( disable : 4700 )

int main(void){

BITMAPFILEHEADER BmpHead = { 0 };
int R, G, B, y;
FILE *fpi, *fpy;

/* y値出力のオープン */
if((fpy=fopen("test.txt", "a")) == NULL){
fprintf(stderr, "output file open error\n");
exit(1);
}

/*画像の読込*/
if((fpi = fopen("filename.bmp","rb")) != NULL ){
fread( &BmpHead, sizeof(BmpHead), 1, fpi );
fseek( fpi, BmpHead.bfOffBits, SEEK_SET );

int h,l;
static int matrixy[480][640];//画像のサイズ480×640
for(h=0;h<480;h++){
for(l=0;l<640;l++){

B = fgetc(fpi);
G = fgetc(fpi);
R = fgetc(fpi);

y=0.298912*R+0.586611*G+0.114478*B;/*輝度の算出*/

fprintf(fpy,"%f,",y);
}
fprintf(fpy,"\n");
}
}
fclose(fpy);
fclose(fpi);
}

よろしくお願いします。

A 回答 (6件)

最初に書いたように、示された条件に限定すれば問題無いはずです。


となれば
・条件が間違っている
「24bitBGR無圧縮」「幅640x高さ480」「BMPファイル」のどれかが実際と違う
画像閲覧ソフトには、その画像の詳細なデータを調べられるものがります。それで条件が間違ってないか確認してみましょう。

・テキストの確認方法が間違っている
1行に (1~3桁(0~255)+カンマ1桁) x 640 = 1280~2560桁です。
使用したテキストエディタやビューアによっては、途中までしか表示できなかったり、折り返して次の行になっていたりする可能性があります。
特に、最初の内は0が多いので桁数も少ないですが、円の中心に近付けば255が多くなって桁が増えます。

確実に表示できるソフトを使う、とか、csvとしてExcel(2007以降でないと列が足りない)やOpenOfficeで開いてみるとかしてはどうでしょう。
    • good
    • 0
この回答へのお礼

ご指摘の通りcsvファイルとしてエクセル2007で開いたところ問題なく動いていました。
勉強になりました。ありがとうございました。

お礼日時:2011/02/04 11:49

手元で 640×480 の bmp ファイルを作って試した限りでは, 想定した通りに動作します.


「画像のサイズに間違いはない」というのはどのように確かめたのでしょうか?
    • good
    • 0
この回答へのお礼

画像のプロパティから画像のサイズを見ました。
また、皆さんのご指摘の通りCSVファイルで書き込み、エクセル2007で開いたら問題なく動いていました。お手数かけてすみませんでした。勉強になりました。
ありがとうございました。

お礼日時:2011/02/04 11:46

#3 です



>ここが原因でずれていってしまうのでしょうか?

>>どうして、「ずれる」と判ったのでしょうか。

 640×10桁として、1行6400文字となりますが、「ずれる」と判った?テキストエディタ?の「折り返し」設定は大丈夫でしょうか。
 私のソースのように、1行の文字数を少なくして試されることをお勧めします。

>ご掲示して頂いたソースコードは書き込みがバイナリになってますが、テキストを開いたら文字化けしていませんか?

 すみません、ミスりました。正 "w" ← 誤 "wb"

 しかし、fwrite() でなく、fprintf() ですので、文字化けはしません。
 試していただければ確認できます。

#2お礼>本プログラムは%dで計算しています。

   y = (int)( 0.5 + 0.298912 * (double)R + 0.586611 * (double)G + 0.114478 * (double)B );

   fprintf( fpy, "%3d,", y );

 ということでしょうか。
    • good
    • 0
この回答へのお礼

>どうして、「ずれる」と判ったのでしょうか。

読み込んでる画像が黒地に白の円が中央にある画像なので、最初と最後が0でなければおかしいですよね?最初は0となっているんですが、最後が255となっていておかしなことになっているので、どこかでずれているのかと。


>  y = (int)( 0.5 + 0.298912 * (double)R + 0.586611 * (double)G + 0.114478 * (double)B );
 ということでしょうか。

 y = (int)( 0.5 + 0.298912 * (int)R + 0.586611 * (int)G + 0.114478 * (int)B );
という計算です。

お礼日時:2011/02/02 17:19

>BMPファイル(480×640)



 通常は、横480、縦640の記述ですよね、

   for(h=0;h<480;h++){
   for(l=0;l<640;l++){

 これだと、横640、縦480のループかと思います。
 下のURLの「画像データ」で、記録方式を確認して下さい。

>・・その画像の輝度を配列(480×640)でテキストファイルに書き込みたいのですが、途中から配列がずれてしまいます。

 プログラムでは、配列は用いていませんが、どうして、「ずれる」と判ったのでしょうか。

>どなたかご教示お願いします。

 「情報ヘッダ」を読み込み、その「横・縦」を用いればいいと思います。

  http://www.kk.iij4u.or.jp/~kondo/bmp/

 なお、↑の「画像データ」に、
 「画像の横のラインのデータは,long (4 byte) の境界に揃えなければいけない」
 とあるため、/* ◆ */の行(読み飛ばし)が必須となります。
(今回は、4の倍数なので、読み飛ばし動作無し)

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

int main( void )
{
 double y; // ++++++
 int R, G, B, h, l;
 FILE *fpi, *fpy;
 BITMAPFILEHEADER BmpHead;
 BITMAPINFOHEADER BmpInfo;

 if( NULL == ( fpy = fopen( "Z:/test.txt", "wb" ) ) ){

  fprintf( stderr, "output file open error\n" );
  exit( 1 );
 }
 if( NULL == ( fpi = fopen( "Z:/filename.bmp", "rb" ) ) ){

  fprintf( stderr, "input file open error\n" );
  exit( 1 );
 }
 fread( &BmpHead, 1, sizeof( BITMAPFILEHEADER ), fpi );
 fread( &BmpInfo, 1, sizeof( BITMAPINFOHEADER ), fpi );

 fprintf( stderr, "BitCnt%5d\n", BmpInfo.biBitCount );
 fprintf( stderr, "width %5d\n", BmpInfo.biWidth );
 fprintf( stderr, "height%5d\n", BmpInfo.biHeight );

 for( h = 0; h < BmpInfo.biHeight; h++ ){

  for( l = 0; l < BmpInfo.biWidth; l++ ){

   B = fgetc( fpi );
   G = fgetc( fpi );
   R = fgetc( fpi );

   y = 0.298912 * R + 0.586611 * G + 0.114478 * B;

   fprintf( fpy, "%02X %02X %02X %f\n", B, G, R, y );
  }
/* ◆ */ for( l = 0; l < ( ( 4 - ( BmpInfo.biWidth % 4 ) ) % 4 ); l++ ) fgetc( fpi );
 }
 fclose( fpy );
 fclose( fpi );

 return( 0 );
}
注:インデントに全角空白を用いています。コピペ後、タブに一括変換して下さい。
    • good
    • 0
この回答へのお礼

ご指摘の通り、サイズ表記が逆になっていました。正しくはBMPファイル(640×480)です。
また、

for(h=0;h<480;h++){
for(l=0;l<640;l++){

B = fgetc(fpi);
G = fgetc(fpi);
R = fgetc(fpi);

y=0.298912*R+0.586611*G+0.114478*B;/*輝度の算出*/

fprintf(fpy,"%f,",y);
}
fprintf(fpy,"\n");
}

のところでテキストには横640、縦480の形で配列されると思うのですが、ここが原因でずれていってしまうのでしょうか?
また、ご掲示して頂いたソースコードは書き込みがバイナリになってますが、テキストを開いたら文字化けしていませんか?

お礼日時:2011/02/02 13:58

多分



fprintf(fpy,"%f,",y);

の箇所が間違い。

%f書式指定はfloat/doubleに対する書式で、可変個引数として渡された値はfloat/doubleと判断され、さらに内部でdouble(Win32だと64bit浮動小数点数)に格上げされて扱われるので、int型の変数y(Win32だと32bit符号付き整数)を渡すと異常な値が出力されるだけ。
C++が使えてなおかつ速度性能をあまり追求しないのならば、printf系のこういう弱点を避けて、極力ストリーム(std::ofstream)を使うことをお勧めします。
    • good
    • 0
この回答へのお礼

回答ありがとうございます。ご指摘の通り、こちらに載せているソースの%dを%fと書き間違えていました。すみません。本プログラムは%dで計算しています。

お礼日時:2011/02/02 13:48

ヘッダを読んで画素の先頭へシーク、とやりかたは特に間違っていないと思いますが。


/*
もっと正確には、BmpHead.bfTypeが正しいこと、BITMAPINFOHEADERの分も読み込んで24bitカラー圧縮無しで画素数とかが正しいことも確認した方がいいですが
*/

画素データは幅方向に4バイト単位なるように、足りない分はダミーデータを入れることになっていますが、480x640なら3倍しても4の倍数なので、それは考えず連続で読むことができます。

BMPのY座標の並びは画面下が先に来ます。よくある画像データでの左上が(0,0)のものとは上下逆になります。

> BMPファイル(480×640)

念の為確認ですが、高さ480x幅640の横長でよろしいでしょうか?

あと「ずれる」とはどんな状態のことを言っていますか?
    • good
    • 0
この回答へのお礼

御即答ありがとうございます。
画像の表記の仕方が逆になってました。すみません。ご指摘の通り幅640、高さ480です。
説明不足ですみません。「ずれる」というのは、実は扱ってる画像が黒の画像でして、中央に白の円が書かれ、の輝度の値を並べたら、0と255の値が縦480、横640で配列され、255が円を描くようになるはずです。しかし、その結果のテキストを見ると最初は0,0,0,0・・・255、255、・・・0,0,0,0ときれいに並んであるのですが、後半が0,0,0,0・・・0,0,0,0・・・255,255,255,255という風に最後の値が255になってしまいます。画像のサイズに間違いはないです。

お礼日時:2011/02/02 13:44

お探しのQ&Aが見つからない時は、教えて!gooで質問しましょう!