記事ディレクトリ
特定のフレームを読み取る
このメソッドは特定のフレームを取得できます。
while True:
cap.set(cv2.CAP_PROP_POS_FRAMES, current_frame)
ret, frame = cap.read()
if not ret:
break
待機ボタン
このメソッドは現在のフレームを表示し、ボタンを待ちます。
# 显示当前帧
cv2.imshow('Video Frame', frame)
# 等待按键输入
key = cv2.waitKey(0) # 使用较短的等待时间以确保视频正常播放
if key == 27: # ESC
break
elif key == ord('q'): # Q 键(往回跳一帧)
if current_frame > 0:
current_frame -= 1
elif key == ord('w'): # W 键(往前播放一帧)
if current_frame < len(json_data) - 1:
current_frame += 1
このフラグをオンにすると、mp4 ビデオを保存できるようになります。
FLAG_SAVE_VIDEOS = False
ファイル形式に応じた書き込みデコード方式
通常、ビデオ ファイル形式が異なれば、使用するコーデックも異なるため、作成するビデオ ファイル形式に基づいて適切な 4 文字のエンコード識別子を選択する必要があります。一般的なビデオ ファイル形式と、対応する 4 文字のエンコード識別子の例をいくつか示します。
-
H.264 エンコーディング(通常は .mp4 ファイルに使用されます):
fourcc = cv2.VideoWriter_fourcc(*'H264')
-
XVID エンコーディング(通常は .avi ファイルに使用されます):
fourcc = cv2.VideoWriter_fourcc(*'XVID')
-
MJPG エンコード(通常は .avi ファイルに使用され、フレームあたりの画質が高いシーンに適しています):
fourcc = cv2.VideoWriter_fourcc(*'MJPG')
-
DIVX エンコーディング(通常は .avi ファイルに使用されます):
fourcc = cv2.VideoWriter_fourcc(*'DIVX')
-
VP8 エンコーディング(通常は .webm ファイルに使用されます):
fourcc = cv2.VideoWriter_fourcc(*'VP80')
-
VP9 エンコーディング(通常は .webm ファイルに使用されます):
fourcc = cv2.VideoWriter_fourcc(*'VP90')
これらは、一般的なビデオ ファイル形式と、対応する 4 文字のエンコード識別子の例です。ニーズと使用するビデオ ファイル形式に応じて、適切なエンコード フラグを選択して、ビデオ ファイルが正しくエンコードおよびデコードできるようにします。ビデオ編集ソフトウェアやプレーヤーによってサポートされるコーデックも異なるため、最終用途に応じて調整する必要がある場合があります。
すべてのコード
import logging
import time
import cv2
import json
# 读取JSON文件
with open('../inoutdir/long.json', 'r') as f:
json_data = json.load(f)
# 打开视频文件
cap = cv2.VideoCapture('../inoutdir/long.mp4')
current_frame = 0
# 配置日志记录
logging.basicConfig(level=logging.INFO, format='%(asctime)s [Frame %(frame)d / %(frame_all)d] %(message)s')
logger = logging.getLogger()
FLAG_SAVE_VIDEOS = False
if FLAG_SAVE_VIDEOS:
output_file = '../output/long_draw.mp4'
fourcc = cv2.VideoWriter_fourcc(*'mp4v')
frame_width = int(cap.get(3))
frame_height = int(cap.get(4))
out = cv2.VideoWriter(output_file, fourcc, 30, (frame_width, frame_height))
# 初始化时间统计
start_time = time.time()
total_frames = len(json_data)
while True:
cap.set(cv2.CAP_PROP_POS_FRAMES, current_frame)
ret, frame = cap.read()
if not ret:
break
# 记录时间戳
frame_timestamp = time.time()
# 从JSON中获取当前帧的检测结果
if current_frame < len(json_data):
detections = json_data[current_frame]['dets']
# 在每个检测上绘制边界框
for det in detections:
x1, y1, x2, y2, score, class_id = det
color = (0, 255, 0) # 绿色边界框
label = f'{
int(class_id)},{
score:.2f}'
cv2.rectangle(frame, (int(x1), int(y1)), (int(x2), int(y2)), color, 2)
# 计算文本位置以确保在框内
text_x = int(x1)
text_y = int(y1) - 10
if text_y - 10 < 0:
text_y = int(y1) + 20 # 如果文本位置超出了帧的上边界,则将其放在边界框的下方
cv2.putText(frame, label, (text_x, text_y), cv2.FONT_HERSHEY_SIMPLEX, 0.5, color, 2)
if FLAG_SAVE_VIDEOS:
out.write(frame) # 将当前帧写入输出视频
current_frame += 1
else:
# 显示当前帧
cv2.imshow('Video Frame', frame)
# 等待按键输入
key = cv2.waitKey(0) # 使用较短的等待时间以确保视频正常播放
if key == 27: # ESC
break
elif key == ord('q'): # Q 键(往回跳一帧)
if current_frame > 0:
current_frame -= 1
elif key == ord('w'): # W 键(往前播放一帧)
if current_frame < len(json_data) - 1:
current_frame += 1
# 计算每一帧消耗的时间并记录到日志中
frame_processing_time = time.time() - frame_timestamp
logger.info(f'Frame processed in {
frame_processing_time:.4f} seconds',extra={
'frame': current_frame, 'frame_all': total_frames})
# 计算总共消耗的时间
total_processing_time = time.time() - start_time
average_frame_time = total_processing_time / total_frames if total_frames > 0 else 0
print(total_processing_time)
print(average_frame_time)
# 释放视频文件、关闭窗口和输出视频文件
cap.release()
if FLAG_SAVE_VIDEOS:
out.release()
cv2.destroyAllWindows()