はじめての投稿です。よろしくお願いします。
ただいま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);
}
よろしくお願いします。
No.6ベストアンサー
- 回答日時:
最初に書いたように、示された条件に限定すれば問題無いはずです。
となれば
・条件が間違っている
「24bitBGR無圧縮」「幅640x高さ480」「BMPファイル」のどれかが実際と違う
画像閲覧ソフトには、その画像の詳細なデータを調べられるものがります。それで条件が間違ってないか確認してみましょう。
・テキストの確認方法が間違っている
1行に (1~3桁(0~255)+カンマ1桁) x 640 = 1280~2560桁です。
使用したテキストエディタやビューアによっては、途中までしか表示できなかったり、折り返して次の行になっていたりする可能性があります。
特に、最初の内は0が多いので桁数も少ないですが、円の中心に近付けば255が多くなって桁が増えます。
確実に表示できるソフトを使う、とか、csvとしてExcel(2007以降でないと列が足りない)やOpenOfficeで開いてみるとかしてはどうでしょう。
ご指摘の通りcsvファイルとしてエクセル2007で開いたところ問題なく動いていました。
勉強になりました。ありがとうございました。
No.4
- 回答日時:
#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 );
ということでしょうか。
>どうして、「ずれる」と判ったのでしょうか。
読み込んでる画像が黒地に白の円が中央にある画像なので、最初と最後が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 );
という計算です。
No.3
- 回答日時:
>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 );
}
注:インデントに全角空白を用いています。コピペ後、タブに一括変換して下さい。
ご指摘の通り、サイズ表記が逆になっていました。正しくは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の形で配列されると思うのですが、ここが原因でずれていってしまうのでしょうか?
また、ご掲示して頂いたソースコードは書き込みがバイナリになってますが、テキストを開いたら文字化けしていませんか?
No.2
- 回答日時:
多分
fprintf(fpy,"%f,",y);
の箇所が間違い。
%f書式指定はfloat/doubleに対する書式で、可変個引数として渡された値はfloat/doubleと判断され、さらに内部でdouble(Win32だと64bit浮動小数点数)に格上げされて扱われるので、int型の変数y(Win32だと32bit符号付き整数)を渡すと異常な値が出力されるだけ。
C++が使えてなおかつ速度性能をあまり追求しないのならば、printf系のこういう弱点を避けて、極力ストリーム(std::ofstream)を使うことをお勧めします。
回答ありがとうございます。ご指摘の通り、こちらに載せているソースの%dを%fと書き間違えていました。すみません。本プログラムは%dで計算しています。
No.1
- 回答日時:
ヘッダを読んで画素の先頭へシーク、とやりかたは特に間違っていないと思いますが。
/*
もっと正確には、BmpHead.bfTypeが正しいこと、BITMAPINFOHEADERの分も読み込んで24bitカラー圧縮無しで画素数とかが正しいことも確認した方がいいですが
*/
画素データは幅方向に4バイト単位なるように、足りない分はダミーデータを入れることになっていますが、480x640なら3倍しても4の倍数なので、それは考えず連続で読むことができます。
BMPのY座標の並びは画面下が先に来ます。よくある画像データでの左上が(0,0)のものとは上下逆になります。
> BMPファイル(480×640)
念の為確認ですが、高さ480x幅640の横長でよろしいでしょうか?
あと「ずれる」とはどんな状態のことを言っていますか?
御即答ありがとうございます。
画像の表記の仕方が逆になってました。すみません。ご指摘の通り幅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になってしまいます。画像のサイズに間違いはないです。
お探しのQ&Aが見つからない時は、教えて!gooで質問しましょう!
関連するカテゴリからQ&Aを探す
おすすめ情報
- ・漫画をレンタルでお得に読める!
- ・【大喜利】【投稿~11/12】 急に朝起こしてきた母親に言われた一言とは?
- ・好きな和訳タイトルを教えてください
- ・うちのカレーにはこれが入ってる!って食材ありますか?
- ・好きな「お肉」は?
- ・あなたは何にトキメキますか?
- ・おすすめのモーニング・朝食メニューを教えて!
- ・「覚え間違い」を教えてください!
- ・とっておきの手土産を教えて
- ・「平成」を感じるもの
- ・秘密基地、どこに作った?
- ・【お題】NEW演歌
- ・カンパ〜イ!←最初の1杯目、なに頼む?
- ・一回も披露したことのない豆知識
- ・これ何て呼びますか
- ・チョコミントアイス
- ・初めて自分の家と他人の家が違う、と意識した時
- ・「これはヤバかったな」という遅刻エピソード
- ・これ何て呼びますか Part2
- ・許せない心理テスト
- ・この人頭いいなと思ったエピソード
- ・牛、豚、鶏、どれか一つ食べられなくなるとしたら?
- ・あなたの習慣について教えてください!!
- ・ハマっている「お菓子」を教えて!
- ・高校三年生の合唱祭で何を歌いましたか?
- ・【大喜利】【投稿~11/1】 存在しそうで存在しないモノマネ芸人の名前を教えてください
- ・好きなおでんの具材ドラフト会議しましょう
- ・餃子を食べるとき、何をつけますか?
- ・あなたの「必」の書き順を教えてください
- ・ギリギリ行けるお一人様のライン
- ・10代と話して驚いたこと
- ・家の中でのこだわりスペースはどこですか?
- ・つい集めてしまうものはなんですか?
- ・自分のセンスや笑いの好みに影響を受けた作品を教えて
- ・【お題】引っかけ問題(締め切り10月27日(日)23時)
- ・大人になっても苦手な食べ物、ありますか?
- ・14歳の自分に衝撃の事実を告げてください
- ・架空の映画のネタバレレビュー
- ・「お昼の放送」の思い出
- ・昨日見た夢を教えて下さい
- ・ちょっと先の未来クイズ第4問
- ・【大喜利】【投稿~10/21(月)】買ったばかりの自転車を分解してひと言
- ・メモのコツを教えてください!
- ・CDの保有枚数を教えてください
- ・ホテルを選ぶとき、これだけは譲れない条件TOP3は?
- ・家・車以外で、人生で一番奮発した買い物
- ・人生最悪の忘れ物
- ・【コナン30周年】嘘でしょ!?と思った○○周年を教えて【ハルヒ20周年】
- ・あなたの習慣について教えてください!!
- ・都道府県穴埋めゲーム
デイリーランキングこのカテゴリの人気デイリーQ&Aランキング
-
ファイル入力のデータを構造体...
-
テキストファイルを後ろから読...
-
ファイル内の(&H0A)を(&H0D0A)...
-
Cで2次元配列にCSVファイルを...
-
VBAでテキストファイルを複数開...
-
日本語を配列に収め、そして表...
-
バイナリデータの書き換え
-
ファイルのアクセス回数について
-
エクセルのプロパティーでセキ...
-
カンマ区切りのCSVファイルから...
-
Windows10でコマンドプロンプト...
-
エクセルのハイパーリンクがコ...
-
【VBA】テキストファイルを指定...
-
エクセルで複数のコメントのサ...
-
Excel 相対パス
-
バッチファイル 別ファイルにリ...
-
エクセルVBAで一つ上の階層...
-
[エクセル]コピーするとオブジ...
-
Vba初心者です。下記のコード助...
-
エクセル2010、図が大きすぎま...
マンスリーランキングこのカテゴリの人気マンスリーQ&Aランキング
-
テキストファイルを後ろから読...
-
VBAでテキストファイルを複数開...
-
バイト型のデータを16進表記で...
-
DXFファイルをVBで取り込み、図...
-
バイナリファイルでOutOfMemory...
-
VBAでテキストファイルの改行を...
-
VBSにてCSV読み込みし比較
-
CSVファイルによる検索の高速化
-
ファイル入力のデータを構造体...
-
RGBのバイナリデータをCImageに...
-
ファイル内の(&H0A)を(&H0D0A)...
-
ファイルをメモリに出力する方法
-
[VBS] 16進数でバイナリファイ...
-
VBScriptの配列は、要素数を指...
-
バイナリデータの書き換え
-
配列操作について
-
Cで2次元配列にCSVファイルを...
-
バイナリ出力
-
ファイル操作
-
Unicodeのファイル読み込みがう...
おすすめ情報