ショット変更検出のチュートリアル

対象

このチュートリアルは、Video Intelligence API を使用するアプリケーションの調査と開発をすぐに開始できるように作られています。基本的なプログラミングについて理解されている方を対象としていますが、プログラミングの深い知識がなくても、チュートリアルに沿って学習できるようになっています。このチュートリアルを終了すると、リファレンス ドキュメントを使用して独自の基本的なアプリケーションを作成できるようになります。

このチュートリアルでは、Python コードの Video Intelligence API アプリケーションを使用します。ここでの目的は、Python クライアント ライブラリについて説明することではなく、Video Intelligence API を呼び出す方法を説明することです。Java や Node.js のアプリケーションも基本的にはこれと同様です。

コードのみの例や他の言語のサンプルについては、関連する入門ガイドをご覧ください。

前提条件

このチュートリアルでは次の事前準備が必要です。

ショット変更検出で動画にアノテーションを付ける

このチュートリアルでは、SHOT_CHANGE_DETECTION リクエストを使用する基本的な Video API アプリケーションの作成について順を追って説明します。SHOT_CHANGE_DETECTION リクエストに対しては、次のアノテーションの結果が返されます。

  • 動画内で発生したショットのリスト
  • 各ショットの開始時間と終了時間

まずコード全体を示します(このコードのコメントのほとんどは削除されています。これは、コードそのものは単純であることを示すためです。コードについて説明していく中で、コメントを追加で示します)。

import argparse

from google.cloud import videointelligence

def analyze_shots(path):
    """Detects camera shot changes."""
    video_client = videointelligence.VideoIntelligenceServiceClient()
    features = [videointelligence.Feature.SHOT_CHANGE_DETECTION]
    operation = video_client.annotate_video(
        request={"features": features, "input_uri": path}
    )
    print("\nProcessing video for shot change annotations:")

    result = operation.result(timeout=120)
    print("\nFinished processing.")

    for i, shot in enumerate(result.annotation_results[0].shot_annotations):
        start_time = (
            shot.start_time_offset.seconds + shot.start_time_offset.microseconds / 1e6
        )
        end_time = (
            shot.end_time_offset.seconds + shot.end_time_offset.microseconds / 1e6
        )
        print("\tShot {}: {} to {}".format(i, start_time, end_time))

if __name__ == "__main__":
    parser = argparse.ArgumentParser(
        description=__doc__, formatter_class=argparse.RawDescriptionHelpFormatter
    )
    parser.add_argument("path", help="GCS path for shot change detection.")
    args = parser.parse_args()

    analyze_shots(args.path)

この簡単なアプリケーションでは次のタスクを実行します。

  • アプリケーションの実行に必要なライブラリをインポートする
  • Cloud Storage URI に保存されている動画ファイルを引数として受け取り、main() 関数に渡す
  • Video Intelligence API サービスの実行に必要な認証情報を取得する
  • 動画サービスに送信する動画アノテーション リクエストを作成する
  • リクエストを送信し、長時間実行オペレーションを返す
  • 動画が処理されて戻り値が返されるまで、長時間実行オペレーションをループする
  • サービスのレスポンスを解析してユーザーにレスポンスを表示する

これらのステップについて、以下で詳しく説明します。

ライブラリをインポートする

import argparse

from google.cloud import videointelligence

argparse をインポートして、アプリケーションが入力ファイル名を引数として受け取れるようにします。

また、Video Intelligence API を使用するため、API 呼び出しのディレクトリと列挙定数を保持する google.cloud.videointelligence ライブラリもインポートします。

アプリケーションの実行

parser = argparse.ArgumentParser(
    description=__doc__, formatter_class=argparse.RawDescriptionHelpFormatter
)
parser.add_argument("path", help="GCS path for shot change detection.")
args = parser.parse_args()

analyze_shots(args.path)

ここでは、渡された引数を解析して動画ファイル名の Google Cloud Storage URI を取得し、main() 関数に渡します。

API に対する認証

Video Intelligence API サービスと通信する前に、事前に取得した認証情報を使用してサービスを認証する必要があります。アプリケーション内で認証情報を取得する最も簡単な方法は、アプリケーションのデフォルト認証情報(ADC)を使用することです。 デフォルトでは、ADC は GOOGLE_APPLICATION_CREDENTIALS 環境ファイルから認証情報を取得しようとします。このファイルは、サービス アカウントの JSON キーファイルを指すように設定されているはずです(クイックスタートで、ADC を使用するためのサービス アカウントと環境を設定しました。詳細は、サービス アカウントの設定をご覧ください)。

リクエストを作成する

video_client = videointelligence.VideoIntelligenceServiceClient()
features = [videointelligence.Feature.SHOT_CHANGE_DETECTION]
operation = video_client.annotate_video(
    request={"features": features, "input_uri": path}
)

Video Intelligence API サービスの準備ができたので、そのサービスに対するリクエストを作成できます。Video Intelligence API へのリクエストは JSON オブジェクトとして作成されます。このようなリクエストの具体的な構造については、Video Intelligence API リファレンスをご覧ください。

このコード スニペットにより、次の処理が行われます。

  1. annotate_video() メソッドに対する POST リクエストの JSON を作成する。
  2. 渡された動画ファイルが存在する Google Cloud Storage の場所をリクエストに挿入する。
  3. annotate メソッドが SHOT_CHANGE_DETECTION を実行する必要があることを示す。

長時間実行オペレーションを作成する

Video Intelligence API に対するリクエストを初めて実行するとき、すぐに結果は得られません。その代わり、レスポンス内の name フィールドからオペレーション名を取得します。この名前を使用して後で結果を確認します。

オペレーション名(数字の文字列)を Video Intelligence API の Operations Service operations メソッドに渡すと、オペレーションの現在の状態が返されます。次のようなレスポンスが返されます。

{
   "response":{
      "@type":"type.googleapis.com/google.cloud.videointelligence.v1.AnnotateVideoResponse"
   },
   "name":"us-west1.17159971042783089144",
   "metadata":{
      "annotationProgress":[
         {
            "inputUri":"/video/gbikes_dinosaur.mp4",
            "updateTime":"2017-01-27T19:45:54.297807Z",
            "startTime":"2017-01-27T19:45:54.275023Z"
         }
      ],
      "@type":"type.googleapis.com/google.cloud.videointelligence.v1.AnnotateVideoProgress"
   }
}

この例の response フィールドには、そのレスポンスのタイプを示す @type レスポンスのみが含まれます。実際に結果が使用可能になると、レスポンスのフィールドにはこのタイプの結果が含まれます。

オペレーションを確認する

result = operation.result(timeout=120)
print("\nFinished processing.")

既存のオペレーションのリクエストを使用して while ループを作成し、オペレーションの状態を定期的に確認します。オペレーションが done 状態になったら、ループを抜け、レスポンスを解析します。

レスポンスをパースする

for i, shot in enumerate(result.annotation_results[0].shot_annotations):
    start_time = (
        shot.start_time_offset.seconds + shot.start_time_offset.microseconds / 1e6
    )
    end_time = (
        shot.end_time_offset.seconds + shot.end_time_offset.microseconds / 1e6
    )
    print("\tShot {}: {} to {}".format(i, start_time, end_time))

オペレーションが完了すると、レスポンスにAnnotateVideoResponseが含まれます。これは、リクエストで送信された各動画に対応する annotationResults のリストで構成されています。この例では 1 つの動画のみをリクエストで送信したため、結果の最初の shotAnnotations を使用します。動画のすべてのセグメントを順に処理します。

アプリケーションを実行する

アプリケーションは、動画の Cloud Storage URI を単にアプリケーションに渡すだけで実行できます。

$ python shotchange.py gs://cloud-samples-data/video/gbikes_dinosaur.mp4
operationId=us-west1.12468772851081463748
Operation us-west1.12468772851081463748 started: 2017-01-30T01:53:45.981043Z
Processing video for shot change annotations:
Finished processing.
  Shot 0: 0.0 to 5.166666
  Shot 1: 5.233333 to 10.066666
  Shot 2: 10.1 to 28.133333
  Shot 3: 28.166666 to 42.766666

これで完了です。Video Intelligence API を使用してアノテーション タスクを実行しました。