【Azure Kinect图像采集软件---python开发】


前言——附软件下载地址

上一篇博客中,基于pyk4a实现了使用单个Azure Kinect相机在python环境下进行图像采集,但是需要进行一定的环境配置,所以本文进行了一些改进,写了一个软件界面,并且进行了封装。有需要的朋友可自取

软件下载链接

!!!软件存放路径中不要有中文!!!
!!!软件存放路径中不要有中文!!!
!!!软件存放路径中不要有中文!!!

一、软件功能

1、官方SDK中dll文件的封装

该软件封装了Kinect的官方SDK中的相关dll文件
SDK中的dll文件
也封装了opencv、numpy、pyk4a等相关的包

2、软件使用pyqt5制作界面,基本功能有如下:

(1)、能够实时显示彩色视频流、实时显示伪彩色的深度视频流
(2)、能够自定义图像存储路径路径无中文字符
(3)、点击“拍照”后能够自动为所采集图像进行编号,方便科研数据整理
(4)、采集图像不满意,允许点击“撤销”按钮进行图像的删除,并且下一组图的编号自动更新
(5)、以Qlabel模仿控制台输出,方便错误检查

二、软件代码

1、主函数cap_img.py的原始代码

# -*- coding: utf-8 -*-
from Ui_jiemian import Ui_MainWindow
from PyQt5 import QtGui, QtWidgets
import sys
import os
from PyQt5 import QtWidgets 
from Ui_jiemian import Ui_MainWindow
from PyQt5.QtWidgets import QMainWindow, QMessageBox
import numpy as np
import cv2
import pyk4a
from pyk4a import PyK4A, Config, connected_device_count
from PyQt5.QtGui import QImage, QPixmap
from typing import Optional, Tuple
from PyQt5.QtCore import *
from PyQt5.QtGui import *



def color_depth(
    image: np.ndarray,
    clipping_range: Tuple[Optional[int], Optional[int]] = (None, None),
    colormap: int = cv2.COLORMAP_HSV,
) -> np.ndarray:
    if clipping_range[0] or clipping_range[1]:
        img = image.clip(clipping_range[0], clipping_range[1])
    else:
        img = image.copy()
    img = cv2.normalize(img, None, 0, 255, cv2.NORM_MINMAX, dtype=cv2.CV_8U)
    img = cv2.applyColorMap(img, colormap)
    return img

def display_video(self):
    try:
        self.cnt = connected_device_count()
        print("设备数为:", self.cnt  )
        self.label_6.setText(f"检测到设备数为: {self.cnt}" )
        if self.cnt == 1:
            self.k4a = PyK4A(
                Config(
                    color_resolution=pyk4a.ColorResolution.RES_3072P,   
                    depth_mode=pyk4a.DepthMode.WFOV_UNBINNED,
                    camera_fps =pyk4a.FPS.FPS_15          
                )
            )
            self.k4a.start()    
            while True:
                capture = self.k4a.get_capture()

                rgb_image_show = cv2.resize(capture.color, ( 406, 297))
                rows, cols = rgb_image_show.shape[:2]
                rgb_image_show = cv2.cvtColor(rgb_image_show, cv2.COLOR_BGR2RGB)
                show_RGB = QtGui.QImage(rgb_image_show.data,  cols,rows, cols*3, QImage.Format_RGB888)   #说明:QImage 函数中,如果 bytesPerline 参数不设置,则会默认按照 4 字节对齐的方式显示图像(如果不满足四字节对齐要求则不会使用零填充),对于不满足四字节对齐的影像在显示的时候就会出现上述失真问题,若将 bytesPerline 参数设置为 image.cols*image.channels() (如上述代码所示)则可解决图像显示失真问题(如上图显示结果)!!!
                self.label_2.setPixmap(QPixmap.fromImage(show_RGB))  # 在 GUI 界面上显示 QImage 对象
                
                depth_image_show = cv2.resize(color_depth(capture.transformed_depth, colormap=cv2.COLORMAP_JET), ( 406, 297))
                rows, cols = depth_image_show.shape[:2]
                depth_image_show = cv2.cvtColor(depth_image_show, cv2.COLOR_BGR2RGB)
                show_depth = QtGui.QImage(depth_image_show.data,  cols,rows, cols*3, QImage.Format_RGB888)
                self.label_3.setPixmap(QPixmap.fromImage(show_depth))  # 在 GUI 界面上显示 QImage 对象
                
                cv2.waitKey(0)
                
                if not self.k4a.opened :
                    print("视频流已关闭")
                    self.label_6.setText("视频流已关闭")
                    break 
        else:
            # 当设备数量不等于1时,弹出错误消息框
            QMessageBox.critical(None, "设备数异常", "请检查相机连接情况")
    except Exception as e:
        print(f"An error occurred: {e}")
        QMessageBox.critical(None, "相机连接异常", f"{e}")
   
def close_video(self):
    try:
        self.cnt = connected_device_count()
        self.cnt_label_text == self.cnt 
        if self.cnt_label_text == 1:
            self.k4a.stop()  
            white_back1 = np.ones((self.label_2.width(), self.label_2.height(), 4), dtype=np.uint8) * 255
            None_RGB = QtGui.QImage(white_back1.data,  self.label_2.width(),self.label_2.height(), self.label_2.height()*3, QImage.Format_RGB888)
            self.label_2.setPixmap(QPixmap.fromImage(None_RGB))
            white_back2 = np.ones((self.label_3.width(), self.label_3.height(), 4), dtype=np.uint8) * 255
            none_depth = QtGui.QImage(white_back2.data,  self.label_3.width(),self.label_3.height(), self.label_3.height()*3, QImage.Format_RGB888)
            self.label_3.setPixmap(QPixmap.fromImage(none_depth))
            print("空白背景填充")
            # self.label_6.setText("视频流已关闭")
        else:
            # 当设备数量不等于2时,弹出错误消息框
            QMessageBox.critical(None, "关闭异常", "设备数异常")
    except Exception as e:
        # 异常处理,可以在这里记录错误或采取其他措施
        QMessageBox.critical(None, "关闭方式错误", "相机未正常开启")
        
        
class MyMainWindow(QMainWindow, Ui_MainWindow):
    def __init__(self, parent=None):
        super(MyMainWindow, self).__init__(parent)   # 初始化父类
        self.setupUi(self)  # 继承 Ui_MainWindow 界面类
        self.label_2.setScaledContents(True)  # 调整 label 大小以适应图片大小
        self.label_3.setScaledContents(True)  # 调整 label 大小以适应图片大小
        self.checkBox.stateChanged.connect(self.on_state_changed)
        self.count = 0  # 该参数用于给所拍摄的照片进行编号

            
            
            
    def select_folder(self):
        
        current_dir = self.lineEdit.text()
        self.savepath = QtWidgets.QFileDialog.getExistingDirectory(None, "选取文件夹", current_dir)  # 起始路径为当前文本框中的路径
        print(self.savepath)
        self.label_6.setText("存储路径为:" + self.savepath)
        self.lineEdit.setText(self.savepath)   # 已修改

    def closeEvent(self, event):
        try:
            if self.k4a.opened:
                self.k4a.stop()
        except AttributeError:
                event.accept()

             
    def on_state_changed(self, state):
        if state == Qt.Checked:  # 选中
            display_video(self)
        else:
            close_video(self)
            
    def take_pictures(self):
        try:
            if not self.k4a.opened:
                print("相机未启动,请检查")
                self.label_6.setText("相机未启动,请检查")
            else:
                # 检查变量A是否定义
                try:
                    self.savepath
                except AttributeError:
                    print("请先确定存储路径")
                    self.label_6.setText("请先确定存储路径")
                    QMessageBox.information(None, "拍照失败", "请检查存储路径")
                else:
                    self.count += 1
                    Kinect_rgb_filename = f"{self.savepath}/rgb-{self.count}.png"
                    cv2.imwrite(Kinect_rgb_filename , self.k4a.get_capture().color)
                    
                    Kinect_depth_filename = f"{self.savepath}/depth-{self.count}.png"
                    cv2.imwrite(Kinect_depth_filename , self.k4a.get_capture().depth)
                    
                    Kinect_ir_filename = f"{self.savepath}/ir-{self.count}.png"
                    cv2.imwrite(Kinect_ir_filename , self.k4a.get_capture().ir)
                    
                    Kinect_morp_filename = f"{self.savepath}/morp-{self.count}.png"
                    cv2.imwrite(Kinect_morp_filename , self.k4a.get_capture().transformed_depth)
                    print(f"基于Kinect的\n rgb-{self.count}.png\n depth-{self.count}.png\n ir-{self.count}.png\n morp-{self.count}.png  已保存!")   
                    self.label_6.setText(f"基于Kinect的、rgb-{self.count}.png、depth-{self.count}.png、ir-{self.count}.png、morp-{self.count}.png  已保存!")
        except Exception as e:
            # 异常处理,可以在这里记录错误或采取其他措施
            QMessageBox.critical(None, "错误", "未检测到相机连接")
                
    def delete_pictures(self):    
        if self.count == 0 :
            print("暂无最新拍摄照片,请检查")
            self.label_6.setText("暂无最新拍摄照片,请检查")
            QMessageBox.information(None, "撤销失败", "暂无最新拍摄照片,请检查")
        else:
            try:
                os.remove(f"{self.savepath}/rgb-{self.count}.png")
                os.remove(f"{self.savepath}/depth-{self.count}.png")
                os.remove(f"{self.savepath}/ir-{self.count}.png")
                os.remove(f"{self.savepath}/morp-{self.count}.png")
                print(f"基于Kinect的\n rgb-{self.count}.png\n depth-{self.count}.png\n ir-{self.count}.png\n morp-{self.count}.png  已删除!")    
                self.count -= 1 
                print("下一张图片编号为:", format(self.count+1))
                self.label_6.setText(f"基于Kinect的rgb-{self.count}.png 、depth-{self.count}.png 、ir-{self.count}.png 、 morp-{self.count}.png  已删除!\n"  "下一张图片编号为:"+ format(self.count+1))
                return True
            except OSError as e:
                print("删除错误!")
                self.label_6.setText("删除错误!")
                QMessageBox.information(None, "删除错误!", "删除错误!")
                return False


if __name__ == '__main__':
    app = QtWidgets.QApplication(sys.argv)  # 初始化界面
    # MainWindow = QMainWindow()  # 创建主窗口
    myWin = MyMainWindow()  # 实例化 MyMainWindow 类,创建主窗口
    myWin.show()  # 在桌面显示控件 myWin
    sys.exit(app.exec_())  # 结束进程,退出程序


2、软件界面代码

软件界面使用QT Designer制作,相机开关使用了一个checkBox类来进行状态的切换

# -*- coding: utf-8 -*-

# Form implementation generated from reading ui file 'd:\Python\Image_camera\1_Kinect\jiemian.ui'
#
# Created by: PyQt5 UI code generator 5.15.6
#
# WARNING: Any manual changes made to this file will be lost when pyuic5 is
# run again.  Do not edit this file unless you know what you are doing.


from PyQt5 import QtCore, QtGui, QtWidgets


class Ui_MainWindow(object):
    def setupUi(self, MainWindow):
        MainWindow.setObjectName("MainWindow")
        MainWindow.resize(850, 550)
        MainWindow.setMinimumSize(QtCore.QSize(850, 550))
        MainWindow.setLayoutDirection(QtCore.Qt.LeftToRight)
        MainWindow.setTabShape(QtWidgets.QTabWidget.Triangular)
        self.centralwidget = QtWidgets.QWidget(MainWindow)
        self.centralwidget.setLayoutDirection(QtCore.Qt.LeftToRight)
        self.centralwidget.setAutoFillBackground(False)
        self.centralwidget.setObjectName("centralwidget")
        self.gridLayout = QtWidgets.QGridLayout(self.centralwidget)
        self.gridLayout.setContentsMargins(7, 0, 0, 0)
        self.gridLayout.setSpacing(0)
        self.gridLayout.setObjectName("gridLayout")
        self.frame = QtWidgets.QFrame(self.centralwidget)
        self.frame.setMinimumSize(QtCore.QSize(850, 550))
        self.frame.setStyleSheet("#frame {\n"
"\n"
"    background-color: rgba(203, 255, 181,50);\n"
"}\n"
"QPushButton{\n"
"    \n"
"}")
        self.frame.setFrameShape(QtWidgets.QFrame.StyledPanel)
        self.frame.setFrameShadow(QtWidgets.QFrame.Raised)
        self.frame.setObjectName("frame")
        self.verticalLayout = QtWidgets.QVBoxLayout(self.frame)
        self.verticalLayout.setSizeConstraint(QtWidgets.QLayout.SetMinAndMaxSize)
        self.verticalLayout.setContentsMargins(0, 0, 0, 0)
        self.verticalLayout.setSpacing(0)
        self.verticalLayout.setObjectName("verticalLayout")
        self.frame_2 = QtWidgets.QFrame(self.frame)
        sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Preferred, QtWidgets.QSizePolicy.Expanding)
        sizePolicy.setHorizontalStretch(0)
        sizePolicy.setVerticalStretch(1)
        sizePolicy.setHeightForWidth(self.frame_2.sizePolicy().hasHeightForWidth())
        self.frame_2.setSizePolicy(sizePolicy)
        self.frame_2.setFrameShape(QtWidgets.QFrame.StyledPanel)
        self.frame_2.setFrameShadow(QtWidgets.QFrame.Raised)
        self.frame_2.setObjectName("frame_2")
        self.horizontalLayout_4 = QtWidgets.QHBoxLayout(self.frame_2)
        self.horizontalLayout_4.setObjectName("horizontalLayout_4")
        self.label = QtWidgets.QLabel(self.frame_2)
        font = QtGui.QFont()
        font.setFamily("幼圆")
        font.setPointSize(19)
        font.setBold(True)
        font.setWeight(75)
        self.label.setFont(font)
        self.label.setAlignment(QtCore.Qt.AlignCenter)
        self.label.setObjectName("label")
        self.horizontalLayout_4.addWidget(self.label)
        self.verticalLayout.addWidget(self.frame_2)
        self.frame_3 = QtWidgets.QFrame(self.frame)
        sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Preferred, QtWidgets.QSizePolicy.Expanding)
        sizePolicy.setHorizontalStretch(0)
        sizePolicy.setVerticalStretch(9)
        sizePolicy.setHeightForWidth(self.frame_3.sizePolicy().hasHeightForWidth())
        self.frame_3.setSizePolicy(sizePolicy)
        self.frame_3.setFrameShape(QtWidgets.QFrame.StyledPanel)
        self.frame_3.setFrameShadow(QtWidgets.QFrame.Raised)
        self.frame_3.setObjectName("frame_3")
        self.verticalLayout_2 = QtWidgets.QVBoxLayout(self.frame_3)
        self.verticalLayout_2.setContentsMargins(0, 0, 0, 0)
        self.verticalLayout_2.setSpacing(0)
        self.verticalLayout_2.setObjectName("verticalLayout_2")
        self.frame_4 = QtWidgets.QFrame(self.frame_3)
        sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Preferred, QtWidgets.QSizePolicy.Expanding)
        sizePolicy.setHorizontalStretch(0)
        sizePolicy.setVerticalStretch(3)
        sizePolicy.setHeightForWidth(self.frame_4.sizePolicy().hasHeightForWidth())
        self.frame_4.setSizePolicy(sizePolicy)
        self.frame_4.setStyleSheet("QPushButton{\n"
"        \n"
"    background-color: rgb(255, 255, 255);\n"
"    \n"
"    color: rgb(0, 0, 0);\n"
"    \n"
"    border-radius:15px;\n"
"\n"
"}\n"
"QPushButton:hover {\n"
"    padding-bottom:2px\n"
"}\n"
"QPushButton:pressed {\n"
"    padding: 2px 2px 0 0;\n"
"\n"
"}\n"
"\n"
"QPushButton:released {\n"
"    padding: 0;\n"
"\n"
"}")
        self.frame_4.setFrameShape(QtWidgets.QFrame.StyledPanel)
        self.frame_4.setFrameShadow(QtWidgets.QFrame.Raised)
        self.frame_4.setObjectName("frame_4")
        self.horizontalLayout_6 = QtWidgets.QHBoxLayout(self.frame_4)
        self.horizontalLayout_6.setContentsMargins(1, 1, 1, 1)
        self.horizontalLayout_6.setSpacing(1)
        self.horizontalLayout_6.setObjectName("horizontalLayout_6")
        self.frame_13 = QtWidgets.QFrame(self.frame_4)
        self.frame_13.setFrameShape(QtWidgets.QFrame.StyledPanel)
        self.frame_13.setFrameShadow(QtWidgets.QFrame.Raised)
        self.frame_13.setObjectName("frame_13")
        self.verticalLayout_7 = QtWidgets.QVBoxLayout(self.frame_13)
        self.verticalLayout_7.setContentsMargins(0, 0, 0, 0)
        self.verticalLayout_7.setSpacing(0)
        self.verticalLayout_7.setObjectName("verticalLayout_7")
        self.frame_15 = QtWidgets.QFrame(self.frame_13)
        self.frame_15.setFrameShape(QtWidgets.QFrame.StyledPanel)
        self.frame_15.setFrameShadow(QtWidgets.QFrame.Raised)
        self.frame_15.setObjectName("frame_15")
        self.toolButton = QtWidgets.QToolButton(self.frame_15)
        self.toolButton.setGeometry(QtCore.QRect(230, 10, 71, 21))
        self.toolButton.setObjectName("toolButton")
        self.checkBox = QtWidgets.QCheckBox(self.frame_15)
        self.checkBox.setGeometry(QtCore.QRect(30, 10, 90, 30))
        self.checkBox.setObjectName("checkBox")
        self.verticalLayout_7.addWidget(self.frame_15)
        self.frame_16 = QtWidgets.QFrame(self.frame_13)
        self.frame_16.setFrameShape(QtWidgets.QFrame.StyledPanel)
        self.frame_16.setFrameShadow(QtWidgets.QFrame.Raised)
        self.frame_16.setObjectName("frame_16")
        self.pushButton_3 = QtWidgets.QPushButton(self.frame_16)
        self.pushButton_3.setGeometry(QtCore.QRect(290, 10, 81, 31))
        self.pushButton_3.setObjectName("pushButton_3")
        self.lineEdit = QtWidgets.QLineEdit(self.frame_16)
        self.lineEdit.setGeometry(QtCore.QRect(20, 10, 231, 31))
        self.lineEdit.setAlignment(QtCore.Qt.AlignLeading|QtCore.Qt.AlignLeft|QtCore.Qt.AlignVCenter)
        self.lineEdit.setObjectName("lineEdit")
        self.verticalLayout_7.addWidget(self.frame_16)
        self.horizontalLayout_6.addWidget(self.frame_13)
        self.frame_14 = QtWidgets.QFrame(self.frame_4)
        self.frame_14.setFrameShape(QtWidgets.QFrame.StyledPanel)
        self.frame_14.setFrameShadow(QtWidgets.QFrame.Raised)
        self.frame_14.setObjectName("frame_14")
        self.pushButton_2 = QtWidgets.QPushButton(self.frame_14)
        self.pushButton_2.setGeometry(QtCore.QRect(160, 60, 61, 31))
        self.pushButton_2.setObjectName("pushButton_2")
        self.pushButton = QtWidgets.QPushButton(self.frame_14)
        self.pushButton.setGeometry(QtCore.QRect(160, 10, 61, 31))
        self.pushButton.setObjectName("pushButton")
        self.horizontalLayout_6.addWidget(self.frame_14)
        self.verticalLayout_2.addWidget(self.frame_4)
        self.frame_6 = QtWidgets.QFrame(self.frame_3)
        sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Preferred, QtWidgets.QSizePolicy.Expanding)
        sizePolicy.setHorizontalStretch(0)
        sizePolicy.setVerticalStretch(10)
        sizePolicy.setHeightForWidth(self.frame_6.sizePolicy().hasHeightForWidth())
        self.frame_6.setSizePolicy(sizePolicy)
        self.frame_6.setStyleSheet("#frame_6{\n"
"        \n"
"    \n"
"    background-color: rgba(230, 255, 244, 100);\n"
"}\n"
"QLabel{\n"
"    \n"
"    background-color: rgba(168, 170, 166, 50);\n"
"}")
        self.frame_6.setFrameShape(QtWidgets.QFrame.StyledPanel)
        self.frame_6.setFrameShadow(QtWidgets.QFrame.Raised)
        self.frame_6.setObjectName("frame_6")
        self.horizontalLayout = QtWidgets.QHBoxLayout(self.frame_6)
        self.horizontalLayout.setSpacing(6)
        self.horizontalLayout.setObjectName("horizontalLayout")
        self.frame_7 = QtWidgets.QFrame(self.frame_6)
        self.frame_7.setFrameShape(QtWidgets.QFrame.StyledPanel)
        self.frame_7.setFrameShadow(QtWidgets.QFrame.Raised)
        self.frame_7.setObjectName("frame_7")
        self.verticalLayout_3 = QtWidgets.QVBoxLayout(self.frame_7)
        self.verticalLayout_3.setContentsMargins(0, 0, 0, 0)
        self.verticalLayout_3.setSpacing(0)
        self.verticalLayout_3.setObjectName("verticalLayout_3")
        self.frame_9 = QtWidgets.QFrame(self.frame_7)
        sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Preferred, QtWidgets.QSizePolicy.Expanding)
        sizePolicy.setHorizontalStretch(0)
        sizePolicy.setVerticalStretch(1)
        sizePolicy.setHeightForWidth(self.frame_9.sizePolicy().hasHeightForWidth())
        self.frame_9.setSizePolicy(sizePolicy)
        self.frame_9.setFrameShape(QtWidgets.QFrame.StyledPanel)
        self.frame_9.setFrameShadow(QtWidgets.QFrame.Raised)
        self.frame_9.setObjectName("frame_9")
        self.horizontalLayout_2 = QtWidgets.QHBoxLayout(self.frame_9)
        self.horizontalLayout_2.setContentsMargins(0, 0, 0, 0)
        self.horizontalLayout_2.setSpacing(0)
        self.horizontalLayout_2.setObjectName("horizontalLayout_2")
        self.label_4 = QtWidgets.QLabel(self.frame_9)
        self.label_4.setAlignment(QtCore.Qt.AlignCenter)
        self.label_4.setObjectName("label_4")
        self.horizontalLayout_2.addWidget(self.label_4)
        self.verticalLayout_3.addWidget(self.frame_9)
        self.frame_10 = QtWidgets.QFrame(self.frame_7)
        sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Preferred, QtWidgets.QSizePolicy.Expanding)
        sizePolicy.setHorizontalStretch(0)
        sizePolicy.setVerticalStretch(10)
        sizePolicy.setHeightForWidth(self.frame_10.sizePolicy().hasHeightForWidth())
        self.frame_10.setSizePolicy(sizePolicy)
        self.frame_10.setFrameShape(QtWidgets.QFrame.StyledPanel)
        self.frame_10.setFrameShadow(QtWidgets.QFrame.Raised)
        self.frame_10.setObjectName("frame_10")
        self.verticalLayout_6 = QtWidgets.QVBoxLayout(self.frame_10)
        self.verticalLayout_6.setContentsMargins(0, 0, 0, 0)
        self.verticalLayout_6.setSpacing(0)
        self.verticalLayout_6.setObjectName("verticalLayout_6")
        self.label_2 = QtWidgets.QLabel(self.frame_10)
        self.label_2.setText("")
        self.label_2.setAlignment(QtCore.Qt.AlignCenter)
        self.label_2.setObjectName("label_2")
        self.verticalLayout_6.addWidget(self.label_2)
        self.verticalLayout_3.addWidget(self.frame_10)
        self.horizontalLayout.addWidget(self.frame_7)
        self.frame_8 = QtWidgets.QFrame(self.frame_6)
        self.frame_8.setFrameShape(QtWidgets.QFrame.StyledPanel)
        self.frame_8.setFrameShadow(QtWidgets.QFrame.Raised)
        self.frame_8.setObjectName("frame_8")
        self.verticalLayout_4 = QtWidgets.QVBoxLayout(self.frame_8)
        self.verticalLayout_4.setContentsMargins(0, 0, 0, 0)
        self.verticalLayout_4.setSpacing(0)
        self.verticalLayout_4.setObjectName("verticalLayout_4")
        self.frame_11 = QtWidgets.QFrame(self.frame_8)
        sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Preferred, QtWidgets.QSizePolicy.Expanding)
        sizePolicy.setHorizontalStretch(0)
        sizePolicy.setVerticalStretch(1)
        sizePolicy.setHeightForWidth(self.frame_11.sizePolicy().hasHeightForWidth())
        self.frame_11.setSizePolicy(sizePolicy)
        self.frame_11.setFrameShape(QtWidgets.QFrame.StyledPanel)
        self.frame_11.setFrameShadow(QtWidgets.QFrame.Raised)
        self.frame_11.setObjectName("frame_11")
        self.horizontalLayout_3 = QtWidgets.QHBoxLayout(self.frame_11)
        self.horizontalLayout_3.setContentsMargins(0, 0, 0, 0)
        self.horizontalLayout_3.setSpacing(0)
        self.horizontalLayout_3.setObjectName("horizontalLayout_3")
        self.label_5 = QtWidgets.QLabel(self.frame_11)
        self.label_5.setAlignment(QtCore.Qt.AlignCenter)
        self.label_5.setObjectName("label_5")
        self.horizontalLayout_3.addWidget(self.label_5)
        self.verticalLayout_4.addWidget(self.frame_11)
        self.frame_12 = QtWidgets.QFrame(self.frame_8)
        sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Preferred, QtWidgets.QSizePolicy.Expanding)
        sizePolicy.setHorizontalStretch(0)
        sizePolicy.setVerticalStretch(10)
        sizePolicy.setHeightForWidth(self.frame_12.sizePolicy().hasHeightForWidth())
        self.frame_12.setSizePolicy(sizePolicy)
        self.frame_12.setFrameShape(QtWidgets.QFrame.StyledPanel)
        self.frame_12.setFrameShadow(QtWidgets.QFrame.Raised)
        self.frame_12.setObjectName("frame_12")
        self.verticalLayout_5 = QtWidgets.QVBoxLayout(self.frame_12)
        self.verticalLayout_5.setContentsMargins(0, 0, 0, 0)
        self.verticalLayout_5.setSpacing(0)
        self.verticalLayout_5.setObjectName("verticalLayout_5")
        self.label_3 = QtWidgets.QLabel(self.frame_12)
        self.label_3.setLayoutDirection(QtCore.Qt.LeftToRight)
        self.label_3.setText("")
        self.label_3.setAlignment(QtCore.Qt.AlignCenter)
        self.label_3.setObjectName("label_3")
        self.verticalLayout_5.addWidget(self.label_3)
        self.verticalLayout_4.addWidget(self.frame_12)
        self.horizontalLayout.addWidget(self.frame_8)
        self.verticalLayout_2.addWidget(self.frame_6)
        self.frame_5 = QtWidgets.QFrame(self.frame_3)
        sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Preferred, QtWidgets.QSizePolicy.Expanding)
        sizePolicy.setHorizontalStretch(0)
        sizePolicy.setVerticalStretch(1)
        sizePolicy.setHeightForWidth(self.frame_5.sizePolicy().hasHeightForWidth())
        self.frame_5.setSizePolicy(sizePolicy)
        self.frame_5.setFrameShape(QtWidgets.QFrame.StyledPanel)
        self.frame_5.setFrameShadow(QtWidgets.QFrame.Raised)
        self.frame_5.setObjectName("frame_5")
        self.horizontalLayout_5 = QtWidgets.QHBoxLayout(self.frame_5)
        self.horizontalLayout_5.setContentsMargins(0, 0, 0, 2)
        self.horizontalLayout_5.setSpacing(0)
        self.horizontalLayout_5.setObjectName("horizontalLayout_5")
        self.label_7 = QtWidgets.QLabel(self.frame_5)
        sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Preferred, QtWidgets.QSizePolicy.Preferred)
        sizePolicy.setHorizontalStretch(2)
        sizePolicy.setVerticalStretch(0)
        sizePolicy.setHeightForWidth(self.label_7.sizePolicy().hasHeightForWidth())
        self.label_7.setSizePolicy(sizePolicy)
        self.label_7.setObjectName("label_7")
        self.horizontalLayout_5.addWidget(self.label_7)
        self.label_6 = QtWidgets.QLabel(self.frame_5)
        sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Preferred, QtWidgets.QSizePolicy.Expanding)
        sizePolicy.setHorizontalStretch(23)
        sizePolicy.setVerticalStretch(0)
        sizePolicy.setHeightForWidth(self.label_6.sizePolicy().hasHeightForWidth())
        self.label_6.setSizePolicy(sizePolicy)
        self.label_6.setText("")
        self.label_6.setAlignment(QtCore.Qt.AlignLeading|QtCore.Qt.AlignLeft|QtCore.Qt.AlignVCenter)
        self.label_6.setObjectName("label_6")
        self.horizontalLayout_5.addWidget(self.label_6)
        self.verticalLayout_2.addWidget(self.frame_5)
        self.verticalLayout.addWidget(self.frame_3)
        self.gridLayout.addWidget(self.frame, 0, 0, 1, 1)
        MainWindow.setCentralWidget(self.centralwidget)

        self.retranslateUi(MainWindow)
        self.pushButton_3.clicked.connect(MainWindow.select_folder) # type: ignore
        self.pushButton.clicked.connect(MainWindow.take_pictures) # type: ignore
        self.pushButton_2.clicked.connect(MainWindow.delete_pictures) # type: ignore
        QtCore.QMetaObject.connectSlotsByName(MainWindow)

    def retranslateUi(self, MainWindow):
        _translate = QtCore.QCoreApplication.translate
        MainWindow.setWindowTitle(_translate("MainWindow", "图像采集软件"))
        self.label.setText(_translate("MainWindow", "AzureKinect图像采集"))
        self.toolButton.setText(_translate("MainWindow", "相机配置"))
        self.checkBox.setText(_translate("MainWindow", "相机开关"))
        self.pushButton_3.setText(_translate("MainWindow", "选定路径"))
        self.lineEdit.setText(_translate("MainWindow", "Path for Save:"))
        self.pushButton_2.setText(_translate("MainWindow", "撤销"))
        self.pushButton.setText(_translate("MainWindow", "拍照"))
        self.label_4.setText(_translate("MainWindow", "RGB图像"))
        self.label_5.setText(_translate("MainWindow", "depth图像(伪彩色处理)"))
        self.label_7.setText(_translate("MainWindow", "控制台输出"))


3、常见错误的预防

为了防止界面因常见错误而崩溃或卡住。。。。

软件使用try_except语句,结合QT界面的QMessageBox类进行提示弹窗,对一些常见错误进行了处理
(具体语句可通过主函数的源码查看)

(1)相机未连接即打开CheckBOX按钮

弹窗
在出现此类错误时界面会进行弹窗报警,此时将按钮关闭后正确连接相机,再点击界面**“相机开关”**即可

(2)相机未正常连接,在按钮的开启状态,点击“相机开关”

错误弹窗
此时界面不会直接崩溃,弹出窗口报警。这种情况下界面不会崩溃,关闭弹窗,将相机正常连接后,再点击“相机开关”,即可重新打开视频流,全称不用重新启动界面。

(3)在未连接相机时直接点击“拍照”

在未连接相机时直接点击“拍照”

(4)在未连接相机时直接点击“撤销”

在未连接相机时直接点击“撤销”

三、软件使用说明

1、将相机连接至电脑
Azure Kinect相机有两根线,一根供电线、一根数据线
需注意Azure Kinect相机对供电功率有要求,如使用电脑的USB接口供电,则有可能会因为供电不足而出现SDK的报错。我自己测试后发现,一般USB3.0的接口都能够进行供电,USB2.0的接口进行供电则会报错,建议可以进行10W充电器的独立供电。
2、点击软件项目文件夹中的exe文件,运行软件界面
在这里插入图片描述

3、点击“相机开关”,checkBox开关处于触发状态,等待几秒钟,显示视频流
在这里插入图片描述
4、点击“选定路径”,选择图像存储路径,可新建,也可选择现有
!!!路径中不要出现中文!!!
!!!路径中不要出现中文!!!
!!!路径中不要出现中文!!!
在这里插入图片描述
5、点击“拍照”,进行图像采集,按需点击“撤销”进行图像的删除
图像采集
图像删除

6、图像采集结果
在这里插入图片描述
如下图所示,图像已成功采集,其中Morp图像即为D-RGB图像,其分辨率与彩色图像完全一致,便于处理

在这里插入图片描述

总结与展望

本文详细讲解了单Azure Kinect相机图像采集软件的使用方法,并且提供了主函数与主界面的源码,该软件的优点在于不用配置任何环境,也不用安装相机SDK,使用起来较为方便,大家可自行取用

但本软件仍存在一下改进的方向,但因此功能已满足课题数据采集需要,就并未进一步优化
各位大佬如果有时间可以帮忙加以改进,到时候可以@我去给大家点赞哈哈哈

1、软件界面视觉效果优化

本软件为了课题图像采集需要而编写,时间仓促,且本人审美水平一言难尽,故并未优化界面视觉效果
现提供界面UI文件,各位大佬如有闲时可自行拿去进行优化
UI界面链接

2、相机配置——未填的坑

本软件界面中有一个按钮,在预想中是用于进行“相机配置”的设置,Azure Kinect相机为彩色、深度图像的采集提供了不同的模式。下面截取一段pyk4a库的config.py文件的源码,源码中呈现的是pyk4a库所提供的不同相机配置

# k4a_fps_t
class FPS(IntEnum):
    FPS_5 = 0
    FPS_15 = 1
    FPS_30 = 2


# k4a_image_format_t
class ImageFormat(IntEnum):
    COLOR_MJPG = 0
    COLOR_NV12 = 1
    COLOR_YUY2 = 2
    COLOR_BGRA32 = 3
    DEPTH16 = 4
    IR16 = 5
    CUSTOM8 = 6
    CUSTOM16 = 7
    CUSTOM = 8


# k4a_depth_mode_t
class DepthMode(IntEnum):
    OFF = 0
    NFOV_2X2BINNED = 1
    NFOV_UNBINNED = 2
    WFOV_2X2BINNED = 3
    WFOV_UNBINNED = 4
    PASSIVE_IR = 5


# k4a_color_resolution_t
class ColorResolution(IntEnum):
    OFF = 0
    RES_720P = 1
    RES_1080P = 2
    RES_1440P = 3
    RES_1536P = 4
    RES_2160P = 5
    RES_3072P = 6


# k4a_wired_sync_mode_t
class WiredSyncMode(IntEnum):
    STANDALONE = 0
    MASTER = 1
    SUBORDINATE = 2


# k4a_color_control_command_t
class ColorControlCommand(IntEnum):
    EXPOSURE_TIME_ABSOLUTE = 0
    AUTO_EXPOSURE_PRIORITY = 1  # deprecated
    BRIGHTNESS = 2
    CONTRAST = 3
    SATURATION = 4
    SHARPNESS = 5
    WHITEBALANCE = 6
    BACKLIGHT_COMPENSATION = 7
    GAIN = 8
    POWERLINE_FREQUENCY = 9


# k4a_color_control_mode_t
class ColorControlMode(IntEnum):
    AUTO = 0
    MANUAL = 1

但是在本人的图像采集软件中,相机配置是一段写死的代码,其设定如下:

            self.k4a = PyK4A(
                Config(
                    color_resolution=pyk4a.ColorResolution.RES_3072P,   
                    depth_mode=pyk4a.DepthMode.WFOV_UNBINNED,
                    camera_fps =pyk4a.FPS.FPS_15          
                )
            )
            self.k4a.start()    

在最初的设想中“相机配置”这一按钮,点击以后会出现不同的下拉菜单,菜单首先提供一个默认配置,但是也可以满足用户不同的需要进行搭配,大致想法如下:
相机配置
用户根据相机配置的设置,选择是否保存某类图像,并且在可选范围内,设定不同图像的分辨率

但是以上功能由于本人课题需求并不大,所以只能留待有缘人来完善了

3、软件测试

本软件将一些基本的,较为常见的错误进行了处理,但仍可能存在一些未测试出的问题(写代码是这样的),有需要的朋友可以自行进行优化

把try_except语句给我拉满!!!!!!!!

4、软件完整地封装

本软件封装其实并不完整,没有将其封装为一个单一的exe文件,有需要的朋友可以自行重新封装(并且可以的话,教教我该怎么做),如果有懂这方面的朋友,可以在评论区交流指点一下

5、解决中文路径报错

其实一直没搞懂,为什么有些软件可以安装在中文路径下,有些软件不可以,是不是在软件写作、或者软件封装的过程中,可以通过一定的操作来规避中文路径报错这一问题吗,如果有懂这方面的朋友,也请在评论区交流指点一下

关于RGB-D图像与D-RGB图像

彩色图像对齐到深度图像、深度图像对齐到彩色图像,这两种情况在深度相机相关的项目中,都有可能会与遇到的情况

1、彩色对齐到深度(RGB-D)

此种情况主要是将彩色图像与深度图像逐像素对齐,在RGB-D图像中进行图像分割,提取掩膜等操作,该掩膜可直接应用于D图像中。比较适用于需要对深度图像进行分割的场景

2、深度对齐到彩色(D-RGB)

此种情况下,可以将D图像的分辨率,通过插值算法(最邻近、或双线性)强行拉至与RGB图像一致。大大提高深度图像素点的数量
Azure Kinect相机:
RGB图像最高分辨率为(3072,4096)
Depth图像最高分辨率为(1024,1024)
有此基础,如果需要进行点云处理,将D-RGB图像转换为点云以后,也相当于提高了点云分辨率
故比较适用于点云处理场景

以上内容,既有本人做课题的经验,也有本人的课题经验,也参考了官方教程
官方教程——use-image-transformation

在这里插入图片描述
“去别”——>“区别”

哈哈,图中有个错别字

后续将会更新一下双视角Kinect图像采集的相关代码与软件,希望能帮助到大家

新人博主,点个赞求求!

  • 10
    点赞
  • 13
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值