Realsense深度相机+pyqt5+应用案例(基础篇1)

主要Python环境:

python==3.7.4;

pyrealsense2==2.38.1.2225;

pyqt5==5.11.2;

numpy=1.17.0; 

opencv-python==4.2.0.32;

上述为笔者的环境配置,若无必要不用修改。


前言

本教程旨在整理本人多年来使用Intel公司出品的Realsense深度相机相关的开发经验和案例,涉及的主要内容有:Realsense D435i深度相机API的基本操作、Pyqt的基本使用、结合计算机视觉的一些应用案例。希望能够帮助到有需要的同学。

一、Realsense D435i深度相机

有关Realsense D435i深度相机的详细资料请参考Intel官网链接https://www.intelrealsense.com/depth-camera-d435i/

本基础篇教程主要介绍一些基本功能,包括RGB图和深度图的读取与显示、深度画面预设、IMU数据的读取、深度图的几种后处理方式等,并同时介绍相关的PyQt知识。

二、使用步骤

1.引入库

代码如下:

import cv2
import numpy as np
import math
from PyQt5 import QtCore, QtGui, QtWidgets
import sys
from PyQt5.QtGui import *
from PyQt5.QtWidgets import *
import pyrealsense2 as rs

2.初始化Ui_MainWindow

首先实例化pyqt的窗体类Ui_MainWindow,代码如下:

class Ui_MainWindow(QMainWindow):
    def __init__(self):
        super(Ui_MainWindow, self).__init__()
        self.timer_camera = QtCore.QTimer()  # 初始化定时器
        self.timer_realsense = QtCore.QTimer()
        # 定义realsense视频数据流
        self.pipeline = rs.pipeline()
        # 定义IMU数据流
        self.imu_pipeline = rs.pipeline()
        self.imu_config = rs.config()
        self.imu_config.enable_stream(rs.stream.accel, rs.format.motion_xyz32f, 63)  # acceleration
        self.imu_config.enable_stream(rs.stream.gyro, rs.format.motion_xyz32f, 200)  # gyroscope
        # 定义点云
        self.pc = rs.pointcloud()
        self.config = rs.config()
        # 设置对其方式为:深度图向RGB图对齐
        self.align_to = rs.stream.color
        self.alignedFs = rs.align(self.align_to)
        # 创建着色器(其实这个可以替代opencv的convertScaleAbs()和applyColorMap()函数)
        self.colorizer = rs.colorizer()
        # 深度图像画面预设
        self.preset = 0
        # 记录点云的数组
        self.vtx = None
        self.height = 720
        self.width = 1280
        # 设置字体
        self.font2 = QFont()
        self.font2.setFamily("宋体")
        self.font2.setPixelSize(22)
        self.font2.setBold(True)
        # 深度相机返回的图像和三角函数值
        self.depth_image = None
        self.img_r = None
        self.pitch = None
        self.roll = None

上述代码中需要注意的是画面预设self.preset,对于不同型号的相机画面预设配置模式是不一样的,可以参考Intel官方提供的Intel RealSense Viewer,对于D435i相机,如下图所示:


其中self.preset = 0 即代表第一行的预设Custom,往下同理直接通过序号调用。

3.定义setupUi

接下来,在setupUi中设置自己的UI界面,包括各类窗体控件(label、button、groupbox等)的位置、大小、属性等内容,代码如下:

    def setupUi(self, MainWindow):
        MainWindow.setObjectName("MainWindow")
        MainWindow.resize(1920, 1080)
        MainWindow.setAcceptDrops(True)

        MainWindow.setAutoFillBackground(False)
        MainWindow.setStyleSheet("background-color: rgb(240, 248, 255);")

        self.centralwidget = QtWidgets.QWidget(MainWindow)
        self.centralwidget.setObjectName("centralwidget")
        # 所有控件的定义要从此处才能定义
        # 显示RGB图
        self.label_show_camera = QtWidgets.QLabel(self.centralwidget)
        self.label_show_camera.setGeometry(QtCore.QRect(0, 0, 960, 540))
        self.label_show_camera.setStyleSheet("background-color: rgb(255,255,255);")
        self.label_show_camera.setObjectName("label_show_camera")
        self.label_show_camera.setScaledContents(True)
        # 显示深度图
        self.label_show_camera1 = QtWidgets.QLabel(self.centralwidget)
        self.label_show_camera1.setGeometry(QtCore.QRect(960, 0, 960, 540))
        self.label_show_camera1.setStyleSheet("background-color: rgb(255,255,255);")
        self.label_show_camera1.setObjectName("label_show_camera1")
        self.label_show_camera1.setScaledContents(True)
        # 显示相机位姿
        self.label_show_camera2 = QtWidgets.QLabel(self.centralwidget)
        self.label_show_camera2.setGeometry(QtCore.QRect(960, 560, 512, 512))
        self.label_show_camera2.setStyleSheet("background-color: rgb(255,255,255);")
        self.label_show_camera2.setObjectName("label_show_camera2")
        self.label_show_camera2.setScaledContents(True)

        # 显示目标坐标
        self.label_show_performance = QtWidgets.QLabel(self.centralwidget)
        self.label_show_performance.setGeometry(QtCore.QRect(300, 560, 600, 30))
        self.label_show_performance.setObjectName("label_show_performance")
        self.label_show_performance.setScaledContents(True)
        self.label_show_performance.setStyleSheet("color:blue")
        self.label_show_performance.setFont(self.font2)

        # 显示加速度
        self.label_show_accel = QtWidgets.QLabel(self.centralwidget)
        self.label_show_accel.setGeometry(QtCore.QRect(1480, 660, 600, 30))
        self.label_show_accel.setObjectName("label_show_accel")
        self.label_show_accel.setScaledContents(True)
        self.label_show_accel.setStyleSheet("color:blue")
        self.label_show_accel.setFont(self.font2)

        # 显示欧拉角
        self.label_show_pose = QtWidgets.QLabel(self.centralwidget)
        self.label_show_pose.setGeometry(QtCore.QRect(1480, 760, 600, 30))
        self.label_show_pose.setObjectName("label_show_pose")
        self.label_show_pose.setScaledContents(True)
        self.label_show_pose.setStyleSheet("color:blue")
        self.label_show_pose.setFont(self.font2)

        # 开启相机的按钮
        self.button_open_camera = QtWidgets.QPushButton(self.centralwidget)
        self.button_open_camera.setGeometry(QtCore.QRect(20, 560, 200, 50))
        self.button_open_camera.setStyleSheet("color: rgb(255, 255, 255);\n"
                                              "border-color: rgb(0, 0, 0);\n"
                                              "background-color: rgb(50,50,237);")
        self.button_open_camera.setFlat(False)
        self.button_open_camera.setObjectName("button_open_camera")
        self.button_open_camera.setFont(QFont("宋体", 12, QFont.Bold))


        MainWindow.setCentralWidget(self.centralwidget)
        self.retranslateUi(MainWindow)
        QtCore.QMetaObject.connectSlotsByName(MainWindow)

4.设置控件文字显示

接下来,我们要设置窗体控件的初始显示内容,并建立控件与对应的触发事件函数之间的联系,代码如下:

    def retranslateUi(self, MainWindow):
        _translate = QtCore.QCoreApplication.translate
        MainWindow.setWindowTitle(_translate("MainWindow", "Realsense D435i"))
        self.button_open_camera.setText(_translate("MainWindow", "Start Detection"))
        self.label_show_accel.setText(_translate("MainWindow", "Accel"))
        self.label_show_pose.setText(_translate("MainWindow", "Pose"))

    def slot_init(self):  # 建立通信连接
        self.button_open_camera.clicked.connect(self.button_open_camera_click)
        self.timer_realsense.timeout.connect(self.get_photo)

5.定义事件函数

在上一步中我们建立了与两个事件函数的通信连接,其中self.button_open_camera_click用于定义按下button的事件,self.get_photo用于定义定时器打开的事件。

按下button会开启深度相机的数据流并打开定时器,定时器开启后会调用self.get_photo函数获取深度相机返回的图像和IUM数据等,代码分别如下:

    def button_open_camera_click(self):
        if not self.timer_camera.isActive():
            # 开启深度相机数据流
            profile = self.pipeline.start(self.config)
            depth_sensor = profile.get_device().first_depth_sensor()
            # 开启IMU数据流
            imu_profile = self.imu_pipeline.start(self.imu_config)
            # 设置画面预设
            sensor = self.pipeline.get_active_profile().get_device().query_sensors()[0]
            sensor.set_option(rs.option.visual_preset, self.preset)
            self.timer_realsense.start(50)
            self.timer_camera.start(50)
    def get_photo(self):
        # 从数据流中读取一帧并进行对齐
        frames = self.pipeline.wait_for_frames()
        aligned_frames = self.alignedFs.process(frames)
        # 分别获得深度帧和RGB帧
        depth_frame = aligned_frames.get_depth_frame()
        color_frame = aligned_frames.get_color_frame()
        # 获取IMU数据
        imu_frames = self.imu_pipeline.wait_for_frames()
        accel_frame = imu_frames.first_or_default(rs.stream.accel, rs.format.motion_xyz32f)
        #gyro_frame = imu_frames.first_or_default(rs.stream.gyro, rs.format.motion_xyz32f)
        accel_info = accel_frame.as_motion_frame().get_motion_data()
        gx, gy, gz = accel_info.x, accel_info.y, accel_info.z
        self.label_show_accel.setText('Accel  gx:' + format(gx, '.3f') + ' gy:' + format(gy, '.3f') + ' gz:' + format(gz, '.3f'))
        # 计算欧拉角
        # 俯仰角
        pitch = int(180/math.pi * math.atan(abs(gz)/math.sqrt(gx * gx + gy * gy)))
        # 滚转角
        roll = int(180/math.pi * math.atan(abs(gx)/math.sqrt(gy * gy + gz * gz)))
        # 计算出三角函数值方便坐标转换
        vector = math.sqrt(gx * gx + gy * gy + gz * gz)
        sin_pitch = abs(gz) / vector
        cos_pitch = math.sqrt(gx * gx + gy * gy) / vector
        sin_roll = abs(gx) / vector
        cos_roll = abs(gy * gy + gz * gz) / vector
        self.label_show_pose.setText('Pose  pitch:' + str(pitch) + '° roll:' + str(roll) + '°')
        # 获取帧的宽高
        self.width = depth_frame.get_width()
        self.height = depth_frame.get_height()
        # 获取点云
        self.pc.map_to(color_frame)
        points = self.pc.calculate(depth_frame)
        self.vtx = np.asanyarray(points.get_vertices())
        self.vtx = np.reshape(self.vtx, (self.height, self.width, -1))
        # 将深度帧和RBG帧转换为数组
        img_r = np.asanyarray(color_frame.get_data())
        depth_image = np.asanyarray(self.colorizer.colorize(depth_frame).get_data())

        self.img_r = img_r
        self.depth_image = depth_image
        self.pitch = (sin_pitch, cos_pitch)
        self.roll = (sin_roll, cos_roll)
        showImage = QtGui.QImage(img_r.data, img_r.shape[1], img_r.shape[0], QtGui.QImage.Format_RGB888)
        self.label_show_camera.setPixmap(QtGui.QPixmap.fromImage(showImage))  # 读取图片到label_show_camera控件中
        showImage1 = QtGui.QImage(depth_image.data, depth_image.shape[1], depth_image.shape[0],
                                  QtGui.QImage.Format_RGB888)
        self.label_show_camera1.setPixmap(QtGui.QPixmap.fromImage(showImage1))

6.启动窗体

记得最后一定要添加如下代码启动窗体:

if __name__ == "__main__":
    app = QApplication(sys.argv)
    mainWindow = QMainWindow()
    ui = Ui_MainWindow()
    ui.setupUi(mainWindow)
    ui.slot_init()
    mainWindow.show()
    sys.exit(app.exec_())

7.效果

可以看到窗体成功显示了RGB图和与之对应的深度图(由于房间没开灯,所以RGB图是黑的)。右下角空白窗体用于绘制相机位姿图,这个在下一篇文章会介绍。右下角控件显示了当前的重力加速度的三个分力和计算出的相机姿态角,分别为俯仰角5°,滚转角0°。

总结

以上就是今天要讲的内容,本文介绍了Realsense D435i深度相机最基本的一些接口和操作,将RGB图、深度图以及IMU数据通过PyQt显示在了窗体应用程序中,下一篇文章将继续介绍深度图的后处理方法和相机位姿的绘制。

欢迎点赞👍、收藏⭐、留言📝、讨论,如有错误敬请指正!

  • 3
    点赞
  • 20
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 4
    评论
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

我每样都懂yi点点

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值