场景:有一系列图像,需要查看图像每列的像素值的大小,可以把图像读出来然后指定列,再查看,但比较麻烦,每看一列都要修改一下。后面又用回调函数滑动条,这样不用每次都修改列了,但假如换张图像的话还是要修改图像路径。所以就想做个界面,可以选择打开图像,并且鼠标单击一下图像中某点,就会画出这个点所在列(当然也可以是行)的一整列像素值的折线图。
最终的效果如下,还可以基本满足。
代码如下:
from PyQt5.QtWidgets import QApplication, QMessageBox, QFileDialog, QGridLayout
from PyQt5.QtGui import QPainter, QPixmap
from PyQt5 import uic,QtWidgets
from PyQt5.QtCore import Qt, QPoint
from plot2 import Ui_MainWindow # 这里的plot2是通过plot2.ui转成的plot2.py文件
import sys
import matplotlib
matplotlib.use("Qt5Agg") # 声明使用QT5
from matplotlib.backends.backend_qt5agg import FigureCanvasQTAgg as FigureCanvas
from matplotlib.figure import Figure
import matplotlib.pyplot as plt
import numpy as np
import cv2
plt.rcParams['font.sans-serif']=['SimHei'] # 显示中文标签
plt.rcParams['axes.unicode_minus']=False
#创建一个matplotlib图形绘制类
class MyFigure(FigureCanvas):
def __init__(self,width=5, height=4, dpi=600):
#第一步:创建一个创建Figure
self.fig = Figure(figsize=(width, height), dpi=dpi)
#第二步:在父类中激活Figure窗口
super(MyFigure,self).__init__(self.fig) #此句必不可少,否则不能显示图形
#第三步:创建一个子图,用于绘制图形用,111表示子图编号,如matlab的subplot(1,1,1)
self.axes = self.fig.add_subplot(111)
class MyWindow(QtWidgets.QMainWindow, Ui_MainWindow):
def __init__(self):
super(MyWindow, self).__init__()
self.setupUi(self)
self.button_1.clicked.connect(self.open)
# 第五步:定义MyFigure类的一个实例
self.F = MyFigure(width=3, height=2, dpi=600)
def plotcol(self, col, row):
print(col)
col = col - self.label_1.x()
row = row - self.label_1.y()
print(col)
if(col >= 0 and col <= self.label_1.width() and row >= 0 and row <= self.label_1.height()):
img_1 = cv2.imread(self.imgName, 0)
img_1 = cv2.resize(img_1, (self.label_2.width(), self.label_2.height()), interpolation=cv2.INTER_AREA)
cols_ = img_1[:, col]
x = np.arange(0, self.label_2.height(), 1)
self.F.axes.plot(x, cols_)
self.F.fig.suptitle("列像素折线图")
self.F.fig.savefig('tmp.jpg')
self.label_2.setPixmap(QPixmap('tmp.jpg').scaled(self.label_2.width(), self.label_2.height()))
self.F.axes.clear()
def open(self):
self.imgName, imgType = QFileDialog.getOpenFileName(self.label_1, "打开图片", "", "*.tiff;;*.jpg;;*.png;;All Files(*)")
self.jpg = QPixmap(self.imgName).scaled(self.label_1.width(), self.label_1.height())
# self.label.setPixmap(jpg)
if (self.jpg.isNull() != True):
self.label_1.setPixmap(self.jpg)
def mousePressEvent (self, event):
if event.button() == Qt.LeftButton:
print(event.pos())
self.plotcol(event.pos().x(), event.pos().y())
if __name__ == '__main__':
app = QtWidgets.QApplication(sys.argv)
mywindow = MyWindow()
mywindow.show()
sys.exit(app.exec_())
自己话好ui后,用工具自动转成py文件,只要ui中包含这三个组件,并且名字对应,就行。
这里还遇到一些状况,就是开始的时候选择的窗体是Dialog和widget这两个都试过,但最后运行的界面总和预览的不一致,但是如果不加布局的话,是一致的。搞了很久都不行,最后换成了Main Window窗体,可以。
还遇到一些其它问题:
(1)最开始的时候尝试使用的是加载动态ui,就是不转换为py文件,但是后面需要用到鼠标事件,没办法重写鼠标事件函数了
将其转换为py后,就比较方便重写
(2)另外一个问题就是怎么将plot画的图在label组件里显示,一定有方法,只是我还不知道,最后采用的方法比较笨,就是先把plot画的图保存为图片,然后label加载图片。后面再研究一下不这么笨的方法。
(3)还要对鼠标单击位置的坐标转换一下,转换为对应的图像中的坐标,并约束坐标只有在图像内部时画图。