单目相机自拍器¶
此示例需要运行 TK library (用于打开文件对话框)
还需要人脸检测模型,请查看 这个教程 学习如何编译一个。
运行此示例需要 双目相机 , 它可以是 BW1097 - RaspberryPi 计算模块 , BW1098OBC - USB3 板载摄像头版 或使用 DepthAI 单目相机 自定义设置。
源代码¶
import cv2
import depthai
device = depthai.Device('', False)
pipeline = device.create_pipeline(config={
'streams': ['left', 'right', 'metaout'],
'ai': {
"blob_file": "/path/to/face-detection-retail-0004.blob",
"blob_file_config": "/path/to/face-detection-retail-0004.json",
},
'camera': {'mono': {'resolution_h': 720, 'fps': 30}},
})
if pipeline is None:
raise RuntimeError('Pipeline creation failed!')
detections = []
face_frame_left = None
face_frame_right = None
while True:
nnet_packets, data_packets = pipeline.get_available_nnet_and_data_packets()
for nnet_packet in nnet_packets:
detections = list(nnet_packet.getDetectedObjects())
for packet in data_packets:
if packet.stream_name == 'left' or packet.stream_name == 'right':
frame = packet.getData()
img_h = frame.shape[0]
img_w = frame.shape[1]
for detection in detections:
left = int(detection.x_min * img_w)
top = int(detection.y_min * img_h)
right = int(detection.x_max * img_w)
bottom = int(detection.y_max * img_h)
face_frame = frame[top:bottom, left:right]
if face_frame.size == 0:
continue
cv2.imshow(f'face-{packet.stream_name}', face_frame)
if packet.stream_name == 'left':
face_frame_left = face_frame
else:
face_frame_right = face_frame
key = cv2.waitKey(1)
if key == ord('q'):
break
if key == ord(' ') and face_frame_left is not None and face_frame_right is not None:
from tkinter import Tk, messagebox
from tkinter.filedialog import asksaveasfilename
Tk().withdraw()
filename = asksaveasfilename(defaultextension=".png", filetypes=(("Image files", "*.png"),("All Files", "*.*")))
joined_frame = cv2.hconcat([face_frame_left, face_frame_right])
cv2.imwrite(filename, joined_frame)
messagebox.showinfo("Success", "Image saved successfully!")
Tk().destroy()
del pipeline
del device
说明¶
我们的网络返回它检测到的面的边界框(将它们存储在 detections
数组中)。
因此,在此示例中,我们必须做两件事: 裁剪框架 以仅包含脸部并将其 保存 到用户指定的位置。
执行裁剪¶
裁剪框架 要求我们修改 示例-访问 DepthAI 相机所需的最少代码 的代码, 这样我们就不会产生矩形的两个点,而是需要全部四个点:其中两个点决定裁剪的开始( top
开始Y轴裁剪, left
开始X轴裁剪),另外两个点作为裁剪的结束( bottom
结束Y轴裁剪, right
结束X轴裁剪)。
left = int(detection.x_min * img_w)
top = int(detection.y_min * img_h)
right = int(detection.x_max * img_w)
bottom = int(detection.y_max * img_h)
现在,由于我们的帧是 HWC
f 格式(高度、宽度、通道),我们首先裁剪 Y 轴(高度),然后裁剪X轴(宽度)。所以裁剪代码是这样的:
face_frame = frame[top:bottom, left:right]
现在,还有一件事要做。因为有时网络可能会产生这样的边界框,当被裁剪后会产生一个空框,我们必须保证自己不受这种情况的影响,因为如果在空框的情况下调用 cv2.imshow
会抛出一个错误。
if face_frame.size == 0:
continue
cv2.imshow('face', face_frame)
稍后,由于我们有两台相机同时工作,我们将把显示的画面分配给左面或右面画面变量,这将有助于我们以后保存图像。
if packet.stream_name == 'left':
face_frame_left = face_frame
else:
face_frame_right = face_frame
保存帧¶
为了 保存图片 我们需要两步:
将左右两台相机的脸部画面合并为一帧。
将准备好的框架保存到磁盘中。
值得庆幸的是,OpenCV 已经把这一切都解决了,所以对于每一个点,我们只用一行代码就可以了。 调用 cv2.hconcat
进行帧合并,调用 cv2.imwrite
存储图像。
其余的代码,利用 tkinter
包, 是可选的,如果你不需要用户交互来保存帧,可以删除。
在这个例子中,我们使用 tkinter
来保存两个对话框:
获取目标文件路径(存储为
filepath
),允许我们调用cv2.imwrite
,因为它需要路径作为第一个参数。确认文件已成功保存。
key = cv2.waitKey(1)
if key == ord('q'):
break
if key == ord(' ') and face_frame_left is not None and face_frame_right is not None:
from tkinter import Tk, messagebox
from tkinter.filedialog import asksaveasfilename
Tk().withdraw()
filename = asksaveasfilename(defaultextension=".png", filetypes=(("Image files", "*.png"),("All Files", "*.*")))
joined_frame = cv2.hconcat([face_frame_left, face_frame_right])
cv2.imwrite(filename, joined_frame)
messagebox.showinfo("Success", "Image saved successfully!")
Tk().destroy()
有疑问?
我们很乐意为您提供代码或其他问题的帮助。