python提取论文图片波形数据:pyautogui键盘移动鼠标,跨模块全局变量使用,cv2局部放大窗口,matplotlib图片在pyQT5lable显示,坐标变换,多线程同时使用

发布时间 2023-09-30 17:49:53作者: 菜芽caiya

最近写了一个python提取论文图片波形数据的脚本,代码如下。

涉及新知识点:pyautogui键盘移动鼠标,跨模块全局变量使用,cv2局部放大窗口,matplotlib图片在pyQT5lable显示,坐标变换,多线程同时使用。搜索相关关键字去对应代码区看注释就可以了。

gui窗口:

  1 # -*- coding: utf-8 -*-
  2 
  3 # Form implementation generated from reading ui file 'caiyagui.ui'
  4 #
  5 # Created by: PyQt5 UI code generator 5.14.2
  6 #
  7 # WARNING! All changes made in this file will be lost!
  8 
  9 
 10 from PyQt5 import QtCore, QtGui, QtWidgets
 11 
 12 
 13 class Ui_MainWindow(object):
 14     def setupUi(self, MainWindow):
 15         MainWindow.setObjectName("MainWindow")
 16         MainWindow.resize(905, 472)
 17         self.centralwidget = QtWidgets.QWidget(MainWindow)
 18         self.centralwidget.setObjectName("centralwidget")
 19         self.verticalLayout = QtWidgets.QVBoxLayout(self.centralwidget)
 20         self.verticalLayout.setObjectName("verticalLayout")
 21         self.label_12 = QtWidgets.QLabel(self.centralwidget)
 22         self.label_12.setAlignment(QtCore.Qt.AlignCenter)
 23         self.label_12.setObjectName("label_12")
 24         self.verticalLayout.addWidget(self.label_12)
 25         self.gridLayout = QtWidgets.QGridLayout()
 26         self.gridLayout.setObjectName("gridLayout")
 27         self.label_6 = QtWidgets.QLabel(self.centralwidget)
 28         self.label_6.setObjectName("label_6")
 29         self.gridLayout.addWidget(self.label_6, 2, 5, 1, 1)
 30         self.lineEdit_7 = QtWidgets.QLineEdit(self.centralwidget)
 31         self.lineEdit_7.setObjectName("lineEdit_7")
 32         self.gridLayout.addWidget(self.lineEdit_7, 1, 7, 1, 1)
 33         self.lineEdit_8 = QtWidgets.QLineEdit(self.centralwidget)
 34         self.lineEdit_8.setObjectName("lineEdit_8")
 35         self.gridLayout.addWidget(self.lineEdit_8, 2, 4, 1, 1)
 36         self.label_2 = QtWidgets.QLabel(self.centralwidget)
 37         self.label_2.setObjectName("label_2")
 38         self.gridLayout.addWidget(self.label_2, 1, 5, 1, 1)
 39         self.lineEdit_2 = QtWidgets.QLineEdit(self.centralwidget)
 40         self.lineEdit_2.setObjectName("lineEdit_2")
 41         self.gridLayout.addWidget(self.lineEdit_2, 1, 6, 1, 1)
 42         self.lineEdit_6 = QtWidgets.QLineEdit(self.centralwidget)
 43         self.lineEdit_6.setObjectName("lineEdit_6")
 44         self.gridLayout.addWidget(self.lineEdit_6, 1, 4, 1, 1)
 45         self.label_3 = QtWidgets.QLabel(self.centralwidget)
 46         self.label_3.setObjectName("label_3")
 47         self.gridLayout.addWidget(self.label_3, 1, 2, 1, 1)
 48         self.lineEdit_3 = QtWidgets.QLineEdit(self.centralwidget)
 49         self.lineEdit_3.setObjectName("lineEdit_3")
 50         self.gridLayout.addWidget(self.lineEdit_3, 1, 3, 1, 1)
 51         self.lineEdit_4 = QtWidgets.QLineEdit(self.centralwidget)
 52         self.lineEdit_4.setObjectName("lineEdit_4")
 53         self.gridLayout.addWidget(self.lineEdit_4, 2, 6, 1, 1)
 54         self.lineEdit_5 = QtWidgets.QLineEdit(self.centralwidget)
 55         self.lineEdit_5.setObjectName("lineEdit_5")
 56         self.gridLayout.addWidget(self.lineEdit_5, 2, 3, 1, 1)
 57         self.lineEdit_9 = QtWidgets.QLineEdit(self.centralwidget)
 58         self.lineEdit_9.setObjectName("lineEdit_9")
 59         self.gridLayout.addWidget(self.lineEdit_9, 2, 7, 1, 1)
 60         self.label_5 = QtWidgets.QLabel(self.centralwidget)
 61         self.label_5.setObjectName("label_5")
 62         self.gridLayout.addWidget(self.label_5, 2, 2, 1, 1)
 63         self.label_7 = QtWidgets.QLabel(self.centralwidget)
 64         sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Preferred, QtWidgets.QSizePolicy.Fixed)
 65         sizePolicy.setHorizontalStretch(0)
 66         sizePolicy.setVerticalStretch(0)
 67         sizePolicy.setHeightForWidth(self.label_7.sizePolicy().hasHeightForWidth())
 68         self.label_7.setSizePolicy(sizePolicy)
 69         self.label_7.setAlignment(QtCore.Qt.AlignCenter)
 70         self.label_7.setObjectName("label_7")
 71         self.gridLayout.addWidget(self.label_7, 0, 4, 1, 1)
 72         self.label_8 = QtWidgets.QLabel(self.centralwidget)
 73         sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Preferred, QtWidgets.QSizePolicy.Fixed)
 74         sizePolicy.setHorizontalStretch(0)
 75         sizePolicy.setVerticalStretch(0)
 76         sizePolicy.setHeightForWidth(self.label_8.sizePolicy().hasHeightForWidth())
 77         self.label_8.setSizePolicy(sizePolicy)
 78         self.label_8.setAlignment(QtCore.Qt.AlignCenter)
 79         self.label_8.setObjectName("label_8")
 80         self.gridLayout.addWidget(self.label_8, 0, 3, 1, 1)
 81         self.label_9 = QtWidgets.QLabel(self.centralwidget)
 82         sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Preferred, QtWidgets.QSizePolicy.Fixed)
 83         sizePolicy.setHorizontalStretch(0)
 84         sizePolicy.setVerticalStretch(0)
 85         sizePolicy.setHeightForWidth(self.label_9.sizePolicy().hasHeightForWidth())
 86         self.label_9.setSizePolicy(sizePolicy)
 87         self.label_9.setAlignment(QtCore.Qt.AlignCenter)
 88         self.label_9.setObjectName("label_9")
 89         self.gridLayout.addWidget(self.label_9, 0, 6, 1, 1)
 90         self.label_10 = QtWidgets.QLabel(self.centralwidget)
 91         sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Preferred, QtWidgets.QSizePolicy.Fixed)
 92         sizePolicy.setHorizontalStretch(0)
 93         sizePolicy.setVerticalStretch(0)
 94         sizePolicy.setHeightForWidth(self.label_10.sizePolicy().hasHeightForWidth())
 95         self.label_10.setSizePolicy(sizePolicy)
 96         self.label_10.setAlignment(QtCore.Qt.AlignCenter)
 97         self.label_10.setObjectName("label_10")
 98         self.gridLayout.addWidget(self.label_10, 0, 7, 1, 1)
 99         self.verticalLayout.addLayout(self.gridLayout)
100         self.line_5 = QtWidgets.QFrame(self.centralwidget)
101         self.line_5.setFrameShape(QtWidgets.QFrame.HLine)
102         self.line_5.setFrameShadow(QtWidgets.QFrame.Sunken)
103         self.line_5.setObjectName("line_5")
104         self.verticalLayout.addWidget(self.line_5)
105         spacerItem = QtWidgets.QSpacerItem(20, 40, QtWidgets.QSizePolicy.Minimum, QtWidgets.QSizePolicy.Expanding)
106         self.verticalLayout.addItem(spacerItem)
107         self.line_2 = QtWidgets.QFrame(self.centralwidget)
108         self.line_2.setFrameShape(QtWidgets.QFrame.HLine)
109         self.line_2.setFrameShadow(QtWidgets.QFrame.Sunken)
110         self.line_2.setObjectName("line_2")
111         self.verticalLayout.addWidget(self.line_2)
112         self.horizontalLayout_3 = QtWidgets.QHBoxLayout()
113         self.horizontalLayout_3.setObjectName("horizontalLayout_3")
114         self.label_13 = QtWidgets.QLabel(self.centralwidget)
115         self.label_13.setObjectName("label_13")
116         self.horizontalLayout_3.addWidget(self.label_13)
117         self.label = QtWidgets.QLabel(self.centralwidget)
118         self.label.setObjectName("label")
119         self.horizontalLayout_3.addWidget(self.label)
120         self.lineEdit = QtWidgets.QLineEdit(self.centralwidget)
121         self.lineEdit.setObjectName("lineEdit")
122         self.horizontalLayout_3.addWidget(self.lineEdit)
123         self.pushButton_3 = QtWidgets.QPushButton(self.centralwidget)
124         self.pushButton_3.setObjectName("pushButton_3")
125         self.horizontalLayout_3.addWidget(self.pushButton_3)
126         self.verticalLayout.addLayout(self.horizontalLayout_3)
127         self.horizontalLayout_2 = QtWidgets.QHBoxLayout()
128         self.horizontalLayout_2.setObjectName("horizontalLayout_2")
129         self.label_14 = QtWidgets.QLabel(self.centralwidget)
130         sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Fixed, QtWidgets.QSizePolicy.Fixed)
131         sizePolicy.setHorizontalStretch(0)
132         sizePolicy.setVerticalStretch(0)
133         sizePolicy.setHeightForWidth(self.label_14.sizePolicy().hasHeightForWidth())
134         self.label_14.setSizePolicy(sizePolicy)
135         self.label_14.setObjectName("label_14")
136         self.horizontalLayout_2.addWidget(self.label_14)
137         self.label_4 = QtWidgets.QLabel(self.centralwidget)
138         self.label_4.setObjectName("label_4")
139         self.horizontalLayout_2.addWidget(self.label_4)
140         self.pushButton_4 = QtWidgets.QPushButton(self.centralwidget)
141         sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Fixed, QtWidgets.QSizePolicy.Fixed)
142         sizePolicy.setHorizontalStretch(0)
143         sizePolicy.setVerticalStretch(0)
144         sizePolicy.setHeightForWidth(self.pushButton_4.sizePolicy().hasHeightForWidth())
145         self.pushButton_4.setSizePolicy(sizePolicy)
146         self.pushButton_4.setObjectName("pushButton_4")
147         self.horizontalLayout_2.addWidget(self.pushButton_4)
148         self.verticalLayout.addLayout(self.horizontalLayout_2)
149         self.line = QtWidgets.QFrame(self.centralwidget)
150         self.line.setFrameShape(QtWidgets.QFrame.HLine)
151         self.line.setFrameShadow(QtWidgets.QFrame.Sunken)
152         self.line.setObjectName("line")
153         self.verticalLayout.addWidget(self.line)
154         spacerItem1 = QtWidgets.QSpacerItem(20, 40, QtWidgets.QSizePolicy.Minimum, QtWidgets.QSizePolicy.Expanding)
155         self.verticalLayout.addItem(spacerItem1)
156         self.line_4 = QtWidgets.QFrame(self.centralwidget)
157         self.line_4.setFrameShape(QtWidgets.QFrame.HLine)
158         self.line_4.setFrameShadow(QtWidgets.QFrame.Sunken)
159         self.line_4.setObjectName("line_4")
160         self.verticalLayout.addWidget(self.line_4)
161         self.horizontalLayout_5 = QtWidgets.QHBoxLayout()
162         self.horizontalLayout_5.setObjectName("horizontalLayout_5")
163         self.textBrowser = QtWidgets.QTextBrowser(self.centralwidget)
164         sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Preferred, QtWidgets.QSizePolicy.Preferred)
165         sizePolicy.setHorizontalStretch(0)
166         sizePolicy.setVerticalStretch(0)
167         sizePolicy.setHeightForWidth(self.textBrowser.sizePolicy().hasHeightForWidth())
168         self.textBrowser.setSizePolicy(sizePolicy)
169         self.textBrowser.setObjectName("textBrowser")
170         self.horizontalLayout_5.addWidget(self.textBrowser)
171         self.label_11 = QtWidgets.QLabel(self.centralwidget)
172         sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Fixed, QtWidgets.QSizePolicy.Fixed)
173         sizePolicy.setHorizontalStretch(0)
174         sizePolicy.setVerticalStretch(0)
175         sizePolicy.setHeightForWidth(self.label_11.sizePolicy().hasHeightForWidth())
176         self.label_11.setSizePolicy(sizePolicy)
177         self.label_11.setAlignment(QtCore.Qt.AlignCenter)
178         self.label_11.setObjectName("label_11")
179         self.horizontalLayout_5.addWidget(self.label_11)
180         self.verticalLayout.addLayout(self.horizontalLayout_5)
181         self.line_3 = QtWidgets.QFrame(self.centralwidget)
182         self.line_3.setFrameShape(QtWidgets.QFrame.HLine)
183         self.line_3.setFrameShadow(QtWidgets.QFrame.Sunken)
184         self.line_3.setObjectName("line_3")
185         self.verticalLayout.addWidget(self.line_3)
186         spacerItem2 = QtWidgets.QSpacerItem(20, 40, QtWidgets.QSizePolicy.Minimum, QtWidgets.QSizePolicy.Expanding)
187         self.verticalLayout.addItem(spacerItem2)
188         self.horizontalLayout = QtWidgets.QHBoxLayout()
189         self.horizontalLayout.setObjectName("horizontalLayout")
190         self.pushButton = QtWidgets.QPushButton(self.centralwidget)
191         self.pushButton.setText("")
192         self.pushButton.setObjectName("pushButton")
193         self.horizontalLayout.addWidget(self.pushButton)
194         self.checkBox_2 = QtWidgets.QCheckBox(self.centralwidget)
195         self.checkBox_2.setObjectName("checkBox_2")
196         self.horizontalLayout.addWidget(self.checkBox_2)
197         self.checkBox = QtWidgets.QCheckBox(self.centralwidget)
198         self.checkBox.setObjectName("checkBox")
199         self.horizontalLayout.addWidget(self.checkBox)
200         spacerItem3 = QtWidgets.QSpacerItem(40, 20, QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Minimum)
201         self.horizontalLayout.addItem(spacerItem3)
202         self.pushButton_5 = QtWidgets.QPushButton(self.centralwidget)
203         self.pushButton_5.setObjectName("pushButton_5")
204         self.horizontalLayout.addWidget(self.pushButton_5)
205         self.pushButton_6 = QtWidgets.QPushButton(self.centralwidget)
206         self.pushButton_6.setObjectName("pushButton_6")
207         self.horizontalLayout.addWidget(self.pushButton_6)
208         self.pushButton_2 = QtWidgets.QPushButton(self.centralwidget)
209         self.pushButton_2.setObjectName("pushButton_2")
210         self.horizontalLayout.addWidget(self.pushButton_2)
211         self.verticalLayout.addLayout(self.horizontalLayout)
212         MainWindow.setCentralWidget(self.centralwidget)
213         self.statusbar = QtWidgets.QStatusBar(MainWindow)
214         self.statusbar.setObjectName("statusbar")
215         MainWindow.setStatusBar(self.statusbar)
216 
217         self.retranslateUi(MainWindow)
218         QtCore.QMetaObject.connectSlotsByName(MainWindow)
219 
220     def retranslateUi(self, MainWindow):
221         _translate = QtCore.QCoreApplication.translate
222         MainWindow.setWindowTitle(_translate("MainWindow", "caiya tools"))
223         self.label_12.setText(_translate("MainWindow", "图像数据提取工具"))
224         self.label_6.setText(_translate("MainWindow", "Y1"))
225         self.label_2.setText(_translate("MainWindow", "X1"))
226         self.label_3.setText(_translate("MainWindow", "X0"))
227         self.label_5.setText(_translate("MainWindow", "Y0"))
228         self.label_7.setText(_translate("MainWindow", "y"))
229         self.label_8.setText(_translate("MainWindow", "x"))
230         self.label_9.setText(_translate("MainWindow", "x"))
231         self.label_10.setText(_translate("MainWindow", "y"))
232         self.label_13.setText(_translate("MainWindow", "保存路径:"))
233         self.label.setText(_translate("MainWindow", "目录"))
234         self.pushButton_3.setText(_translate("MainWindow", "Browse"))
235         self.label_14.setText(_translate("MainWindow", "导入路径:"))
236         self.label_4.setText(_translate("MainWindow", "文件路径"))
237         self.pushButton_4.setText(_translate("MainWindow", "Open File"))
238         self.label_11.setText(_translate("MainWindow", "处理波形显示"))
239         self.checkBox_2.setText(_translate("MainWindow", "x轴对数分度坐标"))
240         self.checkBox.setText(_translate("MainWindow", "y轴对数分度坐标"))
241         self.pushButton_5.setText(_translate("MainWindow", "校准坐标"))
242         self.pushButton_6.setText(_translate("MainWindow", "标记数据点"))
243         self.pushButton_2.setText(_translate("MainWindow", "Save"))

全局变量部分:

#跨模块全局变量
#模态运行标志位
punlic_flag=10
#坐标校准点
public_coord=[(0,0),(0,0),(0,0),(0,0)]
#图片尺寸
public_size=(0,0)
#坐标轴绘制点
public_cood_data=[(0,0),(0,0),(0,0),(0,0)]
#坐标原点
public_cood_origin=(0,0)
#提取点数坐标
public_data_point=[]

cv2图片处理部分:

import os
import cv2
import pyautogui
import FlagUse
import pandas as pd

def save_excel(path_in,data_in):
    try:
        if os.path.exists(path_in)==True:
            os.remove(path_in)
    except Exception as exc:
        error_str=str(exc)
        return error_str
    else:
        try:
            data_save=pd.DataFrame(data_in)
            data_save.to_excel(path_in,index=False)
        except Exception as exc:
            error_str = str(exc)
            return error_str
        else:
            return "Done!"

# 定义标注窗口的默认名称
WINDOW_NAME = 'image curve data get'

# 定义画面刷新的大概帧率(是否能达到取决于电脑性能)
FPS = 30

# ESC键对应的cv.waitKey()的返回值
# 注意这个值根据操作系统不同有不同
KEY_ESC = 27

# 定义物体框标注工具类
class SimpleBBoxLabeling:

    def __init__(self, inage, fps=FPS, window_name=None):
        self. inage= inage
        self.fps = fps
        self.window_name = window_name if window_name else WINDOW_NAME

        # pt0是正在画的左上角坐标,pt1是鼠标所在坐标
        self._pt0 = None
        #h 高度,w宽度
        h,w=self.inage.shape[:2]
        self._pt1 = (int(h/2),int(w/2))
        FlagUse.public_size=(h,w)

        # 表明当前是否正在画框的状态标记
        self._drawing = False

        # 当前标注物体的名称
        self._cur_label = None

        # 当前图像对应的曲线的点
        self._bboxes = []
        # 当前图像坐标校准的点
        self._bboxes_coord = []

        #放大窗口
        self.dx = 30
        self.y0_last = self._pt1[1] - self.dx
        self.y1_last = self._pt1[1] + self.dx
        self.x0_last = self._pt1[0] - self.dx
        self.x1_last = self._pt1[0] + self.dx
        self.yy0_last = 0;self.yy1_last = 0;self.xx0_last = 0;self.xx1_last = 0

    # 鼠标回调函数
    def _mouse_ops(self, event, x, y, flags, param):

        # 按下左键时,坐标为左上角,同时表明开始画框,改变drawing标记为True
        if event == cv2.EVENT_LBUTTONDOWN:
            self._drawing = True
            self._pt0 = (x, y)

        # 左键抬起,表明当前框画完了,坐标记为右下角,并保存,同时改变drawing标记为False
        elif event == cv2.EVENT_LBUTTONUP:
            self._drawing = False
            self._pt1 = (x, y)
            #坐标轴校准
            if FlagUse.punlic_flag==0:
                if self._pt1[0] == self._pt0[0] and self._pt1[1] == self._pt0[1]:#不是在画框
                    if len(self._bboxes_coord)<4:#最大只能4个点
                        self._bboxes_coord.append((self._cur_label, self._pt0))
                    if len(self._bboxes_coord)==4:#校准点画满,更新全局变量
                        for i in range(len(self._bboxes_coord)):
                            FlagUse.public_coord[i]=self._bboxes_coord[i][1]
            #数据点提取
            elif FlagUse.punlic_flag==1:
                if self._pt1[0]!=self._pt0[0] and self._pt1[1]!=self._pt0[1]:#不是在画框
                    if self._pt1[0] >= self._pt0[0] and self._pt1[1] >= self._pt0[1]:#判断不是反向画框
                        if len(self._bboxes)!=0:#数据点存在
                            inx=[]
                            for i in range(len(self._bboxes)):#找到哪些点在方框中
                                if self._bboxes[i][1][0]>self._pt0[0] and self._bboxes[i][1][0]<self._pt1[0] and self._bboxes[i][1][1]>self._pt0[1] and self._bboxes[i][1][1]<self._pt1[1]:
                                    inx.append(i)
                            inx.sort(reverse=True)#删除框选的点
                            for i in inx:
                                self._bboxes.pop(i)
                else:#添加数据点
                    self._bboxes.append((self._cur_label, self._pt0))
                    FlagUse.public_data_point=[]
                    for i in self._bboxes:
                        FlagUse.public_data_point.append(i[1])

        # 实时更新右下角坐标方便画框
        elif event == cv2.EVENT_MOUSEMOVE:
            self._pt1 = (x, y)

        # 鼠标右键删除最近画好的框
        elif event == cv2.EVENT_RBUTTONUP:
            if FlagUse.punlic_flag == 0:
                if self._bboxes_coord:
                    self._bboxes_coord.pop()
            elif FlagUse.punlic_flag == 1:
                if self._bboxes:
                    self._bboxes.pop()

    # 清除所有标注框和当前状态
    def _clean_bbox(self):
        self._pt0 = None
        self._pt1 = None
        self._drawing = False
        self._bboxes = []

    # 画标注框和当前信息的函数
    def _draw_bbox(self, img):
        canvas = cv2.copyMakeBorder(img, 0, 0, 0, 0, cv2.BORDER_CONSTANT, value=(255, 0, 0))#新建画布
        # 画出已经标好的点和对应名字
        i=0
        for label, bpt0 in self._bboxes:
            cv2.circle(canvas, bpt0,5, (0, 0, 255), -1)
            #字体
            font=cv2.FONT_HERSHEY_SIMPLEX
            #标记点
            cv2.putText(canvas,"a%s"%i,bpt0,font,1,(200,50,0),2)
            i=i+1
        i=0
        for label, bpt0 in self._bboxes_coord:
            cv2.circle(canvas, bpt0,5, (0, 0, 255), -1)
            #字体
            font=cv2.FONT_HERSHEY_SIMPLEX
            #标记点
            if i==0 or i==1:
                cv2.putText(canvas,"X%s-%s"%(i,bpt0[1]),bpt0,font,1,(200,50,0),2)
            else:
                cv2.putText(canvas, "Y%s-%s" % (i-2,bpt0[0]), bpt0, font, 1, (200, 50, 0), 2)
            i=i+1
        if FlagUse.punlic_flag==2:#显示坐标轴
            cv2.line(canvas, FlagUse.public_cood_data[0], FlagUse.public_cood_data[1], (255,0, 255), 2)
            cv2.line(canvas, FlagUse.public_cood_data[2], FlagUse.public_cood_data[3], (255, 0, 255), 2)
            font = cv2.FONT_HERSHEY_SIMPLEX
            cv2.putText(canvas, "(%s,%s)" % (FlagUse.public_cood_origin[0],FlagUse.public_cood_origin[1]), FlagUse.public_cood_origin, font, 1, (200, 50, 0), 2)

        # 画正在标注的框和对应名字
        if self._drawing:
            if self._pt1[0] >= self._pt0[0] and self._pt1[1] >= self._pt0[1]:
                cv2.rectangle(canvas, self._pt0, self._pt1, (0, 255, 0), thickness=2)

        #实时刷新显示鼠标像素坐标
        font = cv2.FONT_HERSHEY_SIMPLEX
        cv2.putText(canvas, "(%s,%s)" % (self._pt1[0],self._pt1[1]), self._pt1, font, 1, (200, 50, 0), 2)

        return canvas

    # 画放大窗口
    def _draw_bbox1(self, img):
        h, w = img.shape[:2]
        #边界附近处理
        if self._pt1[1]<h and self._pt1[1]>0 and self._pt1[0]<w and self._pt1[0]>0:
            y0=self._pt1[1]-self.dx;y1 = self._pt1[1] +self.dx;x0 = self._pt1[0] - self.dx;x1 = self._pt1[0] +self.dx
            yy0=0;yy1=0;xx0=0;xx1=0
            if y0<0:
                y0=0
                yy0=self.dx-self._pt1[1]
            if y1>h:
                y1=h
                yy1=self._pt1[1] +self.dx-h
            if x0<0:
                x0=0
                xx0=self.dx-self._pt1[0]
            if x1>w:
                x1=w
                xx1=self._pt1[0] +self.dx-w
            self.y0_last = y0;self.y1_last = y1;self.x0_last = x0;self.x1_last = x1
            self.yy0_last = yy0;self.yy1_last = yy1;self.xx0_last =xx0;self.xx1_last = xx1
            useimg=self.inage[y0:y1,x0:x1]
            canvas = cv2.copyMakeBorder(useimg, yy0, yy1, xx0, xx1, cv2.BORDER_CONSTANT, value=(255, 255, 255))
        else:
            useimg = self.inage[self.y0_last:self.y1_last, self.x0_last:self.x1_last]
            canvas = cv2.copyMakeBorder(useimg, self.yy0_last, self.yy1_last, self.xx0_last, self.xx1_last, cv2.BORDER_CONSTANT, value=(255, 255,255))
        # 画十字标
        cv2.line(canvas,(0,self.dx),(self.dx*2,self.dx),(0,165,255),1)
        cv2.line(canvas, (self.dx, 0), (self.dx, self.dx*2), (0, 165, 255), 1)
        return canvas

    # 开始OpenCV窗口循环的方法,定义了程序的主逻辑
    def start(self):

        # 定义窗口和鼠标回调
        cv2.namedWindow(self.window_name,0)
        cv2.namedWindow("Magnifier",0)
        cv2.setMouseCallback(self.window_name, self._mouse_ops)
        key = 0

        # 定义每次循环的持续时间
        delay = int(1000 / FPS)

        img = self.inage

        # 只要没有按下Esc键或者窗口关闭,就持续循环
        while key != KEY_ESC and cv2.getWindowProperty(self.window_name,cv2.WND_PROP_AUTOSIZE)==0.0 and cv2.getWindowProperty("Magnifier",cv2.WND_PROP_AUTOSIZE)==0.0:
            # 主窗口刷新显示
            canvas = self._draw_bbox(img)
            cv2.imshow(self.window_name, canvas)
            #当大窗口刷新显示
            canvas1=self._draw_bbox1(img)
            cv2.imshow("Magnifier",canvas1)
            key = cv2.waitKey(delay)
            #按键移动鼠标,使用pyautogui模块
            if key==119:
                pyautogui.move(0,-1)
            elif key==115:
                pyautogui.move(0,1)
            elif key==97:
                pyautogui.move(-1,0)
            elif key==100:
                pyautogui.move(1,0)

        cv2.destroyAllWindows()
        return 'Finished!'

if __name__ == '__main__':
    img = cv2.imread('11.png')
    labeling_task = SimpleBBoxLabeling(img)
    labeling_task.start()

主程序部分:

import os
import sys
from sys import argv
import qtawesome
from PyQt5.QtGui import QPixmap, QImage
from matplotlib.backends.backend_qt5agg import FigureCanvasQTAgg as FigureCanvas
import caiya
from PyQt5 import QtCore
from PyQt5.QtCore import QThread
from PyQt5.QtWidgets import QApplication, QMainWindow, QFileDialog
import caiyagui
import cv2
import FlagUse
import math
import matplotlib.pyplot as plt
plt.switch_backend('agg')

class my_mainwindow():
    def __init__(self):
        # PyQt5中,每个应用程序都必须实例化一个QApplication():
        app = QApplication(argv)
        app.setWindowIcon(qtawesome.icon("fa.github-alt",color="green"))
        self.my_MainWindow = QMainWindow()
        self.my_ui = caiyagui.Ui_MainWindow()
        self.my_ui.setupUi(self.my_MainWindow)
        ####################################################################
        self.my_ui.textBrowser.document().setMaximumBlockCount(10000)
        self.my_ui.pushButton.setStyleSheet('''QPushButton{background:#6DDF6D;border-radius:5px;}''')
        self.my_ui.pushButton.setDisabled(True)
        self.my_ui.lineEdit.setPlaceholderText("xlsx")
        self.my_ui.pushButton_5.setStyleSheet('''QPushButton{background:#00ff00;}QPushButton:hover{background:yellow;}''')
        self.my_ui.pushButton_6.setStyleSheet(
            '''QPushButton{background:#00ff00;}QPushButton:hover{background:yellow;}''')
        self.my_ui.checkBox_2.setDisabled(True)
        self.my_ui.checkBox.setDisabled(True)
        self.my_ui.pushButton_2.setStyleSheet(
            '''QPushButton{background:#DDA0DD;}QPushButton:hover{background:#90EE90;}''')
        ####################################################################
        #子进程运行
        self.key_flag = 1
        #坐标轴校准
        self.align_flag = 0
        # 坐标系建立ok
        self.use_falg = 0
        # 数据选择ok
        self.datapoint_falg = 0
        # 坐标系旋转角度
        self.thate = 0
        # 坐标翻转
        self.cood_turn = 0
        # 最终坐标平移原点
        self.my_orign = (0, 0)
        # 缩放比例
        self.zoom = [0, 0]
        #保存数据
        self.data = {"x": [], "y": []}
        self.name_data = list(self.data.keys())
        #图片
        fig = plt.figure()
        plt.plot([1, 2, 3], [4, 5, 6], color='r', linestyle='-')
        canvas = FigureCanvas(fig)
        # 渲染画面
        canvas.draw()
        width, height = canvas.get_width_height()
        # 转化为QImage
        im = QImage(canvas.buffer_rgba(), width, height, QImage.Format_ARGB32)
        # 转化为QPixmap
        self.png = QPixmap(im)
        self.my_ui.label_11.setPixmap(self.png)  # 设置文本标签的图形
        #坐标轴信息
        self.ax0=(0,0)
        self.ax1 = (0, 0)
        self.ay0 = (0, 0)
        self.ay1 = (0, 0)
        self.a0 = (0, 0)
        self.a1 = (0, 0)
        self.y0 = (0, 0)
        self.y1 = (0, 0)
        self.origin=(0,0)
        #要提取的点
        self.datapoint=[]
        #线程传递信息
        self.send_lint=[]
        self.openfile_name=None
        self.savefile_name=None
        self.my_ui.textBrowser.append("放大窗口微调:A-LEFT|D-RIGHT|W-UP|S-DOWN")
        self.my_ui.textBrowser.append("鼠标右键-删除最近标记点|鼠标左键长按拖动-批量删除数据提取标记点")
        self.mywork=myworkthread(self.send_lint)
        self.mywork.finishsignal.connect(self.workend)
        self.click_pushbutton(self.my_MainWindow)
        #####################################################################
        self.my_MainWindow.show()
        sys.exit(app.exec_())

    def click_pushbutton(self,my_MainWindow):
        self.my_ui.pushButton_2.clicked.connect(self.save_data)
        self.my_ui.pushButton_3.clicked.connect(lambda:self.savefile(my_MainWindow))
        self.my_ui.pushButton_4.clicked.connect(lambda: self.openfile(my_MainWindow))
        self.my_ui.pushButton_5.clicked.connect(self.align)
        self.my_ui.pushButton_6.clicked.connect(self.data_point)

    def data_point(self):
        if self.use_falg==0:
            self.my_ui.textBrowser.append("坐标系未建立")
            return
        if self.datapoint_falg==0:
            FlagUse.punlic_flag=1
            self.datapoint_falg=1
            self.my_ui.pushButton_6.setStyleSheet(
                '''QPushButton{background:red;}QPushButton:hover{background:yellow;}''')
            self.my_ui.textBrowser.append("标记提取点")
        elif self.datapoint_falg==1:
            self.datapoint=[]
            #提取数据点
            for i in FlagUse.public_data_point:
                self.datapoint.append(i)
            self.data = {"x": [], "y": []}
            self.name_data = list(self.data.keys())
            #数据点坐标转换
            for i in range(len(self.datapoint)):
                self.datapoint[i]=self.Coordinate_trans(self.origin, self.thate, self.datapoint[i], True, True, True, True)
            #x从小到大排序
            self.datapoint.sort(reverse=False)
            #存入保存字典
            for i in range(len(self.datapoint)):
                datamy = [self.datapoint[i][0],self.datapoint[i][1]]
                for j in range(len(datamy)):
                    self.data[self.name_data[j]].append(datamy[j])
            self.my_ui.textBrowser.append("数据提取OK")
            self.datapoint_falg=0
            self.my_ui.pushButton_6.setStyleSheet(
                '''QPushButton{background:#00ff00;}QPushButton:hover{background:yellow;}''')
            FlagUse.punlic_flag = 10
            #matplotlib图片在lable显示
            fig = plt.figure()
            plt.plot(self.data[self.name_data[0]], self.data[self.name_data[1]], color='r', linestyle='-')
            canvas = FigureCanvas(fig)
            # 渲染画面
            canvas.draw()
            width, height = canvas.get_width_height()
            # 转化为QImage
            im = QImage(canvas.buffer_rgba(), width, height, QImage.Format_ARGB32)
            # 转化为QPixmap
            self.png = QPixmap(im)
            self.my_ui.label_11.setPixmap(self.png)  # 设置文本标签的图形

    def Coordinate_trans(self,origin,thate,s_point,TURN,MOVE,ZOOM,LOG_FLAG):
        datapoint=[0,0]
        # 平移变换
        datapoint[0] = s_point[0] - origin[0]
        datapoint[1] = s_point[1] - origin[1]
        # 旋转变换
        datapoint[0] = datapoint[0] * math.cos(thate) + datapoint[1] * math.sin(thate)
        datapoint[1] = datapoint[1] * math.cos(thate) - datapoint[0] * math.sin(thate)
        #坐标翻转
        if TURN:
            if self.cood_turn|0x02==0x03:
                datapoint[0]=-datapoint[0]
            if self.cood_turn|0x01==0x03:
                datapoint[1] = -datapoint[1]
        #坐标缩放
        if ZOOM:
            datapoint[0]=datapoint[0]/self.zoom[0]
            datapoint[1] = datapoint[1] / self.zoom[1]
        #坐标最终平移
        if MOVE:
            datapoint[0] = datapoint[0] + self.my_orign[0]
            datapoint[1] = datapoint[1] + self.my_orign[1]
        #对数分度转化
        if LOG_FLAG:
            if self.my_ui.checkBox_2.isChecked():  # 变换x
                datapoint[0] = 10**datapoint[0]
            if self.my_ui.checkBox.isChecked():  # 变换y
                datapoint[1]=10**datapoint[1]
        return datapoint

    def openfile(self,my_MainWindow):
        if self.key_flag==1:
            # 打开对话框, "打开文件"(对话框的名字), '.'(打开当前的路径), '图像文件(*.jpg *.png)'(打开文件的格式)
            openfile_name_back=QFileDialog.getOpenFileName(my_MainWindow,"选择路径",'.', '图像文件(*.jpg *.png)')
            if len(openfile_name_back[0])==0:
                return
            else:
                self.openfile_name=openfile_name_back[0]
                self.my_ui.label_4.setText(self.openfile_name)
                # 新建线程开始计算
                self.send_lint=[]
                self.send_lint.append(self.openfile_name)
                self.send_lint.append(1)
                self.mywork = myworkthread(self.send_lint)
                self.mywork.finishsignal.connect(self.workend)
                self.mywork.start()
                self.key_flag=0
                self.my_ui.textBrowser.append("请校准坐标系")
                self.my_ui.pushButton.setStyleSheet('''QPushButton{background:#D23550;border-radius:5px;}''')
        else:
            self.my_ui.textBrowser.append("还有未完成任务")

    def align(self):
        if self.align_flag==0 and self.key_flag==0:
            FlagUse.punlic_flag=0
            self.my_ui.pushButton_5.setStyleSheet(
                '''QPushButton{background:red;}QPushButton:hover{background:yellow;}''')
            self.align_flag=1
            self.my_ui.textBrowser.append("开始校准")
            self.my_ui.checkBox_2.setDisabled(False)
            self.my_ui.checkBox.setDisabled(False)
        elif self.key_flag==1:
            self.my_ui.textBrowser.append("暂无任务")
        elif self.align_flag==1:
            try:
                # 输入参数
                self.x0 = (float(self.my_ui.lineEdit_3.text()), float(self.my_ui.lineEdit_6.text()))
                self.x1 = (float(self.my_ui.lineEdit_2.text()), float(self.my_ui.lineEdit_7.text()))
                self.y0 = (float(self.my_ui.lineEdit_5.text()), float(self.my_ui.lineEdit_8.text()))
                self.y1 = (float(self.my_ui.lineEdit_4.text()), float(self.my_ui.lineEdit_9.text()))
                #对数转换
                if self.my_ui.checkBox_2.isChecked():#变换x
                    self.x0 = (math.log10(self.x0[0]), self.x0[1])
                    self.x1 = (math.log10(self.x1[0]), self.x1[1])
                    self.y0 = (math.log10(self.y0[0]), self.y0[1])
                    self.y1 = (math.log10(self.y1[0]), self.y1[1])
                if self.my_ui.checkBox.isChecked():#变换y
                    self.x0 = (self.x0[0], math.log10(self.x0[1]))
                    self.x1 = (self.x1[0], math.log10(self.x1[1]))
                    self.y0 = (self.y0[0], math.log10(self.y0[1]))
                    self.y1 = (self.y1[0], math.log10(self.y1[1]))
            except Exception as exc:
                error_str = str(exc)
                self.my_ui.textBrowser.append(error_str)
            else:
                #判断坐标校准点是否设置完
                for i in FlagUse.public_coord:
                    if i==(0,0):
                        self.my_ui.textBrowser.append("坐标轴定义不全")
                        return
                self.ax0 = FlagUse.public_coord[0]
                self.ax1 = FlagUse.public_coord[1]
                self.ay0 = FlagUse.public_coord[2]
                self.ay1 = FlagUse.public_coord[3]
                #这一段是获取坐标轴在图像上绘制的两个端点
                if(self.ax0[0]-self.ax1[0])!=0:
                    k1=(self.ax0[1]-self.ax1[1])/(self.ax0[0]-self.ax1[0])
                    if abs(k1) == 0:
                        k1 = 1 * 10 ** -6
                else:
                    k1=1*10**6
                b1 = self.ax1[1] - k1 * self.ax1[0]
                kx1=b1
                kx2=k1*FlagUse.public_size[1]+b1
                kx3=-b1/k1
                kx4=(FlagUse.public_size[0]-b1)/k1
                mx=[]
                mx.append((0,int(kx1)))
                mx.append((FlagUse.public_size[1],int(kx2)))
                mx.append((int(kx3),0))
                mx.append((int(kx4),FlagUse.public_size[0]))
                flag_x=0
                m1=(0,0)
                m2=(0,0)
                if kx1>0 and kx1<FlagUse.public_size[0]:
                    m1=mx[0]
                    flag_x=flag_x+1
                if kx2>0 and kx2<FlagUse.public_size[0]:
                    if flag_x!=0:
                        m2=mx[1]
                    else:
                        m1=mx[1]
                    flag_x = flag_x + 1
                if kx3>0 and kx3<FlagUse.public_size[1]:
                    if flag_x != 0:
                        m2 = mx[2]
                    else:
                        m1 = mx[2]
                    flag_x = flag_x + 1
                if kx4>0 and kx4<FlagUse.public_size[1]:
                    if flag_x != 0:
                        m2 = mx[3]
                    else:
                        m1 = mx[3]
                    flag_x = flag_x + 1
                if flag_x!=2:
                    self.my_ui.textBrowser.append("坐标轴定义错误")
                    return
                else:
                    FlagUse.public_cood_data[0]=m1
                    FlagUse.public_cood_data[1] = m2
                if (self.ay0[0] - self.ay1[0]) != 0:
                    k2 = (self.ay0[1] - self.ay1[1]) / (self.ay0[0] - self.ay1[0])
                    if abs(k1) == 0:
                        k2 = 1 * 10 ** -6
                else:
                    k2 = 1 * 10 ** 6
                b2 = self.ay1[1] - k2 * self.ay1[0]
                ky1 = b2
                ky2 = k2 * FlagUse.public_size[1] + b2
                ky3 = -b2 / k2
                ky4 = (FlagUse.public_size[0] - b2) / k2
                my = []
                my.append((0, int(ky1)))
                my.append((FlagUse.public_size[1], int(ky2)))
                my.append((int(ky3), 0))
                my.append((int(ky4), FlagUse.public_size[0]))
                flag_y = 0
                m3 = (0, 0)
                m4 = (0, 0)
                if ky1 > 0 and ky1 < FlagUse.public_size[0]:
                    m3 = my[0]
                    flag_y = flag_y + 1
                if ky2 > 0 and ky2 < FlagUse.public_size[0]:
                    if flag_y != 0:
                        m4 = my[1]
                    else:
                        m3 = my[1]
                    flag_y = flag_y + 1
                if ky3 > 0 and ky3 < FlagUse.public_size[1]:
                    if flag_y != 0:
                        m4 = my[2]
                    else:
                        m3 = my[2]
                    flag_y = flag_y + 1
                if ky4 > 0 and ky4 < FlagUse.public_size[1]:
                    if flag_y != 0:
                        m4 = my[3]
                    else:
                        m3 = my[3]
                    flag_y = flag_y + 1
                if flag_y != 2:
                    self.my_ui.textBrowser.append("坐标轴定义错误")
                    return
                else:
                    FlagUse.public_cood_data[2] = m3
                    FlagUse.public_cood_data[3] = m4
                if k1*k2+1>0.1:
                    if abs(k1-k2)<1*10**3:
                        self.my_ui.textBrowser.append("暂不支持非直角坐标系")
                        return
                #获取坐标原点坐标
                orign_x=(b2-b1)/(k1-k2)
                orign_y=k1*orign_x+b1
                self.origin=(int(orign_x),int(orign_y))
                #获取坐标轴旋转角度
                self.thate=math.atan(k1)
                FlagUse.public_cood_origin=self.origin
                # 判断是否翻转
                use_x0=self.Coordinate_trans(self.origin,self.thate,self.ax0,False,False,False,False)
                use_x1 = self.Coordinate_trans(self.origin, self.thate, self.ax1,False,False,False,False)
                use_y0 = self.Coordinate_trans(self.origin, self.thate, self.ay0,False,False,False,False)
                use_y1 = self.Coordinate_trans(self.origin, self.thate, self.ay1,False,False,False,False)
                if (use_x0[0] - use_x1[0]) * (self.x0[0] -self.x1[0])<0:
                    self.cood_turn=self.cood_turn|0x01
                if (use_y0[1] - use_y1[1]) * (self.y0[1] -self.y1[1])<0:
                    self.cood_turn=self.cood_turn|0x02
                #获取缩放比例
                use_x0 = self.Coordinate_trans(self.origin, self.thate, self.ax0, True, False,False,False)
                use_x1 = self.Coordinate_trans(self.origin, self.thate, self.ax1, True, False,False,False)
                use_y0 = self.Coordinate_trans(self.origin, self.thate, self.ay0, True, False,False,False)
                use_y1 = self.Coordinate_trans(self.origin, self.thate, self.ay1, True, False,False,False)
                self.zoom[0]=(use_x0[0]-use_x1[0])/(self.x0[0]-self.x1[0])
                self.zoom[1] = (use_y0[1] - use_y1[1]) / (self.y0[1] - self.y1[1])
                #获取最终平移坐标
                use_dx=self.y0[0]
                USE_dy=self.x0[1]
                self.my_orign=(use_dx,USE_dy)
                #相关标志位刷新
                self.align_flag = 0
                self.use_falg=1
                self.my_ui.pushButton_5.setStyleSheet(
                    '''QPushButton{background:#00ff00;}QPushButton:hover{background:yellow;}''')
                FlagUse.punlic_flag = 2
                self.my_ui.textBrowser.append("坐标轴定义成功")
                self.my_ui.checkBox_2.setDisabled(True)
                self.my_ui.checkBox.setDisabled(True)

    def savefile(self,my_MainWindow):
        # 打开对话框, "打开文件"(对话框的名字), '.'(打开当前的路径), '图像文件(*.jpg *.png)'(打开文件的格式)
        savefile_name_back=QFileDialog.getExistingDirectory(my_MainWindow,"选择路径")
        if len(savefile_name_back)==0:
            return
        else:
            self.savefile_name=savefile_name_back
            self.my_ui.label.setText(self.savefile_name)

    def workend(self,ins):
        if ins[0]==1:
            self.my_ui.textBrowser.append(ins[1])
            self.key_flag=1
            self.my_ui.pushButton.setStyleSheet('''QPushButton{background:#6DDF6D;border-radius:5px;}''')
            self.align_flag =0
            self.my_ui.pushButton_5.setStyleSheet(
                '''QPushButton{background:#00ff00;}QPushButton:hover{background:yellow;}''')
            FlagUse.punlic_flag = 10
            FlagUse.public_coord = [(0, 0), (0, 0), (0, 0), (0, 0)]
            FlagUse.public_data_point=[]
            self.use_falg=0
            self.datapoint_falg = 0
            self.my_ui.pushButton_6.setStyleSheet(
                '''QPushButton{background:#00ff00;}QPushButton:hover{background:yellow;}''')
            self.my_ui.pushButton.setStyleSheet('''QPushButton{background:#D23550;border-radius:5px;}''')
        else:
            self.my_ui.textBrowser.append(ins[1])

    def save_data(self):
        try:
            if os.path.exists(self.savefile_name)==False:
                self.my_ui.textBrowser.append("路径出错")
        except Exception as exc:
            error_str = str(exc)
            self.my_ui.textBrowser.append(error_str)
        else:
            file_name=self.my_ui.lineEdit.text()
            if len(file_name)==0:
                self.my_ui.textBrowser.append("文件名为空")
                return
            str_limit=["\\","/",":","*","?",'"',"<",">","!"]
            for i in range(len(str_limit)):
                if file_name.find(str_limit[i])!=-1:
                    self.my_ui.textBrowser.append("文件名格式错误")
                    return
            usestr=self.savefile_name+"/"+file_name+".xlsx"
            self.send_lint = []
            self.send_lint.append(usestr)
            self.send_lint.append(2)
            self.send_lint.append(self.data)
            self.png.save("GotCurve.PNG")
            self.mywork1 = myworkthread(self.send_lint)
            self.mywork1.finishsignal.connect(self.workend)
            self.mywork1.start()

#新建线程
class myworkthread(QThread):
    finishsignal=QtCore.pyqtSignal(list)
    def __init__(self,in_list):
        super(myworkthread,self).__init__()
        self.in_list=in_list

    def run(self):
        #耗时程序
        if self.in_list[1]==1:
            img = cv2.imread(self.in_list[0])
            labeling_task = caiya.SimpleBBoxLabeling(img)
            backstr=labeling_task.start()
            back_list = []
            back_list.append(1)
            back_list.append(backstr)
        else:
            backstr = caiya.save_excel(self.in_list[0], self.in_list[2])
            back_list=[]
            back_list.append(2)
            back_list.append(backstr)
        self.finishsignal.emit(back_list)

if __name__=="__main__":
    my_mainwindow()