赞
踩
PyQt5实现打开可见光相机摄像头的功能,我们之前已经介绍过了,具体可参考:https://blog.csdn.net/WYKB_Mr_Q/article/details/129827685
上篇文章中我们介绍了奥比中光深度相机基于Python的环境配置部分。具体可参考:https://blog.csdn.net/WYKB_Mr_Q/article/details/137040226
这篇文章我们在配置好Python环境的基础上,使用PyQt5写个界面,并且设计逻辑,通过点击一个设计好的按钮来打开深度相机。深度相机的打开方法和可见光相机的打开方法略有不同,可见光相机可以利用OpenCV来直接调用,奥比中光深度相机主要是利用官方给出的SDK源码来调用。本文中,我们借鉴官方源码,将调用深度相机的主要代码提取出来,并和我们自己写的代码结合,实现在PyQt5界面中通过点击按钮打开深度相机。
官方给出了打开深度相机的Python SDK源码,链接为:https://github.com/orbbec/pyorbbecsdk
其中也包含了一些.py示例文件,存储在pyorbbecsdk/examples
文件夹中,我们找到 “depth_viewer.py” 文件,该文件的主要作用是为了调用深度相机,显示深度图像的。咱们可以先连接上奥比中光深度相机,运行一下该代码试一试,看看是否能够正常运行,展示出深度视频流。如果一切正常,你就可以看到如下界面了。
下面部分是 “depth_viewer.py” 文件的源代码:
from pyorbbecsdk import Pipeline from pyorbbecsdk import Config from pyorbbecsdk import OBSensorType, OBFormat from pyorbbecsdk import OBError import cv2 import numpy as np import time ESC_KEY = 27 PRINT_INTERVAL = 1 # seconds MIN_DEPTH = 20 # 20mm MAX_DEPTH = 10000 # 10000mm # 管理时间流,这部分不用管 class TemporalFilter: def __init__(self, alpha): self.alpha = alpha self.previous_frame = None def process(self, frame): if self.previous_frame is None: result = frame else: result = cv2.addWeighted(frame, self.alpha, self.previous_frame, 1 - self.alpha, 0) self.previous_frame = result return result def main(): # 配置深度相机文件 config = Config() pipeline = Pipeline() temporal_filter = TemporalFilter(alpha=0.5) try: # 调用深度摄像头 profile_list = pipeline.get_stream_profile_list(OBSensorType.DEPTH_SENSOR) assert profile_list is not None try: # 配置深度视频流参数,包括视频帧长宽,视频流格式,以及每秒采集的视频帧数 depth_profile = profile_list.get_video_stream_profile(640, 0, OBFormat.Y16, 30) except OBError as e: print("Error: ", e) depth_profile = profile_list.get_default_video_stream_profile() assert depth_profile is not None print("depth profile: ", type(depth_profile)) config.enable_stream(depth_profile) except Exception as e: print(e) return pipeline.start(config) last_print_time = time.time() while True: try: frames = pipeline.wait_for_frames(100) if frames is None: continue depth_frame = frames.get_depth_frame() if depth_frame is None: continue width = depth_frame.get_width() height = depth_frame.get_height() scale = depth_frame.get_depth_scale() depth_data = np.frombuffer(depth_frame.get_data(), dtype=np.uint16) depth_data = depth_data.reshape((height, width)) depth_data = depth_data.astype(np.float32) * scale depth_data = np.where((depth_data > MIN_DEPTH) & (depth_data < MAX_DEPTH), depth_data, 0) depth_data = depth_data.astype(np.uint16) # Apply temporal filtering depth_data = temporal_filter.process(depth_data) center_y = int(height / 2) center_x = int(width / 2) center_distance = depth_data[center_y, center_x] current_time = time.time() if current_time - last_print_time >= PRINT_INTERVAL: print("center distance: ", center_distance) last_print_time = current_time depth_image = cv2.normalize(depth_data, None, 0, 255, cv2.NORM_MINMAX, dtype=cv2.CV_8U) depth_image = cv2.applyColorMap(depth_image, cv2.COLORMAP_JET) cv2.imshow("Depth Viewer", depth_image) key = cv2.waitKey(1) if key == ord('q') or key == ESC_KEY: break except KeyboardInterrupt: break pipeline.stop() if __name__ == "__main__": main()
我们主要是想将调用奥比中光深度相机的关键部分提取出来,并应用在我们自己的代码中。
由于官方给的SDK源码文件较多,如果全部复制到我们的项目中,显得项目很臃肿。
经过我们不断的尝试和测试,发现如果要正常调用深度相机,正常运行 “depth_viewer.py” 文件,只需要将 “OrbbecSDK.dll
” 和 “pyorbbecsdk.pyd
” 文件复制出去就可以。
就是下面这三个文件在一个文件夹里,就可以正常调用深度相机了,其余官方提供的文件都可以不要了。这样看起来是不是简单多了?
这里主要参考我之前的博客,https://blog.csdn.net/WYKB_Mr_Q/article/details/129827685,不再做详细介绍。
我们将构建的ui代码放置到ui_code文件夹里,命名为depth_camera.py,我们这里做一个如下简单的界面做测试:
通过以下两行代码,实现点击按钮与函数功能的连接。
self.pushButton.clicked.connect(self.open_camera) # 点击第一个按钮运行打开摄像头的函数
self.pushButton_2.clicked.connect(self.close_camera) # 点击第二个按钮运行关闭摄像头的函数
通过以下代码可以实现视频流的调用,并将深度视频帧转化为伪彩色图像。
self.config = Config() self.pipeline = Pipeline() # 获取深度摄像头的所有流配置,包括流分辨率、帧速率和帧格式 profile_list = self.pipeline.get_stream_profile_list(OBSensorType.DEPTH_SENSOR) # 选择分辨率打开流 depth_profile = profile_list.get_video_stream_profile(1280, 800, OBFormat.Y16, 10) self.config.enable_stream(depth_profile) self.pipeline.start(self.config) self.condition = True while self.condition: try: # 以阻塞方式等待数据帧,数据帧是包含配置中启用的所有流的帧数据的复合帧,并将帧等待超时设置为 100ms frames = self.pipeline.wait_for_frames(100) if frames is None: continue depth_frame = frames.get_depth_frame() if depth_frame is None: continue width = depth_frame.get_width() height = depth_frame.get_height() scale = depth_frame.get_depth_scale() depth_data = np.frombuffer(depth_frame.get_data(), dtype=np.uint16) depth_data = depth_data.reshape((height, width)) depth_data = depth_data.astype(np.float32) * scale depth_data = np.where((depth_data > 20) & (depth_data < 10000), depth_data, 0) depth_data = depth_data.astype(np.uint16) # 将数据转化为伪彩色图像 depth_image = cv2.normalize(depth_data, None, 0, 255, cv2.NORM_MINMAX, dtype=cv2.CV_8U) depth_image = cv2.applyColorMap(depth_image, cv2.COLORMAP_JET)
我们主要通过保存当前视频帧,并读取展示视频帧的方式显示视频流。以下函数可以实现视频帧保存本地,读取并居中显示到设计好的界面上。
# 展示伪彩色图像功能函数
def show_pic_func(self, jet_image):
cv2.imwrite("./read_image_copy.png", jet_image)
img = QPixmap("./read_image_copy.png")
w = img.width()
h = img.height()
ratio = max(w / self.label.width(), h / self.label.height())
img.setDevicePixelRatio(ratio)
self.label.setAlignment(Qt.AlignCenter)
self.label.setPixmap(img)
在显示视频帧时,需要调用cv2.waitkey()
函数,不然显示出来的视频帧是灰色的,看不到图像。
self.key = cv2.waitKey(1)
if self.key == ord('q') or self.key == 27:
break
关闭相机主要依靠pipeline.stop()
函数实现,由于我们在打开摄像头时利用了 self.condition 的值,并将其设置为True
,因此这里我们需要将其设置为False
来终止循环语句。
# 关闭相机
def close_camera(self):
self.condition = False
self.pipeline.stop()
# 将相机id设置为None
self.CAM_NUM = None
self.pushButton.setEnabled(True)
self.pushButton_2.setEnabled(False)
注意我们调用了ui界面设计生成的.py文件,命名为depth_camera.py,并放置到ui_code文件夹中,所以我们这里的调用代码为from ui_code.depth_camera import Ui_MainWindow
,这里根据自己的命名做对应的更改。
import sys from pyorbbecsdk import Pipeline from pyorbbecsdk import Config from pyorbbecsdk import OBSensorType, OBFormat from pyorbbecsdk import OBError from PyQt5.QtWidgets import * from PyQt5.QtGui import * from PyQt5.QtCore import * import cv2 import numpy as np import time from ui_code.depth_camera import Ui_MainWindow class MainWindow(QMainWindow, Ui_MainWindow): def __init__(self, parent=None): super(MainWindow, self).__init__(parent) # UI界面 self.setupUi(self) self.CAM_NUM = 0 self.background() self.condition = None def background(self): self.pushButton.clicked.connect(self.open_camera) self.pushButton_2.clicked.connect(self.close_camera) self.pushButton.setEnabled(True) # 初始状态不能关闭摄像头 self.pushButton_2.setEnabled(False) # 展示伪彩色图像功能函数 def show_pic_func(self, jet_image): cv2.imwrite("./read_image_copy.png", jet_image) img = QPixmap("./read_image_copy.png") w = img.width() h = img.height() ratio = max(w / self.label.width(), h / self.label.height()) img.setDevicePixelRatio(ratio) self.label.setAlignment(Qt.AlignCenter) self.label.setPixmap(img) def temporal_filter(self, frame, alpha, previous_frame=None): if previous_frame is None: result = frame else: result = cv2.addWeighted(frame, alpha, previous_frame, 1 - alpha, 0) previous_frame = result return result def open_camera(self): self.label.setEnabled(True) # 选择相机型号 self.CAM_NUM = self.comboBox.currentIndex() # 支持奥比中光相机 if self.CAM_NUM == 0: # 可以关闭摄像头 self.pushButton_2.setEnabled(True) self.pushButton.setEnabled(False) self.config = Config() self.pipeline = Pipeline() # 获取深度摄像头的所有流配置,包括流分辨率、帧速率和帧格式 profile_list = self.pipeline.get_stream_profile_list(OBSensorType.DEPTH_SENSOR) # 选择分辨率打开流 depth_profile = profile_list.get_video_stream_profile(1280, 800, OBFormat.Y16, 10) self.config.enable_stream(depth_profile) self.pipeline.start(self.config) self.condition = True while self.condition: try: # 以阻塞方式等待数据帧,数据帧是包含配置中启用的所有流的帧数据的复合帧,并将帧等待超时设置为 100ms frames = self.pipeline.wait_for_frames(100) if frames is None: continue depth_frame = frames.get_depth_frame() if depth_frame is None: continue width = depth_frame.get_width() height = depth_frame.get_height() scale = depth_frame.get_depth_scale() depth_data = np.frombuffer(depth_frame.get_data(), dtype=np.uint16) depth_data = depth_data.reshape((height, width)) depth_data = depth_data.astype(np.float32) * scale depth_data = np.where((depth_data > 20) & (depth_data < 10000), depth_data, 0) depth_data = depth_data.astype(np.uint16) # Apply temporal filtering depth_data = self.temporal_filter(depth_data, alpha=0.5) depth_image = cv2.normalize(depth_data, None, 0, 255, cv2.NORM_MINMAX, dtype=cv2.CV_8U) depth_image = cv2.applyColorMap(depth_image, cv2.COLORMAP_JET) # 展示伪彩色深度图像 self.show_pic_func(depth_image) self.key = cv2.waitKey(1) if self.key == ord('q') or self.key == 27: break except KeyboardInterrupt: break else: QMessageBox.information(self, "警告", "我们暂时仅支持奥比中光,请选择奥比中光相机!", QMessageBox.Ok) # 关闭相机 def close_camera(self): self.condition = False self.pipeline.stop() self.CAM_NUM = None self.pushButton.setEnabled(True) self.pushButton_2.setEnabled(False) if __name__ == "__main__": app = QApplication(sys.argv) main = MainWindow() main.show() sys.exit(app.exec_())
该专栏博文地址:
界面开发(1) — PyQt5环境配置
界面开发(2)— 使用PyQt5制作用户登陆界面
界面开发(3)— PyQt5用户登录界面连接数据库
界面开发(4)— PyQt5实现打开图像及视频播放功能
界面开发(5)— PyQt5实现打开摄像头采集视频功能
奥比中光深度相机(一) — 环境配置
日常学习记录,一起交流讨论吧!侵权联系~
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。