PyQt5-QImage、QPixmap、Opencv与QLabel、Matplotlib的互动

文章目录

  • 前言
  • 一、转换
    • 1.1 Opencv_to_QPixmap
    • 1.2 QImage_to_QPixmap
    • 1.3 QPixmap_to_Opencv
    • 1.4 QImage_to_Opencv
    • 1.5 Opencv_to_QImage
  • 二、实战案例
    • 2.1 案例1-图像旋转
  • 总结


前言

早期进行图像旋转用的笨方法是:

  1. cv2.imread()读取图像
  2. numpy旋转图像
  3. 将旋转后的图像保存cv2.imwrite()并且从新读取图像

由于图像基本操作我是个小白,什么都没有接触过。因此,前期的想法就是这样,这种方法简单,明了,但是缺点你懂的

后来,偶尔看到了这篇文章:【PyQt5】显示多张图片并支持滚动,其中的一行代码:label.setScaledContents(True) 自适应窗口控件大小,于是就在网上搜集各种资料,并且自己测试,最终总结为该篇博客。

这里基本汇聚了简单的图像处理+图像界面设计用到的基本格式转换,希望可以帮助到你!


一、转换

  • 测试图像
    PyQt5-QImage、QPixmap、Opencv与QLabel、Matplotlib的互动_第1张图片
    PyQt5-QImage、QPixmap、Opencv与QLabel、Matplotlib的互动_第2张图片
  • path、photo
path = r'F:\python\gradu_design\gra_des\compr\bamarket115.jpg'
# r'F:\python\gradu_design\gra_des\imges\logo1_1.jpg'

# 调用
photo = QImage(path)
# print('photo type:', type(photo), photo.width(), photo.height())

下面方法涉及到的参数photopath来源于此

  • 显示问题

下面方法会看到两张在一起对比的图片:这是单独使用matplotlib显示查看转换的效果:
matplotlib是显示RGB图片的,由于测试图片是红色的,因此若结果显示蓝色,则证明图片是BGR格式的,反之若和原图一样则是RGB个格式

# image 类型必须为,plt才可以显示
def plt_show(self,image):
    plt.subplot(121)
    plt.title('格式检查-BGR')
    plt.imshow(image)

    plt.subplot(122)
    plt.title('格式检查-RGB')
    plt.imshow(image[:,:,::-1])  # 正常显示

    plt.show()

1.1 Opencv_to_QPixmap

完整过程:Opencv -> QImage -> QPixmap

  • 代码
# 调用  cv2 读取图像 -> QPixmap 让QLabel显示
self.cvread_labelshow(pic_show_label=self.label,path=path)

# cv2 读取图像 -> QPixmap 让QLabel显示
def Opencv_to_QPixmap(self,pic_show_label,path):
    print('-----cvread_labelshow-----')
    
    # 图片路径
    img_path = path
    
    # 通过cv读取图片  BGR格式
    img = cv2.imread(img_path)
    print('cv2 : ',type(img))# cv2 :  
    plt.subplot(121)
    plt.title('BGR-格式')
    plt.imshow(img)  # img本来是BGR格式,通过img[:,:,::-1]转为RGB格式

    # 通道转化  BGR->RGB
    RGBImg = cv2.cvtColor(img, cv2.COLOR_BGR2RGB)
    plt.subplot(122)
    plt.title('RGB-格式')
    plt.imshow(RGBImg)  # matplotlib只能显示RGB图像
    plt.show() 
    
    # 将图片转化成Qt可读格式   QImage
    qimage = QImage(RGBImg, RGBImg.shape[1], RGBImg.shape[0], QImage.Format_RGB888)
    print('qimage type:', type(qimage))
    piximage = QPixmap(qimage)
    print('piximage type:', type(piximage))
    
    # 显示图片
    pic_show_label.setPixmap(piximage)
    pic_show_label.setScaledContents(True)
    print('pic_show_label mess:',pic_show_label.width(), pic_show_label.height())
    print('piximage mess:',piximage.width(),piximage.height())
  • 测试结果
  1. PyQt5-QImage、QPixmap、Opencv与QLabel、Matplotlib的互动_第3张图片

  2. 在这里插入图片描述

  3. PyQt5-QImage、QPixmap、Opencv与QLabel、Matplotlib的互动_第4张图片

  • 结论
  • matplotlib只能显示numpy.adarry类型,且显示RGB格式
  • 自适应并没有改变图像的实际大小

1.2 QImage_to_QPixmap

  • 代码
self.QImage_to_QPixmap(photo)

# 让读取的图像自适应QLabel  QImage -> QPixmap
def QImage_to_QPixmap(self,photo):
    print('-----Adjust_Img_Size-----')
    width = self.label.width()
    height = self.label.height()
    print('photo size:',type(photo),photo.width(),photo.height())

    size = QSize(width, height)
    # Qt.IgnoreAspectRatio、Qt.KeepAspectRatio、
    # https://www.cnblogs.com/qixianyu/p/6891054.html
    pixphoto = QPixmap.fromImage(photo.scaled(size, Qt.KeepAspectRatio,Qt.SmoothTransformation)) # QImage -> QPixmap  IgnoreAspectRatio:忽略纵横比

    self.label.setPixmap(pixphoto)
    self.label.setScaledContents(True)  # 图像自适应窗口大小

    print('pixphoto type:', type(pixphoto), width,height)
  • 测试结果
  1. 在这里插入图片描述

将代码

  • pixphoto = QPixmap.fromImage(photo.scaled(size, Qt.KeepAspectRatio,Qt.SmoothTransformation))

改为

  • pixphoto = QPixmap(photo)

QPixmap形状改变

  1. 在这里插入图片描述

1.3 QPixmap_to_Opencv

  • 代码
pixphoto = QPixmap(path)
# 调用 Pixmap_to_Opencv
pixarr = self.Pixmap_to_Opencv(pixphoto)
plt.imshow(pixarr)
plt.show()
print('pixarr : ', type(pixarr))  # 看测试结果1

# QPixmap 转为 CV2
def Pixmap_to_Opencv(self,qtpixmap):
    print('-----QPixmap_to_Opencv-----')
    print('qtpixmap type:',type(qtpixmap))
    qimg = qtpixmap.toImage()  # QPixmap-->QImage
    print('qimg type:', type(qimg))

    temp_shape = (qimg.height(), qimg.bytesPerLine() * 8 // qimg.depth())
    temp_shape += (4,)
    ptr = qimg.bits()
    ptr.setsize(qimg.byteCount())
    result = np.array(ptr, dtype=np.uint8).reshape(temp_shape)
    result = result[..., :3]
    # cv2.imwrite('./result.jpg',result) # 保存的话会显示RGB格式
    return result
  • 测试结果
  1. PyQt5-QImage、QPixmap、Opencv与QLabel、Matplotlib的互动_第5张图片

  2. PyQt5-QImage、QPixmap、Opencv与QLabel、Matplotlib的互动_第6张图片

  3. 仔细审阅代码你会发现有这一行代码:
    cv2.imwrite('./result.jpg',result)
    由测试结果1可知调用Pixmap_to_Opencv方法后图像是BGR格式,那保存该图像也会是BGR格式吗?
    答:不是 (这行代码就是用来测试效果的)
    保存的图像居然是彩色的(若是BGR格式,图像应该为蓝色),因此我们推断使用opencv进行图像保存到时候应该存在格式准换(有兴趣的可以去查看源码,在此不做赘述)

    PyQt5-QImage、QPixmap、Opencv与QLabel、Matplotlib的互动_第7张图片

  4. 修改调用代码
    pixphoto = QPixmap(path) ① pixarr = self.Pixmap_to_Opencv(pixphoto)② print('pixarr : ', type(pixarr)) ③
    改为
    pixphoto = QPixmap(path)① pixarr = self.Pixmap_to_Opencv(pixphoto)② print('pixarr : ', type(pixarr))③ self.plt_show(pixarr)④

    查看matlibplot显示的效果:

    PyQt5-QImage、QPixmap、Opencv与QLabel、Matplotlib的互动_第8张图片

1.4 QImage_to_Opencv

  • 代码
# 调用 QImage_to_Opencv
Imagearr = self.QImage_to_Opencv(photo)
print('Imagearr : ', type(Imagearr))
self.plt_show(Imagearr)

# QImage 转为 Opencv
def QImage_to_Opencv(self,qimg):
    print('-----QImage_to_Opencv-----')
    tmp = qimg
    # 使用numpy创建空的图象
    cv_image = np.zeros((tmp.height(), tmp.width(), 3), dtype=np.uint8)
    print('begin cv_image type:',type(cv_image))
    for row in range(0, tmp.height()):
        for col in range(0, tmp.width()):
            r = qRed(tmp.pixel(col, row))
            g = qGreen(tmp.pixel(col, row))
            b = qBlue(tmp.pixel(col, row))
            # cv_image[row, col, 0] = r
            # cv_image[row, col, 1] = g
            # cv_image[row, col, 2] = b
            cv_image[row, col, 0] = b
            cv_image[row, col, 1] = g
            cv_image[row, col, 2] = r
    print('end cv_image type:', type(cv_image))
    cv2.imwrite('./QImage_to_Opencv.jpg',cv_image)
    return cv_image
  • 测试结果
  1. PyQt5-QImage、QPixmap、Opencv与QLabel、Matplotlib的互动_第9张图片
  2. PyQt5-QImage、QPixmap、Opencv与QLabel、Matplotlib的互动_第10张图片

1.5 Opencv_to_QImage

需求:在进行图像旋转90°的情况下发生了失真情况,如下:

PyQt5-QImage、QPixmap、Opencv与QLabel、Matplotlib的互动_第11张图片

分析:
图像旋转的整个过程是 QPixmap -> Qpencv -> QPixmap,我分别在QPixmap -> Qpencv ①和Qpencv -> QPixmap②两个过程中进行测试,发现过程②是问题所在原因,因此我将整个过程改为:
QPixmap -> Qpencv -> QImage -> QPixmap

  • 代码
# 调用 QPixmap_to_Opencv
pixphoto = QPixmap(path)
pixarr = self.QPixmap_to_Opencv(pixphoto)

print('pixarr : ', type(pixarr))
img_rotate = np.rot90(pixarr, 1)

print('img_rotate : ', type(img_rotate))
plt.imshow(img_rotate[:, :, ::-1])
plt.show()

# 调用 Opencv_to_QImage
QtImg = self.Opencv_to_QImage(img_rotate)
self.QImage_to_QPixmap(QtImg,self.label_2) # 这是QImage_to_QPixmap 的修改版

def Opencv_to_QImage(self,img):
    
    # 将图片转成BGRA模式;
    img_rgb = cv2.cvtColor(img, cv2.COLOR_BGR2BGRA)
    QtImg = QImage(img_rgb.data, img_rgb.shape[1], img_rgb.shape[0],QImage.Format_RGB32)
    
    # # 显示图片到label中;
    # self.labImage.resize(QSize(img_rgb.shape[1],img_rgb.shape[0]))
    # self.labImage.setPixmap(QPixmap.fromImage(QtImg))

    return QtImg
  • 测试结果
    PyQt5-QImage、QPixmap、Opencv与QLabel、Matplotlib的互动_第12张图片

完整源码见 2.1 案例1-图像旋转


二、实战案例

2.1 案例1-图像旋转

  • test_resize.ui文件
    PyQt5-QImage、QPixmap、Opencv与QLabel、Matplotlib的互动_第13张图片
  • 图像旋转源码
import sys
import cv2
from PyQt5.QtCore import *
from PyQt5.QtGui import *
from PyQt5.QtWidgets import *

import numpy as np
import matplotlib.pyplot as plt
from PyQt5.uic import loadUi

class QLabel_resize(QMainWindow):
    def __init__(self):
        super().__init__()

        self.setupUi()
        self.resize_QLabel()

    def setupUi(self):
        loadUi('./test_resize.ui', self)
        plt.rcParams['font.sans-serif'] = ['KaiTi']

    def resize_QLabel(self):
        print('-----resize_QLabel-----')
         
        path = r'F:\python\gradu_design\gra_des\compr\jasper_johns.jpg'

        photo = QImage(path)
        print('photo type:', type(photo), photo.width(), photo.height())

        self.all_iamge_type_conversion(path,photo)

    def all_iamge_type_conversion(self,path,photo):
		
		# QImage_to_QPixmap 先读取图像显示在QLabel
        self.QImage_to_QPixmap(photo,self.label)  

        pixphoto = QPixmap(path)
        pixarr = self.QPixmap_to_Opencv(pixphoto)
        print('pixarr : ', type(pixarr))
        img_rotate = np.rot90(pixarr, 1)

        print('img_rotate : ', type(img_rotate))
        plt.imshow(img_rotate[:, :, ::-1])
        plt.show()

        # 调用 Opencv_to_QImage
        QtImg = self.Opencv_to_QImage(img_rotate)
        self.QImage_to_QPixmap(QtImg,self.label_2)


    # 让读取的图像自适应QLabel  QImage -> QPixmap
    def QImage_to_QPixmap(self,photo,label):
        print('-----Adjust_Img_Size-----')
        label.setStyleSheet("border:1px solid gray") # 使QLabel带有边框
        
        width = self.label.width()
        height = self.label.height()
        
        print('photo size:',type(photo),photo.width(),photo.height())

        size = QSize(width, height)
        
        # Qt.IgnoreAspectRatio、Qt.KeepAspectRatio、
        # https://www.cnblogs.com/qixianyu/p/6891054.html
        pixphoto = QPixmap.fromImage(photo.scaled(size, Qt.KeepAspectRatio,Qt.SmoothTransformation)) # QImage -> QPixmap  IgnoreAspectRatio:忽略纵横比
        # pixphoto = QPixmap(photo)
        label.setPixmap(pixphoto)


    # QPixmap 转为 Opencv   
    def QPixmap_to_Opencv(self,qtpixmap):
        print('-----QPixmap_to_Opencv-----')
        print('qtpixmap type:',type(qtpixmap))
        qimg = qtpixmap.toImage()  # QPixmap-->QImage

        temp_shape = (qimg.height(), qimg.bytesPerLine() * 8 // qimg.depth())
        temp_shape += (4,)
        ptr = qimg.bits()
        ptr.setsize(qimg.byteCount())
        result = np.array(ptr, dtype=np.uint8).reshape(temp_shape)
        result = result[..., :3]

        return result

    def Opencv_to_QImage(self,img):
        # 将图片转成BGRA模式;
        img_rgb = cv2.cvtColor(img, cv2.COLOR_BGR2BGRA)
        QtImg = QImage(img_rgb.data, img_rgb.shape[1], img_rgb.shape[0],QImage.Format_RGB32)
        return QtImg


def main():
    app = QApplication(sys.argv)
    window = QLabel_resize()
    window.show()
    app.exec_()

if __name__ == "__main__":
    main()
  • 测试效果
    PyQt5-QImage、QPixmap、Opencv与QLabel、Matplotlib的互动_第14张图片

总结

  • 参考资源
  1. matplotlib面向对象绘图小白终结版
  2. 将Python Opencv图片对象转成PyQt4中的QImage对象 ⭐
  3. python pyqt5图片(QPixmap)和opencv图片数据结构相互转换 ⭐
  4. PyQt5番外篇(1):PyQt5与Opencv的小小融合

你可能感兴趣的:(#,PyQt5教程,#,opencv图像处理,python,opencv,gui,pyqt5,matplotlib)