基于pyqt的图像处理界面设计

阿里云国内75折 回扣 微信号:monov8
阿里云国际,腾讯云国际,低至75折。AWS 93折 免费开户实名账号 代冲值 优惠多多 微信号:monov8 飞机:@monov6

以下是一个小白因为某个原因而学习pyqt的学习结果

首先是环境因为python的环境问题花了不少时间着实头痛了一阵所以把各种版本写在前面总之逢山开路遇水搭桥度娘解决一切

使用python3.9pyqt5opencv-python 4.6.0.66其余环境就隐去不表

安装pyqt5以及相关配置、设置外部工具qt designer以及pyuic等等过程请自行百度这里不再详述直接开始界面的设计。

新建一个.ui文件

 从左侧拉出Label组件作为显示图像的工具再拉出Tab Widget在其中放入几个Buttom按钮增加Tab Widget的页数组件右键->插入页添加菜单栏最上方“在这里输入”处双击更改文字内容后回车

按照以上步骤设计一些按钮以及菜单栏设计完成如下图

 “文件”下有两个子菜单“打开”以及“保存”

以下进行程序的编辑

首先使按钮和自定义的函数链接起来使用槽函数实现。

点击Qt Designer的"编辑"->"编辑信号/槽"

长按一个Buttom形成如下效果

 会弹出如下弹窗

 点击左栏的clicked点击右栏下面的“编辑”自定义一个函数名

在上栏中点击加号自定义一个函数名称如下图自定义一个函数为“pic_show()”

 将所有按钮的自定义函数都完成之后进行保存。

这里特别说明菜单栏添加槽函数可以双击已经添加了的自定义函数调出“配置连接”界面按照上面所说自定义一个函数然后在右下角的“信号/槽 编辑器”页面中“发送者”选择菜单按键的名称“信号”选择triggered“接收者”选择MainWindow“槽”选择刚刚自定义好的函数名。事实上所有的按钮都可以采用以上过程进行信号和槽函数的连接这里不再赘述。

全部完成后如下图

 右上角保存这个.ui然后关闭Qt Designer。如果想再次进入这个界面编辑ui界面可以右键项目中的.ui文件选择外部工具中添加好的Qt。

下面将.ui文件翻译成.py文件。右键项目中的.ui文件选择添加好的外部工具pyuic这里注意如果配置好的python环境使用PyQt5就请也使用pyuic5不要用pyuic6否则编译程序时会产生错误。我自己做的时候就这样两掺了结果还是乖乖的改成pyuic5了qt设计时Qt Designer是否也必须用5我不确定我自己好像就是用的6里面带的。

翻译好后项目中会出现一个和.ui文件名字一样的.py文件这样就可以进行下一步具体程序的编写了。

为确保之后的书写中不会遗漏import的内容这里把所有用到的都写在前面。

import numpy as np
from PyQt5 import QtCore, QtGui, QtWidgets
from PyQt5.QtWidgets import QFileDialog
from PIL import ImageEnhance
from PIL import ImageQt
import os
import cv2

如果想要运行编写的界面需要添加主函数直接写在最后就行注意不要写到类里面去

import sys

if __name__ == '__main__':
    app = QtWidgets.QApplication(sys.argv)
    mainWindow = QtWidgets.QMainWindow()
    ui = Ui_MainWindow()
    ui.setupUi(mainWindow)
    mainWindow.show()
    sys.exit(app.exec_())

添加好主函数可以运行一下看看有没有错误运行结果如下图

 与设计好的一样。

下面需要对翻译好的内容做一些更改找到所有

self.某按键或菜单名称.clicked.connect(MainWindow.自定义函数名)

将其中的MainWindow改为self如果使用pycharm此时“self”应该变为紫色

下面编写载入图像的函数对应的按钮是菜单栏中的“打开”程序如下

def pic_show(self):
    # 打开文件路径
    # 设置文件扩展名过滤,注意用双分号间隔
    imgName, imgType = QFileDialog.getOpenFileName(None, "打开图片", "",
                                                   " *.jpg;;*.png;;*.jpeg;;*.bmp;;All Files (*)")
    print(imgName)
    self.img_path = imgName
    image = QtGui.QPixmap(imgName)
    self.befow.setPixmap(image)

这个函数可以由使用者自己去选择图片所在路径打开后如下图

 为了实现如上图中图片自动适应框的大小需要对Label组件进行设置。打开Label的属性编辑器在Qt的右侧栏

 勾选其中的scaledContents。然后保存、重新pyuic。。。。是的刚刚改写和添加的程序都白干了请从头再来一遍原本想把这个事情放在文章的最后说的想来想去还是不要这么跳脱了hhhh。这个事情也告诉我们写好的程序最好备份一下修改ui之后可以直接复制过去。

下面来写一个保存处理好的图片的函数对应按键为菜单栏中的“保存”

def pic_save(self):
    img = self.pp
    name_str = self.name
    print(name_str)
    if name_str == 'F:/change2.jpg':
        img.save(name_str)
    else:
        cv2.imwrite(name_str, img)
    print("已保存")

这里的self.name是一个定义在类内的变量储存 一个地址用于储存图片。self.pp储存的是处理好的图片。下面的if语句是因为后面的处理方式不同采取的保存方式也不同本质上就是格式的问题想要改变应该添加格式转换程序就可以

下面是直方图均衡化的程序

def pic_change1(self):
    imgpt = self.img_path
    print(imgpt)
    img = cv2.imread(imgpt)
    yuv = cv2.cvtColor(img, cv2.COLOR_BGR2YUV)
    yuv[:, :, 0] = cv2.equalizeHist(yuv[:, :, 0])
    output = cv2.cvtColor(yuv, cv2.COLOR_YUV2BGR)
    cv2.imwrite("F:/12.jpg", output)
    image3 = QtGui.QPixmap(r"F:/12.jpg")
    self.dis(image3)
    self.pp = output
    self.name = 'F:/change1.jpg'
    print('直方图均衡化')
    os.remove(r"F:/12.jpg")

这个程序当中存在一个问题正如程序中所写的采取的是将处理好的图片使用opencv库中的imwrite函数存入电脑然后使用Qt中的QtGui.QPixmap函数读取这张图片并显示最后再删除这张图片的方式简言之就是饶了好大一个圈子。究其原因依旧是图片格式的问题cv2处理的图片采用的是Image格式而Qt的显示需要QPixmap格式事实上是存在格式转换函数的

ImageQt.toqpixmap

另附一些图片格式转换的函数PIL.Image 、QImage和QPixmap的相互转化_JlexZzzz的博客-CSDN博客_qpixmap转qimage

但不知为何使用这个函数并没有成功或者是我使用的方法有问题鉴于时间缘故只能采取一种舍近求远的方式解决问题。之后各个函数都使用这样的方式之后就不再赘述等未来有时间再回过头来好好研究一下问题出在哪。

直方图均衡化的结果如下

 

再下面是对比度增强的函数

    def pic_change2(self):
        img = self.img_path
        print(img)
        image = QtGui.QPixmap(img)
        image2 = ImageQt.fromqimage(image)
        imgg = ImageEnhance.Contrast(image2).enhance(2)
        imgg.save(r"F:\\文件\\11.jpg")
        image3 = QtGui.QPixmap(r"F:\\文件\\11.jpg")
        self.dis(image3)
        self.pp = imgg
        self.name = 'F:/change2.jpg'
        print('对比度增强')
        os.remove(r"F:\\文件\\11.jpg")

结果如下

接下来是均值滤波

    def pic_change3(self):
        imgpt = self.img_path
        print(imgpt)
        img = cv2.imread(imgpt)
        avg = cv2.blur(img, (3, 3))
        cv2.imwrite("F:/12.jpg", avg)
        image3 = QtGui.QPixmap(r"F:/12.jpg")
        self.dis(image3)
        self.pp = avg
        self.name = 'F:/change3.jpg'
        print('均值滤波')
        os.remove(r"F:/12.jpg")

结果如下

在下面是中值滤波

    def pic_change4(self):
        imgpt = self.img_path
        print(imgpt)
        img = cv2.imread(imgpt)
        mid = cv2.medianBlur(img, 5)
        cv2.imwrite("F:/12.jpg", mid)
        image3 = QtGui.QPixmap(r"F:/12.jpg")
        self.dis(image3)
        self.pp = mid
        self.name = 'F:/change4.jpg'
        print('中值滤波')
        os.remove(r"F:/12.jpg")

结果如下

接下来是高斯滤波

    def pic_change5(self):
        imgpt = self.img_path
        print(imgpt)
        img = cv2.imread(imgpt)
        guass = cv2.GaussianBlur(img, (15, 15), 0)
        cv2.imwrite("F:/12.jpg", guass)
        image3 = QtGui.QPixmap(r"F:/12.jpg")
        self.dis(image3)
        self.pp = guass
        self.name = 'F:/change5.jpg'
        print('高斯滤波')
        os.remove(r"F:/12.jpg")

结果如下

正如三个滤波的结果所显示的效果并不明显应该是代码中相关参数调节的问题留到之后有时间再调吧。

下面是图像分割部分首先是Canny算子

    def pic_change6(self):
        imgpt = self.img_path
        print(imgpt)
        img = cv2.imread(imgpt)
        grarimg = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
        gauss = cv2.GaussianBlur(grarimg, (3, 3), 0)
        canny = cv2.Canny(gauss, 50, 150)
        cv2.imwrite("F:/12.jpg", canny)
        image3 = QtGui.QPixmap(r"F:/12.jpg")
        self.dis(image3)
        self.pp = canny
        self.name = 'F:/change6.jpg'
        print('图像分割Canny')
        os.remove(r"F:/12.jpg")

结果如下

下面是Roberts算子

    def pic_change7(self):
        imgpt = self.img_path
        print(imgpt)
        img = cv2.imread(imgpt)
        grarimg = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
        # 算子
        kkx = np.array([[-1, 0], [0, 1]], dtype=int)
        kky = np.array([[0, -1], [1, 0]], dtype=int)
        x = cv2.filter2D(grarimg, cv2.CV_16S, kkx)
        y = cv2.filter2D(grarimg, cv2.CV_16S, kky)

        absx = cv2.convertScaleAbs(x)
        absy = cv2.convertScaleAbs(y)
        outputimg = cv2.addWeighted(absx, 0.5, absy, 0.5, 0)
        cv2.imwrite("F:/12.jpg", outputimg)
        image3 = QtGui.QPixmap(r"F:/12.jpg")
        self.dis(image3)
        self.pp = outputimg
        self.name = 'F:/change7.jpg'
        print('图像分割Roberts')
        os.remove(r"F:/12.jpg")

结果如下

 接下来是Sobel算子

 def pic_change8(self):
        imgpt = self.img_path
        print(imgpt)
        img = cv2.imread(imgpt)
        grarimg = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
        # 算子
        x = cv2.Sobel(grarimg, cv2.CV_16S, 1, 0)
        y = cv2.Sobel(grarimg, cv2.CV_16S, 0, 1)
        absx = cv2.convertScaleAbs(x)
        absy = cv2.convertScaleAbs(y)
        outputimg = cv2.addWeighted(absx, 0.5, absy, 0.5, 0)
        cv2.imwrite("F:/12.jpg", outputimg)
        image3 = QtGui.QPixmap(r"F:/12.jpg")
        self.dis(image3)
        self.pp = outputimg
        self.name = 'F:/change8.jpg'
        print('图像分割Sobel')
        os.remove(r"F:/12.jpg")

结果如下

下面是Prewitt算子

    def pic_change9(self):
        imgpt = self.img_path
        print(imgpt)
        img = cv2.imread(imgpt)
        grarimg = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
        # 算子
        kkx = np.array([[1, 1, 1], [0, 0, 0], [-1, -1, -1]], dtype=int)
        kky = np.array([[-1, 0, 1], [-1, 0, 1], [-1, 0, 1]], dtype=int)
        x = cv2.filter2D(grarimg, cv2.CV_16S, kkx)
        y = cv2.filter2D(grarimg, cv2.CV_16S, kky)

        absx = cv2.convertScaleAbs(x)
        absy = cv2.convertScaleAbs(y)
        outputimg = cv2.addWeighted(absx, 0.5, absy, 0.5, 0)
        cv2.imwrite("F:/12.jpg", outputimg)
        image3 = QtGui.QPixmap(r"F:/12.jpg")
        self.dis(image3)
        self.pp = outputimg
        self.name = 'F:/change9.jpg'
        print('图像分割Prewitt')
        os.remove(r"F:/12.jpg")

结果如下

最后是分水岭算法

    def pic_change10(self):
        imgpt = self.img_path
        print(imgpt)
        img = cv2.imread(imgpt)
        grarimg = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
        ret, binary = cv2.threshold(grarimg, 0, 255, cv2.THRESH_BINARY + cv2.THRESH_OTSU)

        contours, hierarchy = cv2.findContours(binary, cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE)

        cv2.drawContours(img, contours, -1, (0, 255, 0), 1)

        cv2.imwrite("F:/12.jpg", img)
        image3 = QtGui.QPixmap(r"F:/12.jpg")
        self.dis(image3)
        self.pp = img
        self.name = 'F:/change10.jpg'
        print('图像分割分水岭')
        os.remove(r"F:/12.jpg")

结果如下

 与滤波算法相同分割的效果有些不尽如人意具体参数的调节留后再补

后面是形态学相关的内容首先是腐蚀

    def pic_change11(self):
        imgpt = self.img_path
        print(imgpt)
        img = cv2.imread(imgpt)
        kernel = np.ones((5, 5), np.uint8)

        fs = cv2.erode(img, kernel)
        cv2.imwrite("F:/12.jpg", fs)
        image3 = QtGui.QPixmap(r"F:/12.jpg")
        self.dis(image3)
        self.pp = fs
        self.name = 'F:/change11.jpg'
        print('腐蚀')
        os.remove(r"F:/12.jpg")

结果如下

然后是膨胀

 def pic_change12(self):
        imgpt = self.img_path
        print(imgpt)
        img = cv2.imread(imgpt)
        kernel = np.ones((5, 5), np.uint8)

        fs = cv2.dilate(img, kernel)
        cv2.imwrite("F:/12.jpg", fs)
        image3 = QtGui.QPixmap(r"F:/12.jpg")
        self.dis(image3)
        self.pp = fs
        self.name = 'F:/change12.jpg'
        print('膨胀')
        os.remove(r"F:/12.jpg")

结果如下

接下来是高帽

    def pic_change13(self):
        imgpt = self.img_path
        print(imgpt)
        img = cv2.imread(imgpt)
        kernel = np.ones((5, 5), np.uint8)

        fs = cv2.morphologyEx(img, cv2.MORPH_TOPHAT, kernel)
        cv2.imwrite("F:/12.jpg", fs)
        image3 = QtGui.QPixmap(r"F:/12.jpg")
        self.dis(image3)
        self.pp = fs
        self.name = 'F:/change13.jpg'
        print('高帽')
        os.remove(r"F:/12.jpg")

结果如下

最后是低帽

    def pic_change14(self):
        imgpt = self.img_path
        print(imgpt)
        img = cv2.imread(imgpt)
        kernel = np.ones((5, 5), np.uint8)
        fs = cv2.morphologyEx(img, cv2.MORPH_BLACKHAT, kernel)
        cv2.imwrite("F:/12.jpg", fs)
        image3 = QtGui.QPixmap(r"F:/12.jpg")
        self.dis(image3)
        self.pp = fs
        self.name = 'F:/change14.jpg'
        print('低帽')
        os.remove(r"F:/12.jpg")

结果如下

最后一个函数程序是对应于四个“原图”按钮的用来显示载入的原图

    def pic_show2(self):
        print('原图')
        imgName=self.img_path
        image = QtGui.QPixmap(imgName)
        self.befow.setPixmap(image)

以上函数中的self.dis函数是用来显示处理后的函数具体如下

    def dis(self, img2):
        self.befow.setPixmap(img2)

现存的问题

1.主函数和其他内容的分离。

2.猜想应该有不需要每次修改.ui文件就要把一堆函数重新复制一遍的方法。

3.存储图片的名字现在仍为“changeX.jpg”如果在路径中改为中文名称则最终存储的名称为中文乱码猜测可能是因为opencv不能接受中文路径的原因。

4.格式转换

5.各个程序的具体参数调节

以上问题留待再次需要pyqt时再细想历时4天的研究成果自此结束一半时间都在安装环境以及解决版本等等问题简直太折磨了

卿某

2022.9.27

阿里云国内75折 回扣 微信号:monov8
阿里云国际,腾讯云国际,低至75折。AWS 93折 免费开户实名账号 代冲值 优惠多多 微信号:monov8 飞机:@monov6