网站建设服务器篇,北京企业网站建设,wordpress文章id排序,英文站友情链接去哪里查欢迎关注『OpenCV-PyQT项目实战 Youcans』系列#xff0c;持续更新中 OpenCV-PyQT项目实战#xff08;1#xff09;安装与环境配置 OpenCV-PyQT项目实战#xff08;2#xff09;QtDesigner 和 PyUIC 快速入门 OpenCV-PyQT项目实战#xff08;3#xff09;信号与槽机制 … 欢迎关注『OpenCV-PyQT项目实战 Youcans』系列持续更新中 OpenCV-PyQT项目实战1安装与环境配置 OpenCV-PyQT项目实战2QtDesigner 和 PyUIC 快速入门 OpenCV-PyQT项目实战3信号与槽机制 OpenCV-PyQT项目实战4OpenCV 与PyQt的图像转换 OpenCV-PyQT项目实战5项目案例01图像模糊 OpenCV-PyQT项目实战6项目案例02滚动条应用 OpenCV-PyQT项目实战7项目案例03鼠标框选 文章目录OpenCV-PyQT项目实战7项目案例03鼠标框选1. OpenCV实现鼠标框选2. PyQt实现鼠标框选2.1 支持鼠标事件的自定义 Label 类2.2 例程7-2支持鼠标事件的自定义 MyLabel 类3. 项目实战PyQt 鼠标框选3.1 使用 QtDesigner 开发 PyQt5 图形界面3.2. 项目主程序的开发3.2.1 实例化 MyLabel 类3.2.2 框选图像槽函数3.2.3 信号与槽的连接3.3 完整例程 OpenCVPyqt08.pyOpenCV-PyQT项目实战7项目案例03鼠标框选
本节介绍OpenCV和PyQt 实现鼠标框选的方法和案例通过案例学习PyQt中的鼠标动作。 1. OpenCV实现鼠标框选
OpenCV中的函数 cv.selectROI 可以通过鼠标在图像上选择感兴趣的矩形区域ROIregion of interest。
函数原型 cv.selectROI(windowName, img[, showCrosshairtrue, fromCenterfalse]) → retval 函数cv.selectROI创建一个显示窗口允许用户使用鼠标选择ROI按Space或Enter键完成选择按c键取消选择。
参数说明
● img选择矩形区域的图像
● windowName图像显示窗口的名称
● showCrosshair默认值true显示选择矩形的中心十字线
● fromCenter默认值false表示鼠标初始位置作为矩形的角点true表示鼠标初始位置作为矩形的中心点
● retval返回值为Rect矩形类格式为元组 (x , y, w, h)
注意问题
⒈函数的返回值是Rect矩形类元组 (x , y, w, h) 分别表示矩形左上角顶点坐标 (x,y)、矩形的宽度w和高度h。
⒉函数创建一个窗口设置自己的鼠标回调完成后将为使用的窗口设置一个空回调。
例程7-1OpenCV鼠标框选 # 1.17 图像的裁剪 (ROI)img1 cv2.imread(../images/imgLena.tif, flags1) # flags1 读取彩色图像(BGR)roi cv2.selectROI(img1, showCrosshairTrue, fromCenterFalse)xmin, ymin, w, h roi # 矩形裁剪区域 (ymin:yminh, xmin:xminw) 的位置参数imgROI img1[ymin:yminh, xmin:xminw].copy() # 切片获得裁剪后保留的图像区域cv2.imshow(DemoRIO, imgROI)cv2.waitKey(0)总结OpenCV实现鼠标框选非常简单但无法与 PyQt5 的 GUI 集成只能在 OpenCV GUI 进行简单的操作。 2. PyQt实现鼠标框选
PyQt 中实现鼠标框选本质上是鼠标动作的响应。
2.1 支持鼠标事件的自定义 Label 类
基本的 QLabel 类并不支持鼠标动作因此需要自定义一个支持鼠标动作的 Label 类。
PyQt中每个事件类型都被封装成相应的事件类如鼠标事件为QMouseEvent键盘事件为QKeyEvent等。而它们的基类是QEvent。
QMouseEvent 鼠标事件 mousePressEvent (self, event)鼠标按下事件 mouseReleaseEvent (self, event)鼠标释放事件 mouseDoubieCiickEvent (self, event)双击鼠标事件 mouseMoveEvent(selfevent)鼠标移动事件 enterEvent (self, event)鼠标进入控件事件 leaveEvent (self, event)鼠标离开控件事件 wheelEvent (self, event)滚轮滚动事件 QMouseEvent 鼠标方法 ignore()让父控件继续收到鼠标事件 accept()不让父控件继续收到鼠标事件 x()、y()返回相对于控件空间的鼠标坐标值 pos()返回相对于控件空间的QPoint对象 localPos()返回相对于控件空间的QPointF对象 globalX()、globalY()返回相对于屏幕的x,y 坐标值 globalPos()返回相对于屏幕的QPoint对象 windowPos()返回相对于窗口的QPointF对象 screenPos()返回相对于屏幕的QPointF对象 timestamp()返回事件发生的时间 QMouseEvent 鼠标事件的具体内容 按下并释放鼠标按钮时将调用以下方法 mousePressEvent (self, event) - 鼠标键按下时调用; mouseReleaseEvent (self, event) - 鼠标键公开时调用; mouseDoubieCiickEvent (self, event) - 双击鼠标时调用。必须注意在双击之前的其他事件。双击时的事件顺序如下: - MouseButtonPress
- MouseButtonRelease
- MouseButtonDblClick
- MouseButtonPress
- MouseButtonRelease2.2 例程7-2支持鼠标事件的自定义 MyLabel 类
class MyLabel(QLabel):def __init__(self,parentNone):super(MyLabel, self).__init__(parent)self.x0 0self.y0 0self.x1 1self.y1 1self.flag False# 鼠标点击事件def mousePressEvent(self, event):self.flag True # 鼠标点击状态self.x0 event.x()self.y0 event.y()# 鼠标释放事件def mouseReleaseEvent(self, event):self.flag False # 鼠标释放状态self.x1 event.x()self.y1 event.y()# 鼠标移动事件def mouseMoveEvent(self, event):if self.flag:self.x1 event.x()self.y1 event.y()self.update()# 绘制事件def paintEvent(self, event):super().paintEvent(event)rect QRect(self.x0, self.y0, abs(self.x1 - self.x0), abs(self.y1 - self.y0))painter QPainter(self)painter.setPen(QPen(Qt.red, 2, Qt.SolidLine))painter.drawRect(rect) 3. 项目实战PyQt 鼠标框选
本项目基于 PyQt5 GUI使用鼠标框选 ROI 区域在窗口中显示 ROI 区域并对 ROI 进行处理。 3.1 使用 QtDesigner 开发 PyQt5 图形界面
本例的 UI 集自 uiDemo4.ui [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-SzG6cP8y-1676360319630)(D:\OpenCVPyQt\images\OpenCV_20.png)]
于是我们就完成了本项目的图形界面设计将其保存为 uiDemo7.ui文件。
在 PyCharm中使用 PyUIC 将选中的 uiDemo7.ui 文件转换为 .py 文件就得到了 uiDemo7.py 文件。 3.2. 项目主程序的开发
3.2.1 实例化 MyLabel 类
自定义的 MyLabel 类不能在 QtDesigner 中创建要在主程序中定义如下。 self.label_1 MyLabel(self.centralwidget)self.label_1.setGeometry(QRect(20, 20, 400, 320))self.label_1.setAlignment(Qt.AlignCenter)self.label_1.setObjectName(label_1)3.2.2 框选图像槽函数
click_pushButton槽函数由 pushButton_3.clicked 按钮信号触发。 def click_pushButton_3(self): # 点击 pushButton_3 触发 框选图像print(pushButton_3)self.label_1.setGeometry(QRect(20, 20, 400, 320))hImg, wImg self.img1.shape[:2]wLabel self.label_1.width()hLabel self.label_1.height()x0 self.label_1.x0 * wImg//wLabely0 self.label_1.y0 * hImg//hLabelx1 self.label_1.x1 * wImg//wLabely1 self.label_1.y1 * hImg//hLabelprint(hImg,wImg({},{}), x1,y1({},{}).format(hImg, wImg, hLabel, wLabel))print(x0,y0({},{}), x1,y1({},{}).format(x0, y0, x1, y1))self.img2 np.zeros((self.img1.shape), np.uint8)self.img2[y0:y1, x0:x1, :] self.img1[y0:y1, x0:x1, :]self.refreshShow(self.img2, self.label_2) # 刷新显示return3.2.3 信号与槽的连接 # 通过 connect 建立信号/槽连接点击按钮事件发射 triggered 信号执行相应的子程序 click_pushButtonself.pushButton_1.clicked.connect(self.click_pushButton_1) # 按钮触发导入图像self.pushButton_2.clicked.connect(self.click_pushButton_2) # # 按钮触发灰度显示self.pushButton_3.clicked.connect(self.click_pushButton_3) # # 按钮触发框选图像self.pushButton_4.clicked.connect(self.trigger_actHelp) # # 按钮触发调整色阶self.pushButton_5.clicked.connect(self.close) # 点击 # 按钮触发关闭3.3 完整例程 OpenCVPyqt08.py
# OpenCVPyqt08.py
# Demo07 of GUI by PyQt5
# Copyright 2023 Youcans, XUPT
# Crated2023-02-12import sys
import cv2 as cv
import numpy as np
from PyQt5.QtCore import QObject, pyqtSignal, QPoint, QRect, qDebug, Qt
from PyQt5.QtWidgets import *
from PyQt5.QtGui import *
from uiDemo8 import Ui_MainWindow # 导入 uiDemo8.py 中的 Ui_MainWindow 界面类class MyLabel(QLabel):def __init__(self,parentNone):super(MyLabel, self).__init__(parent)self.x0 0self.y0 0self.x1 1self.y1 1self.flag False# 鼠标点击事件def mousePressEvent(self, event):self.flag True # 鼠标点击状态self.x0 event.x()self.y0 event.y()# 鼠标释放事件def mouseReleaseEvent(self, event):self.flag False # 鼠标释放状态self.x1 event.x()self.y1 event.y()# 鼠标移动事件def mouseMoveEvent(self, event):if self.flag:self.x1 event.x()self.y1 event.y()self.update()# 绘制事件def paintEvent(self, event):super().paintEvent(event)rect QRect(self.x0, self.y0, abs(self.x1 - self.x0), abs(self.y1 - self.y0))painter QPainter(self)painter.setPen(QPen(Qt.red, 2, Qt.SolidLine))painter.drawRect(rect)class MyMainWindow(QMainWindow, Ui_MainWindow): # 继承 QMainWindow 类和 Ui_MainWindow 界面类def __init__(self, parentNone):super(MyMainWindow, self).__init__(parent) # 初始化父类self.setupUi(self) # 继承 Ui_MainWindow 界面类self.label_1 MyLabel(self.centralwidget)self.label_1.setGeometry(QRect(20, 20, 400, 320))self.label_1.setAlignment(Qt.AlignCenter)self.label_1.setObjectName(label_1)# 菜单栏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_pushButtonself.pushButton_1.clicked.connect(self.click_pushButton_1) # 按钮触发导入图像self.pushButton_2.clicked.connect(self.click_pushButton_2) # # 按钮触发灰度显示self.pushButton_3.clicked.connect(self.click_pushButton_3) # # 按钮触发框选图像self.pushButton_4.clicked.connect(self.trigger_actHelp) # # 按钮触发调整色阶self.pushButton_5.clicked.connect(self.close) # 点击 # 按钮触发关闭# 初始化self.img1 np.ndarray(()) # 初始化图像 ndarry用于存储图像self.img2 np.ndarray(()) # 初始化图像 ndarry用于存储图像self.img1 cv.imread(../images/Lena.tif) # OpenCV 读取图像self.refreshShow(self.img1, self.label_1)# self.refreshShow(self.img1, self.label_2)returndef click_pushButton_1(self): # 点击 pushButton_1 触发self.img1 self.openSlot() # 读取图像self.img2 self.img1.copy()print(click_pushButton_1, self.img1.shape)self.refreshShow(self.img1, self.label_1) # 刷新显示returndef click_pushButton_2(self): # 点击 pushButton_2 触发print(pushButton_2)self.img2 cv.cvtColor(self.img2, cv.COLOR_BGR2GRAY) # 图片格式转换BGR - Grayself.refreshShow(self.img2, self.label_2) # 刷新显示returndef click_pushButton_3(self): # 点击 pushButton_3 触发 框选图像print(pushButton_3)self.label_1.setGeometry(QRect(20, 20, 400, 320))hImg, wImg self.img1.shape[:2]wLabel self.label_1.width()hLabel self.label_1.height()x0 self.label_1.x0 * wImg//wLabely0 self.label_1.y0 * hImg//hLabelx1 self.label_1.x1 * wImg//wLabely1 self.label_1.y1 * hImg//hLabelprint(hImg,wImg({},{}), x1,y1({},{}).format(hImg, wImg, hLabel, wLabel))print(x0,y0({},{}), x1,y1({},{}).format(x0, y0, x1, y1))self.img2 np.zeros((self.img1.shape), np.uint8)self.img2[y0:y1, x0:x1, :] self.img1[y0:y1, x0:x1, :]print(self.img2.shape)# cv.imshow(Demo, self.img2)# key cv.waitKey(0) # 等待下一个按键命令# self.gRightLayout.removeWidget(self.label_2) # 删除原有 labelCover 控件及显示图表# sip.delete(self.labelCover) # 删除控件 labelCover# self.img2 np.zeros(self.img1.shape, np.int8)self.refreshShow(self.img2, self.label_2) # 刷新显示returndef refreshShow(self, img, label):print(img.shape, label)qImg self.cvToQImage(img) # OpenCV 转为 PyQt 图像格式# label.setScaledContents(False) # 需要在图片显示之前进行设置label.setPixmap((QPixmap.fromImage(qImg))) # 加载 PyQt 图像returndef openSlot(self, flag1): # 读取图像文件# OpenCV 读取图像文件fileName, _ QFileDialog.getOpenFileName(self, Open Image, ../images/, *.png *.jpg *.tif)if flag0 or flaggray:img cv.imread(fileName, cv.IMREAD_GRAYSCALE) # 读取灰度图像else:img cv.imread(fileName, cv.IMREAD_COLOR) # 读取彩色图像print(fileName, img.shape)return imgdef saveSlot(self): # 保存图像文件# 选择存储文件 dialogfileName, 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)returndef cvToQImage(self, image):# 8-bits unsigned, NO. OF CHANNELS1if 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 MatqImg 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 MatqImg QImage(image, image.shape[1], image.shape[0], image.strides[0], QImage.Format_Indexed8)return qImgelse: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 转换为 QImageshape (qImg.height(), qImg.bytesPerLine() * 8 // qImg.depth())shape (4,)ptr qImg.bits()ptr.setsize(qImg.byteCount())image np.array(ptr, dtypenp.uint8).reshape(shape) # 定义 OpenCV 图像image image[..., :3]return imagedef trigger_actHelp(self): # 动作 actHelp 触发QMessageBox.about(self, About,数字图像处理工具箱 v1.0\nCopyright YouCans, XUPT 2023)returnif __name__ __main__:app QApplication(sys.argv) # 在 QApplication 方法中使用创建应用程序对象myWin MyMainWindow() # 实例化 MyMainWindow 类创建主窗口myWin.show() # 在桌面显示控件 myWinsys.exit(app.exec_()) # 结束进程退出程序 运行结果 【本节完】 版权声明
Copyright 2023 youcans, XUPT
Crated2023-2-14