LoginSignup
0
0

More than 1 year has passed since last update.

GCP Video Intelligence APIの返り値nanos秒オブジェクトが、'datetime.timedelta' object has no attribute 'nanos'エラーで扱えない件

Last updated at Posted at 2021-07-25

nanoを取り出して、したいこと

次のサイトにならい、各フレームが動画の最初のフレームから何分何秒後のフレームなのかを、PythonのDataFrameに格納してみようと思いました。

if cap.isOpened():
    fps = cap.get(cv2.CAP_PROP_FPS)
    for sec in df['FrameTime']:
        # fpsと秒から何フレーム目かを計算する
        cap.set(cv2.CAP_PROP_POS_FRAMES, round(fps * sec))

上記のサイトに書かれている通り、「各フレームが動画の最初のフレームから何分何秒後のフレームなのか」がわかれば、動画のフレームレート数と合わせて、各フレームが動画中の何フレーム目のフレームなのかも、計算で求めることができます。

AttributeError: 'datetime.timedelta' object has no attribute 'nanos'エラーが発生

>>> import json
>>> from google.cloud import videointelligence
>>> from google.oauth2 import service_account
>>> service_account_key_name = "electroncgpvision-8bf54f743c93.json"
>>> info = json.load(open(service_account_key_name))
>>> creds = service_account.Credentials.from_service_account_info(info)
>>> video_client = videointelligence.VideoIntelligenceServiceClient(credentials=creds)
>>> features = [videointelligence.Feature.OBJECT_TRACKING]
>>> path = './olympic.mp4'
>>> import io
>>> 
>>> with io.open(path, 'rb') as file:
...     input_content = file.read()
... 
>>>
>>> operation = video_client.annotate_video(
...     request={"features": features, "input_content": input_content}
... )
>>>
>>> timeout = 300
>>> result = operation.result(timeout=timeout)

>>> 
>>> 
>>> import types
>>> print(type(result))
<class 'google.cloud.videointelligence_v1.types.video_intelligence.AnnotateVideoResponse'>
>>>
>>> for object_annotation in object_annotations:
...     for frame in object_annotation.frames:
...             box = frame.normalized_bounding_box
...             result_table.append([
...             object_annotation.entity.description,
...             object_annotation.confidence,
...             object_annotation.segment.start_time_offset.seconds + object_annotation.segment.start_time_offset.nanos / 1e9,
...             object_annotation.segment.end_time_offset.seconds + object_annotation.segment.end_time_offset.nanos / 1e9,
...             frame.time_offset.seconds + frame.time_offset.nanos / 1e9,
...             box.left,
...             box.top,
...             box.right,
...             box.bottom,
...             [box.left, box.top, box.right, box.bottom],
...             object_annotation.entity.entity_id
...             ])
... 
Traceback (most recent call last):
  File "<stdin>", line 7, in <module>
AttributeError: 'datetime.timedelta' object has no attribute 'nanos'
>>> 

>>> start_time_offset_listp = [object.segment.start_time_offset for object in object_list]
>>> start_time_offset_list = [object.segment.start_time_offset for object in object_list]
>>> len(start_time_offset_list)
1143
>>> 
>>> start_time_offset_list[0:2]
[datetime.timedelta(0), datetime.timedelta(seconds=1, microseconds=201200)]
>>> 
>>> print(start_time_offset_list[0:2])
[datetime.timedelta(0), datetime.timedelta(seconds=1, microseconds=201200)]
>>> 
>>> start_time_seconds_list = [object.segment.start_time_offset.seconds for object in object_list]
>>> len(start_time_seconds_list)
1143
>>> print(start_time_seconds_list[0:2])
[0, 1]
>>> 
>>> print(start_time_seconds_list[0:10])
[0, 1, 2, 4, 5, 7, 7, 7, 7, 7]
>>> 
>>> start_time_nanos_list = [object.segment.start_time_offset.nanos for object in object_list]
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "<stdin>", line 1, in <listcomp>
AttributeError: 'datetime.timedelta' object has no attribute 'nanos'
>>> 
>>> start_time_offset_list = [object.segment.start_time_offset for object in object_list]
>>> print(start_time_offset_list[0])
0:00:00
>>> 
>>> print(start_time_offset_list[0].seconds)
0
>>> 
>>> print(start_time_offset_list[0].nanos)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
AttributeError: 'datetime.timedelta' object has no attribute 'nanos'
>>> 

nanoを取り出して、したいこと

次のサイトにならい、各フレームが動画の最初のフレームから何分何秒後のフレームなのかを、PythonのDataFrameに格納してみようと思いました。

if cap.isOpened():
    fps = cap.get(cv2.CAP_PROP_FPS)
    for sec in df['FrameTime']:
        # fpsと秒から何フレーム目かを計算する
        cap.set(cv2.CAP_PROP_POS_FRAMES, round(fps * sec))

上記のサイトに書かれている通り、「各フレームが動画の最初のフレームから何分何秒後のフレームなのか」がわかれば、動画のフレームレート数と合わせて、各フレームが動画中の何フレーム目のフレームなのかも、計算で求めることができます。

動画のフレーム数は、Pythonで出力できます。

# fps
fps = video.get(cv2.CAP_PROP_FPS)

先ほどのサイトでは、以下の部分でfpsを取得しています。

fps = cap.get(cv2.CAP_PROP_FPS)

その上で、先ほどのサイトでは、以下の最後の行の次の部分で「あるフレームが動画内で何フレーム目に位置するフレームなのか」を計算しています。

round(fps * sec)

あるフレームが、動画の最初から数えて1,000sec経過後に登場するシーン(フレーム)であり、この動画が、15fps(1秒間に15フレーム表示される)のとき、「あるフレーム」は、動画の最初から数えて、1,000*15 = 15,000フレーム目に位置する計算になります。

そして、cap.set()メソッドで、「あるフレーム」に「現在のフレーム位置」を移動させて、OpenCV2を使って、目的のフレーム画像を取得しています。

if cap.isOpened():
    fps = cap.get(cv2.CAP_PROP_FPS)
    for sec in df['FrameTime']:
        # fpsと秒から何フレーム目かを計算する
        cap.set(cv2.CAP_PROP_POS_FRAMES, round(fps * sec))

cap.set()メソッドの仕様は、次の通りです。

  • 第一引数: 「フレームの現在位置」を指すcv2.CAP_PROP_POS_FRAMESを指定する。
  • 第二引数: 動画の最初から数えたフレーム数を渡す。

その結果、「フレームの現在位置」が、「あるフレーム」になるよう、位置指定が行われます。

print(cap.set(cv2.CAP_PROP_POS_FRAMES, 100))
このCAP_PROP_POS_FRAMESは動画の現在位置を表すプロパティ。後述。

解決策を探索中

以下のサイトを見て、解決策を模索中です。

計算を伴わない以下もエラー

エラー

>>> for object_annotation in object_annotations:
...     for frame in object_annotation.frames:
...             box = frame.normalized_bounding_box
...             result_table.append([
...                     object_annotation.entity.description,
...                     object_annotation.confidence,
...                     object_annotation.segment.start_time_offset.seconds,
...                     object_annotation.segment.start_time_offset.nanos,
...                     object_annotation.segment.end_time_offset.seconds,
...                     object_annotation.segment.end_time_offset.nanos,
...                     frame.time_offset.seconds,
...                     frame.time_offset.nanos,
...                     box.left,
...                     box.top,
...                     box.right,
...                     box.bottom,
...                     [box.left, box.top, box.right, box.bottom],
...                     object_annotation.entity.entity_id
...             ])
... 
Traceback (most recent call last):
  File "<stdin>", line 8, in <module>
AttributeError: 'datetime.timedelta' object has no attribute 'nanos'
>>> 

エラー

>>> tmp = [object_annotation.segment.start_time_offset.nanos for object_annotation in object_annotations]
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "<stdin>", line 1, in <listcomp>
AttributeError: 'datetime.timedelta' object has no attribute 'nanos'
>>> 

エラー

>>> tmp = [float(object_annotation.segment.start_time_offset.nanos) for object_annotation in object_annotations]
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "<stdin>", line 1, in <listcomp>
AttributeError: 'datetime.timedelta' object has no attribute 'nanos'
>>> 

エラー

>>> tmp = [str(object_annotation.segment.start_time_offset.nanos) for object_annotation in object_annotations]
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "<stdin>", line 1, in <listcomp>
AttributeError: 'datetime.timedelta' object has no attribute 'nanos'
>>> 

エラー

>>> tmp = [int(object_annotation.segment.start_time_offset.nanos) for object_annotation in object_annotations]
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "<stdin>", line 1, in <listcomp>
AttributeError: 'datetime.timedelta' object has no attribute 'nanos'
>>> 

nanos呼出しがない処理は走る

>>> tmp = [object_annotation.segment.start_time_offset.seconds for object_annotation in object_annotations]
>>> len(tmp)
1142
>>> tmp[0:10]
[0, 1, 2, 4, 5, 7, 7, 7, 7, 7]
>>> 
0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0