- ベストアンサー
SDKにてRAW画像(ヘッダ情報0)の表示
現在RAW画像(ヘッダ情報0)の表示プログラムをSDKにて作成中です。 色々と細かな質問に対してお答えいただいた皆様に感謝します。 おかげで一応表示することができました。 しかし新たな疑問が出てきてしまいました。 詳しく説明します。 まず入力画像情報をグローバルな構造体により管理するため、 typedef struct{ unsigned char *Input_Image; int Width; int Height; HWND hwnd; char szFileName[MAX_PATH]; char szFileTitle[MAX_PATH]; LPBITMAPINFO lpBitmapInfo; HANDLE hMemBitmapInfo; HANDLE hMemInput_Image; int flag; }IMAGEINFORMATION; static IMAGEINFORMATION *Image; このように定義しました。 ちなみにこの構造体メンバの最初のメンバ*Input_Imageは入力画像が格納するポインタです。今回の問題に対しこの*Input_Imageメンバのみ注意をお願いします。 画像入力処理として Image->hMemInput_Image = GlobalAlloc(GHND, sizeof(unsigned char) * Image->Height * Image->Width); Image->Input_Image = (unsigned char *)GlobalLock(Image->hMemInput_Image); により画像情報のポインタをImage->Input_Imageに格納します。 しかし入力した情報をそのまま使用すると、表示した場合に上下さかさまに反転して表示されてしまうので、この後に画像情報の反転処理を行わなければなりません。この反転処理を行う関数をvoid ReverseBitmap(unsigned char *)として、内容を次に示します。 void ReverseBitmap(unsigned char *Input) { int i, j, width, height; unsigned char temp; width = Image->Width-1; height = Image->Height-1; for(i=0; i<=height; i++){ for(j=0; j<=width; j++){ temp = Input[width * (height - i) + j]; Input[width * (height - i) + j] = Input[width * i + j]; Input[width * i + j] = temp; } } } 関数実行の記述は ReverseBitmap(Image->Input_Image); のように行いました。 これにより反転した配列が ReverseBitmap関数の引数に格納されていると考えたのですが、結果は反映されていませんでした。 結果として色々と試してみたのですが、どうやってもさかさまのまま表示されてしまいます。 関数への引数の渡し方、反転の仕方に問題があるようならアドバイスをお願いします。 そして、反転処理を記述した場合、2次元画像を1次元配列で操作するのは結構めんどくさいです。なのでこの上の定義をもとに、反転処理を2次元配列にて行うような方法はないでしょうか? こちらの疑問もよろしくお願いします。
- みんなの回答 (3)
- 専門家の回答
質問者が選んだベストアンサー
★横一列を1ブロックとして上下をミラー反転すればよい。 ・横の Image->Width バイト分のデータを CopyMemory() 関数で一括操作します。 (1)上部ラインを一時ラインにコピー (2)下部ラインを上部ラインにコピー (3)一時ラインを下部ラインにコピー この3ステップで1ラインのデータを交換(反転)出来ます。 ・あとは スキャンする上部ポインタを1ライン分だけ下に進め、 スキャンする下部ポインタを1ライン分だけ上に進めます。 そして、上部ポインタと下部ポインタが交差するときに処理を終了します。→while ( top < end ) 実装例: void ReverseBitmap( unsigned char *Input ) { unsigned char *tmp; ←一時メモリ領域 unsigned char *top; ←上部ライン領域 unsigned char *end; ←下部ライン領域 if ( (tmp = (unsigned char *)GlobalAlloc(GPTR,Image->Width)) != NULL ){ top = &Input[ 0 ]; end = &Input[ (Image->Height - 1) * Image->Width ]; while ( top < end ){ CopyMemory( tmp, top, Image->Width ); CopyMemory( top, end, Image->Width ); CopyMemory( end, tmp, Image->Width ); top += Image->Width; ←1ライン下に進む end -= Image->Width; ←1ライン上に進む } GlobalFree( tmp ); } } その他: ・StretchBlt() 関数でコピー先のサイズをマイナス指定すると反転します。 『コピー先長方形の横幅』をマイナス値に指定すると左右反転、 『コピー先長方形の高さ』をマイナス値に指定すると上下反転します。 ・この関数が使えるのならば、描画時は ReverseBitmap() でデータ反転しなくても 『生データ』のままで上下反転できます。ただし、マイナス値にしたら座標位置にも 注意して下さい。上下反転の場合は、y 座標が 0 位置ならば Image->Height の数を y 座標に指定します。これは指定された y 座標の位置からマイナスのサイズ分上に 向かって描画することになるからです。横の場合は、x 座標に Image->Width の数を 足します。 ・つまり、 通常描画が(0,0)の座標から横100、縦80のサイズは 左右反転では(100,0)の座標から横-100、縦80のサイズで左右反転の描画となり、 上下反転では(0,80)の座標から横100、縦-80のサイズで上下反転の描画となります。 上下左右の反転では(100,80)の座標から横-100、縦-80のサイズで上下左右反転の描画となります。 ・以上。参考に!
その他の回答 (2)
- redfox63
- ベストアンサー率71% (1325/1856)
画像バッファを上から下まで反転させてしまったら 元通りになりますよ 元 1234 5678 ABCD EFGH 1回目 EFGH ... B 5678 ABCD 1234 ... T 2回目 EFGH ABCD ... B 5678 ... T 1234 0ラインから2ラインまで反転させれば 元の状態の反転ですよね 3回目 EFGH 5678 ... B ABCD ... T 1234 4回目 1234 ... B 5678 ABCD EFGH ... T
お礼
返信ありがとうございました。 自分の厳密性のなさにあきれてしまいました。 確かにそうですよね・・・・・元に戻りますよね・・・・・ 頭の中では1行の入れ替えのみ完璧に動作すれば、後は全ての行で同じ処理を行えばいいと考えていたことがそもそもの失敗でしたね。 参考意見に感謝します。
- MrBan
- ベストアンサー率53% (331/615)
# > sizeof(unsigned char) * Image->Height * Image->Width # 1点あたりsizeof(unsigned char)=1でよいのですか?256色モード? > これにより反転した配列が ReverseBitmap関数の引数に格納されていると考えたのですが、結果は反映されていませんでした。 どんな処理を書いてるか知りませんが、 マイナスの高さを指定して描画すれば反転しませんでしたっけ>ビットマップ系API メモリ上できちんと反転できてることは、デバッガ等で確認してますか? > 反転処理を記述した場合、2次元画像を1次元配列で操作するのは結構めんどくさいです。 > なのでこの上の定義をもとに、反転処理を2次元配列にて行うような方法はないでしょうか? 1ライン単位で上下反転するのでしょうから、処理効率的にも、 内側のループで1byteづつ反転する意味は薄いと思います。 memcpy等で1ラインづつ処理すればよいかと。
お礼
返信ありがとうございました。 現在作成しているのは256階調のグレースケール画像を扱うソフトなんです。 色々と参考になる情報を教えていただきありがとうございました。
お礼
返信ありがとうございました。 CopyMemoryという関数があることにはじめて知りました。 無知でしたね・・・・ プログラムを見れば一発でどのような動作を振舞うのか、各引数の意味など即時に理解できる簡単な関数ですね。 これからも必要に応じて使用していきたいと思います。 またStretchBlt() 関数の説明までいただきありがとうございました。