none
StretchDIBitsの、ビットマップ配列をビットマップ配列に拡縮コピーするようなものはありますか? RRS feed

  • 質問

  • 動画デコーダで得られた32ビットカラー画像を一定サイズに縮小し、それをクライアント領域に書き込んでいくという処理を書いています。

    元画像は32ビットピクセルの配列で、これをStretchDIBitsでメモリデバイスコンテキスト(ビットマップはDIB)縮小画像に変換し、それをまたStretchDIBitsでクライアント領域に書き込みます。

    いったんメモリデバイスコンテキストに縮小画像を受けているのは、とっておいてOnPaintの際に再描画で使うからです。さてこの中間バッファですが、これへの書き込みはデバイスコンテキスト経由、これから書き出すときにはビットマップ配列から直接となっています。どうせなら書き込むときもデバイスコンテキストを経由せず直接ビットマップ配列へ書き込んでくれれば良いのにと思うわけです。

    StrechDIBitsは書き込み先がHDC, 読み出し元がvoid*なわけですが、両方ともvoid*なような同機能関数、ないでしょうか。

    2015年11月27日 12:56

すべての返信

  • DIBSectionをつくれば、メモリ(ポインタ)と、それに紐付くDCがとれますが、そのあたりでいいのでしょうか。

    あるいは操作自体は純粋な計算(アルゴリズム)なわけで、OpenCVのcv::resizeとか、IPPのippResize8uあたりを呼び出す手はあると思います。


    jzkey

    2015年11月27日 15:29
  • MFC/ATL/WTLなどを使わずに、Win32 APIを直接利用しているのでしょうか? 質問するときはコンパイラーやOSのバージョンなど、環境に関する情報をきちんと詳しく書きましょう。

    なお、動画から得られた32bitカラー画像の縦横サイズはどの程度でしょうか? 色の並び順はBGRXフォーマットですか?

    StretchDIBits/StretchBlt関数は拡大縮小のアルゴリズムをSetStretchBltMode関数で変更できますが、いずれもあまり品質や処理速度がよくないです。2回も縮小をかけるとなるとなおさらです。

    縮小後の中間バッファをとっておいてファイルとして保存するなどの目的がないのであれば、まず32bitのBGRX生画像データを、あらかじめCreateDIBSection/CreateDIBitmapなどで作成しておいた同サイズのGDI DIB/DDBにmemcpy/SetDIBitsなどを使ってそのまま流し込むだけにして、描画時にStretchDIBits/StretchBltを使ってそのGDI DIB/DDBをウィンドウにDC経由で転送する、という形にしたほうがいいと思います。

    もし拡大縮小描画の処理速度と描画品質がともに重要で、なおかつWindows Vista以降がターゲットであれば、GDIではなくDirect2Dを使うとよいです(生画像データからDirect2Dビットマップへの転送は、ID2D1Bitmap::CopyFromMemoryを使います)。

    もし画面表示とは別に、保存用に動画フレームを縮小した高品質な静止画セットが欲しいのであれば、すでに提示されているようにOpenCVのcv::resize()でINTER_LINEAR/INTER_CUBIC/INTER_LANCZOS4を使ってオフスクリーン処理するという方法もあります。

    2015年11月28日 9:27