OpenCV-PyQT项目实战(6)项目案例02:滚动条应用

news/2024/7/21 6:46:32 标签: opencv, pyqt, 计算机视觉, 图像处理, GUI

欢迎关注『OpenCV-PyQT项目实战 @ Youcans』系列,持续更新中
OpenCV-PyQT项目实战(1)安装与环境配置
OpenCV-PyQT项目实战(2)QtDesigner 和 PyUIC 快速入门
OpenCV-PyQT项目实战(3)信号与槽机制
OpenCV-PyQT项目实战(4)OpenCV 与PyQt的图像转换
OpenCV-PyQT项目实战(5)项目案例01:图像模糊
OpenCV-PyQT项目实战(6)项目案例02:滚动条应用
OpenCV-PyQT项目实战(7)项目案例03:鼠标框选
OpenCV-PyQT项目实战(8)项目案例04:鼠标定位
OpenCV-PyQT项目实战(9)项目案例04:视频播放
OpenCV-PyQT项目实战(10)项目案例06:键盘事件与视频抓拍
OpenCV-PyQT项目实战(11)项目案例07:摄像头操作与拍摄视频

文章目录

  • OpenCV-PyQT项目实战(6)项目案例02:滚动条应用
    • 1. 调节输入控件
      • 1.1 输入控件
      • 1.2 水平/垂直滚动条(QScrollBar)
      • 1.3 水平/垂直滑动槽(QSlider)
      • 1.4 旋转调节盘(QDial)
      • 1.5 其它输入调节控件
    • 2. 项目实战:使用滑动槽(QSlider)调节模糊尺度
      • 2.1 使用 QtDesigner 开发 PyQt5 图形界面
      • 2.2. 项目主程序的开发
        • 2.2.1 getHorizontalSliderValue 槽函数
        • 2.2.2 getSpinBoxValue槽函数
        • 2.2.3 信号与槽的连接
      • 2.3 主程序
      • 2.4. 项目例程的测试
    • 3. 项目实战:调节图像亮度和对比度
      • 3.1 使用 QtDesigner 开发 PyQt5 图形界面
      • 3.2. 项目主程序的开发
        • 3.2.1 getHorizontalSliderValue 槽函数
        • 3.2.2 getSpinBoxValue槽函数
        • 3.2.3 信号与槽的连接
      • 3.3 完整例程及运行结果


OpenCV-PyQT项目实战(6)项目案例02:滚动条应用

本节介绍两个 OpenCV-PyQt 项目案例,通过案例学习滚动条等调节输入控件。


1. 调节输入控件

1.1 输入控件

在 QtDesigner 左侧的 “WidgetBox” 工具栏中的"Input Widget" 组,设有多种不同类型的输入控件,例如:
文本输入控件:QlineEdit(单行输入)、QTextEdit(多行输入)、QPlainTextEdit(普通多行输入);
数字输入控件:QSpinBox(整型数据输入)、QDoubleSpinBox(浮点数据输入);
调节输入控件:QAbstractSpinBox(步长调节输入)、QDateEdit(日期输入)、QTimeEdit(时间输入)、QDateTimeEdit(日期和时间输入)。

用鼠标将工具栏中的输入控件拖拽到 QtDesigner 中间的图形界面编辑窗口,就可以在图像界面创建了一个按钮控件。

在这里插入图片描述


1.2 水平/垂直滚动条(QScrollBar)

PyQt 中提供了的滚动条组件 QScrollBar,包括水平滚动条(Horizontal Scroll Bar)和垂直滚动条(Vertical Scroll Bar)。
滚动条为当前位置提供视觉指示,用于访问当前不可见的文档或图像区域。滚动条有一个滑块,也可以用于用于调节整数值,但默认不显示数字。

QScrollBar的常用属性:

  • minimum:最小值
  • maximum:最大值
  • singlestep:步距
  • value:初始值
  • sliderposition:位置,如果数字是从1开始且步距是1,则value和sliderposition是一致的。
  • notchesVisible :是否设置刻度
  • wrapping :是否刻度不留缺口
  • notchTarget :设置刻度密度,即单位刻度所代表的大小

QScrollBar的常用方法:

  • setMinimum(): 设置滚动条的最小值
  • setMaximum(): 设置滚动条的最大值
  • setSingleStep(): 设置滚动条的步长
  • setValue(): 设置滚动条的值
  • value(): 获得滚动条控件的值

QScrollBar可以发送的信号(即可以使用这些信号来触发槽函数):

  • valueChanged: 当滑块的值发生改变时发射此信号,此信号是最常用的
  • sliderPressed: 当用户按下滑块时发射此信号
  • sliderMoved: 当用户拖动滑块时发射此信号
  • sliderReleased: 当用户释放滑块时发射此信号

1.3 水平/垂直滑动槽(QSlider)

PyQt 中提供了的滑动槽组件 QSlider,包括水平滑动槽(Horizontal Slider)和垂直滑动槽(Vertical Slider)。
滑动槽组件展示了一个可以移动的滑块,它是控制有界值的部件,常用于调节整数大小。

QSlider的常用属性:

  • minimum:最小值
  • maximum:最大值
  • singlestep:步距
  • value:初始值
  • sliderposition:位置,如果数字是从1开始且步距是1,则value和sliderposition是一致的。
  • notchesVisible :是否设置刻度
  • wrapping :是否刻度不留缺口
  • notchTarget :设置刻度密度,即单位刻度所代表的大小

QSlider的常用方法:

  • setMinimum(): 设置滑动槽的最小值
  • setMaximum(): 设置滑动槽的最大值
  • setSingleStep(): 设置滑动槽的递增步长
  • setTickInterval():将刻度数放在凹槽上
  • setValue(): 设置滑动槽的值
  • value(): 获得滑动槽控件的值

QSlider可以发送的信号(即可以使用这些信号来触发槽函数):

  • valueChanged: 当滑块的值发生改变时发射此信号,此信号是最常用的
  • sliderPressed: 当用户按下滑块时发射此信号
  • sliderMoved: 当用户拖动滑块时发射此信号
  • sliderReleased: 当用户释放滑块时发射此信号

1.4 旋转调节盘(QDial)

QDial是一个圆表盘控件, 也称为旋转调节盘,可以用于处理整数或浮点数值。各种仪表仪盘都可以抽象成一个圆表盘控件,例如汽车仪表盘上的速度计。

QDial的常用属性:

  • minimum:最小值
  • maximum:最大值
  • singlestep:步距
  • value:初始值
  • sliderposition:位置,如果数字是从1开始且步距是1,则value和sliderposition是一致的。
  • notchesVisible :是否设置刻度
  • wrapping :是否刻度不留缺口
  • notchTarget :设置刻度密度,即单位刻度所代表的大小

QDial常用方法:

  • setNotchesVisible(): 设置是否显示刻度
  • notchesVisile(): 刻度可见返回True,不可见返回False
  • setWrapping(): 设置是否回绕
  • wrapping(): 如果回绕则返回True, 否则返回False
  • setNotchTarget(): 设置刻度之间的目标刻度
  • notchTarget(): 返回刻度间的目标宽度
  • notchSize(): 当前刻度尺寸

1.5 其它输入调节控件

步长调节输入(QAbstractSpinBox)

QAbstractSpinBox 将所有步长调节器的通用的功能抽象出了一个父类,也可以直接实例化使用。QAbstractSpinBox包含了一个QLineEdit和两个QPushbutton,数据的更改可以通过点击按钮或使用键盘输入。

日期和时间输入(QDateEdit/QTimeEdit/QDateTimeEdit)

QDateEdit 控件用于编辑日期,QTimeEdit 控件用于编辑时间,QDateTimeEdit同时编辑日期时间的控件。可以使用键盘上的上下键头按钮来增加或减少日期、时间。

整型数字调节框(QSpinBox)

QSpinBox 是一个计数器控件,允许用户选择一个整数通过上下按键递增或者递减,也可以直接输入整数的数值。默认取值范围为 0-99,每次调节的步长为 1。

浮点数字调节框(QDoubleSpinBox)

QDoubleSpinBox 是浮点数据计数器控件,用于处理浮点数值。默认精度为 2位小数。



2. 项目实战:使用滑动槽(QSlider)调节模糊尺度

在uiDemo4.ui中,我们创建了按钮控件:“1 打开”、“2 灰度”、“3 模糊”、“4 帮助”、“5 退出”。其中模糊功能中,模糊尺度是在程序内部设置的。本例中,我们使用滑动槽(QSlider)调节模糊尺度。



2.1 使用 QtDesigner 开发 PyQt5 图形界面

使用 QtDesigner 开发 PyQt5 图形界面的基本步骤是:
(1)使用图形界面设计工具 QtDesigner 进行图形界面设计,生成 .ui 文件;
(2)使用 UI 转换工具 PyUIC 将 .ui 文件转换为 .py 文件;
(3)编写一个 Python 应用程序调用 .py 界面文件,就可以实现 Python 平台的 GUI 编程。

本例在 uiDemo4.ui 的基础上,添加一个滑动槽控件 QSlider:

从 QtDesigner 左侧控件栏的 “Input Widgets” 中选择 滑动槽控件 QSlider,移动鼠标将滑动槽 QSlider拖动到新建图形窗口内的任意位置,就在图形窗口位置生成了一个 QSlider 对象。

  • 鼠标左键选中图形窗口中的这个 QSlider滑动槽对象,拖动鼠标可以调整控件的位置。
  • 鼠标选中 QSlider滑动槽对象,可以在右侧的 “属性编辑器” 内对对象的属性进行编辑和修改,例如:
    • 将 QSlider 对象的高度修改为 80,宽度修改为 40;
    • 设置QSlider 对象的最小值minimum=1、最大值maximum=64和步长singleStep=1。

类似地,添加一个整型数字调节框(QSpinBox)控件。


在这里插入图片描述

于是,我们就完成了本项目的图形界面设计,将其保存为 uiDemo5.ui文件。

在 PyCharm中,使用 PyUIC 将选中的 uiDemo5.ui 文件转换为 .py 文件,就得到了 uiDemo5.py 文件。



2.2. 项目主程序的开发

2.2.1 getHorizontalSliderValue 槽函数

getHorizontalSliderValue 槽函数,由valueChanged信号触发。

    def getHorizontalSliderValue(self):
        self.sigma = max(self.horizontalSlider.value(),3)  # 修改模糊尺度
        ksize = (self.sigma, self.sigma)  # 高斯滤波器核的尺寸
        print("HorizontalSlider=", self.sigma)

2.2.2 getSpinBoxValue槽函数

getSpinBoxValue槽函数,由valueChanged信号触发。

    def getSpinBoxValue(self):
        self.sigma = self.spinBox.value()  # 修改模糊尺度
        print("SpinBoxValue=", self.sigma)
        ksize = (self.sigma, self.sigma)  # 高斯滤波器核的尺寸
        blur = cv.GaussianBlur(self.img1, ksize, 0)  # sigma 由 ksize 计算
        self.refreshShow(blur, self.label_2)  # 刷新显示

2.2.3 信号与槽的连接

        # 通过 connect 建立信号/槽连接,点击按钮事件发射 triggered 信号,执行相应的子程序 click_pushButton
        # self.pushButton_1.clicked.connect(self.openSlot)  # 点击 pushButton_1 触发
        self.pushButton_1.clicked.connect(self.click_pushButton_1)  # 点击 pushButton_1 触发
        # self.pushButton_2.clicked.connect(self.click_pushButton_2)  # 点击 pushButton_2 触发
        self.pushButton_3.clicked.connect(self.click_pushButton_3)  # 点击 pushButton_3 触发
        # self.pushButton_4.clicked.connect(self.trigger_actHelp)  # 点击 pushButton_4 触发
        self.pushButton_5.clicked.connect(self.close)  # 点击 pushButton_5 关闭窗口
        self.spinBox.valueChanged.connect(self.getSpinBoxValue)  # spinBox控件valueChanged信号与getSpinBoxValue槽函数关联
        self.horizontalSlider.valueChanged.connect(self.getHorizontalSliderValue)  # horizontalSlider控件valueChanged信号触发

2.3 主程序

# OpenCVPyqt06.py
# Demo06 of GUI by PyQt5
# Copyright 2023 Youcans, XUPT
# Crated:2023-02-03

if __name__ == '__main__':
    app = QApplication(sys.argv)  # 在 QApplication 方法中使用,创建应用程序对象
    myWin = MyMainWindow()  # 实例化 MyMainWindow 类,创建主窗口
    myWin.show()  # 在桌面显示控件 myWin
    sys.exit(app.exec_())  # 结束进程,退出程序

2.4. 项目例程的测试

测试应用程序 OpenCVPyqt06.py的各项功能:

(1)运行 OpenCVPyqt06,弹出程序窗口,自动加载图像 Fig0301。

(2)点击 “1 打开”,运行 click_pushButton_1 槽函数。选择目录路径和图像文件,读取图像并在窗口显示彩色图像。

(3)点击 "3 模糊"按钮,运行 click_pushButton_3 槽函数。在窗口右侧显示高斯模糊处理的彩色图像。

(4)调节滑动槽或整型数字调节框,用户设置模糊尺度,则在 Label_2 刷新模糊图像。

在这里插入图片描述


(5)点击 "5 退出"按钮,关闭窗口。



3. 项目实战:调节图像亮度和对比度

本项目模拟 PhotoShop 与 AcdSee 中的图像亮度和对比度方法,通过手动调节阴影、中间调和高光参数设置,调节图像的亮度和对比度。相关方法的原理和OpenCV算法实现,详见:【OpenCV 例程300篇】206. Photoshop 色阶调整算法。



3.1 使用 QtDesigner 开发 PyQt5 图形界面

本例在 uiDemo4.ui 的基础上,添加滑动槽控件 QSlider:

从 QtDesigner 左侧控件栏的 “Input Widgets” 中选择 滑动槽控件 QSlider,移动鼠标将滑动槽 QSlider拖动到新建图形窗口内的任意位置,就在图形窗口位置生成了一个 QSlider 对象。

  • 鼠标左键选中图形窗口中的这个 QSlider滑动槽对象,拖动鼠标可以调整控件的位置。
  • 鼠标选中 QSlider滑动槽对象,可以在右侧的 “属性编辑器” 内对对象的属性进行编辑和修改,例如:
    • 将 QSlider 对象的高度修改为 80,宽度修改为 40;
    • 设置QSlider 对象的最小值minimum=1、最大值maximum=64和步长singleStep=1。

类似地,添加一个整型数字调节框(QSpinBox)控件。


在这里插入图片描述

于是,我们就完成了本项目的图形界面设计,将其保存为 uiDemo7.ui文件。

在 PyCharm中,使用 PyUIC 将选中的 uiDemo7.ui 文件转换为 .py 文件,就得到了 uiDemo7.py 文件。



3.2. 项目主程序的开发

3.2.1 getHorizontalSliderValue 槽函数

getHorizontalSliderValue 槽函数,由valueChanged信号触发。

    def getHorizontalSliderValue_1(self):  # 最小值
        slideValue1 = self.horizontalSlider_1.value()
        self.spinBox_1.setValue(slideValue1)  # 同步修改
        self.spinBox_3.setMinimum(slideValue1)  # 关联修改
        self.horizontalSlider_3.setMinimum(slideValue1)  # 关联修改
        print("HorizontalSliderValue_1 = ", slideValue1)

    def getHorizontalSliderValue_2(self):
        slideValue2 = self.horizontalSlider_2.value()
        self.spinBox_2.setValue(slideValue2)
        print("HorizontalSliderValue_2 = ", slideValue2)

    def getHorizontalSliderValue_3(self):
        slideValue3 = self.horizontalSlider_3.value()
        self.spinBox_3.setValue(slideValue3)  # 同步修改
        self.spinBox_1.setMaximum(slideValue3)  # 关联修改
        self.horizontalSlider_1.setMaximum(slideValue3)  # 关联修改
        print("HorizontalSliderValue_3 = ", slideValue3)

3.2.2 getSpinBoxValue槽函数

getSpinBoxValue槽函数,由valueChanged信号触发。

    def getSpinBoxValue_1(self):
        spinBoxValue1 = self.spinBox_1.value()
        self.horizontalSlider_1.setValue(spinBoxValue1)
        self.spinBox_3.setMinimum(spinBoxValue1)  # 关联修改
        self.horizontalSlider_3.setMinimum(spinBoxValue1)  # 关联修改
        print("SpinBoxValue_1 = ", spinBoxValue1)

    def getSpinBoxValue_2(self):
        spinBoxValue2 = self.spinBox_2.value()
        self.horizontalSlider_2.setValue(spinBoxValue2)
        print("SpinBoxValue_2 = ", spinBoxValue2)

    def getSpinBoxValue_3(self):
        spinBoxValue3 = self.spinBox_3.value()
        self.horizontalSlider_3.setValue(spinBoxValue

3.2.3 信号与槽的连接

        # 菜单栏
        self.actionOpen.triggered.connect(self.openSlot)  # 连接并执行 openSlot 子程序
        self.actionSave.triggered.connect(self.saveSlot)  # 连接并执行 saveSlot 子程序
        self.actionHelp.triggered.connect(self.trigger_actHelp)  # 连接并执行 trigger_actHelp 子程序
        self.actionQuit.triggered.connect(self.close)  # 连接并执行 trigger_actHelp 子程序

        # 通过 connect 建立信号/槽连接,点击按钮事件发射 triggered 信号,执行相应的子程序 click_pushButton
        self.pushButton_1.clicked.connect(self.click_pushButton_1)  # 按钮触发:导入图像
        self.pushButton_3.clicked.connect(self.click_pushButton_3)  # # 按钮触发:调整色阶
        self.pushButton_5.clicked.connect(self.close)  # 点击 # 按钮触发:关闭
        self.horizontalSlider_1.valueChanged.connect(self.getHorizontalSliderValue_1)  # horizontalSlider控件valueChanged信号触发
        self.horizontalSlider_2.valueChanged.connect(self.getHorizontalSliderValue_2)
        self.horizontalSlider_3.valueChanged.connect(self.getHorizontalSliderValue_3)
        self.spinBox_1.valueChanged.connect(self.getSpinBoxValue_1)  # spinBox控件valueChanged信号与getSpinBoxValue槽函数关联
        self.spinBox_2.valueChanged.connect(self.getSpinBoxValue_2)
        self.spinBox_3.valueChanged.connect(self.getSpinBoxValue_3)

3.3 完整例程及运行结果

# OpenCVPyqt07.py
# Demo07 of GUI by PyQt5
# Copyright 2023 Youcans, XUPT
# Crated:2023-02-08

import sys
import cv2 as cv
import numpy as np
from PyQt5 import QtCore
from PyQt5.QtWidgets import *
from PyQt5.QtGui import *
from uiDemo7 import Ui_MainWindow  # 导入 uiDemo5.py 中的 Ui_MainWindow 界面类

class MyMainWindow(QMainWindow, Ui_MainWindow):  # 继承 QMainWindow 类和 Ui_MainWindow 界面类
    def __init__(self, parent=None):
        super(MyMainWindow, self).__init__(parent)  # 初始化父类
        self.setupUi(self)  # 继承 Ui_MainWindow 界面类
        self.img1 = np.ndarray(())  # 初始化图像 ndarry,用于存储图像
        # self.img2 = np.ndarray(())

        # 菜单栏
        self.actionOpen.triggered.connect(self.openSlot)  # 连接并执行 openSlot 子程序
        self.actionSave.triggered.connect(self.saveSlot)  # 连接并执行 saveSlot 子程序
        self.actionHelp.triggered.connect(self.trigger_actHelp)  # 连接并执行 trigger_actHelp 子程序
        self.actionQuit.triggered.connect(self.close)  # 连接并执行 trigger_actHelp 子程序

        # 通过 connect 建立信号/槽连接,点击按钮事件发射 triggered 信号,执行相应的子程序 click_pushButton
        self.pushButton_1.clicked.connect(self.click_pushButton_1)  # 按钮触发:导入图像
        self.pushButton_3.clicked.connect(self.click_pushButton_3)  # # 按钮触发:调整色阶
        self.pushButton_5.clicked.connect(self.close)  # 点击 # 按钮触发:关闭
        self.horizontalSlider_1.valueChanged.connect(self.getHorizontalSliderValue_1)  # horizontalSlider控件valueChanged信号触发
        self.horizontalSlider_2.valueChanged.connect(self.getHorizontalSliderValue_2)
        self.horizontalSlider_3.valueChanged.connect(self.getHorizontalSliderValue_3)
        self.spinBox_1.valueChanged.connect(self.getSpinBoxValue_1)  # spinBox控件valueChanged信号与getSpinBoxValue槽函数关联
        self.spinBox_2.valueChanged.connect(self.getSpinBoxValue_2)
        self.spinBox_3.valueChanged.connect(self.getSpinBoxValue_3)

        # 初始化
        self.img1 = cv.imread("../images/Fig0301.png")  # OpenCV 读取图像
        self.refreshShow(self.img1, self.label_1)
        self.refreshShow(self.img1, self.label_2)
        return

    def getHorizontalSliderValue_1(self):  # 最小值
        slideValue1 = self.horizontalSlider_1.value()
        self.spinBox_1.setValue(slideValue1)  # 同步修改
        self.spinBox_3.setMinimum(slideValue1)  # 关联修改
        self.horizontalSlider_3.setMinimum(slideValue1)  # 关联修改
        print("HorizontalSliderValue_1 = ", slideValue1)

    def getHorizontalSliderValue_2(self):
        slideValue2 = self.horizontalSlider_2.value()
        self.spinBox_2.setValue(slideValue2)
        print("HorizontalSliderValue_2 = ", slideValue2)

    def getHorizontalSliderValue_3(self):
        slideValue3 = self.horizontalSlider_3.value()
        self.spinBox_3.setValue(slideValue3)  # 同步修改
        self.spinBox_1.setMaximum(slideValue3)  # 关联修改
        self.horizontalSlider_1.setMaximum(slideValue3)  # 关联修改
        print("HorizontalSliderValue_3 = ", slideValue3)

    def getSpinBoxValue_1(self):
        spinBoxValue1 = self.spinBox_1.value()
        self.horizontalSlider_1.setValue(spinBoxValue1)
        self.spinBox_3.setMinimum(spinBoxValue1)  # 关联修改
        self.horizontalSlider_3.setMinimum(spinBoxValue1)  # 关联修改
        print("SpinBoxValue_1 = ", spinBoxValue1)

    def getSpinBoxValue_2(self):
        spinBoxValue2 = self.spinBox_2.value()
        self.horizontalSlider_2.setValue(spinBoxValue2)
        print("SpinBoxValue_2 = ", spinBoxValue2)

    def getSpinBoxValue_3(self):
        spinBoxValue3 = self.spinBox_3.value()
        self.horizontalSlider_3.setValue(spinBoxValue3)
        print("SpinBoxValue_3 = ", spinBoxValue3)

    def click_pushButton_1(self):  # 点击 pushButton_1 触发
        self.img1 = self.openSlot()  # 读取图像
        print("click_pushButton_1", self.img1.shape)
        self.refreshShow(self.img1, self.label_1)  # 刷新显示
        return

    def click_pushButton_2(self):  # 点击 pushButton_2 触发
        print("pushButton_2")
        self.img2 = cv.cvtColor(self.img1, cv.COLOR_BGR2GRAY)  # 图片格式转换:BGR -> Gray
        self.refreshShow(self.img2, self.label_2)  # 刷新显示
        return

    def click_pushButton_3(self):  # 点击 pushButton_3 触发 调整色阶
        print("pushButton_3")
        Sin = self.horizontalSlider_1.value()
        Mt = self.horizontalSlider_2.value()
        Hin = self.horizontalSlider_3.value()
        Sin = min(max(Sin, 0), Hin - 2)  # Sin, 黑场阈值, 0<=Sin<Hin
        Hin = min(Hin, 255)  # Hin, 白场阈值, Sin<Hin<=255
        Mt = min(max(Mt, 0.01), 9.99)  # Mt, 灰场调节值, 0.01~9.99
        Sout = 0#min(max(Sout, 0), Hout - 2)  # Sout, 输出黑场阈值, 0<=Sout<Hout
        Hout = 255#min(Hout, 255)  # Hout, 输出白场阈值, Sout<Hout<=255
        print("Sin={},Hin={},Mt={}".format(Sin, Hin, Mt))

        difIn = Hin - Sin
        difOut = Hout - Sout
        table = np.zeros(256, np.uint8)
        for i in range(256):
            V1 = min(max(255 * (i - Sin) / difIn, 0), 255)  # 输入动态线性拉伸
            V2 = 255 * np.power(V1 / 255, 1 / Mt)  # 灰场伽马调节
            table[i] = min(max(Sout + difOut * V2 / 255, 0), 255)  # 输出线性拉伸

        imgTone = cv.LUT(self.img1, table)
        self.refreshShow(imgTone, self.label_2)  # 刷新显示
        return

    def refreshShow(self, img, label):
        print(img.shape, label)
        qImg = self.cvToQImage(img)  # OpenCV 转为 PyQt 图像格式
        label.setPixmap((QPixmap.fromImage(qImg)))  # 加载 PyQt 图像
        return

    def openSlot(self, flag=1):  # 读取图像文件
        # OpenCV 读取图像文件
        fileName, _ = QFileDialog.getOpenFileName(self, "Open Image", "../images/", "*.png *.jpg *.tif")
        if flag==0 or flag=="gray":
            img = cv.imread(fileName, cv.IMREAD_GRAYSCALE)  # 读取灰度图像
        else:
            img = cv.imread(fileName, cv.IMREAD_COLOR)  # 读取彩色图像
        print(fileName, img.shape)
        return img

    def saveSlot(self):  # 保存图像文件
        # 选择存储文件 dialog
        fileName, tmp = QFileDialog.getSaveFileName(self, "Save Image", "../images/", '*.png; *.jpg; *.tif')
        if self.img1.size == 1:
            return
        # OpenCV 写入图像文件
        ret = cv.imwrite(fileName, self.img1)
        if ret:
            print(fileName, self.img.shape)
        return

    def cvToQImage(self, image):
        # 8-bits unsigned, NO. OF CHANNELS=1
        if image.dtype == np.uint8:
            channels = 1 if len(image.shape) == 2 else image.shape[2]
        if channels == 3:  # CV_8UC3
            # Create QImage with same dimensions as input Mat
            qImg = QImage(image, image.shape[1], image.shape[0], image.strides[0], QImage.Format_RGB888)
            return qImg.rgbSwapped()
        elif channels == 1:
            # Create QImage with same dimensions as input Mat
            qImg = QImage(image, image.shape[1], image.shape[0], image.strides[0], QImage.Format_Indexed8)
            return qImg
        else:
            QtCore.qDebug("ERROR: numpy.ndarray could not be converted to QImage. Channels = %d" % image.shape[2])
            return QImage()

    def qPixmapToCV(self, qPixmap):  # PyQt图像 转换为 OpenCV图像
        qImg = qPixmap.toImage()  # QPixmap 转换为 QImage
        shape = (qImg.height(), qImg.bytesPerLine() * 8 // qImg.depth())
        shape += (4,)
        ptr = qImg.bits()
        ptr.setsize(qImg.byteCount())
        image = np.array(ptr, dtype=np.uint8).reshape(shape)  # 定义 OpenCV 图像
        image = image[..., :3]
        return image

    def trigger_actHelp(self):  # 动作 actHelp 触发
        QMessageBox.about(self, "About",
                          """数字图像处理工具箱 v1.0\nCopyright YouCans, XUPT 2023""")
        return

if __name__ == '__main__':
    app = QApplication(sys.argv)  # 在 QApplication 方法中使用,创建应用程序对象
    myWin = MyMainWindow()  # 实例化 MyMainWindow 类,创建主窗口
    myWin.show()  # 在桌面显示控件 myWin
    sys.exit(app.exec_())  # 结束进程,退出程序



运行结果:

在这里插入图片描述


【本节完】


版权声明:

Copyright 2023 youcans, XUPT

Crated:2023-2-8



http://www.niftyadmin.cn/n/101331.html

相关文章

基于nodejs+vue地方特色的风景文化宣传网站vscode

管理员可以根据系统给定的账号进行登录&#xff0c;登录后可以进入木里风景文化管理平台对木里风景文化所有模块进行管理。包括查看和修改自己的个人信息以及登录密码。 该系统为每一个用户都分配了一个用户账号&#xff0c;用户通过账号的登录可以在系统中查看木里风景文化信息…

eddsa 算法

信息安全课程设计&#xff1a;eddsa 算法 一、项目要求 使用 C 语言开发&#xff1b;可以实现公私钥生成、签名、认证&#xff1b;只需要手动输入明文&#xff0c;代码会自动生成公私钥、签名、认证&#xff1b;记录公私钥生成、签名、认证的时间&#xff1b;在 VS 上运行&am…

数据结构与算法之树结构基础

目录为什么要使用树结构树结构基本概念树的种类树的存储与表示常见的一些树的应用场景为什么要使用树结构 线性结构中不论是数组还是链表&#xff0c;他们都存在着诟病&#xff1b;比如查找某个数必须从头开始查&#xff0c;消耗较多的时间。使用树结构&#xff0c;在插入和查…

获取浏览器(服务端)请求中特定的Cookie

有必要解释一下HttpServletRequest接口&#xff0c;因为我们需要从它里面获取Cookie。 HttpServletRequest HttpServletRequest是一个Java接口&#xff0c;提供了访问HTTP请求信息的方法&#xff0c;例如HTTP方法、请求URI、头部、参数和会话属性。它是Java Servlet API的一部…

Laravel框架03:DB类操作数据库

Laravel框架03&#xff1a;DB类操作数据库一、概述二、数据表的创建与配置三、增删改操作1. 增加信息2. 修改数据3. 删除数据四、查询操作1. 取出基本数据2. 取出单行数据3. 获取一个字段的值4. 获取多个字段的值5. 排序6. 分页五、执行任意的SQL语句一、概述 按照MVC的架构&a…

Python蓝桥杯训练:基本数据结构 [哈希表]

Python蓝桥杯训练&#xff1a;基本数据结构 [哈希表] 文章目录Python蓝桥杯训练&#xff1a;基本数据结构 [哈希表]一、哈希表理论基础知识1、开放寻址法2、链式法二、有关哈希表的一些常见操作三、力扣上面一些有关哈希表的题目练习1、[有效的字母异位词](https://leetcode.cn…

mesoscale hydrologic model (mHM) 和multiscale parameter regionalization (MPR)

文章目录常见问题what is mesoscale hydrologic model (mHM)how does the mHm model upscale the parameterswhat is the multiscale parameter regionalization (MPR)how does MPR aggregating the parameters at a small scale to the parameters at the regional scale<3…

爬虫知识简介

爬虫简介 爬虫与网络请求 ​ 网络爬虫是一个自动提取网页的程序&#xff0c;一般都分为3步&#xff1a;数据爬取&#xff0c;数据解析&#xff0c;数据存储。数据爬取就是模拟浏览器发送请求&#xff0c;所以需要对网络请求HTTP/HTTPS有一定了解 相关概念&#xff1a; ​ H…