OpenCVを使うと、簡単に動画再生ができる(スクリプトが書ける)のですが、基本的にはキーによる制御しかサポートされていません。というか、キー入力待ちの期間に表示、イベント受け取りが行なわれる様な構造になっています。
動画からフレームを抽出して、再生タイミングに合わせた表示(+キー待ち)を行なう事で動画が再生されます。フレーム画像に手を加えることができるので、動画に対する学習結果を見せるのに使われているようです(検出結果をマークしたりね)。
■フレームへの追記、テキスト描画について
フレームに書き込むためのAPIが用意されていて、基本的な図形と文字を書き込むことができます。ただ、この文字描画が曲者でして、独自のベクターフォントを使っているとかで、US-ASCII の文字しか表示できないのです。
漢字テキストも描画したいという要望が多いようで、ネットを探すと日本語表示するための工夫が見つかります(「openCV 漢字」で探すといくつも出てきます)。基本は、pillow の描画空間を用意して、そこに描画されたテキストを OpenCV の画像に取り込む、ですね。ただ注意点として
- OpenCV/PILで画像データの持ち方が異なっているので変換が必要になります。
- カラーも BGR/RGBでデータ順序が異なっているのでこれについても変換が必要になります。
この変換、内部データ構造参照しているので、少々気持ち悪い処理になっていました。
PillowのAPIを見ていたら、pillow 側の
ピクセルデータを参照する機能がありました。Pillow側の描画空間を二値画像にすれば、描画された文字ピクセルのオン・オフが判ります。なので、pillow 側の画像データをスキャンラインの集合に展開すると、OpenCV側では直線描画だけで、文字を描画できます。
Pillowで文字列を描画すると、その文字列画像のデータ(ピクセル)が書き込まれた範囲、エクステント(外接矩形)を求めることができます。これを使うと、効率的にスキャンライン展開が可能になります。
- pspc=Image.new('1', (幅,高さ),color=0)
モノクロームのイメージ空間を用意します。
- draw=ImageDraw.Draw(pspc)
イメージに対する描画空間(ハンドル)を取得します。draw経由でpsrcへの描画が行なわれます。
- font=ImageFont.truetype(フォントパス, サイズ)
TrueTypeフォントを用意します。
- draw.text((0,0), テキスト, 1, font)
PILイメージへのテキスト描画
- bbox=pspc.getbbox()
描画されたテキスト領域(外接矩形)を取得します。画像はこの矩形内だけに存在しています。ああ、難点として描画したテキストが空白だとこれがエラーになる様です。空白の場合はスキップする必要がありました。
- for y in range(bbox[1], bbox[3])
外接矩形の各スキャンラインについて
inline=False フラグ初期値
sp = 基準位置
ep = 基準位置
- for x in range(bbox[0], bbox[2])
スキャンラインの水平方向について
if pspc.getpixel((x, y )) :
if not inline :
sp = (base[0] x, base[1 + y])
inline=True
else:
if inline:
ep = (base[0] x, base[1 + y])
cv2.line(画像, sp, ep, 表示色, 1)
inline=False