检测镜头变化

镜头变化分析用于检测视频中的镜头变化。

本部分介绍分析视频以获取镜头变化的几种方法。

以下示例展示如何对 Cloud Storage 中的文件执行视频分析以获取镜头变化。

想要更深入了解其他内容?请查看我们的详细 Python 教程

REST

发送视频注解请求

下面演示了如何向 videos:annotate 方法发送 POST 请求。该示例使用 Google Cloud CLI 创建访问令牌。如需了解如何安装 gcloud CLI,请参阅 Video Intelligence API 快速入门

在使用任何请求数据之前,请先进行以下替换:

  • INPUT_URI:包含要添加注释的文件的 Cloud Storage 存储桶(包括文件名)。必须以 gs:// 开头。
  • PROJECT_NUMBER:您的 Google Cloud 项目的数字标识符

HTTP 方法和网址:

POST https://videointelligence.googleapis.com/v1/videos:annotate

请求 JSON 正文:

{
    "inputUri": "INPUT_URI",
    "features": ["SHOT_CHANGE_DETECTION"]
}

如需发送您的请求,请展开以下选项之一:

您应该收到类似以下内容的 JSON 响应:

如果响应成功,Video Intelligence API 将返回您的操作的 name。上面的示例展示了此类响应的示例,其中 project-name 是您的项目名称,operation-id 是为请求创建的长时间运行的操作的 ID。

  • PROJECT_NUMBER:您项目的编号
  • LOCATION_ID:在其中添加注解的 Cloud 区域。支持的云区域为:us-east1us-west1europe-west1asia-east1。如果未指定区域,系统将根据视频文件位置确定区域。
  • OPERATION_ID:是为请求创建的长时间运行的操作的 ID,并在启动操作时在响应中提供,例如 12345....

获取注解结果

要检索操作的结果,请使用从 videos:annotate 调用返回的操作名称发出 GET 请求,如以下示例所示。

在使用任何请求数据之前,请先进行以下替换:

  • OPERATION_NAME:Video Intelligence API 返回的操作名称。操作名称采用 projects/PROJECT_NUMBER/locations/LOCATION_ID/operations/OPERATION_ID 格式
  • PROJECT_NUMBER:您的 Google Cloud 项目的数字标识符

HTTP 方法和网址:

GET https://videointelligence.googleapis.com/v1/OPERATION_NAME

如需发送您的请求,请展开以下选项之一:

您应该收到类似以下内容的 JSON 响应:

镜头检测注释以 shotAnnotations 列表的形式返回。注意:仅当值为 True 时,才会返回 done 字段。操作未完成的响应中不包含该字段。

下载注解结果

将来源中的注解复制到目标存储桶(请参阅复制文件和对象):

gsutil cp gcs_uri gs://my-bucket

注意:如果输出 gcs uri 由用户提供,则注解存储在该 gcs uri 中。

Go


func shotChangeURI(w io.Writer, file string) error {
	ctx := context.Background()
	client, err := video.NewClient(ctx)
	if err != nil {
		return err
	}
	defer client.Close()

	op, err := client.AnnotateVideo(ctx, &videopb.AnnotateVideoRequest{
		Features: []videopb.Feature{
			videopb.Feature_SHOT_CHANGE_DETECTION,
		},
		InputUri: file,
	})
	if err != nil {
		return err
	}
	resp, err := op.Wait(ctx)
	if err != nil {
		return err
	}

	// A single video was processed. Get the first result.
	result := resp.AnnotationResults[0].ShotAnnotations

	for _, shot := range result {
		start, _ := ptypes.Duration(shot.StartTimeOffset)
		end, _ := ptypes.Duration(shot.EndTimeOffset)

		fmt.Fprintf(w, "Shot: %s to %s\n", start, end)
	}

	return nil
}

Java

如需向 Video Intelligence 进行身份验证,请设置应用默认凭据。如需了解详情,请参阅为本地开发环境设置身份验证

// Instantiate a com.google.cloud.videointelligence.v1.VideoIntelligenceServiceClient
try (VideoIntelligenceServiceClient client = VideoIntelligenceServiceClient.create()) {
  // Provide path to file hosted on GCS as "gs://bucket-name/..."
  AnnotateVideoRequest request =
      AnnotateVideoRequest.newBuilder()
          .setInputUri(gcsUri)
          .addFeatures(Feature.SHOT_CHANGE_DETECTION)
          .build();

  // Create an operation that will contain the response when the operation completes.
  OperationFuture<AnnotateVideoResponse, AnnotateVideoProgress> response =
      client.annotateVideoAsync(request);

  System.out.println("Waiting for operation to complete...");
  // Print detected shot changes and their location ranges in the analyzed video.
  for (VideoAnnotationResults result : response.get().getAnnotationResultsList()) {
    if (result.getShotAnnotationsCount() > 0) {
      System.out.println("Shots: ");
      for (VideoSegment segment : result.getShotAnnotationsList()) {
        double startTime =
            segment.getStartTimeOffset().getSeconds()
                + segment.getStartTimeOffset().getNanos() / 1e9;
        double endTime =
            segment.getEndTimeOffset().getSeconds()
                + segment.getEndTimeOffset().getNanos() / 1e9;
        System.out.printf("Location: %.3f:%.3f\n", startTime, endTime);
      }
    } else {
      System.out.println("No shot changes detected in " + gcsUri);
    }
  }
}

Node.js

如需向 Video Intelligence 进行身份验证,请设置应用默认凭据。如需了解详情,请参阅为本地开发环境设置身份验证

// Imports the Google Cloud Video Intelligence library
const video = require('@google-cloud/video-intelligence').v1;

// Creates a client
const client = new video.VideoIntelligenceServiceClient();

/**
 * TODO(developer): Uncomment the following line before running the sample.
 */
// const gcsUri = 'GCS URI of file to analyze, e.g. gs://my-bucket/my-video.mp4';

const request = {
  inputUri: gcsUri,
  features: ['SHOT_CHANGE_DETECTION'],
};

// Detects camera shot changes
const [operation] = await client.annotateVideo(request);
console.log('Waiting for operation to complete...');
const [operationResult] = await operation.promise();
// Gets shot changes
const shotChanges = operationResult.annotationResults[0].shotAnnotations;
console.log('Shot changes:');

if (shotChanges.length === 1) {
  console.log('The entire video is one shot.');
} else {
  shotChanges.forEach((shot, shotIdx) => {
    console.log(`Scene ${shotIdx} occurs from:`);
    if (shot.startTimeOffset === undefined) {
      shot.startTimeOffset = {};
    }
    if (shot.endTimeOffset === undefined) {
      shot.endTimeOffset = {};
    }
    if (shot.startTimeOffset.seconds === undefined) {
      shot.startTimeOffset.seconds = 0;
    }
    if (shot.startTimeOffset.nanos === undefined) {
      shot.startTimeOffset.nanos = 0;
    }
    if (shot.endTimeOffset.seconds === undefined) {
      shot.endTimeOffset.seconds = 0;
    }
    if (shot.endTimeOffset.nanos === undefined) {
      shot.endTimeOffset.nanos = 0;
    }
    console.log(
      `\tStart: ${shot.startTimeOffset.seconds}` +
        `.${(shot.startTimeOffset.nanos / 1e6).toFixed(0)}s`
    );
    console.log(
      `\tEnd: ${shot.endTimeOffset.seconds}.` +
        `${(shot.endTimeOffset.nanos / 1e6).toFixed(0)}s`
    );
  });
}

Python

如需详细了解如何安装和使用 Python 版 Video Intelligence API 客户端库,请参阅 Video Intelligence API 客户端库
"""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=90)
print("\nFinished processing.")

# first result is retrieved because a single video was processed
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))

其他语言

C#:请按照“客户端库”页面上的 C# 设置说明操作,然后访问 .NET 的 Video Intelligence 参考文档

PHP:请按照客户端库页面上的 PHP 设置说明操作,然后访问 PHP 版 Video Intelligence 参考文档

Ruby:请按照客户端库页面上的 Ruby 设置说明操作,然后访问 Ruby 版 Video Intelligence 参考文档