From c610dadb415aa63e3c8783cd168971ac8fc380c8 Mon Sep 17 00:00:00 2001 From: Yu-Han Liu Date: Tue, 12 Dec 2017 21:22:45 -0800 Subject: [PATCH 01/18] add beta_snippets.py --- video/cloud-client/analyze/beta_snippets.py | 90 +++++++++++++++++++++ 1 file changed, 90 insertions(+) create mode 100644 video/cloud-client/analyze/beta_snippets.py diff --git a/video/cloud-client/analyze/beta_snippets.py b/video/cloud-client/analyze/beta_snippets.py new file mode 100644 index 00000000000..4ff99fc079a --- /dev/null +++ b/video/cloud-client/analyze/beta_snippets.py @@ -0,0 +1,90 @@ +#!/usr/bin/env python + +# Copyright 2017 Google Inc. All Rights Reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +"""This application demonstrates face detection, label detection, +explicit content, and shot change detection using the Google Cloud API. + +Usage Examples: + + python beta_snippets.py faces gs://demomaker/google_gmail.mp4 + python beta_snippets.py faces gs://sandboxdata/video_face/google_gmail_short.mp4 +""" + +import argparse +import io + +from google.cloud import videointelligence_v1beta2 as videointelligence + + +def analyze_faces(path): + """ Detects faces given a GCS path. """ + video_client = videointelligence.VideoIntelligenceServiceClient() + features = [videointelligence.enums.Feature.FACE_DETECTION] + + config = videointelligence.types.FaceConfig( + include_bounding_boxes=True) + context = videointelligence.types.VideoContext( + face_detection_config=config) + + operation = video_client.annotate_video( + path, features=features, video_context=context) + print('\nProcessing video for face annotations:') + + result = operation.result(timeout=600) + print('\nFinished processing.') + + # first result is retrieved because a single video was processed + faces = result.annotation_results[0].face_annotations + for face_id, face in enumerate(faces): + print('Face {}'.format(face_id)) + print('Thumbnail size: {}'.format(len(face.thumbnail))) + + for segment_id, segment in enumerate(face.segments): + start_time = (segment.segment.start_time_offset.seconds + + segment.segment.start_time_offset.nanos / 1e9) + end_time = (segment.segment.end_time_offset.seconds + + segment.segment.end_time_offset.nanos / 1e9) + positions = '{}s to {}s'.format(start_time, end_time) + print('\tSegment {}: {}'.format(segment_id, positions)) + + # There are typically many frames for each face, + # here we print information on only the first frame. + frame = face.frames[0] + time_offset = (frame.time_offset.seconds + + frame.time_offset.nanos / 1e9) + box = frame.normalized_bounding_boxes[0] + print('First frame time offset: {}s'.format(time_offset)) + print('First frame normalized bounding box:') + print('\tleft: {}'.format(box.left)) + print('\ttop: {}'.format(box.top)) + print('\tright: {}'.format(box.right)) + print('\tbottom: {}'.format(box.bottom)) + print('\n') + + +if __name__ == '__main__': + parser = argparse.ArgumentParser( + description=__doc__, + formatter_class=argparse.RawDescriptionHelpFormatter) + subparsers = parser.add_subparsers(dest='command') + analyze_faces_parser = subparsers.add_parser( + 'faces', help=analyze_faces.__doc__) + analyze_faces_parser.add_argument('path') + + args = parser.parse_args() + + if args.command == 'faces': + analyze_faces(args.path) From 4bed5f6683b78beb8e0d0a98539ed97e1835ddf4 Mon Sep 17 00:00:00 2001 From: Yu-Han Liu Date: Fri, 12 Jan 2018 08:38:59 -0800 Subject: [PATCH 02/18] add beta_snippets for face detection features --- video/cloud-client/analyze/beta_snippets.py | 119 +++++++++++++++----- 1 file changed, 93 insertions(+), 26 deletions(-) diff --git a/video/cloud-client/analyze/beta_snippets.py b/video/cloud-client/analyze/beta_snippets.py index 4ff99fc079a..b5baec97f8e 100644 --- a/video/cloud-client/analyze/beta_snippets.py +++ b/video/cloud-client/analyze/beta_snippets.py @@ -18,19 +18,21 @@ explicit content, and shot change detection using the Google Cloud API. Usage Examples: + python beta_snippets.py boxes \ + gs://python-docs-samples-tests/video/googlework_short.mp4 - python beta_snippets.py faces gs://demomaker/google_gmail.mp4 - python beta_snippets.py faces gs://sandboxdata/video_face/google_gmail_short.mp4 + python beta_snippets.py \ + emotions gs://python-docs-samples-tests/video/googlework_short.mp4 """ import argparse -import io from google.cloud import videointelligence_v1beta2 as videointelligence -def analyze_faces(path): - """ Detects faces given a GCS path. """ +# [START video_face_bounding_boxes] +def face_bounding_boxes(path): + """ Detects faces' bounding boxes. """ video_client = videointelligence.VideoIntelligenceServiceClient() features = [videointelligence.enums.Feature.FACE_DETECTION] @@ -43,36 +45,95 @@ def analyze_faces(path): path, features=features, video_context=context) print('\nProcessing video for face annotations:') - result = operation.result(timeout=600) + result = operation.result(timeout=900) print('\nFinished processing.') - # first result is retrieved because a single video was processed - faces = result.annotation_results[0].face_annotations - for face_id, face in enumerate(faces): - print('Face {}'.format(face_id)) - print('Thumbnail size: {}'.format(len(face.thumbnail))) + # There is only one result because a single video was processed. + faces = result.annotation_results[0].face_detection_annotations + for i, face in enumerate(faces): + print('Face {}'.format(i)) - for segment_id, segment in enumerate(face.segments): - start_time = (segment.segment.start_time_offset.seconds + - segment.segment.start_time_offset.nanos / 1e9) - end_time = (segment.segment.end_time_offset.seconds + - segment.segment.end_time_offset.nanos / 1e9) - positions = '{}s to {}s'.format(start_time, end_time) - print('\tSegment {}: {}'.format(segment_id, positions)) + # Each face_detection_annotation has only one segment. + segment = face.segments[0] + start_time = (segment.segment.start_time_offset.seconds + + segment.segment.start_time_offset.nanos / 1e9) + end_time = (segment.segment.end_time_offset.seconds + + segment.segment.end_time_offset.nanos / 1e9) + positions = '{}s to {}s'.format(start_time, end_time) + print('\tSegment: {}\n'.format(positions)) # There are typically many frames for each face, # here we print information on only the first frame. frame = face.frames[0] + time_offset = (frame.time_offset.seconds + frame.time_offset.nanos / 1e9) - box = frame.normalized_bounding_boxes[0] - print('First frame time offset: {}s'.format(time_offset)) + box = frame.attributes[0].normalized_bounding_box + + print('First frame time offset: {}s\n'.format(time_offset)) + print('First frame normalized bounding box:') - print('\tleft: {}'.format(box.left)) - print('\ttop: {}'.format(box.top)) - print('\tright: {}'.format(box.right)) + print('\tleft : {}'.format(box.left)) + print('\ttop : {}'.format(box.top)) + print('\tright : {}'.format(box.right)) print('\tbottom: {}'.format(box.bottom)) print('\n') +# [END video_face_bounding_boxes] + + +# [START video_face_emotions] +def face_emotions(path): + """ Analyze faces' emotions over frames. """ + video_client = videointelligence.VideoIntelligenceServiceClient() + features = [videointelligence.enums.Feature.FACE_DETECTION] + + # include_bounding_boxes must be set to True for include_emotions + # to work. + config = videointelligence.types.FaceConfig( + include_bounding_boxes=True, + include_emotions=True) + context = videointelligence.types.VideoContext( + face_detection_config=config) + + operation = video_client.annotate_video( + path, features=features, video_context=context) + print('\nProcessing video for face annotations:') + + result = operation.result(timeout=600) + print('\nFinished processing.') + + # There is only one result because a single video was processed. + faces = result.annotation_results[0].face_detection_annotations + for i, face in enumerate(faces): + print('Face {}'.format(i)) + + frame_emotions = [] + for frame in face.frames: + time_offset = (frame.time_offset.seconds + + frame.time_offset.nanos / 1e9) + emotions = frame.attributes[0].emotions + + # from videointelligence.enums + emotion_labels = ( + 'EMOTION_UNSPECIFIED', 'AMUSEMENT', 'ANGER', + 'CONCENTRATION', 'CONTENTMENT', 'DESIRE', + 'DISAPPOINTMENT', 'DISGUST', 'ELATION', + 'EMBARRASSMENT', 'INTEREST', 'PRIDE', 'SADNESS', + 'SURPRISE') + + emotion, score = sorted( + [(em.emotion, em.score) for em in emotions], + key=lambda p: p[1])[-1] + emotion_label = emotion_labels[emotion] + + frame_emotions.append((time_offset, emotion_label, score)) + + frame_emotions = sorted(frame_emotions, key=lambda p: p[0]) + for time_offset, emotion_label, score in frame_emotions: + print('\t{:04.2f}s: {:14}({:4.3f})'.format( + time_offset, emotion_label, score)) + print('\n') +# [END video_face_emotions] if __name__ == '__main__': @@ -81,10 +142,16 @@ def analyze_faces(path): formatter_class=argparse.RawDescriptionHelpFormatter) subparsers = parser.add_subparsers(dest='command') analyze_faces_parser = subparsers.add_parser( - 'faces', help=analyze_faces.__doc__) + 'boxes', help=face_bounding_boxes.__doc__) analyze_faces_parser.add_argument('path') + analyze_emotions_parser = subparsers.add_parser( + 'emotions', help=face_emotions.__doc__) + analyze_emotions_parser.add_argument('path') + args = parser.parse_args() - if args.command == 'faces': - analyze_faces(args.path) + if args.command == 'boxes': + face_bounding_boxes(args.path) + elif args.command == 'emotions': + face_emotions(args.path) From c24243ac919afc14af306ad1539192c9633e649d Mon Sep 17 00:00:00 2001 From: Yu-Han Liu Date: Fri, 12 Jan 2018 08:40:08 -0800 Subject: [PATCH 03/18] add beta_snippets test --- .../analyze/beta_snippets_test.py | 41 +++++++++++++++++++ 1 file changed, 41 insertions(+) create mode 100644 video/cloud-client/analyze/beta_snippets_test.py diff --git a/video/cloud-client/analyze/beta_snippets_test.py b/video/cloud-client/analyze/beta_snippets_test.py new file mode 100644 index 00000000000..2779d99e118 --- /dev/null +++ b/video/cloud-client/analyze/beta_snippets_test.py @@ -0,0 +1,41 @@ +#!/usr/bin/env python + +# Copyright 2017 Google, Inc +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +import os + +import pytest + +import beta_snippets + + +BUCKET = os.environ['CLOUD_STORAGE_BUCKET'] +FACES_SHORT_FILE_PATH = '/video/googlework_short.mp4' + + +@pytest.mark.slow +def test_analyze_shots(capsys): + beta_snippets.face_bounding_boxes( + 'gs://{}{}'.format(BUCKET, FACES_SHORT_FILE_PATH)) + out, _ = capsys.readouterr() + assert 'top :' in out + + +@pytest.mark.slow +def test_analyze_explicit_content(capsys): + beta_snippets.face_emotions( + 'gs://{}{}'.format(BUCKET, FACES_SHORT_FILE_PATH)) + out, _ = capsys.readouterr() + assert 'CONCENTRATION' in out From 69071f9753198c325cf9176ce2aaa075e95a505d Mon Sep 17 00:00:00 2001 From: Yu-Han Liu Date: Fri, 12 Jan 2018 09:11:18 -0800 Subject: [PATCH 04/18] correct test names --- video/cloud-client/analyze/beta_snippets_test.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/video/cloud-client/analyze/beta_snippets_test.py b/video/cloud-client/analyze/beta_snippets_test.py index 2779d99e118..fcc3e9361fb 100644 --- a/video/cloud-client/analyze/beta_snippets_test.py +++ b/video/cloud-client/analyze/beta_snippets_test.py @@ -26,7 +26,7 @@ @pytest.mark.slow -def test_analyze_shots(capsys): +def test_face_bounding_boxes(capsys): beta_snippets.face_bounding_boxes( 'gs://{}{}'.format(BUCKET, FACES_SHORT_FILE_PATH)) out, _ = capsys.readouterr() @@ -34,7 +34,7 @@ def test_analyze_shots(capsys): @pytest.mark.slow -def test_analyze_explicit_content(capsys): +def test_face_emotions(capsys): beta_snippets.face_emotions( 'gs://{}{}'.format(BUCKET, FACES_SHORT_FILE_PATH)) out, _ = capsys.readouterr() From 3c1800b1516f7bb777298f65f8a2472808f5e4ca Mon Sep 17 00:00:00 2001 From: Yu-Han Liu Date: Tue, 20 Mar 2018 13:57:36 -0700 Subject: [PATCH 05/18] update client library version --- video/cloud-client/analyze/beta_snippets.py | 2 +- video/cloud-client/analyze/beta_snippets_test.py | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/video/cloud-client/analyze/beta_snippets.py b/video/cloud-client/analyze/beta_snippets.py index b5baec97f8e..0bb561296c6 100644 --- a/video/cloud-client/analyze/beta_snippets.py +++ b/video/cloud-client/analyze/beta_snippets.py @@ -27,7 +27,7 @@ import argparse -from google.cloud import videointelligence_v1beta2 as videointelligence +from google.cloud import videointelligence_v1p1beta1 as videointelligence # [START video_face_bounding_boxes] diff --git a/video/cloud-client/analyze/beta_snippets_test.py b/video/cloud-client/analyze/beta_snippets_test.py index fcc3e9361fb..60790397631 100644 --- a/video/cloud-client/analyze/beta_snippets_test.py +++ b/video/cloud-client/analyze/beta_snippets_test.py @@ -22,13 +22,13 @@ BUCKET = os.environ['CLOUD_STORAGE_BUCKET'] -FACES_SHORT_FILE_PATH = '/video/googlework_short.mp4' +FACES_SHORT_FILE_PATH = 'video/googlework_short.mp4' @pytest.mark.slow def test_face_bounding_boxes(capsys): beta_snippets.face_bounding_boxes( - 'gs://{}{}'.format(BUCKET, FACES_SHORT_FILE_PATH)) + 'gs://{}/{}'.format(BUCKET, FACES_SHORT_FILE_PATH)) out, _ = capsys.readouterr() assert 'top :' in out @@ -36,6 +36,6 @@ def test_face_bounding_boxes(capsys): @pytest.mark.slow def test_face_emotions(capsys): beta_snippets.face_emotions( - 'gs://{}{}'.format(BUCKET, FACES_SHORT_FILE_PATH)) + 'gs://{}/{}'.format(BUCKET, FACES_SHORT_FILE_PATH)) out, _ = capsys.readouterr() assert 'CONCENTRATION' in out From 95a0b50e1bf0f1f8e261b7cb5946998bd12412db Mon Sep 17 00:00:00 2001 From: Yu-Han Liu Date: Tue, 20 Mar 2018 13:57:57 -0700 Subject: [PATCH 06/18] update client library version --- video/cloud-client/analyze/requirements.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/video/cloud-client/analyze/requirements.txt b/video/cloud-client/analyze/requirements.txt index e2ad27b873e..bf3b2da4ddb 100644 --- a/video/cloud-client/analyze/requirements.txt +++ b/video/cloud-client/analyze/requirements.txt @@ -1 +1 @@ -google-cloud-videointelligence==1.0.1 +google-cloud-videointelligence==1.1.0 From 8d633efb99246222a9d6f9b353c7febcf37f8565 Mon Sep 17 00:00:00 2001 From: Yu-Han Liu Date: Tue, 20 Mar 2018 14:49:27 -0700 Subject: [PATCH 07/18] add speech transcription --- video/cloud-client/analyze/beta_snippets.py | 48 +++++++++++++++++++ .../analyze/beta_snippets_test.py | 8 ++++ 2 files changed, 56 insertions(+) diff --git a/video/cloud-client/analyze/beta_snippets.py b/video/cloud-client/analyze/beta_snippets.py index 0bb561296c6..fdcac1e4f71 100644 --- a/video/cloud-client/analyze/beta_snippets.py +++ b/video/cloud-client/analyze/beta_snippets.py @@ -23,6 +23,9 @@ python beta_snippets.py \ emotions gs://python-docs-samples-tests/video/googlework_short.mp4 + + python beta_snippets.py \ + transcription gs://python-docs-samples-tests/video/googlework_short.mp4 """ import argparse @@ -136,6 +139,45 @@ def face_emotions(path): # [END video_face_emotions] +# [START video_speech_transcription] +def speech_transcription(input_uri): + """Transcribe speech from a video stored on GCS.""" + video_client = videointelligence.VideoIntelligenceServiceClient() + + features = [ + videointelligence.enums.Feature.SPEECH_TRANSCRIPTION + ] + + speech_transcription_config = videointelligence.types.SpeechTranscriptionConfig( + language_code='en-US') + video_context = videointelligence.types.VideoContext(speech_transcription_config=speech_transcription_config) + + operation = video_client.annotate_video(input_uri, + features=features, video_context=video_context) + + print('\nProcessing video for speech transcription.') + + result = operation.result(timeout=180) + + annotation_results = result.annotation_results[0] + speech_transcription = annotation_results.speech_transcriptions[0] + alternative = speech_transcription.alternatives[0] + + print('Transcript: {}'.format(alternative.transcript)) + print('Confidence: {}\n'.format(alternative.confidence)) + + print('Word level information:') + for word_info in alternative.words: + word = word_info.word + start_time = word_info.start_time + end_time = word_info.end_time + print('\t{}s - {}s: {}'.format( + start_time.seconds + start_time.nanos * 1e-9, + end_time.seconds + end_time.nanos * 1e-9, + word)) +# [END video_speech_transcription] + + if __name__ == '__main__': parser = argparse.ArgumentParser( description=__doc__, @@ -149,9 +191,15 @@ def face_emotions(path): 'emotions', help=face_emotions.__doc__) analyze_emotions_parser.add_argument('path') + speech_transcription_parser = subparsers.add_parser( + 'transcription', help=speech_transcription.__doc__) + speech_transcription_parser.add_argument('path') + args = parser.parse_args() if args.command == 'boxes': face_bounding_boxes(args.path) elif args.command == 'emotions': face_emotions(args.path) + elif args.command == 'transcription': + speech_transcription(args.path) diff --git a/video/cloud-client/analyze/beta_snippets_test.py b/video/cloud-client/analyze/beta_snippets_test.py index 60790397631..6d27c2fd00e 100644 --- a/video/cloud-client/analyze/beta_snippets_test.py +++ b/video/cloud-client/analyze/beta_snippets_test.py @@ -39,3 +39,11 @@ def test_face_emotions(capsys): 'gs://{}/{}'.format(BUCKET, FACES_SHORT_FILE_PATH)) out, _ = capsys.readouterr() assert 'CONCENTRATION' in out + + +@pytest.mark.slow +def test_speech_transcription(capsys): + beta_snippets.speech_transcription( + 'gs://{}/{}'.format(BUCKET, FACES_SHORT_FILE_PATH)) + out, _ = capsys.readouterr() + assert 'cultural' in out From 974d2370effcafa8ff750a2d708b7c60310eb7eb Mon Sep 17 00:00:00 2001 From: Yu-Han Liu Date: Tue, 20 Mar 2018 14:51:19 -0700 Subject: [PATCH 08/18] flake --- video/cloud-client/analyze/beta_snippets.py | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/video/cloud-client/analyze/beta_snippets.py b/video/cloud-client/analyze/beta_snippets.py index fdcac1e4f71..57c6b2e4322 100644 --- a/video/cloud-client/analyze/beta_snippets.py +++ b/video/cloud-client/analyze/beta_snippets.py @@ -148,12 +148,14 @@ def speech_transcription(input_uri): videointelligence.enums.Feature.SPEECH_TRANSCRIPTION ] - speech_transcription_config = videointelligence.types.SpeechTranscriptionConfig( + config = videointelligence.types.SpeechTranscriptionConfig( language_code='en-US') - video_context = videointelligence.types.VideoContext(speech_transcription_config=speech_transcription_config) + video_context = videointelligence.types.VideoContext( + speech_transcription_config=config) - operation = video_client.annotate_video(input_uri, - features=features, video_context=video_context) + operation = video_client.annotate_video( + input_uri, features=features, + video_context=video_context) print('\nProcessing video for speech transcription.') From f9e2dcc57a56fe411c8dbcd755f76acadf787669 Mon Sep 17 00:00:00 2001 From: Yu-Han Liu Date: Mon, 26 Mar 2018 08:55:13 -0700 Subject: [PATCH 09/18] address review comments --- video/cloud-client/analyze/beta_snippets.py | 18 +++++++----------- 1 file changed, 7 insertions(+), 11 deletions(-) diff --git a/video/cloud-client/analyze/beta_snippets.py b/video/cloud-client/analyze/beta_snippets.py index 57c6b2e4322..de3b97660c3 100644 --- a/video/cloud-client/analyze/beta_snippets.py +++ b/video/cloud-client/analyze/beta_snippets.py @@ -14,8 +14,8 @@ # See the License for the specific language governing permissions and # limitations under the License. -"""This application demonstrates face detection, label detection, -explicit content, and shot change detection using the Google Cloud API. +"""This application demonstrates face detection, face emotions +and speech transcription using the Google Cloud API. Usage Examples: python beta_snippets.py boxes \ @@ -65,8 +65,8 @@ def face_bounding_boxes(path): positions = '{}s to {}s'.format(start_time, end_time) print('\tSegment: {}\n'.format(positions)) - # There are typically many frames for each face, - # here we print information on only the first frame. + # Each detected may appear in many frames of the video. + # Here we process only the first frame. frame = face.frames[0] time_offset = (frame.time_offset.seconds + @@ -90,10 +90,7 @@ def face_emotions(path): video_client = videointelligence.VideoIntelligenceServiceClient() features = [videointelligence.enums.Feature.FACE_DETECTION] - # include_bounding_boxes must be set to True for include_emotions - # to work. config = videointelligence.types.FaceConfig( - include_bounding_boxes=True, include_emotions=True) context = videointelligence.types.VideoContext( face_detection_config=config) @@ -131,7 +128,6 @@ def face_emotions(path): frame_emotions.append((time_offset, emotion_label, score)) - frame_emotions = sorted(frame_emotions, key=lambda p: p[0]) for time_offset, emotion_label, score in frame_emotions: print('\t{:04.2f}s: {:14}({:4.3f})'.format( time_offset, emotion_label, score)) @@ -144,9 +140,7 @@ def speech_transcription(input_uri): """Transcribe speech from a video stored on GCS.""" video_client = videointelligence.VideoIntelligenceServiceClient() - features = [ - videointelligence.enums.Feature.SPEECH_TRANSCRIPTION - ] + features = [videointelligence.enums.Feature.SPEECH_TRANSCRIPTION] config = videointelligence.types.SpeechTranscriptionConfig( language_code='en-US') @@ -161,6 +155,8 @@ def speech_transcription(input_uri): result = operation.result(timeout=180) + # There is only one annotation_result since only + # one video is processed. annotation_results = result.annotation_results[0] speech_transcription = annotation_results.speech_transcriptions[0] alternative = speech_transcription.alternatives[0] From 9bedd7c5f06122974a2f1be1a1753d743477dd8d Mon Sep 17 00:00:00 2001 From: Yu-Han Liu Date: Mon, 26 Mar 2018 09:43:07 -0700 Subject: [PATCH 10/18] fix missing word --- video/cloud-client/analyze/beta_snippets.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/video/cloud-client/analyze/beta_snippets.py b/video/cloud-client/analyze/beta_snippets.py index de3b97660c3..d285d844b46 100644 --- a/video/cloud-client/analyze/beta_snippets.py +++ b/video/cloud-client/analyze/beta_snippets.py @@ -65,7 +65,7 @@ def face_bounding_boxes(path): positions = '{}s to {}s'.format(start_time, end_time) print('\tSegment: {}\n'.format(positions)) - # Each detected may appear in many frames of the video. + # Each detected face may appear in many frames of the video. # Here we process only the first frame. frame = face.frames[0] From 8c0ac588ff05e5c5e260fb3b503c1da486e0b930 Mon Sep 17 00:00:00 2001 From: Yu-Han Liu Date: Mon, 26 Mar 2018 13:51:58 -0700 Subject: [PATCH 11/18] add comment --- video/cloud-client/analyze/beta_snippets.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/video/cloud-client/analyze/beta_snippets.py b/video/cloud-client/analyze/beta_snippets.py index d285d844b46..4c5a21baaf3 100644 --- a/video/cloud-client/analyze/beta_snippets.py +++ b/video/cloud-client/analyze/beta_snippets.py @@ -121,6 +121,8 @@ def face_emotions(path): 'EMBARRASSMENT', 'INTEREST', 'PRIDE', 'SADNESS', 'SURPRISE') + # every emotion gets a score, here we sort them by + # scores and keep only the one that scores the highest. emotion, score = sorted( [(em.emotion, em.score) for em in emotions], key=lambda p: p[1])[-1] From ba30eecc649f9b47e59457f10c790cfedb0e172f Mon Sep 17 00:00:00 2001 From: Yu-Han Liu Date: Mon, 26 Mar 2018 15:27:57 -0700 Subject: [PATCH 12/18] rename path to gcs_uri --- video/cloud-client/analyze/beta_snippets.py | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/video/cloud-client/analyze/beta_snippets.py b/video/cloud-client/analyze/beta_snippets.py index 4c5a21baaf3..0c6c44e6983 100644 --- a/video/cloud-client/analyze/beta_snippets.py +++ b/video/cloud-client/analyze/beta_snippets.py @@ -34,7 +34,7 @@ # [START video_face_bounding_boxes] -def face_bounding_boxes(path): +def face_bounding_boxes(gcs_uri): """ Detects faces' bounding boxes. """ video_client = videointelligence.VideoIntelligenceServiceClient() features = [videointelligence.enums.Feature.FACE_DETECTION] @@ -45,7 +45,7 @@ def face_bounding_boxes(path): face_detection_config=config) operation = video_client.annotate_video( - path, features=features, video_context=context) + gcs_uri, features=features, video_context=context) print('\nProcessing video for face annotations:') result = operation.result(timeout=900) @@ -85,7 +85,7 @@ def face_bounding_boxes(path): # [START video_face_emotions] -def face_emotions(path): +def face_emotions(gcs_uri): """ Analyze faces' emotions over frames. """ video_client = videointelligence.VideoIntelligenceServiceClient() features = [videointelligence.enums.Feature.FACE_DETECTION] @@ -96,7 +96,7 @@ def face_emotions(path): face_detection_config=config) operation = video_client.annotate_video( - path, features=features, video_context=context) + gcs_uri, features=features, video_context=context) print('\nProcessing video for face annotations:') result = operation.result(timeout=600) @@ -185,21 +185,21 @@ def speech_transcription(input_uri): subparsers = parser.add_subparsers(dest='command') analyze_faces_parser = subparsers.add_parser( 'boxes', help=face_bounding_boxes.__doc__) - analyze_faces_parser.add_argument('path') + analyze_faces_parser.add_argument('gcs_uri') analyze_emotions_parser = subparsers.add_parser( 'emotions', help=face_emotions.__doc__) - analyze_emotions_parser.add_argument('path') + analyze_emotions_parser.add_argument('gcs_uri') speech_transcription_parser = subparsers.add_parser( 'transcription', help=speech_transcription.__doc__) - speech_transcription_parser.add_argument('path') + speech_transcription_parser.add_argument('gcs_uri') args = parser.parse_args() if args.command == 'boxes': - face_bounding_boxes(args.path) + face_bounding_boxes(args.gcs_uri) elif args.command == 'emotions': - face_emotions(args.path) + face_emotions(args.gcs_uri) elif args.command == 'transcription': - speech_transcription(args.path) + speech_transcription(args.gcs_uri) From 5a5da60301b793f371a48747409c36f3b4235c85 Mon Sep 17 00:00:00 2001 From: Yu-Han Liu Date: Mon, 26 Mar 2018 15:34:47 -0700 Subject: [PATCH 13/18] process emotions differently --- video/cloud-client/analyze/beta_snippets.py | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/video/cloud-client/analyze/beta_snippets.py b/video/cloud-client/analyze/beta_snippets.py index 0c6c44e6983..bb28d900885 100644 --- a/video/cloud-client/analyze/beta_snippets.py +++ b/video/cloud-client/analyze/beta_snippets.py @@ -123,10 +123,12 @@ def face_emotions(gcs_uri): # every emotion gets a score, here we sort them by # scores and keep only the one that scores the highest. - emotion, score = sorted( - [(em.emotion, em.score) for em in emotions], - key=lambda p: p[1])[-1] - emotion_label = emotion_labels[emotion] + most_likely_emotion = sorted( + [em for em in emotions], + key=lambda em: em.score)[-1] + score = most_likely_emotion.score + emotion_index = most_likely_emotion.emotion + emotion_label = emotion_labels[emotion_index] frame_emotions.append((time_offset, emotion_label, score)) From c15c7295f535bb0527a4560b7a9df33df94845f2 Mon Sep 17 00:00:00 2001 From: Yu-Han Liu Date: Mon, 26 Mar 2018 15:36:53 -0700 Subject: [PATCH 14/18] simpler code --- video/cloud-client/analyze/beta_snippets.py | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/video/cloud-client/analyze/beta_snippets.py b/video/cloud-client/analyze/beta_snippets.py index bb28d900885..4cb7da0f55e 100644 --- a/video/cloud-client/analyze/beta_snippets.py +++ b/video/cloud-client/analyze/beta_snippets.py @@ -123,9 +123,7 @@ def face_emotions(gcs_uri): # every emotion gets a score, here we sort them by # scores and keep only the one that scores the highest. - most_likely_emotion = sorted( - [em for em in emotions], - key=lambda em: em.score)[-1] + most_likely_emotion = sorted(emotions, key=lambda em: em.score)[-1] score = most_likely_emotion.score emotion_index = most_likely_emotion.emotion emotion_label = emotion_labels[emotion_index] From 8d4adf135c1aa9f0cadcd84425310f30a181ae79 Mon Sep 17 00:00:00 2001 From: Yu-Han Liu Date: Mon, 26 Mar 2018 16:31:44 -0700 Subject: [PATCH 15/18] use max instead of sorted --- video/cloud-client/analyze/beta_snippets.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/video/cloud-client/analyze/beta_snippets.py b/video/cloud-client/analyze/beta_snippets.py index 4cb7da0f55e..f7eb7651e41 100644 --- a/video/cloud-client/analyze/beta_snippets.py +++ b/video/cloud-client/analyze/beta_snippets.py @@ -123,7 +123,8 @@ def face_emotions(gcs_uri): # every emotion gets a score, here we sort them by # scores and keep only the one that scores the highest. - most_likely_emotion = sorted(emotions, key=lambda em: em.score)[-1] + most_likely_emotion = max(emotions, + key=lambda emotion: emotion.score) score = most_likely_emotion.score emotion_index = most_likely_emotion.emotion emotion_label = emotion_labels[emotion_index] From 7266d1e9e4033db82482360ff70f876d28253121 Mon Sep 17 00:00:00 2001 From: Yu-Han Liu Date: Mon, 26 Mar 2018 16:32:26 -0700 Subject: [PATCH 16/18] update comment --- video/cloud-client/analyze/beta_snippets.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/video/cloud-client/analyze/beta_snippets.py b/video/cloud-client/analyze/beta_snippets.py index f7eb7651e41..3e46ba922a4 100644 --- a/video/cloud-client/analyze/beta_snippets.py +++ b/video/cloud-client/analyze/beta_snippets.py @@ -121,8 +121,8 @@ def face_emotions(gcs_uri): 'EMBARRASSMENT', 'INTEREST', 'PRIDE', 'SADNESS', 'SURPRISE') - # every emotion gets a score, here we sort them by - # scores and keep only the one that scores the highest. + # every emotion gets a score, here we keep only + # the one that scores the highest. most_likely_emotion = max(emotions, key=lambda emotion: emotion.score) score = most_likely_emotion.score From 0fc6819691f91f97c3b5919c0645e17024f5e80c Mon Sep 17 00:00:00 2001 From: Yu-Han Liu Date: Mon, 26 Mar 2018 16:49:37 -0700 Subject: [PATCH 17/18] process emotions more simply --- video/cloud-client/analyze/beta_snippets.py | 22 ++++++++++----------- 1 file changed, 10 insertions(+), 12 deletions(-) diff --git a/video/cloud-client/analyze/beta_snippets.py b/video/cloud-client/analyze/beta_snippets.py index 3e46ba922a4..5dfd5448b52 100644 --- a/video/cloud-client/analyze/beta_snippets.py +++ b/video/cloud-client/analyze/beta_snippets.py @@ -108,11 +108,13 @@ def face_emotions(gcs_uri): print('Face {}'.format(i)) frame_emotions = [] - for frame in face.frames: + for j, frame in enumerate(face.frames): time_offset = (frame.time_offset.seconds + frame.time_offset.nanos / 1e9) emotions = frame.attributes[0].emotions + print('Face {}, frame {}, time_offset {}\n'.format(i, j, time_offset)) + # from videointelligence.enums emotion_labels = ( 'EMOTION_UNSPECIFIED', 'AMUSEMENT', 'ANGER', @@ -121,19 +123,15 @@ def face_emotions(gcs_uri): 'EMBARRASSMENT', 'INTEREST', 'PRIDE', 'SADNESS', 'SURPRISE') - # every emotion gets a score, here we keep only - # the one that scores the highest. - most_likely_emotion = max(emotions, - key=lambda emotion: emotion.score) - score = most_likely_emotion.score - emotion_index = most_likely_emotion.emotion - emotion_label = emotion_labels[emotion_index] + for emotion in emotions: + emotion_index = emotion.emotion + emotion_label = emotion_labels[emotion_index] + emotion_score = emotion.score + + print('emotion: {} (confidence score: {})'.format(emotion_label, emotion_score)) - frame_emotions.append((time_offset, emotion_label, score)) + print('\n') - for time_offset, emotion_label, score in frame_emotions: - print('\t{:04.2f}s: {:14}({:4.3f})'.format( - time_offset, emotion_label, score)) print('\n') # [END video_face_emotions] From d91bbe0fc34b3d3bf84ad3ea9d8f4036f7fddd8f Mon Sep 17 00:00:00 2001 From: Yu-Han Liu Date: Mon, 26 Mar 2018 16:57:41 -0700 Subject: [PATCH 18/18] flake --- video/cloud-client/analyze/beta_snippets.py | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/video/cloud-client/analyze/beta_snippets.py b/video/cloud-client/analyze/beta_snippets.py index 5dfd5448b52..12ad4197138 100644 --- a/video/cloud-client/analyze/beta_snippets.py +++ b/video/cloud-client/analyze/beta_snippets.py @@ -105,15 +105,13 @@ def face_emotions(gcs_uri): # There is only one result because a single video was processed. faces = result.annotation_results[0].face_detection_annotations for i, face in enumerate(faces): - print('Face {}'.format(i)) - - frame_emotions = [] for j, frame in enumerate(face.frames): time_offset = (frame.time_offset.seconds + frame.time_offset.nanos / 1e9) emotions = frame.attributes[0].emotions - print('Face {}, frame {}, time_offset {}\n'.format(i, j, time_offset)) + print('Face {}, frame {}, time_offset {}\n'.format( + i, j, time_offset)) # from videointelligence.enums emotion_labels = ( @@ -128,7 +126,8 @@ def face_emotions(gcs_uri): emotion_label = emotion_labels[emotion_index] emotion_score = emotion.score - print('emotion: {} (confidence score: {})'.format(emotion_label, emotion_score)) + print('emotion: {} (confidence score: {})'.format( + emotion_label, emotion_score)) print('\n')