我在Python中使用OpenCV,试图仅在视频帧中出现特定类型的对象/标签时(例如“雨伞”)录制/保存这些帧。
问题:
它正确地从首次在帧中发现所述对象/标签的实例开始保存帧,但如果在接下来的几帧中没有该对象/标签,并且在几帧之后才出现,那么这些帧不会被保存到我正在保存的mp4文件中。
它只保存了带有所述对象的第一组连续帧,而不保存后续的帧。
在阅读了此链接中的建议后,我通过将帧写入步骤放入for循环中来编辑代码,如下所示:
OpenCV – 基于特定条件保存视频片段
我尝试改进的帧写入代码片段
# 逐帧保存视频
for frame_numb in range(total_frames):
if i == '':
pass
else:
if "umbrella" in label:
print("umbrella in labels")
# 可能需要更改的导致问题的部分
out_vid.write(frame[frame_numb])
上述代码更改的结果:
它只创建了一个256kb的文件,并且文件无法打开/未写入任何内容
如果我在代码中进行以下更改,那么它只会保存视频中满足条件的第一帧,并在整个时间内重复播放同一帧
# 逐帧保存视频
for frame_numb in range(total_frames):
if i == '':
pass
else:
if "umbrella" in label:
print("umbrella in labels")
# 可能需要更改的导致问题的部分
out_vid.write(frame)
为参考提供更大块的代码如下:
def vid_objects_detection(type=0, confidence_threshold=0.5, image_quality=416):
classes = []
# 从coco文本文件中读取类别名称并插入到classes列表中
with open("coco.names", "r") as f:
classes = [line.strip() for line in f.readlines()]
net = cv2.dnn.readNet("yolov3-tiny.weights", "yolov3-tiny.cfg") # 使用tiny版本的权重和配置文件
layer_names = net.getLayerNames()
output_layers = [layer_names[i[0] - 1] for i in net.getUnconnectedOutLayers()]
# 加载视频
cap = cv2.VideoCapture(type) # 使用0表示网络摄像头
_, frame = cap.read()
height, width, channels = frame.shape
# 提供编解码器以将帧写入视频
fourcc = cv2.VideoWriter_fourcc(*'MP4V')
# 以名称和大小写入视频。应与原始视频的尺寸(宽度,高度)相同
out_vid = cv2.VideoWriter('obj_detect4_'+str(type), fourcc, 20.0, (width,height))
font = cv2.FONT_HERSHEY_COMPLEX_SMALL
starting_time = time.time()
frame_id = 0
while True:
_, frame = cap.read()
frame_id +=1
total_frames = int(cap.get(cv2.CAP_PROP_FRAME_COUNT))
height, width, channels = frame.shape
blob = cv2.dnn.blobFromImage(frame, 0.00392, (image_quality, image_quality), (0, 0, 0), True, crop=False)
net.setInput(blob)
outs = net.forward(output_layers)
# 用于在屏幕上显示信息
class_ids = []
confidences = []
boxes = []
for out in outs:
for detection in out:
# 计算分数,类别ID,置信度
if confidence > confidence_threshold:
# 计算中心_x,中心_y,宽度,高度,x,y
boxes.append([x, y, w, h])
confidences.append(float(confidence))
class_ids.append(class_id)
print("confidences:", confidences)
print(class_ids)
print("boxes", boxes)
indexes = cv2.dnn.NMSBoxes(boxes, confidences, confidence_threshold, 0.4)
for i in range(len(boxes)):
if i in indexes:
x, y, w, h = boxes[i]
label = str(classes[class_ids[i]])
elapsed_time = time.time() - starting_time
fps = frame_id / elapsed_time
time_display = time.strftime("%a, %d%b%Y %H:%M:%S", time.localtime())
cv2.putText(frame,"|FPS: " + str(round(fps,3)), (10, 40), font, 1, (0,255,0), 1)
print(fps)
# 逐帧保存视频
if i == '':
pass
else:
if 'umbrella' in label:
out_vid.write(frame)
key = cv2.waitKey(5)
if key == 27:
break
cap.release()
out_vid.release()
cv2.destroyAllWindows()
# 调用函数
vid_objects_detection("walking.mp4")
我已经修剪了代码中的一些次要计算,并插入注释以减少代码长度
回答:
有时视频编解码器会执行所谓的关键帧压缩。这意味着,每隔10帧会完全存储一帧,而中间的所有其他帧则作为变化或增量存储。在这种情况下,当你尝试仅保存这些中间帧时,它们可能不会被保存。但是在这些情况下,如果你按顺序遍历每一帧,保存帧是有效的。
你可以注释掉行 out_vid = cv2.VideoWriter('obj_detect4_'+str(type), fourcc, 20.0, (width,height))
,并尝试仅根据你的条件从网络摄像头流中保存帧。