見出し画像

【Python】トリミングした動画の縦横比を自動で整えたい

【状況】トラッキングした物体の範囲ぴったりで切り抜いて動画を作ると,絵的に窮屈だし,縦横比がバラバラで扱いづらい
【対処】余白部分を入れて,縦横比は切り抜き前の動画サイズに(だいたい)揃えて切り抜く

先に行った動画の切り抜きは,範囲がぴったりなので,データ処理用としては問題ないのですが,見せる動画としては,縦横比もバラバラですし,対象の周辺に少し余裕が欲しいと思いました.

サイズの定義を考える

切り抜く際に,上下左右に余白を適度に入れつつ,元画像の比率に(だいたい)合わせることにします.

  • 画像の幅と高さを求める

  • 画像の中心を求める

  • 元画像の縦横比と比較し,高さか幅いずれか足りない方を拡大した大きさを求める

  • 新しい幅と高さによる座標を求め,さらに上下左右に1.1倍する

といったようなことができる関数を作ります.

関数を作る

def calculate_aspect_ratio_coordinates(x1, y1, x2, y2, original_width, original_height):
    """
    縦横比率を考慮した矩形の座標値を求める関数

    Args:
        x1 (int): 切り抜く矩形の左上の x 座標
        y1 (int): 切り抜く矩形の左上の y 座標
        x2 (int): 切り抜く矩形の右下の x 座標
        y2 (int): 切り抜く矩形の右下の y 座標
        original_width (int): 元の画像の幅
        original_height (int): 元の画像の高さ

    Returns:
        tuple: 新しい矩形の左上と右下の座標 (new_x1, new_y1, new_x2, new_y2)
    """
    
    # 切り抜いた領域の幅と高さを計算
    width = x2 - x1 + 1
    height = y2 - y1 + 1

    # 中心座標を求める
    x_center = (x1 + x2) // 2
    y_center = (y1 + y2) // 2
    
    # 切り抜いた領域の縦横比率を計算
    aspect_ratio = width / height
    
    # 元のフレームの縦横比率を計算
    original_aspect_ratio = original_width / original_height

    if aspect_ratio > original_aspect_ratio:
        # 切り抜き領域の縦横比率が元のフレームの縦横比率より大きい場合は、高さを拡大して縦横比率を一致させる
        new_width = width
        new_height = int(width / original_aspect_ratio)
    else:
        # 切り抜き領域の縦横比率が元のフレームの縦横比率より小さい場合は、幅を拡大して縦横比率を一致させる
        new_width = int(height * original_aspect_ratio)
        new_height = height

    # 拡大後の矩形の座標を求める(画面中央から新サイズの1/2ずつ伸ばし,縦横に1.1倍して,元画像からはみ出た部分はカット)
    new_x1 = max(0, x_center - int(new_width / 2 * 1.1))
    new_y1 = max(0, y_center - int(new_height / 2 * 1.1))
    new_x2 = min(x_center + int(new_width / 2 * 1.1) - 1, original_width-1)
    new_y2 = min(y_center + int(new_height / 2 * 1.1) - 1, original_height-1)

    return new_x1, new_y1, new_x2, new_y2

トラッキング領域全てを内包する長方形を求めたあとに,上記の関数で得られた値に差し替えるだけで完了します.切り取りの際に,画面からはみ出してしまう場合は(面倒なので)単純にカットしています.その場合は縦横比が狂います.

結果の比較

id1, id2の識別(最初のフレーム)
id1の結果
id2の結果

白枠は,トラッキング領域を内包する領域,緑枠は,縦横比を元画像に合わせて拡大した領域,赤枠は,16の倍数になるようにカットした領域です(id1は,緑と赤が重なっています).

id1は,正方形に近い形状でしたが,横長になりました.ただし,左端が足りなかったので若干左側の余白が小さくなりました.id2は,上下左右に余白が均等にできました.ただし,16の倍数にするときに右と下をカットしたので,若干バランスは崩れるのは仕様です.

id1の最初のフレーム
id1の最後のフレーム
id2の最初のフレーム
id2の最後のフレーム

非対称性が若干気になるけどよしとしよう♪

追加実験

別の動画で犬を切り抜いてみました.

id3の犬をトラッキング

id3の犬の領域が抽出できています.

id3のトラッキング領域(青,白)とトリミング領域(緑→16の倍数化して赤)

動画の途中では,トラッキング対象でない犬が大きく左に動いて重なってきていますが,id3の犬を中心に動画ができていました.

id3の最初のフレーム
id3の途中フレーム(1)
id3の途中のフレーム(2)
id3の最後のフレーム

この記事が気に入ったらサポートをしてみませんか?