【PyQt5】Day 11 – 以 Qlabel 在 PyQt 中顯示圖片 (基於 QImage 使用 OpenCV)

➣ Reading Time: 12 minutes

看完這篇文章你會得到的成果圖

前言

我們接下來的討論,會基於讀者已經先讀過我 day5 文章 的架構下去進行程式設計
如果還不清楚我程式設計的邏輯 (UI.py、controller.py、start.py 分別在幹麻)
建議先閱讀 day5 文章後再來閱讀此文。

【PyQt5】Day 5 – 開始來設計我們的 controller.py,改以「程式角度」來說明如何建立 PyQt 的系統

此篇文章的範例程式碼 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

⭐Python PyQt5 相關文章整理⭐:
⭐基礎知識與架構篇⭐:
1.【PyQt5】Day 1 – 安裝 PyQt,建立自己的第一支 PyQt5 程式
2.【PyQt5】Day 2 – 利用 Qt designer 建立第一支有自己介面的 PyQt5 程式
3.【PyQt5】Day 4 – 重要的 Qt 程式邏輯觀念,務必先有此觀念後面才會懂自己在幹嘛
4.【PyQt5】Day 5 – 開始來設計我們的 controller.py,改以「程式角度」來說明如何建立 PyQt 的系統
⭐基本元件應用篇⭐:
1.【PyQt5】Day 6 – 我們的第一個 output 手段 – Qlabel
2.【PyQt5】Day 7 – 我們的第一個 input 手段 – QPushButton
3.【PyQt5】Day 8 – 我們的第二個 input 手段 – QLineEdit
4.【PyQt5】Day 9 – 以 QLineEdit, QTextEdit, QPlainTextEdit 作為文字的輸入
6.【PyQt5】Day 14 - 使用 QSlider 製作可拖曳的滑條
8.【PyQt5】Day 19 - 使用 QProgressBar,製作進度條的功能
⭐介面系統控制篇⭐:
5.【PyQt5】Day 10 – 以 QFileDialog 讀取系統的檔案、資料夾
7.【PyQt5】Day 18 / Project 使用 QTimer,自製碼表(計時器) PyQt5 stopwatch DIY
1.【PyQt5】Day 20 - PyQt 最重要的 QThread 概念 / 為什麼 windows, mac, ubuntu (linux) 程式會「沒有回應」?
2.【PyQt5】Day 21 – 透過 PyQt 實現滑鼠監聽總整理,完全掌握滑鼠控制 (listen mouse)
3.【PyQt5】Day 22 – PyQt 視窗的個性化/屬性控制 setWindowFlags,禁止放大縮小、永遠顯示於最上層/最下層
4.【PyQt5】Day 23 – 使用系統內建的調色盤 QColorDialog,來替我們選擇顏色 QColor (Color Picker)
5.【PyQt5】Day 24 / Project 偵測滑鼠目前指示顏色的小工具 (滴管工具), 利用 QCursor 偵測滑鼠, QApplication 取得截圖
⭐影像處理篇⭐:
1.【PyQt5】Day 11 – 以 Qlabel 在 PyQt 中顯示圖片 (基於 QImage 使用 OpenCV)
2.【PyQt5】Day 12 – 建立一個可以縮放圖片大小的顯示器 (基於 QImage 使用 OpenCV)
3.【PyQt5】Day 13 – 使用 QVBoxLayout, QscrollArea 製作出捲軸,以高解析度檢視圖片 (基於 QImage 使用 OpenCV)
4.【PyQt5】Day 15 / Project 與檔案功能整合,製作出可讀取圖片並可縮放的 UI 介面 (使用 PyQt + OpenCV)
5.【PyQt5】Day 16 - 在 PyQt5 中取得圖片座標 (滑鼠位置) mousePressEvent,觀察圖片在 Qt 中產生的方式,對原圖進行座標換算處理
6.【PyQt5】Day 17 / Project 製作標註 roi 工具, 開始導入 OpenCV 作為繪圖引擎, 在圖上畫點並顯示座標
⭐project 篇⭐:
1.【PyQt5】Day 25 / Project 自己做一個影片播放器 DIY video player (結合 PyQt + OpenCV)
2.【PyQt5】Day 26 / Project 替我們影片播放器增加一個顯示進度的滑條 video player add slider (與昨日 bottleneck 處理細節)
3.【PyQt5】Day 27 / Project 製作影片 ROI 標註工具 (PyQt 結合 OpenCV 在圖上畫點畫線)
4.【PyQt5】Day 28 / final project – 1 來搞一個自己的 photoshop 吧!UI 篇 + 純程式架構篇 (結合 PyQt + OpenCV)
5.【PyQt5】Day 29 / final project – 2 來搞一個自己的 photoshop 吧!後段程式細節篇 (結合 PyQt + OpenCV)
6.【PyQt5】Day 30 / final project – 3 來搞一個自己的 photoshop 吧!把每個方法封裝起來製作出還原功能吧! (結合 PyQt + OpenCV)
⭐打包程式篇⭐:
1.【PyQt5】Day 3 – 用 pyinstaller 將 python 程式打包,把每天的成果分享給你的親朋好友
⭐【喜歡我的文章嗎? 歡迎幫我按讚~ 讓基金會請創作者喝一杯咖啡!
如果喜歡我的文章,請幫我在下方【按五下Like】 (Google, Facebook 免註冊),會由 「LikeCoin」 贊助作者鼓勵繼續創作,讀者們「只需幫忙按讚,完全不用出錢」哦!

likecoin-steps
預設圖片
Howard Weng

我是 Howard Weng,很多人叫我嗡嗡。這個網站放了我的各種筆記。希望這些筆記也能順便幫助到有需要的人們!如果文章有幫助到你的話,歡迎幫我點讚哦!

文章: 673

1 則留言

★留個言吧!內容有誤或想要補充也歡迎與我討論!