【没钱买ps,PyQt自己写】Day 11 - 以 Qlabel 在 PyQt 中显示图片 (基於 QImage 使用 OpenCV)

看完这篇文章你会得到的成果图

前言

我们接下来的讨论,会基於读者已经先读过我 day5 文章 的架构下去进行程序设计
如果还不清楚我程序设计的逻辑 (UI.py、controller.py、start.py 分别在干麻)
建议先阅读 day5 文章後再来阅读此文。

https://www.wongwonggoods.com/python/pyqt5-5/

此篇文章的范例程序码 github

https://github.com/howarder3/ironman2021_PyQt5_photoshop/tree/main/day11_display_image

以 Qlabel 在 PyQt 中显示图片

我们在先前的文章中已经有提过,我们可以使用 Qlabel 作为显示文字,
同样的,我们也可以使用 Qlabel 来显示图片。

今天我们就要来实作这个功能。

UI 设计部份 (UI.py)

先修改主程序 window 大小

我们先点击 QMainWindow 的部份,
展开 geometry,这里修改 Width, Height 可以直接改变整个视窗的大小。

建议修改要大一点,因为要显示的图片可能也会很大。

新增 Qlabel 作为图片显示

我们使用与之前一样的方式新增一个 Qlabel,文字可以先不用管他,
但我们需要先改变 Qlabel 所占的范围大小,
展开 geometry,这里修改 Width, Height 可以直接改变 Qlabel 显示视窗的大小。

而上面的 X, Y 可以个人需求修改,X, Y 表示的是「相对 MainWindow」此 Label 开始显示的位置。

(从左上角开始算,往右X、往下Y)

这边有两件事情要注意:

  1. 修改後的 Qlabel geometry 必须小於主程序的 QMainWindow` (画面比视窗大不合理吧XD)
  2. 如果 Qlabel geometry 设定的解析度不够大,有可能会只有只显示部份图片的情形 (从左上开始自动剪裁)

读者们可以开始自行设计自己的介面罗,以上为我的示范。

转换成 UI.py

一样的编译指令,我们加上 -x (也可不加),
我们就可以先检视看看转换後的视窗是不是跟我们想像的一样。

转换 day11.ui -> UI.py

pyuic5 -x day11.ui -o UI.py

执行看看 UI.py 画面是否如同我们想像

一样,这程序只有介面 (视觉上的呈现),没有任何互动功能

  • 看看我们制作出来的介面
python UI.py

这边可以看到很单纯的只有一段被初始化的文字,
接下来我们要开始去改变里面的内容。

controller 设计部份 (controller.py)

从 UI.py 中找出物件名称

这次我们只有一个物件 self.label

取得名称後,去修改 controller.py

还记得我们在 day5 中的模板吗?这边我们直接复制过来使用并修改。

from PyQt5 import QtWidgets, QtCore
from PyQt5.QtGui import QImage, QPixmap
import cv2

from UI import Ui_MainWindow

class MainWindow_controller(QtWidgets.QMainWindow):
    def __init__(self):
        super().__init__() # in python3, super(Class, self).xxx = super().xxx
        self.ui = Ui_MainWindow()
        self.ui.setupUi(self)
        self.setup_control()

    def setup_control(self):
        # TODO
        self.img_path = 'cat_small.jpg'
        self.display_img()

    def display_img(self):
        self.img = cv2.imread(self.img_path)
        height, width, channel = self.img.shape
        bytesPerline = 3 * width
        self.qimg = QImage(self.img, width, height, bytesPerline, QImage.Format_RGB888).rgbSwapped()
        self.ui.label.setPixmap(QPixmap.fromImage(self.qimg))

import 新增的部份

  • 「import cv2」:我们为了要显示图片,会使用到 OpenCV 的 function
  • 「from PyQt5.QtGui import QImage, QPixmap」:为了要显示图片,会使用到 PyQt5.QtGui 中的 QImage, QPixmap 这两个物件的定义

setup_control() 修改的部份

  • 「self.img_path = 'cat.jpg'」:要显示图片的路径
  • 「self.display_img()」:等等会去 call 我们写好的显示图片的 function

display_img() 的部份

  • 「self.img = cv2.imread(self.img_path)」:OpenCV 经典的读图 function,之前有介绍过,应该不用我们再多说
  • 「height, width, channel = self.img.shape」:读取图片的 shape 与 channel,等等设定参数会用到
  • 「bytesPerline = 3 * width」:设定「每一行」的影像占用位置数量,目前因为有 3 个 channel,因此是 3 * width (如果有透明度可能就是 4 个 channel)
  • 「self.qimg = QImage(self.img, width, height, bytesPerline, QImage.Format_RGB888).rgbSwapped()」:将转成 OpenCV (numpy) 的格式图片转换成 QImage 的格式,并输入图片对应的长宽,每一行占用的 bytes 数,
    而 QImage.Format_RGB888 代表的是 RGB 3 个 channel,「.rgbSwapped()」 表示将 B, G, R 3 个 channel 转换成 R, G, B (因为 OpenCV 是以 BGR 的方式储存图片,需要先进行转换)
  • 「self.ui.label.setPixmap(QPixmap.fromImage(self.qimg))」:将图片在 label 中显示

执行结果

照我们 day5 的程序架构,我们执行

python start.py

正常显示图片的情形

碰到解析度太大,导致我们设定的 Qlabel 无法完全显示的情形

就会像下图这样,因为图片太大了,800*600 只能显示部份图片

Reference


★ 本文也同步发於我的个人网站(会有内容目录与显示各个小节,阅读起来更流畅):【PyQt5】Day 11 - 以 Qlabel 在 PyQt 中显示图片 (基於 QImage 使用 OpenCV)


<<:  #12 Web Crawler 5

>>:  【Day 11】分散式系统小总结

【Day 8】Adaptation!适应!让BERT更好地过渡到下游任务!

今天开始,我们要进入一个新的主题「Adaptation」。这是指在预训练模型和Fine-tune之间...

[神经机器翻译理论与实作] Google Translate的神奇武器- Seq2Seq (II)

前言 我们紧接着切入 RNN 为架构的编码器-解码器。 在seq2seq之前 RNN Encoder...

Day15:15 - 购物车服务(3) - 後端 - 购物车数量增减、删除API

Kamusta,我是Charlie! 在Day14中,我们完成了前端的购物车商品显示跟加入购物车,而...

JAVA - Windows 10 安装 Maven

JAVA - Windows 10 安装 Maven 参考资料 参考:(一)maven 新手教学: ...

Flutter体验 Day 12-线性布局

线性布局 不管是水平布局或是垂直布局都是布局上常用的配置方式。 布局组件 Row Column Wr...