すべてのプロダクト
Search
ドキュメントセンター

Object Storage Service:IP カメラのインテリジェントなセマンティックインデックスシステムを作成する

最終更新日:Jul 04, 2025

Object Storage Service (OSS) のデータインデックス作成機能とフレームキャプチャ機能を使用して、IP カメラで収集されたビデオのインテリジェントなセマンティックインデックスシステムを作成できます。 このシステムは、収集されたビデオからフレームをキャプチャし、セマンティックコンテンツに基づいてビデオを検索できます。これは、インテリジェントセキュリティなどのシナリオに適しています。

ソリューションの概要

image

インテリジェントなセマンティックインデックスシステムを作成するには、次の手順を実行します。

  1. ビデオが保存されているバケットを作成する: IP カメラで収集されたビデオを保存するバケットを作成し、処理するビデオをアップロードし、後続のビデオ検索のために事前に設定された時間間隔に基づいてキーフレームをキャプチャします。

  2. フレームが保存されているバケットを作成する: ビデオからキャプチャされたキーフレームを保存するバケットを作成し、セマンティックコンテンツに基づくインテリジェントビデオ検索のために AISearch 機能を有効にします。

メリット

  • インテリジェントメディア処理: OSS と Intelligent Media Management (IMM) を一緒に使用して、大規模なビデオデータを処理および分析し、OSS にアップロードされた大規模なビデオデータを自動的に処理し、キーフレームを抽出し、メタデータを生成し、後続のセマンティック検索をサポートします。

  • セマンティック検索: OSS は、自然言語の説明と複数の条件の組み合わせに基づいてデータを正確に検索します。 これにより、目的の画像をすばやく検索し、複雑なシナリオでの検索要件を満たすことができます。 セマンティック検索は、より正確なイベントマッチングを提供し、手動フィルタリングのコストを削減します。

  • クロスモーダル検索: インテリジェントセマンティックインデックスシステムは、ビデオ、画像、テキストなどのマルチモーダルデータの一元管理とクロスモーダル検索機能を提供します。 OSS と IMM に依存するインテリジェントセマンティックインデックスシステムは、すぐに使えるソリューションであり、技術的なしきい値と O&M コストを大幅に削減します。

  • 柔軟なスケーリング: OSS の分散ストレージアーキテクチャは、動的スケーリングをサポートして、大量のデータに簡単に対応できます。 負荷に基づいてコンピューティングリソースを動的にスケーリングして、安定したシステムパフォーマンスを確保できます。

1. ビデオが保存されているバケットを構成する

1.1 バケットを作成し、デバイスから収集されたビデオをアップロードする

  1. OSS コンソール にログオンします。

  2. 左側のナビゲーションウィンドウで、[バケット] をクリックします。 [バケット] ページで、[バケットの作成] をクリックします。

  3. [バケットの作成] ページで、バケットの名前を指定します。 ipc-videos-oss-metaquery-demo などのビジネス関連の名前を使用することをお勧めします。 その他のパラメーターについては、デフォルト設定を保持します。

  4. [OK] をクリックします。 表示されるページで、[バケットに移動]. をクリックします。

  5. オブジェクト ページで、[オブジェクトのアップロード] をクリックします。 [オブジェクトのアップロード] ページで、[ファイルを選択] をクリックし、Video A.mp4 などのアップロードするビデオオブジェクトを選択し、その他のパラメーターについてはデフォルト設定を保持します。 [オブジェクトのアップロード] をクリックします。

1.2 IMM プロジェクトをバケットにバインドする

IMM が提供するフレームキャプチャを使用するには、IMM プロジェクトをバケットにバインドする必要があります。

  1. 左側のナビゲーションウィンドウで、[データ処理] > [メディア処理] を選択します。 表示されるページで、IMM をアクティブ化し、RAM ロールを承認してから、[プロジェクトをバケットにマップ] をクリックします。

  2. [プロジェクトのマップ] ダイアログボックスで、IMM 構成の [プロジェクトの作成] を選択し、[プロジェクト名] フィールドに video-snapshot などのプロジェクト名を入力して、[OK] をクリックします。 システムは、バケットが配置されているリージョンに、対応する IMM プロジェクトを自動的に作成し、IMM プロジェクトを現在のバケットにバインドします。

1.3 フレームキャプチャのスタイルを作成する

フレームキャプチャのスタイルを作成します。 フレームは、ビデオが終了するまで固定された時間間隔でビデオからキャプチャされ、元のサイズで JPG 形式で保存されます。

  1. [ビデオ処理] > [ビデオキャプチャ] を選択し、スタイルを作成 をクリックします。

  2. スタイルを作成 パネルで、次のパラメーターを構成します。

    1. スタイル名: ビジネス関連の名前を指定します。 例: ipc-snap

    2. 出力形式: ドロップダウンリストから jpg を選択します。

    3. フレームキャプチャモード: [間隔でフレームをキャプチャ] を選択し、間隔を指定します。 たとえば、1000 と入力すると、1 秒あたり 1 フレームがキャプチャされます。

    4. その他のパラメーターについては、デフォルト設定を保持します。

  3. OK をクリックします。

image

1.4 フレームキャプチャのコードをコンパイルする

バケットにアップロードされたビデオオブジェクトは、作成されたフレームキャプチャのスタイルに基づいてキャプチャできます。 次のサンプルコードは、Python 用 OSS SDK を使用してフレームキャプチャを実行する方法の例を示しています。

環境を準備する

Python 用 OSS SDK を使用してフレームキャプチャを実行する前に、開発環境とアクセス認証情報を構成していることを確認してください。 詳細については、「はじめに」をご参照ください。

サンプルコード

# -*- coding: utf-8 -*-
import base64
import argparse
import alibabacloud_oss_v2 as oss


def video_processor():
    # OSS の基本パラメーターを構成します。
    args = argparse.Namespace(
        region='cn-beijing',
        target_bucket='ipc-frames-oss-metaquery-demo',    
        bucket='ipc-videos-oss-metaquery-demo',     
        endpoint='https://oss-cn-beijing.aliyuncs.com'
    )
    
    # OSSClient インスタンスを構成します。
    credentials_provider = oss.credentials.EnvironmentVariableCredentialsProvider()
    cfg = oss.config.load_default()
    cfg.credentials_provider = credentials_provider
    cfg.region = args.region
    cfg.endpoint = args.endpoint
    client = oss.Client(cfg)

    # 処理するビデオオブジェクトを指定します。
    videos = [('Video A.mp4', '2025-04-07'), 
              ('Video B.mp4', '2025-04-07'), 
              ('Video C.mp4', '2025-04-07')]
    
    for video, date in videos:
        # キャプチャされた画像を日付別に宛先ディレクトリに保存します。
        target_key = f"{date}/{video}/{{index}}.{{autoext}}"
        
        # 構成されたフレームキャプチャのスタイルを指定します。
        style = 'style/ipc-snap'
        
        # 宛先バケット名とオブジェクト名を Base64 エンコードして、URL セーフであることを確認します。
        target_bucket_base64 = base64.urlsafe_b64encode(args.target_bucket.encode()).decode()
        target_key_base64 = base64.urlsafe_b64encode(target_key.encode()).decode()
        
        # スタイルと宛先パスを含む処理命令を作成します。
        process = f"{style}|sys/saveas,b_{target_bucket_base64},o_{target_key_base64}"
        
        try:
            # 非同期リクエストを送信します。
            result = client.async_process_object(oss.AsyncProcessObjectRequest(
                bucket=args.bucket,
                key=video,
                process=process
            ))
            
            print(f"Status Code: {result.status_code}")
            print(f"RequestId: {result.request_id}")
            print(f"TaskId: {result.task_id}")
            print(f"EventId: {result.event_id}")
            print(f"ProcessRequestId: {result.process_request_id}")
            
        except Exception as e:
            print(f"Error: {e}")

if __name__ == "__main__":
    video_processor()

2. フレームを保存するバケットを構成する

2.1 バケットを作成する

IP カメラからキャプチャされたフレームを保存するバケットを作成します。 これにより、ビデオオブジェクトとフレームは異なるバケットに保存され、データ管理が最適化されます。

  1. 左側のナビゲーションウィンドウで、[バケットリスト] をクリックします。バケットリストページで、[バケットの作成] をクリックします。

  2. [バケットの作成] ページで、バケットの名前を指定します。 ipc-frames-oss-metaquery-demo などのビジネス関連の名前を使用することをお勧めします。 その他のパラメーターについては、デフォルト設定を保持します。

  3. [OK] をクリックします。 表示されるページで、[バケットに移動]. をクリックします。

2.2 バケットの AISearch を有効にする

バケットの AISearch を有効にします。 この場合、自然言語の説明と複数の条件に基づいてフレームを正確に検索できます。

  1. 左側のナビゲーションツリーで、[オブジェクト管理] > [データインデックス作成] を選択します。

  2. [データインデックス作成] ページで、[今すぐ有効にする] をクリックします。

  3. [データインデックス作成] ダイアログボックスで、[AISearch] を選択し、[有効にする] をクリックします。

説明

メタデータインデックスの作成に必要な時間は、バケット内のオブジェクトの数によって異なります。 [データインデックス作成] ページを更新して、AISearch が有効になっているかどうかを確認できます。

image

image

結果を確認する

yard with a car などの説明を指定すると、説明に一致するフレームが返されます。

  1. [バケットリスト] ページで、フレームが保存されているバケットの名前をクリックします。

  2. オブジェクト ページで、キャプチャされたフレームを確認します。

  3. 左側のナビゲーションツリーで、[オブジェクト管理] > [データインデックス作成] を選択します。

  4. [データインデックス作成] ページで、[検索コンテンツ] フィールドに yard with a car と入力し、[マルチメディアタイプ]Image に設定して、[今すぐクエリ] をクリックします。

  5. オブジェクトのパスをコピーします。 オブジェクト ページで、オブジェクトのパスを入力して、キャプチャされたフレームを見つけます。

2025-04-08_16-21-10 (2)

ソリューションを実稼働環境に適用する

現在のインテリジェントセマンティックインデックスシステムが作成されます。 システムを製品にシームレスに統合し、実稼働環境に適用するには、コンシューマーアプリケーションを使用して操作を呼び出し、自然言語の説明を使用して目的のフレームまたはビデオオブジェクトをすばやくクエリして検索します。

コンシューマーアプリケーションの次のサンプルコードは、OSS 仕様に準拠した XML MetaQuery リクエストを作成する方法の例を示しています。

サンプルコード

# -*- coding: utf-8 -*-
import argparse
import alibabacloud_oss_v2 as oss
# XML 形式のレスポンスを解析します。
import xml.etree.ElementTree as ET
import json 
from datetime import datetime 

def get_search_conditions():
    """ユーザーが指定した複数の条件を取得します。"""
    print("セマンティックな説明を指定してください (例: yard with a car)")
    query = input("> セマンティックキーワード: ").strip()
    while not query:
        print("セマンティックキーワードは空にできません!")
        query = input("> セマンティックキーワード: ").strip()
    return query  

def build_metaquery_xml(query):
    """OSS 仕様に準拠した XML MetaQuery リクエストを作成します"""
    xml_parts = [f'<Query>{query}</Query>']

    meta_query_xml = f'''<MetaQuery>
    {"".join(xml_parts)}
</MetaQuery>'''
    return meta_query_xml # 結果を UTF-8 バイトストリームにエンコードします。


def format_result(key, pre_url):
    """検索結果をフォーマットします"""
    return f"""オブジェクトパス: {key}
 オブジェクト URL: {pre_url}
-----------------------"""

def semantic_search():
    # コマンドラインパラメーターに値を割り当てます。
    args = argparse.Namespace(
        region='cn-beijing', # バケットが配置されているリージョンを指定します。
        bucket='ipc-frames-oss-metaquery-demo', # バケットの名前を指定します。
        endpoint='https://oss-cn-beijing.aliyuncs.com', # バケットが配置されているリージョンのエンドポイントを指定します。 必要ない場合は、パラメーターを空のままにするか、パラメーターを削除します。
    )

    # OSSClient インスタンスを初期化します。
    credentials = oss.credentials.EnvironmentVariableCredentialsProvider()
    cfg = oss.config.load_default()
    cfg.credentials_provider = credentials
    cfg.region = args.region
    if args.endpoint:
        cfg.endpoint = args.endpoint
    client = oss.Client(cfg)

    # ユーザー構成を取得します。
    query=get_search_conditions()# 検索条件をクエリします。
    # リクエストを作成します。
    try:
        # XML リクエスト本文を作成します。
        data_str=build_metaquery_xml (query) # 条件を渡さないでください。

        # 操作入力を指定します。
        req = oss.OperationInput(
            op_name='DoMetaQuery', # カスタム操作の名前を指定します。
            method='POST', # HTTP メソッド。
            parameters ={# クエリパラメーター。
                'metaQuery': '',
                'mode': 'semantic',
                'comp': 'query',
            },
            headers=None, # オプション。 カスタムリクエストヘッダー。
            body=data_str.encode("utf-8"), # リクエスト本文。 UTF-8 バイトストリームとしてエンコードされます。
            bucket=args.bucket,          # 宛先バケットの名前。
        )

        # 操作を呼び出します。
        resp = client.invoke_operation(req)

    except oss.exceptions.ServiceError as e:
        print(f "サーバーエラー:{e.message}")
        return
    
    root = ET.fromstring(resp.http_response.content.decode('utf-8'))
     # すべての File 要素を見つけます。
    files = root.findall('.//File')
    
    print(f"\n 合計 {len(objects)} 件が条件に一致します:")
    


    for i, file in enumerate(files, 1):
        # オブジェクトの名前をクエリします。
        key_element = file.find('Filename')
        if key_element is None:
            continue # オブジェクト名が返されない場合は、現在のループの反復をスキップします。
        key = key_element.text
        
        
        # プリサイン URL を生成します。
        pre_url = client.presign(
            oss.GetObjectRequest(
                bucket=args.bucket,  # バケットの名前を指定します。
                key=key, # オブジェクトの名前を指定します。
            )
        )
        
        print(format_result(key, pre_url.url))
        
    

if __name__ == "__main__":
    semantic_search()

プログラムを実行した後、オブジェクトをクエリする説明を指定します。 例: yard with a car。 システムは、キャプチャされたフレームのパスと URL を含む結果を返します。 URL を使用して、フレームの詳細を表示できます。

4 件の一致する結果が見つかりました:")
オブジェクトパス: 2025-04-07/Video A/2.jpg
オブジェクト URL: https://ipc-frames-oss-metaquery-demo.oss-cn-beijing.aliyuncs.com/2025-04-07/%E8%A7%86%E9%A2%91A/2.jpg?x-oss-signature-version=OSS4-HMAC-SHA256&x-oss-date=20250407T025024Z&x-oss-expires=900&x-oss-credential=LTAI********************%2F20250407%2Fcn-beijing%2Foss%2Faliyun_v4_request&x-oss-signature=d2d849c56e230f6beaf199ee1ca756bb99b3f6a14ce64c1fa710127149375fac
------------------------
オブジェクトパス: 2025-04-07/Video C/2.jpg
オブジェクト URL: https://ipc-frames-oss-metaquery-demo.oss-cn-beijing.aliyuncs.com/2025-04-07/%E8%A7%86%E9%A2%91C/2.jpg?x-oss-signature-version=OSS4-HMAC-SHA256&x-oss-date=20250407T025024Z&x-oss-expires=900&x-oss-credential=LTAI********************%2F20250407%2Fcn-beijing%2Foss%2Faliyun_v4_request&x-oss-signature=1b3b456a32f9d0823dcfe5408d156df74e138a194bc06095877e00dd8079511e
------------------------
オブジェクトパス: 2025-04-07/Video C/1.jpg
オブジェクト URL: https://ipc-frames-oss-metaquery-demo.oss-cn-beijing.aliyuncs.com/2025-04-07/%E8%A7%86%E9%A2%91C/1.jpg?x-oss-signature-version=OSS4-HMAC-SHA256&x-oss-date=20250407T025024Z&x-oss-expires=900&x-oss-credential=LTAI********************%2F20250407%2Fcn-beijing%2Foss%2Faliyun_v4_request&x-oss-signature=1fc66719db2bbe611bc86a63a863d7f94ad9aebf14ccfaff8579938094ace3ef
------------------------
オブジェクトパス: 2025-04-07/Video A/1.jpg
オブジェクト URL: https://ipc-frames-oss-metaquery-demo.oss-cn-beijing.aliyuncs.com/2025-04-10/%E8%A7%86%E9%A2%91A/1.jpg?x-oss-signature-version=OSS4-HMAC-SHA256&x-oss-date=20250407T025024Z&x-oss-expires=900&x-oss-credential=LTAI********************%207%2Fcn-beijing%2Foss%2Faliyun_v4_request&x-oss-signature=4dd7f808872b9d4c988efe78a09cb91fd2accbb3e9c12df7cdbdf60bdcc2e7a7
------------------------

詳細情報

キャプチャされたフレームにタグを追加する

より効率的な検索を実現するために、OSS の オブジェクトタグ付け 機能を使用して、キーフレームにメタデータタグを追加できます。 たとえば、タグを使用してビデオのソースまたはビジネスシナリオを識別できます。これにより、多数のオブジェクトからターゲットフレームをすばやく検索できます。

3 つのビデオオブジェクト Video A.mp4Video B.mp4、および Video C.mp4 を分析する場合。

Video A.mp4

Video B.mp4

Video C.mp4

example

example (1)

example

裏庭のカメラから収集され、camera-a で撮影されたものとしてタグ付けされています。

店舗のカメラから収集され、camera-b で撮影されたものとしてタグ付けされています。

裏庭のカメラから収集され、camera-c によって撮影されたものとしてタグ付けされています。

次のサンプルコードは、動画をアップロードした後に、Python 用 OSS SDK を使用して各動画にタグを追加する方法の例を示しています。後続の組み合わせ取得をサポートする自動タグ管理を実装するには、ビジネス要件に基づいてタグを変更するだけで済みます。

サンプルコード

import argparse
import alibabacloud_oss_v2 as oss
from alibabacloud_oss_v2.models import GetObjectTaggingRequest, PutObjectTaggingRequest, Tagging, TagSet, Tag

def list_and_process_frames(client, bucket, prefix, tags):
    """特定のプレフィックスを含む名前のすべてのオブジェクトをリストおよび処理する"""
    try:
        # オブジェクトをリストするリクエストを作成します。
        list_request = oss.models.ListObjectsRequest(
            bucket=bucket,
            prefix=prefix
        )
        
        # オブジェクトを取得して処理します。
        result = client.list_objects(list_request)
        if result.contents:
            for obj in result.contents:
                apply_tags_to_frame(client, bucket, obj.key, tags)
                    
    except Exception as e:
        print(f "ディレクトリの処理に失敗しました: {str(e)}")

def apply_tags_to_frame(client, bucket, frame_key, tags):
    """キャプチャされたフレームにタグを追加する"""
    try:
        # タグを指定します。
        tagging = Tagging(
            version=1,
            tag_set=TagSet(tags=tags)
        )
        
        # タグを更新するリクエストを作成します。
        put_tag_request = PutObjectTaggingRequest(
            bucket=bucket,
            key=frame_key,
            tagging=tagging
        )
        
        # オブジェクトタグを更新します。
        result = client.put_object_tagging(put_tag_request)
        
        # 表示するためにタグを文字列に変換します。
        tags_str = '&'.join([f"{tag.key}={tag.value}" for tag in tags])
        print(f "{frame_key} という名前のイメージにタグを追加しました: {tags_str}")
        return True
    except Exception as e:
        print(f "イメージへのタグの追加に失敗しました: {str(e)}")
        return False

def frame_tags():
    # 基本的な OSS パラメーターを設定します。
    args = argparse.Namespace(
        region='cn-beijing',   
        frame_bucket='ipc-frames-oss-metaquery-demo',     
        endpoint='https://oss-cn-beijing.aliyuncs.com'
    )
    
    # OSSClient インスタンスを設定します。
    credentials_provider = oss.credentials.EnvironmentVariableCredentialsProvider()
    cfg = oss.config.load_default()
    cfg.credentials_provider = credentials_provider
    cfg.region = args.region
    cfg.endpoint = args.endpoint
    client = oss.Client(cfg)

    # 格納されたフレームの名前に含まれるプレフィックスを指定します。
    videos = [
        {
            'frame_prefix': '2025-04-07/Video A.mp4/' 
        },    
        {
            'frame_prefix': '2025-04-07/Video B.mp4/'
        },
        {
            'frame_prefix': '2025-04-07/Video C.mp4/'
        }
    ]

    # 各ビデオのフレームを処理します。
    for video in videos:


        # frame_prefix からビデオ名を抽出します。たとえば、 '2025-04-07/Video A.mp4/' から 'Video A.mp4' を抽出します。
        prefix_parts = video['frame_prefix'].strip('/').split('/')
        video_filename=prefix_parts [-1] if prefix_parts else '' # 空でない最後の部分を取得します。例: Video A.mp4。

        # オブジェクト名の拡張子を削除します。たとえば、 'Video A.mp4' のオブジェクト名の拡張子を削除して 'Video A' を取得します。
        video_name_base = video_filename.split('.')[0] if '.' in video_filename else video_filename

        print(f"\n {video_filename} という名前のビデオのフレームの処理を開始します") # 抽出された元のオブジェクト名を表示します。

        tags = [
            # 拡張子が削除されたビデオ名の最後の単語を使用してカメラ名を指定します。
            Tag(key='camera', value=f'camera-{video_name_base[-1].lower()}' if video_name_base else 'camera-unknown'),
            # Tag(key='category', value='video_monitoring') # 実際のビジネス分類情報を使用してフレームにタグを追加します。
        ]

        # ビデオのすべてのフレームを処理します。
        list_and_process_frames(client, args.frame_bucket, video['frame_prefix'], tags)

        print(f"\n {video_filename} という名前のビデオのフレームの処理を終了します") # 抽出された元のオブジェクト名を表示します。

if __name__ == "__main__":
    frame_tags()

コンシューマー アプリケーションの次のサンプル コードは、セマンティック記述とタグなどの他の条件を使用して、検索結果を取得するための複合クエリを実行する方法の例を示しています。

サンプルコード

# -*- coding: utf-8 -*-
import argparse
import alibabacloud_oss_v2 as oss
# XML 形式のレスポンスを解析します。
import xml.etree.ElementTree as ET
import json
from datetime import datetime
# --- 必要なリソースのインポート ---
from alibabacloud_oss_v2.models import GetObjectTaggingRequest
# --- インポート完了 ---

def get_inputs():
    """セマンティック記述(必須)とフィルタ条件(オプション)を取得します。"""
    # 1. 必須のセマンティック記述を取得します。
    print("セマンティック記述を指定してください(例:車のある庭)")
    query = input("> セマンティックキーワード: ").strip()
    while not query:
        print("セマンティックキーワードは空にできません!")
        query = input("> セマンティックキーワード: ").strip()

    conditions = [] # フィルタ条件を初期化します。
    target_tag=None# --- 新規:ターゲット タグを格納するために使用されます。---

    # 2. (オプション)タグフィルタリング条件を取得します。
    print("\n  クライアントフィルタリングに使用するタグフィルタリング条件を指定します。(例:camera=camera-a。スキップするには Enter キーを押します。)") # プロンプトを変更します。
    tag_input=input ("> タグ(形式:key=value): ").strip()
    if tag_input:
        if '=' in tag_input:
            # --- 変更:conditions に追加するのではなく、target_tag に保存します ---
            # conditions.append({
            #     'field': 'Tags',
            #     'value': tag_input,
            #     'op': 'eq'
            # })
            target_tag = tag_input
            print(f "情報:結果が取得された後、クライアント側でタグ '{target_tag}' がフィルタリングされます。")
            # --- 変更完了 ---
        else:
             print("タグの形式が無効なため無視されました。形式:'key=value'。")


    # 3. (オプション)パスプレフィックスフィルタリング条件を取得します。
    print("\n (オプション)パスプレフィックスフィルタ条件を入力します。(例:YYYY-MM-DD。スキップするには Enter キーを押します。)")
    date_prefix=input ("> パス プレフィックス: ").strip()
    if date_prefix:
        conditions.append({
            'field': 'Filename',
            'value': date_prefix,
            'op': 'prefix'
        })

    # --- 変更:target_tag を返します ---
    return query, conditions, target_tag
    # --- 変更完了 ---

def build_metaquery_xml(query, conditions):
    """OSS 仕様に準拠した XML MetaQuery リクエストを作成します(セマンティック記述とオプションのフィルタ条件を含む)。"""
    # 常にセマンティッククエリ条件を含めます。
    xml_parts = [f'<Query>{query}</Query>']

    # オプションのフィルタリング条件を追加します。セマンティックモードでは、この例のように Filename など、特定のフィールドのみがサポートされます。
    for cond in conditions:
        # セマンティックモードでは、Tags フィールドの SimpleQuery 構築をスキップします。(タグは conditions に追加されなくなりましたが、念のため残しておきます)。
        if cond['field'] == 'Tags':
            # print(f "情報:タグフィルタリング条件 '{cond['value']}' はセマンティック検索モードでは無視されます。") # この行はもう必要ありません。
            continue

        json_query = json.dumps({
            "Field": cond['field'],
            "Value": cond['value'],
            "Operation": cond['op']
        }, ensure_ascii=False)
        xml_parts.append(f'<SimpleQuery>{json_query}</SimpleQuery>')

    """上記の構成により、XML MetaQuery リクエストが作成されます"""
    meta_query_xml = f'''<MetaQuery>
    {"".join(xml_parts)}
</MetaQuery>'''
    return meta_query_xml

def format_result(key, pre_url):
    """検索結果をフォーマットします"""
    return f""" オブジェクト URL: {pre_url}
 オブジェクト パス: {key}
-----------------------"""

def perform_search():
    # コマンドラインパラメータに値を割り当てます。
    args = argparse.Namespace(
        region='cn-beijing', # バケットが配置されているリージョンを指定します。
        bucket='ipc-frames-oss-metaquery-demo', # バケットの名前を指定します。
        endpoint='https://oss-cn-beijing.aliyuncs.com', # バケットが配置されているリージョンのエンドポイントを指定します。
    )

    # OSSClient インスタンスを初期化します。
    credentials = oss.credentials.EnvironmentVariableCredentialsProvider()
    cfg = oss.config.load_default()
    cfg.credentials_provider = credentials
    cfg.region = args.region
    if args.endpoint:
        cfg.endpoint = args.endpoint
    client = oss.Client(cfg)

    # ユーザー構成(セマンティック記述、フィルタ条件、およびターゲット タグ)を取得します。
    # --- 変更:target_tag を受信します ---
    query, conditions, target_tag = get_inputs()
    # --- 変更完了 ---

    # リクエストを作成します。
    try:
        # XML リクエスト本文を作成します。
        # --- conditions のみ渡します。---
        data_str = build_metaquery_xml(query, conditions)
        
        print(f"\n XML MetaQuery リクエストを生成します:\n{data_str}")

        # 操作入力パラメータを指定します。
        req = oss.OperationInput(
            op_name='DoMetaQuery',
            method='POST',
            parameters={
                'metaQuery': '',
                'mode': 'semantic', # <-- セマンティックモードを再入力します。
                'comp': 'query',
            },
            headers=None,
            body=data_str.encode("utf-8"),
            bucket=args.bucket,
        )

        # 操作を呼び出します。
        print("\n DoMetaQuery リクエストを送信します。")
        resp = client.invoke_operation(req)
        print(f"\n リクエスト成功。HTTP ステータスコード: {resp.http_response.status_code}")
    # --- 例外を変更 ---
    except oss.exceptions.ServiceError as e:
        print(f" サーバー エラー (ServiceError): {e.message}")
        print(f"   - HTTP ステータスコード: {e.status_code}")
        print(f"   - エラーコード: {e.error_code}")
        print(f"   - リクエスト ID: {e.request_id}")
        return
    except oss.exceptions.ClientError as e: # クライアントエラーをキャプチャします。
        print(f "クライアントまたはネットワーク エラー (ClientError):{e.message}")
        return
    except Exception as e: # その他の発生する可能性のある例外をキャプチャします。
        print(f "不明なエラー: {e}")
        import traceback
        traceback.print_exc() # 完全なトレースバックを表示します。
        return

    # --- 変更完了 ---

    # 結果を解析して処理します。
    final_results_count = 0 # --- 最終結果のカウンターを追加 ---
    try:
        root = ET.fromstring(resp.http_response.content.decode('utf-8'))
        # すべての File 要素を見つけます。
        files = root.findall('.//File')

        print(f"\n OSS から {len(files)} 件の予備一致結果を取得し、タグのフィルタリングを開始します...")

        if not files:
            # NextContinuationToken パラメータを確認します。
            next_token_elem = root.find('.//NextContinuationToken')
            if next_token_elem is not None and next_token_elem.text:
                print("注:他のページにさらに結果が表示される場合があります。")
            print("\n 結果が見つかりませんでし。")
            return # オブジェクトが見つからない場合は事前に通知されます。


        for i, file in enumerate(files, 1):
            # オブジェクトの名前をクエリします。
            key_element = file.find('Filename')
            if key_element is None:
                print(f "警告: {i} 番目の予備結果に Filename フィールドが構成されていません。結果をスキップします。")
                continue
            key = key_element.text

            # --- クライアント タグ フィルタリング ---
            if target_tag:
                try:
                    tagging_req = GetObjectTaggingRequest(bucket=args.bucket, key=key)
                    tagging_resp = client.get_object_tagging(tagging_req)
                    # 返されたタグ セットにターゲット タグが含まれているかどうかを確認します。
                    tag_found = False
                    target_k, target_v = target_tag.split('=', 1)

                    # --- 変更:.tag の代わりに .tags を使用します。---
                    if tagging_resp.tag_set and tagging_resp.tag_set.tags: # .tags を使用します。
                        for tag in tagging_resp.tag_set.tags: # .tags を使用します。
                    # --- 変更完了 ---
                            if tag.key == target_k and tag.value == target_v:
                                tag_found = True
                                break
                    if not tag_found:
                        continue # タグが一致しません。このオブジェクトをスキップします。
                except oss.exceptions.ServiceError as tag_err:
                     if tag_err.status_code == 404 and tag_err.error_code == 'NoSuchTagSet':
                         continue
                     else:
                        print(f "警告: '{key}' という名前のオブジェクトのタグを取得中にエラーが発生しました: {tag_err.error_code} - {tag_err.message}。エラーをスキップします。")
                        continue
                except Exception as tag_e:
                    print(f "警告: '{key}' という名前のオブジェクトのタグの取得または処理中に不明なエラーが発生しました: {tag_e}。エラーをスキップします。")
                    # --- デバッグを容易にするためにトレースバックを追加 ---
                    import traceback
                    traceback.print_exc()
                    # --- 追加完了 ---
                    continue
            # --- クライアント タグ フィルタリング完了 ---

            # --- タグ フィルタ条件が渡されたか、指定されていない場合は、結果を処理して表示します。---
            final_results_count += 1 # 最終結果に 1 を追加します。
            print(f"\n[{final_results_count}] ファイル '{key}' はすべての条件を満たしています:") # 最終結果を表示します。

            # プリサイン URL を生成します。
            try:
                pre_url = client.presign(
                    oss.GetObjectRequest(
                        bucket=args.bucket,
                        key=key,
                    )
                )
                print(format_result(key, pre_url.url))
            except Exception as presign_e:
                print(f "警告: '{key}' という名前のオブジェクトのプリサイン URL の生成中にエラーが発生しました: {presign_e}")
                print(format_result(key, "[URL の生成に失敗しました]"))
        # --- ループ終了後に最終統計を表示します。---
        print(f"\n クライアント フィルタリング完了。{final_results_count} 件の結果が見つかりました。")

    except ET.ParseError as xml_e:
        print(f" エラー: XML 形式のレスポンスの解析中にエラーが発生しました - {xml_e}")
    except Exception as parse_e:
        print(f" エラー: 結果の処理中に予期しないエラーが発生しました - {parse_e}")


if __name__ == "__main__":
    perform_search()

インテリジェントセマンティックインデックスシステムを実行した後、「庭に車がある」コンテンツに関連するビデオオブジェクトをフィルタリングするには、次の手順を実行します。

  1. 説明フィールドに検索キーワードを入力します: yard with a car

  2. タグのフィルタリング条件を指定します: camera = camera-a

現在のビデオオブジェクトでは、ビデオ A とビデオ C の両方が 庭に車がある という記述に適合しています。ただし、タグのフィルタリング条件により、camera-a タグが付いた取得オブジェクトのみが保持されます。この場合、ビデオ A のみがすべての条件を満たします。

DoMetaQuery リクエストを送信します。

// リクエストは成功しました。 HTTP ステータスコード: 200。
リクエストは成功しました。 HTTP ステータスコード: 200.

// OSS から 4 つの予備一致結果を取得し、クライアントタグフィルタリングを開始します...
OSS から 4 つの予備一致結果を取得し、クライアントタグフィルタリングを開始します...

// [1] '2025-04-07/Video A/2.jpg' という名前のオブジェクトはすべての条件を満たしています。
//  オブジェクト URL: ...
//  オブジェクトパス: ...
[1] '2025-04-07/Video A/2.jpg' という名前のオブジェクトはすべての条件を満たしています。
 オブジェクト URL: https://ipc-frames-oss-metaquery-demo.oss-cn-beijing.aliyuncs.com/2025-04-07/%E8%A7%86%E9%A2%91A/2.jpg?x-oss-signature-version=OSS4-HMAC-SHA256&x-oss-date=20250407T025459Z&x-oss-expires=900&x-oss-credential=LTAI********************%2F20250407%2Fcn-beijing%2Foss%2Faliyun_v4_request&x-oss-signature=5e9d684ec141f9570f2f95713de492ac8291a39d1d655e4bb4c4d35b40d1e554
 オブジェクトパス: 2025-04-07/Video A/2.jpg
-----------------------

// [2] '2025-04-07/Video A/1.jpg' という名前のオブジェクトはすべての条件を満たしています。
//  オブジェクト URL: ...
//  オブジェクトパス: ...
[2] '2025-04-07/Video A/1.jpg' という名前のオブジェクトはすべての条件を満たしています。
 オブジェクト URL: https://ipc-frames-oss-metaquery-demo.oss-cn-beijing.aliyuncs.com/2025-04-07/%E8%A7%86%E9%A2%91A/1.jpg?x-oss-signature-version=OSS4-HMAC-SHA256&x-oss-date=20250407T025459Z&x-oss-expires=900&x-oss-credential=LTAI********************%2F20250407%2Fcn-beijing%2Foss%2Faliyun_v4_request&x-oss-signature=1c13310abdd764e8ac9f67e27a179f02949eaf47c4ed68358eefcb1965a6dd1e
 オブジェクトパス: 2025-04-07/Video A/1.jpg
-----------------------
// クライアントフィルタリングが完了しました。 2 つの結果が見つかりました。
クライアントフィルタリングが完了しました。 2 つの結果が見つかりました。

注: このチュートリアルでは、基本的な JavaScript の知識があることを前提としています。

フレームキャプチャのイベント通知ルールの設定

実際のアプリケーションでは、フレームは非同期でキャプチャされます。 フレームキャプチャタスクの完了時に、キャプチャされたフレームの処理結果を直接取得することはできません。 キャプチャされたフレームの処理結果を取得する場合は、Simple Message Queue (旧称 MNS) (SMQ) を使用してイベント通知を設定することをお勧めします。 この方法では、フレームキャプチャタスクが完了したときにインスタント通知を受信できます。 タスクステータスを繰り返しクエリする必要はありません。

フレームキャプチャのイベント通知ルールを設定するには、ビデオオブジェクトが格納されているバケットと同じリージョンにあるメッセージ Topic を作成する必要があります。 詳細については、「Topic ベースのメッセージングの概要」をご参照ください。 次のサンプルコードは、ビデオオブジェクトからフレームをキャプチャするときにイベント通知ルールを設定する方法を示しています。 Topic 名は Base64 エンコードされている必要があります。 たとえば、Topic 名がtest-topic の場合、エンコードされた名前はdGVzdC10b3BpYw です。

サンプルコード

# -*- coding: utf-8 -*-
import base64
import argparse
import alibabacloud_oss_v2 as oss


def video_processor():
    # OSS の基本パラメータを設定します。
    args = argparse.Namespace(
        region='cn-beijing',
        target_bucket='ipc-frames-oss-metaquery-demo',    
        bucket='ipc-videos-oss-metaquery-demo',     
        endpoint='https://oss-cn-beijing.aliyuncs.com'
    )
    
    # OSSClient インスタンスを設定します。
    credentials_provider = oss.credentials.EnvironmentVariableCredentialsProvider()
    cfg = oss.config.load_default()
    cfg.credentials_provider = credentials_provider
    cfg.region = args.region
    cfg.endpoint = args.endpoint
    client = oss.Client(cfg)

    # 処理するビデオオブジェクトを指定します。
    videos = [('Video A.mp4', '2025-04-07'), 
              ('Video B.mp4', '2025-04-07'), 
              ('Video C.mp4', '2025-04-07')]
    
    for video, date in videos:
        # キャプチャされたイメージを日付別に宛先ディレクトリに保存します。
        target_key = f"{date}/{video}/{{index}}.{{autoext}}"
        
        # フレームキャプチャ用に設定されたスタイルを指定します。
        style = 'style/ipc-snap'
        
        # 宛先バケット名とオブジェクト名を Base64 エンコードして、URL セーフであることを確認します。
        target_bucket_base64 = base64.urlsafe_b64encode(args.target_bucket.encode()).decode()
        target_key_base64 = base64.urlsafe_b64encode(target_key.encode()).decode()
        
        # スタイルと宛先パスを含む処理命令を作成します。 test-topic という名前の Topic を使用して、変換結果の通知を SMQ に送信します。
        process = f"{style}|sys/saveas,b_{target_bucket_base64},o_{target_key_base64}/notify,topic_dGVzdC10b3BpYw"
        
        try:
            # 非同期リクエストを送信します。
            result = client.async_process_object(oss.AsyncProcessObjectRequest(
                bucket=args.bucket,
                key=video,
                process=process
            ))
            
            print(f"Status Code: {result.status_code}")
            print(f"RequestId: {result.request_id}")
            print(f"TaskId: {result.task_id}")
            print(f"EventId: {result.event_id}")
            print(f"ProcessRequestId: {result.process_request_id}")
            
        except Exception as e:
            print(f"Error: {e}")

if __name__ == "__main__":
    video_processor()