5.7. 画像の合成¶
前のページの描画プリミティブは、線、矩形、テキストといった 幾何学的 なマークを画像上に描きます。これはアルゴリズムが可視化する必要のあるアノテーションの大半をカバーしますが、すべてではありません。アノテーション自体が画像である場合もあります。たとえば、現在のフレームと並べて表示するためにキャプチャした参照フレーム、プレビューの隅に表示する以前のキャプチャのサムネイル、キャリブレーション用にライブフレームの上に重ねて表示する事前に保存したテンプレートなどです。ある画像を別の画像の上に描画する仕組みは、たった1つのメソッド draw_image() であり、実際の合成に必要な位置、スケーリング、カラーパレット、透明度を扱うのに十分なパラメータを備えています。
5.7.1. 基本的な呼び出し¶
最も単純な形では、draw_image は別の Image と、それを描画する位置を受け取ります。
reference = image.Image("/sdcard/reference.bmp")
img.draw_image(reference, x=10, y=10)
描画先は img で、ソースは reference です。ソースの左上のピクセルが img の (10, 10) に配置され、ソースの残りのピクセルはそこから右および下方向に続きます。ソースが覆う描画先のピクセルは、対応するソースのピクセルで上書きされます。ソースの占有範囲外のピクセルはそのまま残ります。
ソースが描画先の端を越えて広がる場合、はみ出した部分は何も警告なくクリップされます。これは set_pixel が範囲外の位置に対して示すのと同じ寛容な動作です。アプリケーションコードは、あらかじめ位置を画像の寸法に収める必要はありません。望む位置をそのまま渡せば、メソッドがクリッピングを処理します。
5.7.2. ファイルをインラインで読み込む¶
draw_image は Image 引数の代わりにファイルパスを受け取り、合成する前にそのファイルを読み込みます。
img.draw_image("/sdcard/reference.bmp", x=10, y=10)
これは1行で済む便利な書き方のように見えますし、実際そうですが、その違いは構文以上のものです。ファイルから Image を構築すると、デコードされたピクセルを保持するバッファが割り当てられ、そのバッファはガベージコレクションが解放するまで残ります。パスを直接 draw_image に渡すと、モジュールがファイルをスクラッチバッファにデコードし、そこから合成を行い、呼び出しが戻るときにバッファを解放します。アプリケーションコードがフレーム間で別個の Image への参照を保持する必要はありません。
5.7.3. スケーリング¶
ソースと描画先のサイズが異なる場合、たとえば低解像度のキャプチャをより高解像度のキャンバスに合成する場合や、サムネイルをフレームの特定の割合のサイズに合わせる必要がある場合、2つのスケールパラメータが描画時にソースのリサイズを処理します。
img.draw_image(reference, x=10, y=10, x_scale=2.0, y_scale=2.0)
x_scale と y_scale は独立した浮動小数点数です。両方に同じ値を渡すと一様にスケーリングし、異なる値を渡すと一方の軸に沿ってソースを引き伸ばしたり縮めたりします。スケーリングは描画時に行われ、ソースの reference は変更されません。
ヒント フラグのビットマスクが、スケーリングが実際にピクセル間をどのように補間するかを決定します。image.BILINEAR はより多くの計算と引き換えに、より滑らかな結果を生成します。image.BICUBIC はさらに滑らかな結果を生成し、その分さらにコストがかかります。デフォルトでは最近傍法を使用しますが、これは最も安価で、ソースがすでに描画先のピクセル解像度にある場合の正しい選択です。アスペクト処理フラグ、すなわち SCALE_ASPECT_KEEP、SCALE_ASPECT_EXPAND、SCALE_ASPECT_IGNORE は、ソースのアスペクト比が描画される矩形と一致しない場合の処理を決定します。
5.7.4. アルファブレンディング¶
デフォルトでは、draw_image は描画先のピクセルをソースのピクセルで 置き換え ます。半透明のオーバーレイ、つまり描画先がソースを透かして見えるようにすることが目的の場合、alpha パラメータが両者の混合方法を制御します。alpha=0 は描画先のみを表示し(ソースなし)、alpha=255 はデフォルトでソースのみを表示します(完全な置き換え)。中間の値は両者を比例的に混合します。
img.draw_image(overlay, x=0, y=0, alpha=128)
別個の alpha_palette 引数は、モジュールにおける唯一のピクセル単位のアルファの仕組みです。これは GRAYSCALE 画像を受け取り、その値がソースの対応する位置でアルファとして使用されます。たとえば、強度に応じてアルファが変化するヒートマップなどです。アルファはこの別個のグレースケール引数として供給する必要があります。独自のアルファチャンネルを持つソース画像(透明度を持つPNGなど)は、それを自動的に取り込むことはありません。
5.7.5. ソースのROIとパレット¶
さらに2つのパラメータが合成の仕組みを完成させます。
roi=(x, y, w, h)はソースをそれ自身のサブ矩形に制限するので、その矩形だけが描画先に合成されます。切り取った中間画像を用意せずに、同じ呼び出しの中でクロップするのに便利です。color_paletteは、描画前に各ソースピクセルの値をルックアップテーブルを通して置き換えます。これはto_rainbow()とto_ironbow()が使用するのと同じ仕組みであり、ここで公開されているため、オーバーレイは別個の変換パスを経ることなく、描画先に向かう途中でパレット化できます。
どちらも呼び出し上の他のすべてと組み合わせて使えます。すなわち、スケーリング、アルファ、描画先側の mask 引数、そして 書き込み を描画先の矩形に限定する描画先側の roi パラメータです。