OpenCV与PySide6、QT Designer的联合使用

一、一个简单的demo,用QT Designer创建一个QMainWindow,并且放置一个QLabel,用以显示从OpenCV读取到的图像文件。

1、打开QT Designer,新建QMainWindow,放置一个QLabel,命名为label_show:

 2、将label_show的样式表定义为下图,为其添加边框:border:2px solid #a6a6a6;

 显示效果如下:

3、保存ui文件,命名为demo_window.ui 

4、使用uic工具,将其转换为python的脚本,.py文件。

转换后的脚本命名为:demo_window_rc.py。如果不了解uic工具,方法见下面链接的第二种方法:pyside2加载ui文件的两种方式_from ui import infoui-CSDN博客。题外话,uic工具非常适合并不是把前端设计作为职业的人使用,比如像我这种,搞工控的,编程只是业余玩玩。不需要了解很多QT知识,而且所有的部件都在QT Designer的可视化界面内部署完成,很适合业余玩家。

 5、创建python脚本,调用并显示界面。

import cv2
from PySide6.QtCore import QObject, Signal
from PySide6.QtWidgets import QApplication, QMainWindow
from PySide6.QtGui import QPixmap, QImage
import sys
import demo_window_rc  # 导入需要显示的画面


class MainWindow(QMainWindow, demo_window_rc.Ui_MainWindow):  # 定义需要显示的画面类
    def __init__(self):
        super().__init__()


# #############################主程序###################################
if __name__ == '__main__':
    app = QApplication(sys.argv)

    # #######################项目级别的定义###################################
    class UI(QObject):  # 将项目定义为QObject,用来管理项目级别的信号和变量

        # ###########__init__###############
        def __init__(self):
            super().__init__()

    # ########################本项目的实例化###################################
    ui = UI()

    # ########################实例化画面#################################
    window1 = MainWindow()
    window1.show()  # 显示画面
    window1.setupUi(window1)  # 画面的本体初始化

    sys.exit(app.exec())

 至此,完成了基本的画面创建和调用。并且在主程序中定义了一个名为UI的QObject()类,项目级别的信号和变量都将在这个类中定义。运行效果:

 6、使用OpenCV读取图像并转换格式后在画面中显示。

# encoding: utf-8
import cv2
import numpy as np
from PySide6.QtCore import QObject, Signal
from PySide6.QtWidgets import QApplication, QMainWindow, QFileDialog
from PySide6.QtGui import QPixmap, QImage
import sys
import demo_window_rc  # 导入需要显示的画面


class MainWindow(QMainWindow, demo_window_rc.Ui_MainWindow):  # 定义需要显示的画面类
    def __init__(self):
        super().__init__()


def img2Widget(img, widget, autoScale=True):  # 将OpenCV格式的图像转换为PySide格式,并在小部件上显示
    img_rgb = cv2.cvtColor(img, cv2.COLOR_BGR2RGB)  # 转换 BGR 到 RGB

    # 转换图像到QT的QImage格式
    height, width, channels = img_rgb.shape  # 获取形状
    bytes_per_line = channels * width  # 每行字节数
    q_img = QImage(img_rgb.data, width, height, bytes_per_line, QImage.Format_RGB888)  # 转换成QImage格式

    pixmap = QPixmap.fromImage(q_img)  # 转换成QPixmap格式
    widget.setPixmap(pixmap)
    widget.setScaledContents(autoScale)  # 重新调整图像尺寸,适应小部件


# #############################主程序###################################
if __name__ == '__main__':
    app = QApplication(sys.argv)

    # #######################项目级别的定义###################################
    class UI(QObject):  # 将项目定义为QObject,用来管理项目级别的信号和变量
        # ###########__init__###############
        def __init__(self):
            super().__init__()


    # ########################本项目的实例化###################################
    ui = UI()

    # ########################实例化画面#################################
    window1 = MainWindow()  # 画面实例化

    window1.show()  # 显示画面
    window1.setupUi(window1)  # 画面初始化

    window1.label_show.img = cv2.imdecode(np.fromfile('../IMGS/泡泡.png', dtype=np.uint8), -1)  # 获取图像
    img2Widget(window1.label_show.img, window1.label_show)  # 将OpenCV格式的图像转换为PySide格式,并在小部件上显示

    sys.exit(app.exec())

 运行截图:

 至此,完成了基本的图像调用和显示。

二、在基础调用的框架上增加一些实用功能 

1、在画面上添加几个按钮,分别为:

“打开文件”:命名为btn_openImg,

“转换成灰度”:命名为btn_toGray

“转换成二值”:命名为btn_toBinary

"边缘检测":命名为btn_findEdge

“保存文件”:命名为btn_saveFile

1、使用文件选择对话框打开文件

# encoding: utf-8
import cv2
import numpy as np
from PySide6.QtCore import QObject, Signal
from PySide6.QtWidgets import QApplication, QMainWindow, QFileDialog
from PySide6.QtGui import QPixmap, QImage
import sys
import demo_window_rc  # 导入需要显示的画面


class MainWindow(QMainWindow, demo_window_rc.Ui_MainWindow):  # 定义需要显示的画面类
    def __init__(self):
        super().__init__()


def img2Widget(img, widget, autoScale=True):  # 将OpenCV格式的图像转换为PySide格式,并在小部件上显示
    img_rgb = cv2.cvtColor(img, cv2.COLOR_BGR2RGB)  # 转换 BGR 到 RGB

    # 转换图像到QT的QImage格式
    height, width, channels = img_rgb.shape  # 获取形状
    bytes_per_line = channels * width  # 每行字节数
    q_img = QImage(img_rgb.data, width, height, bytes_per_line, QImage.Format_RGB888)  # 转换成QImage格式

    pixmap = QPixmap.fromImage(q_img)  # 转换成QPixmap格式
    widget.setPixmap(pixmap)
    widget.setScaledContents(autoScale)  # 重新调整图像尺寸,适应小部件


# #############################主程序###################################
if __name__ == '__main__':
    app = QApplication(sys.argv)

    # #######################项目级别的定义###################################
    class UI(QObject):  # 将项目定义为QObject,用来管理项目级别的信号和变量
       
        # ###########__init__###############
        def __init__(self):
            super().__init__()


    # ########################本项目的实例化###################################
    ui = UI()

    # ########################实例化画面#################################
    window1 = MainWindow()  # 画面实例化

    window1.show()  # 显示画面
    window1.setupUi(window1)  # 画面初始化

    # ###########################信号的连接和槽函数####################################
    def btn_openImg_clicked():  # “打开文件”按钮点击的槽函数
        file_path, _ = QFileDialog.getOpenFileName(None, '请选择图片', '../IMGS',
                                                   "Image Files(*.jpg *.png *.bmp)")  # 打开文件选择框
        if file_path:
            window1.label_show.img = cv2.imdecode(np.fromfile(file_path, dtype=np.uint8), -1)  # 获取图像
            img2Widget(window1.label_show.img, window1.label_show)  # 将OpenCV格式的图像转换为PySide格式,并在小部件上显示


    window1.btn_openImg.clicked.connect(btn_openImg_clicked)  # “打开文件”按钮点击的连接

    sys.exit(app.exec())

2、基本的图像处理操作

类似的,定义其他几个图像处理按钮的信号连接以及槽函数。

# encoding: utf-8
import cv2
import numpy as np
from PySide6.QtCore import QObject, Signal
from PySide6.QtWidgets import QApplication, QMainWindow, QFileDialog
from PySide6.QtGui import QPixmap, QImage
import sys
import demo_window_rc  # 导入需要显示的画面


class MainWindow(QMainWindow, demo_window_rc.Ui_MainWindow):  # 定义需要显示的画面类
    def __init__(self):
        super().__init__()


def img2Widget(img, widget, autoScale=True):  # 将OpenCV格式的图像转换为PySide格式,并在小部件上显示
    img_rgb = cv2.cvtColor(img, cv2.COLOR_BGR2RGB)  # 转换 BGR 到 RGB

    # 转换图像到QT的QImage格式
    height, width, channels = img_rgb.shape  # 获取形状
    bytes_per_line = channels * width  # 每行字节数
    q_img = QImage(img_rgb.data, width, height, bytes_per_line, QImage.Format_RGB888)  # 转换成QImage格式

    pixmap = QPixmap.fromImage(q_img)  # 转换成QPixmap格式
    widget.setPixmap(pixmap)
    widget.setScaledContents(autoScale)  # 重新调整图像尺寸,适应小部件


# #############################主程序###################################
if __name__ == '__main__':
    app = QApplication(sys.argv)

    # #######################项目级别的定义###################################
    class UI(QObject):  # 将项目定义为QObject,用来管理项目级别的信号和变量
       
        # ###########__init__###############
        def __init__(self):
            super().__init__()


    # ########################本项目的实例化###################################
    ui = UI()

    # ########################实例化画面#################################
    window1 = MainWindow()  # 画面实例化

    window1.show()  # 显示画面
    window1.setupUi(window1)  # 画面初始化

    # ###########################信号的连接和槽函数####################################
    def btn_openImg_clicked():  # “打开文件”按钮点击的槽函数
        file_path, _ = QFileDialog.getOpenFileName(None, '请选择图片', '../IMGS',
                                                   "Image Files(*.jpg *.png *.bmp)")  # 打开文件选择框
        if file_path:
            window1.label_show.img = cv2.imdecode(np.fromfile(file_path, dtype=np.uint8), -1)  # 获取图像
            img2Widget(window1.label_show.img, window1.label_show)  # 将OpenCV格式的图像转换为PySide格式,并在小部件上显示


    window1.btn_openImg.clicked.connect(btn_openImg_clicked)  # “打开文件”按钮点击的连接


    def btn_toGray_clicked():  # “转换成灰度”按钮点击的槽函数
        if window1.label_show.img.size > 0:
            window1.label_show.gray_img = cv2.cvtColor(window1.label_show.img, cv2.COLOR_BGR2GRAY)
            img2Widget(window1.label_show.gray_img, window1.label_show)  # 将OpenCV格式的图像转换为PySide格式,并在小部件上显示


    window1.btn_toGray.clicked.connect(btn_toGray_clicked)  # “转换成灰度”按钮点击的连接


    def btn_toBinary_clicked():  # "转换成二值"按钮点击的槽函数
        thresh, output = cv2.threshold(window1.label_show.gray_img, 130, 255, cv2.THRESH_BINARY)
        window1.label_show.binary_img = cv2.GaussianBlur(output, (9, 9), 2)
        img2Widget(window1.label_show.binary_img, window1.label_show)  # 将OpenCV格式的图像转换为PySide格式,并在小部件上显示


    window1.btn_toBinary.clicked.connect(btn_toBinary_clicked)  # “转换成二值”按钮点击的连接


    def btn_findEdge_clicked():  # "边缘检测"按钮点击的槽函数
        window1.label_show.edge_img = cv2.Canny(window1.label_show.binary_img, 200, 255)
        img2Widget(window1.label_show.edge_img, window1.label_show)  # 将OpenCV格式的图像转换为PySide格式,并在小部件上显示


    window1.btn_findEdge.clicked.connect(btn_findEdge_clicked)  # “边缘检测”按钮点击的连接

    sys.exit(app.exec())

3、加入文件保存功能后的完整代码

# encoding: utf-8
import cv2
import numpy
import numpy as np
from PySide6.QtCore import QObject, Signal
from PySide6.QtWidgets import QApplication, QMainWindow, QFileDialog
from PySide6.QtGui import QPixmap, QImage
import sys
import demo_window_rc  # 导入需要显示的画面


class MainWindow(QMainWindow, demo_window_rc.Ui_MainWindow):  # 定义需要显示的画面类
    def __init__(self):
        super().__init__()


def img2Widget(img, widget, autoScale=True):  # 将OpenCV格式的图像转换为PySide格式,并在小部件上显示
    img_rgb = cv2.cvtColor(img, cv2.COLOR_BGR2RGB)  # 转换 BGR 到 RGB

    # 转换图像到QT的QImage格式
    height, width, channels = img_rgb.shape  # 获取形状
    bytes_per_line = channels * width  # 每行字节数
    q_img = QImage(img_rgb.data, width, height, bytes_per_line, QImage.Format_RGB888)  # 转换成QImage格式

    pixmap = QPixmap.fromImage(q_img)  # 转换成QPixmap格式
    widget.setPixmap(pixmap)
    widget.setScaledContents(autoScale)  # 重新调整图像尺寸,适应小部件


# #############################主程序###################################
if __name__ == '__main__':
    app = QApplication(sys.argv)

    # #######################项目级别的定义###################################
    class UI(QObject):  # 将项目定义为QObject,用来管理项目级别的信号和变量
        
        # ###########__init__###############
        def __init__(self):
            super().__init__()


    # ########################本项目的实例化###################################
    ui = UI()

    # ########################实例化画面#################################
    window1 = MainWindow()  # 画面实例化

    window1.show()  # 显示画面
    window1.setupUi(window1)  # 画面初始化
    window1.label_show.img = numpy.ndarray

    # ###########################信号的连接和槽函数####################################
    def btn_openImg_clicked():  # “打开文件”按钮点击的槽函数
        file_path, _ = QFileDialog.getOpenFileName(None, '请选择图片文件', '../IMGS',
                                                   "Image Files(*.jpg *.png *.bmp)")  # 打开文件选择框
        if file_path:
            window1.label_show.img = cv2.imdecode(np.fromfile(file_path, dtype=np.uint8), -1)  # 获取图像
            img2Widget(window1.label_show.img, window1.label_show)  # 将OpenCV格式的图像转换为PySide格式,并在小部件上显示
            print(type(window1.label_show.img))


    window1.btn_openImg.clicked.connect(btn_openImg_clicked)  # “打开文件”按钮点击的连接


    def btn_toGray_clicked():  # “转换成灰度”按钮点击的槽函数
        window1.label_show.gray_img = cv2.cvtColor(window1.label_show.img, cv2.COLOR_BGR2GRAY)
        img2Widget(window1.label_show.gray_img, window1.label_show)  # 将OpenCV格式的图像转换为PySide格式,并在小部件上显示


    window1.btn_toGray.clicked.connect(btn_toGray_clicked)  # “转换成灰度”按钮点击的连接


    def btn_toBinary_clicked():  # "转换成二值"按钮点击的槽函数
        if window1.label_show.gray_img.size > 0:
            thresh, output = cv2.threshold(window1.label_show.gray_img, 130, 255, cv2.THRESH_BINARY)
            window1.label_show.binary_img = cv2.GaussianBlur(output, (9, 9), 2)
            img2Widget(window1.label_show.binary_img, window1.label_show)  # 将OpenCV格式的图像转换为PySide格式,并在小部件上显示


    window1.btn_toBinary.clicked.connect(btn_toBinary_clicked)  # “转换成二值”按钮点击的连接


    def btn_findEdge_clicked():  # "边缘检测"按钮点击的槽函数
        if window1.label_show.binary_img.size > 0:
            window1.label_show.edge_img = cv2.Canny(window1.label_show.binary_img, 200, 255)
            img2Widget(window1.label_show.edge_img, window1.label_show)  # 将OpenCV格式图像转换为PySide格式,并在小部件上显示

    window1.btn_findEdge.clicked.connect(btn_findEdge_clicked)  # “边缘检测”按钮点击的连接

    def btn_saveFile_clicked():  # "保存文件"按钮点击的槽函数
        file_path, _ = QFileDialog.getSaveFileName(None, '保存为', '../IMGS',
                                                   "Image Files(*.png)")  # 打开文件选择框
        cv2.imencode('.png', window1.label_show.edge_img)[1].tofile(file_path)    # 保存文件

    window1.btn_saveFile.clicked.connect(btn_saveFile_clicked)  # “保存文件”按钮点击的连接

    sys.exit(app.exec())

运行截图

4、增加相机采图功能

 .首先,获取实时图像并显示在QT的小部件上的代码如下:

import sys
import cv2
from PySide6.QtWidgets import QApplication, QWidget, QLabel, QVBoxLayout
from PySide6.QtCore import QTimer, Qt
from PySide6.QtGui import QImage, QPixmap

class VideoWidget(QWidget):
    def __init__(self):
        super().__init__()

        self.label = QLabel(self)
        self.label.setAlignment(Qt.AlignCenter)

        layout = QVBoxLayout(self)
        layout.addWidget(self.label)

        self.video_capture = cv2.VideoCapture(0)  # 使用摄像头索引0(通常是默认的摄像头)

        self.timer = QTimer(self)
        self.timer.timeout.connect(self.update_frame)
        self.timer.start(1000 // 5)  # 每秒10帧

    def update_frame(self):
        ret, frame = self.video_capture.read()
        if ret:
            frame = cv2.cvtColor(frame, cv2.COLOR_BGR2RGB)  # OpenCV使用的颜色通道顺序是BGR,转换为RGB
            h, w, ch = frame.shape
            bytes_per_line = ch * w
            convert_to_qt_format = QImage(frame.data, w, h, bytes_per_line, QImage.Format_RGB888)
            pixmap = QPixmap.fromImage(convert_to_qt_format)
            pixmap = pixmap.scaled(self.label.size(), Qt.KeepAspectRatio)
            self.label.setPixmap(pixmap)

    def closeEvent(self, event):
        self.video_capture.release()
        event.accept()

if __name__ == "__main__":
    app = QApplication(sys.argv)
    widget = VideoWidget()
    widget.show()
    sys.exit(app.exec())

看得出来,其原理就是每经过间隔时间从摄像机返回的数据流中获取一帧的图像数据,并将其转换为QT格式显示。而将OpenCV格式转换为QT格式并在小部件显示的功能正是之前的自定义函数img2Widget()所实现的。所以,只要周期地获取一帧的图像数据并调用img2Widget()即可。

.具体实施过程

增加一个复选框,命名为:checkBox_video

增加一个组合框:“选择相机”,命名为:comboBox_cameras

增加一个消息框,命名为:label_message

代码:

# encoding: utf-8
import cv2
import numpy as np
from PySide6.QtCore import QObject, QTimer
from PySide6.QtWidgets import QApplication, QMainWindow, QFileDialog
from PySide6.QtGui import QPixmap, QImage
import sys
import demo_window_rc  # 导入需要显示的画面


class MainWindow(QMainWindow, demo_window_rc.Ui_MainWindow):  # 定义需要显示的画面类
    def __init__(self):
        super().__init__()


def find_camera(max_camera=3):  # 查找本地可以用的相机
    window1.label_message.setText('正在查找相机,请稍候……')
    ui.cameras = [x for x in range(max_camera) if cv2.VideoCapture(x).isOpened()]     # 所有的相机的列表
    window1.comboBox_cameras.addItems([f'相机{x}' for x in ui.cameras])          # 更新相机选择组合框的下拉列表
    window1.label_message.setText('')


def activated_camera(i):  # 查找相机并按照给定的序号激活相机
    ui.activated_camera = cv2.VideoCapture(i)  # 激活的相机 cv2.VideoCapture(i)


def window1_sup_setupUi():       # window1的补充初始化
    ui.video_play = False  # 是否实时播放视频
    find_camera()   # 查找相机
    activated_camera(0)   # 激活相机0
    ui.video_play = False    # 是否实时播放视频
    ui.timer_video = QTimer()   # 视频的帧刷新节拍定时器
    ui.timer_video.start(1000 // 5)  # 每秒5帧


def img2Widget(img, widget, autoScale=True):  # 将OpenCV格式的图像转换为PySide格式,并在小部件上显示
    img_rgb = cv2.cvtColor(img, cv2.COLOR_BGR2RGB)  # 转换 BGR 到 RGB

    # 转换图像到QT的QImage格式
    height, width, channels = img_rgb.shape  # 获取形状
    bytes_per_line = channels * width  # 每行字节数
    q_img = QImage(img_rgb.data, width, height, bytes_per_line, QImage.Format_RGB888)  # 转换成QImage格式

    pixmap = QPixmap.fromImage(q_img)  # 转换成QPixmap格式
    widget.setPixmap(pixmap)   # 设置图像到小部件
    widget.setScaledContents(autoScale)  # 重新调整图像尺寸,适应小部件


# #############################主程序###################################
if __name__ == '__main__':
    app = QApplication(sys.argv)

    # #######################项目级别的定义###################################
    class UI(QObject):  # 将项目定义为QObject,用来管理项目级别的信号和变量
        # ###########__init__###############
        def __init__(self):
            super().__init__()

    # ########################本项目的实例化###################################
    ui = UI()    # 项目实例化

    # ########################实例化画面#################################
    window1 = MainWindow()  # 画面实例化

    window1.show()  # 显示画面
    window1.setupUi(window1)  # 画面初始化
    window1_sup_setupUi()     # 画面的补充初始化
    # window1.label_show.img = numpy.ndarray

    # ###########################信号的连接和槽函数####################################

    def update_frame(camera):  # 刷新视频画面
        if ui.video_play:  # 是否实时播放视频
            ret, frame = camera.read()
            if ret:
                window1.label_show.img = frame  # 获取图像数据
                img2Widget(window1.label_show.img, window1.label_show)  # 将OpenCV格式的图像转换为PySide格式,并在小部件上显示

    ui.timer_video.timeout.connect(lambda: update_frame(ui.activated_camera))  # 视频播放的帧定时器超时后连接的槽函数(刷新显示)

    def btn_openImg_clicked():  # “打开文件”按钮点击的槽函数
        file_path, _ = QFileDialog.getOpenFileName(None, '请选择图片文件', '../IMGS',
                                                   "Image Files(*.jpg *.png *.bmp)")  # 打开文件选择框
        if file_path:
            window1.label_show.img = cv2.imdecode(np.fromfile(file_path, dtype=np.uint8), -1)  # 获取图像
            img2Widget(window1.label_show.img, window1.label_show)  # 将OpenCV格式的图像转换为PySide格式,并在小部件上显示

    window1.btn_openImg.clicked.connect(btn_openImg_clicked)  # “打开文件”按钮点击的连接

    def btn_toGray_clicked():  # “转换成灰度”按钮点击的槽函数
        window1.label_show.gray_img = cv2.cvtColor(window1.label_show.img, cv2.COLOR_BGR2GRAY)
        img2Widget(window1.label_show.gray_img, window1.label_show)  # 将OpenCV格式的图像转换为PySide格式,并在小部件上显示

    window1.btn_toGray.clicked.connect(btn_toGray_clicked)  # “转换成灰度”按钮点击的连接

    def btn_toBinary_clicked():  # "转换成二值"按钮点击的槽函数
        if window1.label_show.gray_img.size > 0:
            thresh, output = cv2.threshold(window1.label_show.gray_img, 130, 255, cv2.THRESH_BINARY)
            window1.label_show.binary_img = cv2.GaussianBlur(output, (9, 9), 2)
            img2Widget(window1.label_show.binary_img, window1.label_show)  # 将OpenCV格式的图像转换为PySide格式,并在小部件上显示

    window1.btn_toBinary.clicked.connect(btn_toBinary_clicked)  # “转换成二值”按钮点击的连接


    def find_contour_diameters(binary_img):       # 查找并计算直径
        contours, _ = cv2.findContours(binary_img, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
        diameters = []
        for contour in contours:
            if len(contour) >= 5:
                (x, y), radius = cv2.minEnclosingCircle(contour)
                diameter = radius * 2
                diameters.append(diameter)
        return diameters

    # Inside btn_findEdge_clicked function
    def btn_findEdge_clicked():  # "边缘检测"按钮点击的槽函数
        if window1.label_show.binary_img.size > 0:
            window1.label_show.edge_img = cv2.Canny(window1.label_show.binary_img, 200, 255)
            diameters = find_contour_diameters(window1.label_show.edge_img)
            print("Diameters of contours:", diameters)  # You can print or further process the diameters here
            img2Widget(window1.label_show.edge_img, window1.label_show)  # 将OpenCV格式图像转换为PySide格式,并在小部件上显示

    window1.btn_findEdge.clicked.connect(btn_findEdge_clicked)  # “边缘检测”按钮点击的连接

    def btn_saveFile_clicked():  # "保存文件"按钮点击的槽函数
        file_path, _ = QFileDialog.getSaveFileName(None, '保存为', '../IMGS',
                                                   "Image Files(*.png)")  # 打开文件选择框
        if file_path:
            cv2.imencode('.png', window1.label_show.edge_img)[1].tofile(file_path)    # 保存文件

    window1.btn_saveFile.clicked.connect(btn_saveFile_clicked)  # “保存文件”按钮点击的连接

    def window1_checkBox_video_stateChanged(state):    # “实时视频”复选框的槽函数
        ui.video_play = state

    window1.checkBox_video.stateChanged.connect(window1_checkBox_video_stateChanged)    # “实时视频”复选框的连接

    window1.comboBox_cameras.currentIndexChanged.connect(activated_camera)       # “选择相机”组合框的连接

    def clean_up():
        ui.activated_camera.release()   # 释放相机资源

    app.aboutToQuit.connect(clean_up)  # 退出系统之前的释放资源

    sys.exit(app.exec())

运行截图:

 三、改进了一版的实用程序,增加了一些实用功能

.主脚本:

# encoding: utf-8
import cv2
import numpy as np
from PySide6.QtCore import QObject, QTimer
from PySide6.QtWidgets import QApplication, QMainWindow, QFileDialog
from PySide6.QtGui import QPixmap, QImage
import sys
import demo_window_rc  # 导入需要显示的画面


# 定义需要显示的画面类
class MainWindow(QMainWindow, demo_window_rc.Ui_MainWindow):
    def __init__(self):
        super().__init__()


# 查找本地可以用的相机
def find_camera(max_camera=3):
    # window1.label_message.setText('正在查找相机,请稍候……')
    ui.cameras = [x for x in range(max_camera) if cv2.VideoCapture(x).isOpened()]  # 所有的相机的列表
    window1.comboBox_cameras.addItems([f'相机{x}' for x in ui.cameras])  # 更新相机选择组合框的下拉列表
    # window1.label_message.setText('')


# 按照给定的序号激活相机
def activated_camera(i):
    ui.activated_camera = cv2.VideoCapture(i)  # 激活的相机 cv2.VideoCapture(i)


# window1的补充初始化
def window1_sup_setupUi():
    find_camera()  # 查找相机
    activated_camera(0)  # 激活相机0
    ui.video_play = False  # 是否实时播放视频
    ui.timer_video = QTimer()  # 视频的帧刷新节拍定时器
    ui.timer_video.start(1000 // 5)  # 每秒5帧

    window1.value_threshol_black.setText(str(window1.slider_threshol_black.value()))  # 二值阈值
    window1.value_threshol_min.setText(str(window1.slider_threshol_min.value()))  # 微泡阈值
    window1.value_threshol_edge1.setText(str(window1.slider_threshol_edge1.value()))  # 轮廓参数1
    window1.value_threshol_edge2.setText(str(window1.slider_threshol_edge2.value()))  # 轮廓参数2
    ui.kernel1 = np.array([[-1, -1, -1], [-1, 9, -1], [-1, -1, -1]])  # 提高清晰度函数所需的核心

    window1.btn_capture.setProperty('videoPlay', False)  # 实时采图按钮的初始状态
    ui.diameters = []  # 泡泡尺寸表


# 将OpenCV格式的图像转换为PySide格式,并在小部件上显示
def img2Widget(img, widget, autoScale=True):
    img_rgb = cv2.cvtColor(img, cv2.COLOR_BGR2RGB)  # 转换 BGR 到 RGB

    # 转换图像到QT的QImage格式
    height, width, channels = img_rgb.shape  # 获取形状
    bytes_per_line = channels * width  # 每行字节数
    q_img = QImage(img_rgb.data, width, height, bytes_per_line, QImage.Format_RGB888)  # 转换成QImage格式

    pixmap = QPixmap.fromImage(q_img)  # 转换成QPixmap格式
    widget.setPixmap(pixmap)  # 设置图像到小部件
    widget.setScaledContents(autoScale)  # 重新调整图像尺寸,适应小部件


# #############################主程序###################################
if __name__ == '__main__':
    app = QApplication(sys.argv)

    # #######################项目级别的定义###################################
    class UI(QObject):  # 将项目定义为QObject,用来管理项目级别的信号和变量
        # ###########__init__###############
        def __init__(self):
            super().__init__()


    # ########################本项目的实例化###################################
    ui = UI()  # 项目实例化

    # ########################实例化画面#################################
    window1 = MainWindow()  # 画面实例化

    window1.show()  # 显示画面
    window1.setupUi(window1)  # 画面初始化
    window1_sup_setupUi()  # 画面的补充初始化

    # ###########################信号的连接和槽函数####################################
    # 刷新视频画面
    def update_frame(camera):
        if ui.video_play:  # 是否实时播放视频
            ret, frame = camera.read()  # 相机的返回数据
            if ret:
                blurred = cv2.GaussianBlur(frame, (3, 3), 0)  # 高斯模糊,滤除噪点
                ui.img = cv2.filter2D(blurred, -1, ui.kernel1)  # 提高清晰度并获取图像数据
                img2Widget(ui.img, window1.label_show)  # 将OpenCV格式的图像转换为PySide格式,并在小部件上显示


    # 视频播放的帧定时器超时后连接的槽函数(刷新显示)
    ui.timer_video.timeout.connect(lambda: update_frame(ui.activated_camera))

    # “打开文件”按钮点击的槽函数
    def btn_openImg_clicked():
        file_path, _ = QFileDialog.getOpenFileName(None, '请选择图片文件', '../IMGS',
                                                   "Image Files(*.jpg *.png *.bmp)")  # 打开文件选择框
        if file_path:
            ui.img = cv2.imdecode(np.fromfile(file_path, dtype=np.uint8), -1)  # 获取图像
            img2Widget(ui.img, window1.label_show)  # 将OpenCV格式的图像转换为PySide格式,并在小部件上显示


    # “打开文件”按钮点击的连接
    window1.btn_openImg.clicked.connect(btn_openImg_clicked)

    # 查找并计算直径
    def find_contour_diameters(binary_img):
        contours, _ = cv2.findContours(binary_img, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)  # 查找轮廓
        diameters = []
        for contour in contours:
            if len(contour) >= 1:
                (x, y), radius = cv2.minEnclosingCircle(contour)
                diameter = radius * 2
                diameters.append(diameter)
        return diameters

    # "转换计算"按钮点击的槽函数
    def btn_handle_clicked():
        if ui.img.size > 0:
            ui.gray_img = cv2.cvtColor(ui.img, cv2.COLOR_BGR2GRAY)  # 将原始图转成灰度,用以进行后面的运算
            ui.gray_image_3ch = cv2.cvtColor(ui.gray_img, cv2.COLOR_GRAY2BGR)  # 保留一份显示效果为灰度,但色彩为三通道的图,用以作为最终效果的显示
            thresh, output = cv2.threshold(ui.gray_img, window1.slider_threshol_black.value(), 255,
                                           cv2.THRESH_BINARY)  # 转成黑白二值

            size_min = window1.slider_threshol_min.value()    # 定义最小泡泡
            if size_min % 2 == 0:
                size_min += 1

            ui.binary_img = cv2.GaussianBlur(output, (size_min, size_min), 2)  # 去除微小尺寸泡泡
            ui.edge_img = cv2.Canny(ui.binary_img, window1.slider_threshol_edge1.value(),
                                    window1.slider_threshol_edge2.value())  # 查找边缘并生成轮廓图
            ui.diameters = find_contour_diameters(ui.edge_img)  # 尺寸表输出
            print("Diameters of contours:", ui.diameters)

            contour_img = np.zeros_like(ui.gray_image_3ch)  # 创建0值掩模图,尺寸、格式与之前的灰色3通道图相同
            contour_img[ui.edge_img == 255] = [0, 255, 0]  # 按照轮廓图中的白色位置,将掩模图中对应位置变为绿色
            # if contour_img[0][0].shape[0] == 3:     # 取决于原始图是3通道还是4通道RGB
            #     contour_img[ui.edge_img == 255] = [0, 255, 0]  # 将轮廓图中的白色变为绿色
            # else:
            #     contour_img[ui.edge_img == 255] = [0, 255, 0, 255]  # 将轮廓图中的白色变为绿色

            mask_img = cv2.addWeighted(ui.gray_image_3ch, 0.7, contour_img, 1, 0)  # 将掩模图与灰色3通道图叠加输出
            img2Widget(mask_img, window1.label_show)
    # “转换计算”按钮点击的连接
    window1.btn_handle.clicked.connect(btn_handle_clicked)

    # "保存文件"按钮点击的槽函数
    def btn_saveFile_clicked():
        file_path, _ = QFileDialog.getSaveFileName(None, '保存为', '../IMGS',
                                                   "Image Files(*.png)")  # 打开文件选择框
        if file_path:
            cv2.imencode('.png', ui.edge_img)[1].tofile(file_path)  # 保存文件
    # “保存文件”按钮点击的连接
    window1.btn_saveFile.clicked.connect(btn_saveFile_clicked)

    # “实时/采图”按钮点击的槽函数
    def window1_btn_capture_clicked(state):
        ui.video_play = state  # 相机是否视频实时采图模式
        if window1.btn_capture.property('videoPlay'):  # 按钮的自定义特性:videoPlay
            window1.btn_capture.setProperty('videoPlay', False)
            ui.video_play = False
        else:
            window1.btn_capture.setProperty('videoPlay', True)
            ui.video_play = True
        window1.btn_capture.setStyleSheet(window1.btn_capture.styleSheet())  # 刷新按钮的显示
    # “实时/采图”按钮点击的连接
    window1.btn_capture.clicked.connect(window1_btn_capture_clicked)

    # “选择相机”选项框的连接
    window1.comboBox_cameras.currentIndexChanged.connect(activated_camera)

    # "黑白阈值"调节的槽函数
    def window1_threshol_black_valueChanged(var):
        window1.value_threshol_black.setText(str(var))
        btn_handle_clicked()
    # "黑白阈值"的连接
    window1.slider_threshol_black.valueChanged.connect(window1_threshol_black_valueChanged)

    # "去除杂斑"调节的槽函数
    def window1_threshol_min_valueChanged(var):
        window1.value_threshol_min.setText(str(var))
        btn_handle_clicked()
    # "去除杂斑"的连接
    window1.slider_threshol_min.valueChanged.connect(window1_threshol_min_valueChanged)

    # "轮廓参数1"调节的槽函数
    def window1_threshol_edge1_valueChanged(var):
        window1.value_threshol_edge1.setText(str(var))
        btn_handle_clicked()
    # "轮廓参数1"的连接
    window1.slider_threshol_edge1.valueChanged.connect(window1_threshol_edge1_valueChanged)

    # "轮廓参数2"调节的槽函数
    def window1_threshol_edge2_valueChanged(var):
        window1.value_threshol_edge2.setText(str(var))
        btn_handle_clicked()
    # "轮廓参数2"的连接
    window1.slider_threshol_edge2.valueChanged.connect(window1_threshol_edge2_valueChanged)

    # 退出前的清理
    def clean_up():
        ui.activated_camera.release()  # 释放相机资源


    app.aboutToQuit.connect(clean_up)  # 退出系统之前的释放资源

    sys.exit(app.exec())

 .使用uic工具转换而来的画面脚本

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

################################################################################
## Form generated from reading UI file 'demo_window.ui'
##
## Created by: Qt User Interface Compiler version 6.6.3
##
## WARNING! All changes made in this file will be lost when recompiling UI file!
################################################################################

from PySide6.QtCore import (QCoreApplication, QDate, QDateTime, QLocale,
    QMetaObject, QObject, QPoint, QRect,
    QSize, QTime, QUrl, Qt)
from PySide6.QtGui import (QBrush, QColor, QConicalGradient, QCursor,
    QFont, QFontDatabase, QGradient, QIcon,
    QImage, QKeySequence, QLinearGradient, QPainter,
    QPalette, QPixmap, QRadialGradient, QTransform)
from PySide6.QtWidgets import (QApplication, QComboBox, QHBoxLayout, QLabel,
    QMainWindow, QMenuBar, QPushButton, QSizePolicy,
    QSlider, QStatusBar, QWidget)

class Ui_MainWindow(object):
    def setupUi(self, MainWindow):
        if not MainWindow.objectName():
            MainWindow.setObjectName(u"MainWindow")
        MainWindow.resize(1186, 861)
        self.centralwidget = QWidget(MainWindow)
        self.centralwidget.setObjectName(u"centralwidget")
        self.label_show = QLabel(self.centralwidget)
        self.label_show.setObjectName(u"label_show")
        self.label_show.setGeometry(QRect(140, 40, 960, 540))
        self.label_show.setStyleSheet(u"border:2px solid #a6a6a6;")
        self.btn_openImg = QPushButton(self.centralwidget)
        self.btn_openImg.setObjectName(u"btn_openImg")
        self.btn_openImg.setGeometry(QRect(40, 220, 75, 46))
        self.btn_handle = QPushButton(self.centralwidget)
        self.btn_handle.setObjectName(u"btn_handle")
        self.btn_handle.setGeometry(QRect(40, 280, 75, 46))
        self.btn_saveFile = QPushButton(self.centralwidget)
        self.btn_saveFile.setObjectName(u"btn_saveFile")
        self.btn_saveFile.setGeometry(QRect(40, 340, 75, 46))
        self.comboBox_cameras = QComboBox(self.centralwidget)
        self.comboBox_cameras.setObjectName(u"comboBox_cameras")
        self.comboBox_cameras.setGeometry(QRect(40, 75, 75, 31))
        self.label = QLabel(self.centralwidget)
        self.label.setObjectName(u"label")
        self.label.setGeometry(QRect(53, 50, 51, 21))
        self.btn_capture = QPushButton(self.centralwidget)
        self.btn_capture.setObjectName(u"btn_capture")
        self.btn_capture.setGeometry(QRect(40, 120, 75, 46))
        self.btn_capture.setStyleSheet(u"QPushButton[videoPlay=\"true\"] {\n"
"\n"
"/* \u91c7\u56fe\u65f6\u7684\u6837\u5f0f */\n"
"\n"
"background-color:#007800;\n"
"\n"
"}\n"
"\n"
"")
        self.value_threshol_black = QLabel(self.centralwidget)
        self.value_threshol_black.setObjectName(u"value_threshol_black")
        self.value_threshol_black.setGeometry(QRect(347, 780, 21, 16))
        self.value_threshol_black.setAlignment(Qt.AlignCenter)
        self.label_3 = QLabel(self.centralwidget)
        self.label_3.setObjectName(u"label_3")
        self.label_3.setGeometry(QRect(335, 600, 51, 16))
        self.label_3.setAlignment(Qt.AlignCenter)
        self.lamp_video = QLabel(self.centralwidget)
        self.lamp_video.setObjectName(u"lamp_video")
        self.lamp_video.setGeometry(QRect(150, 50, 20, 20))
        self.lamp_video.setStyleSheet(u"QLabel:{\n"
"/* \u901a\u5e38\u7684\u6837\u5f0f */\n"
"background-color:#00000000;\n"
"border-radius:10px;\n"
"}\n"
"\n"
"QLabel:video {\n"
"/* \u91c7\u56fe\u65f6\u7684\u6837\u5f0f */\n"
"background-color:#007800;\n"
"}\n"
"\n"
"")
        self.label_4 = QLabel(self.centralwidget)
        self.label_4.setObjectName(u"label_4")
        self.label_4.setGeometry(QRect(404, 600, 51, 16))
        self.label_4.setAlignment(Qt.AlignCenter)
        self.value_threshol_min = QLabel(self.centralwidget)
        self.value_threshol_min.setObjectName(u"value_threshol_min")
        self.value_threshol_min.setGeometry(QRect(415, 780, 31, 16))
        self.value_threshol_min.setAlignment(Qt.AlignCenter)
        self.value_threshol_edge2 = QLabel(self.centralwidget)
        self.value_threshol_edge2.setObjectName(u"value_threshol_edge2")
        self.value_threshol_edge2.setGeometry(QRect(564, 780, 31, 16))
        self.value_threshol_edge2.setAlignment(Qt.AlignCenter)
        self.value_threshol_edge1 = QLabel(self.centralwidget)
        self.value_threshol_edge1.setObjectName(u"value_threshol_edge1")
        self.value_threshol_edge1.setGeometry(QRect(493, 780, 21, 16))
        self.value_threshol_edge1.setAlignment(Qt.AlignCenter)
        self.label_5 = QLabel(self.centralwidget)
        self.label_5.setObjectName(u"label_5")
        self.label_5.setGeometry(QRect(480, 600, 57, 16))
        self.label_5.setAlignment(Qt.AlignCenter)
        self.label_6 = QLabel(self.centralwidget)
        self.label_6.setObjectName(u"label_6")
        self.label_6.setGeometry(QRect(550, 600, 57, 16))
        self.label_6.setAlignment(Qt.AlignCenter)
        self.layoutWidget = QWidget(self.centralwidget)
        self.layoutWidget.setObjectName(u"layoutWidget")
        self.layoutWidget.setGeometry(QRect(300, 625, 341, 141))
        self.horizontalLayout = QHBoxLayout(self.layoutWidget)
        self.horizontalLayout.setObjectName(u"horizontalLayout")
        self.horizontalLayout.setContentsMargins(0, 0, 0, 0)
        self.slider_threshol_black = QSlider(self.layoutWidget)
        self.slider_threshol_black.setObjectName(u"slider_threshol_black")
        self.slider_threshol_black.setMaximum(255)
        self.slider_threshol_black.setValue(150)
        self.slider_threshol_black.setOrientation(Qt.Vertical)

        self.horizontalLayout.addWidget(self.slider_threshol_black)

        self.slider_threshol_min = QSlider(self.layoutWidget)
        self.slider_threshol_min.setObjectName(u"slider_threshol_min")
        self.slider_threshol_min.setMinimum(1)
        self.slider_threshol_min.setMaximum(51)
        self.slider_threshol_min.setSingleStep(2)
        self.slider_threshol_min.setValue(9)
        self.slider_threshol_min.setOrientation(Qt.Vertical)

        self.horizontalLayout.addWidget(self.slider_threshol_min)

        self.slider_threshol_edge1 = QSlider(self.layoutWidget)
        self.slider_threshol_edge1.setObjectName(u"slider_threshol_edge1")
        self.slider_threshol_edge1.setMaximum(255)
        self.slider_threshol_edge1.setValue(200)
        self.slider_threshol_edge1.setOrientation(Qt.Vertical)

        self.horizontalLayout.addWidget(self.slider_threshol_edge1)

        self.slider_threshol_edge2 = QSlider(self.layoutWidget)
        self.slider_threshol_edge2.setObjectName(u"slider_threshol_edge2")
        self.slider_threshol_edge2.setMinimum(1)
        self.slider_threshol_edge2.setMaximum(255)
        self.slider_threshol_edge2.setSingleStep(1)
        self.slider_threshol_edge2.setValue(255)
        self.slider_threshol_edge2.setOrientation(Qt.Vertical)

        self.horizontalLayout.addWidget(self.slider_threshol_edge2)

        MainWindow.setCentralWidget(self.centralwidget)
        self.menubar = QMenuBar(MainWindow)
        self.menubar.setObjectName(u"menubar")
        self.menubar.setGeometry(QRect(0, 0, 1186, 21))
        MainWindow.setMenuBar(self.menubar)
        self.statusbar = QStatusBar(MainWindow)
        self.statusbar.setObjectName(u"statusbar")
        MainWindow.setStatusBar(self.statusbar)

        self.retranslateUi(MainWindow)

        QMetaObject.connectSlotsByName(MainWindow)
    # setupUi

    def retranslateUi(self, MainWindow):
        MainWindow.setWindowTitle(QCoreApplication.translate("MainWindow", u"MainWindow", None))
        self.label_show.setText("")
        self.btn_openImg.setText(QCoreApplication.translate("MainWindow", u"\u6253\u5f00\u6587\u4ef6", None))
        self.btn_handle.setText(QCoreApplication.translate("MainWindow", u"\u8f6c\u6362\u8ba1\u7b97", None))
        self.btn_saveFile.setText(QCoreApplication.translate("MainWindow", u"\u4fdd\u5b58\u6587\u4ef6", None))
        self.label.setText(QCoreApplication.translate("MainWindow", u"\u9009\u62e9\u76f8\u673a", None))
        self.btn_capture.setText(QCoreApplication.translate("MainWindow", u"\u5b9e\u65f6\u91c7\u56fe", None))
        self.value_threshol_black.setText(QCoreApplication.translate("MainWindow", u"150", None))
        self.label_3.setText(QCoreApplication.translate("MainWindow", u"\u9ed1\u767d\u9608\u503c", None))
        self.lamp_video.setText("")
        self.label_4.setText(QCoreApplication.translate("MainWindow", u"\u53bb\u9664\u6742\u6591", None))
        self.value_threshol_min.setText(QCoreApplication.translate("MainWindow", u"9", None))
        self.value_threshol_edge2.setText(QCoreApplication.translate("MainWindow", u"255", None))
        self.value_threshol_edge1.setText(QCoreApplication.translate("MainWindow", u"200", None))
        self.label_5.setText(QCoreApplication.translate("MainWindow", u"\u8f6e\u5ed3\u53c2\u65701", None))
        self.label_6.setText(QCoreApplication.translate("MainWindow", u"\u8f6e\u5ed3\u53c2\u65702", None))
    # retranslateUi

 持续更新中。。。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/646894.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

Linux系统命令traceroute详解(语法、选项、原理和实例)

目录 一、traceroute概述 二、语法 1、基本语法 2、命令选项 三、帮助信息 四、示例 1. 使用默认模式(ICMP Echo)追踪到目标主机 2. 使用UDP模式(需要root权限)追踪到目标主机 3. 不解析IP地址为主机名,直接显…

Nodejs(文件操作,构建服务器,express,npm)

文章目录 文件操作1.读取文件1)步骤2)范例 2.写文件1)步骤2)范例 3.删除文件4.重命名文件夹5删除文件夹 Url1.url.parse()2.url.fomat() Query1.query.parse()2.query.stringfy()3.编码和解码 第三方模块1.nodemailer2.body-parse…

反弹shell详细易懂讲解,看这一篇就够了

文章目录 反弹shell详细易懂讲解,看这一篇就够了一: 基础shell知识什么是shell,bash与shell的区别?通俗解释类型功能常见命令 二: 什么是反弹shell三: 反弹shell类型bash反弹shellNetcat 一句话反弹curl反弹shell正确姿势 wget方式反弹awk反弹 Shellsoc…

Linux环境基础开发工具的使用(yum,vim,gcc/g++,make/Makefile,gdb)

Linux 软件包管理器-yum 什么是软件包及安装方式 在Linux下安装软件, 一个通常的办法是下载到程序的源代码, 并进行编译, 得到可执行程序。 但是这样太麻烦了, 于是有些人把一些常用的软件提前编译好, 做成软件包(可以理解成windows上的安装程序)放在一个服务器上, 通过包管理…

【InternLM实战营第二期笔记】02:大模型全链路开源体系与趣味demo

文章目录 00 环境设置01 部署一个 chat 小模型02 Lagent 运行 InternLM2-chat-7B03 浦语灵笔2 第二节课程视频与文档: https://www.bilibili.com/video/BV1AH4y1H78d/ https://github.com/InternLM/Tutorial/blob/camp2/helloworld/hello_world.md 视频和文档内容基…

Java进阶学习笔记29——Math、System、Runtime

Math: 代表的是数学,是一个工具类,里面提供的都是对数据进行操作的一些静态方法。 示例代码: package cn.ensourced1_math;public class MathTest {public static void main(String[] args) {// 目标:了解Math类提供…

安全分析[1]之网络协议脆弱性分析

文章目录 威胁网络安全的主要因素计算机网络概述网络体系结构 网络体系结构脆弱性分组交换认证与可追踪性尽力而为匿名与隐私对全球网络基础实施的依赖无尺度网络互联网的级联特性中间盒子 典型网络协议脆弱性IP协议安全性分析IPSec(IP Security)IPv6问题 ICMP协议安…

Shell环境变量深入:自定义系统环境变量

Shell环境变量深入:自定义系统环境变量 目标 能够自定义系统级环境变量 全局配置文件/etc/profile应用场景 当前用户进入Shell环境初始化的时候会加载全局配置文件/etc/profile里面的环境变量, 供给所有Shell程序使用 以后只要是所有Shell程序或命令使用的变量…

民国漫画杂志《时代漫画》第23期.PDF

时代漫画23.PDF: https://url03.ctfile.com/f/1779803-1248634922-4eafac?p9586 (访问密码: 9586) 《时代漫画》的杂志在1934年诞生了,截止1937年6月战争来临被迫停刊共发行了39期。 ps: 资源来源网络!

Multi-objective reinforcement learning approach for trip recommendation

Multi-objective reinforcement learning approach for trip recommendation A B S T R A C T 行程推荐是一项智能服务,为游客在陌生的城市提供个性化的行程规划。 它旨在构建一系列有序的 POI,在时间和空间限制下最大化用户的旅行体验。 将候选 POI 添…

【C++ 】学习问题及补充

一.自定义类型不初始化直接就赋值&#xff0c;比如string类会怎么样 vectr<string>里已经给每个string对象已经分配好空间&#xff0c;为什么不初始化再赋值会报错 在C中&#xff0c;std::string类是一个动态字符串类&#xff0c;它内部管理着一个字符数组&#xff0c;用…

C++ | Leetcode C++题解之第111题二叉树的最小深度

题目&#xff1a; 题解&#xff1a; class Solution { public:int minDepth(TreeNode *root) {if (root nullptr) {return 0;}queue<pair<TreeNode *, int> > que;que.emplace(root, 1);while (!que.empty()) {TreeNode *node que.front().first;int depth que…

蓝桥杯物联网竞赛_STM32L071_17_DMA收发 不定长DMA接收

前言&#xff1a; 前面已经说过&#xff0c;由于国赛的代码量的增加&#xff0c;cpu在其他代码的时间块会较省赛大大增加&#xff0c;为了减少对cpu的依赖所以学习DMA收发数据 对于串口中断收发来说串口接收数据无法收取不定长数据所以不好用&#xff0c;而DMA有收集不定长数…

汇编:字符串的输出

在16位汇编程序中&#xff0c;可以使用DOS中断21h的功能号09h来打印字符串&#xff1b;下面是一个简单的示例程序&#xff0c;演示了如何在16位汇编程序中打印字符串&#xff1a; assume cs:code,ds:data ​ data segmentszBuffer db 0dh,0ah,HelloWorld$ //定义字符串 data …

Hadoop概览以及编译hadoop说明

一、Hadoop概述 Hadoop 是一个用于跨计算机集群存储和处理大型数据集的软件框架。它旨在处理大数据&#xff0c;即传统数据库无法有效管理的极其庞大和复杂的数据集。Hadoop不是传统意义上的数据仓库&#xff0c;因为它们的用途不同&#xff0c;架构也不同。Hadoop 是一个跨分布…

Elasticsearch 8.1官网文档梳理 - 十三、Search your data(数据搜索)

Search your data 这里有两个比较有用的参数需要注意一下 Search timeout&#xff1a;设置每个分片的搜索超时时间。从集群级别可以通过 search.default_search_timeout 来设置超时时间。如果在 search.default_search_timeout 设置的时间段内未完成搜索请求&#xff0c;就会…

京东应届生公司内网说了一句‘什么时候被pdd收购‘,结果惨遭辞退

京东应届生公司内网说了一句’什么时候被pdd收购’&#xff0c;结果惨遭公司开除 这个事最近在圈子讨论比较多 前二天&#xff0c;有一个上海交大毕业的应届生&#xff0c;在京东实习了9个月&#xff0c;好不容易转正12天后&#xff0c;只因在内网说了一句话&#xff0c;就被…

【传知代码】无监督动画中关节动画的运动表示-论文复现

文章目录 概述动画技术的演进原理介绍核心逻辑环境配置/部署方式小结 本文涉及的源码可从无监督动画中关节动画的运动表示该文章下方附件获取 概述 该文探讨了动画在教育和娱乐中的作用&#xff0c;以及通过数据驱动方法简化动画制作的尝试。近期研究通过无监督运动转移减少对…

python数据分析-CO2排放分析

导入所需要的package import numpy as np import pandas as pd import matplotlib.pyplot as plt import seaborn as sns import datetime %matplotlib inline plt.rcParams[font.sans-serif] [KaiTi] #中文 plt.rcParams[axes.unicode_minus] False #负号 数据清洗…

汇编原理(二)

寄存器&#xff1a;所有寄存器都是16位&#xff08;0-15&#xff09;&#xff0c;可以存放两个字节 AX,BX,CX,DX存放一般性数据&#xff0c;称为通用寄存器 AX的逻辑结构。最大存放的数据为2的16次方减1。可分为AH和AL&#xff0c;兼容8位寄存器。 字&#xff1a;1word 2Byte…