Pillow ImageQt 模块

下面给你一个 Pillow(PIL Fork)中 ImageQt 模块 的完整入门指南,包含 PIL.ImagePyQt / PySide 图像互转、实时显示、动态更新、性能优化、跨平台兼容及高级 GUI 应用。
(基于 Pillow ≥ 9.0,Python 3.8+)


1. 安装依赖

# 安装 PyQt5(或 PySide6)
pip install PyQt5

# 或使用 PySide6(推荐 Qt 官方支持)
# pip install PySide6

# 安装 Pillow
pip install --upgrade pillow

2. 基本导入

from PIL import Image, ImageQt
from PyQt5.QtWidgets import QApplication, QLabel, QMainWindow, QWidget
from PyQt5.QtGui import QPixmap, QImage
import sys

注意ImageQt 模块会根据环境中可用的 Qt 绑定自动选择 PyQt5, PyQt6, PySide2, PySide6


3. 核心功能:ImageQt.ImageQt(img)

PIL.Image 转换为 QImage,可用于 QLabelQPixmap 等 Qt 控件。

img = Image.open("photo.jpg")
qimage = ImageQt.ImageQt(img)  # 自动转换为 QImage

4. 基础示例:显示 PIL 图像

class ImageWindow(QMainWindow):
    def __init__(self):
        super().__init__()
        self.setWindowTitle("Pillow + PyQt5")
        self.setGeometry(100, 100, 800, 600)

        # 打开 PIL 图像
        pil_img = Image.open("photo.jpg").convert("RGB")

        # 转为 QImage
        qimg = ImageQt.ImageQt(pil_img)

        # 创建 QLabel 显示
        label = QLabel(self)
        label.setPixmap(QPixmap.fromImage(qimg))
        label.resize(pil_img.size)

        self.setCentralWidget(label)

# 运行
app = QApplication(sys.argv)
window = ImageWindow()
window.show()
sys.exit(app.exec_())

5. 动态更新图像(实时预览)

import time
from PyQt5.QtCore import QTimer

class LivePreview(QMainWindow):
    def __init__(self):
        super().__init__()
        self.setWindowTitle("实时滤镜预览")
        self.setGeometry(100, 100, 800, 600)

        self.label = QLabel(self)
        self.setCentralWidget(self.label)

        self.img = Image.open("photo.jpg").convert("RGB")

        # 定时器每 100ms 更新
        self.timer = QTimer()
        self.timer.timeout.connect(self.update_filter)
        self.timer.start(100)

        self.angle = 0

    def update_filter(self):
        # 动态旋转 + 模糊
        rotated = self.img.rotate(self.angle, expand=True)
        from PIL import ImageFilter
        blurred = rotated.filter(ImageFilter.GaussianBlur(2))

        qimg = ImageQt.ImageQt(blurred)
        self.label.setPixmap(QPixmap.fromImage(qimg))
        self.label.resize(blurred.size)

        self.angle = (self.angle + 5) % 360

app = QApplication(sys.argv)
window = LivePreview()
window.show()
sys.exit(app.exec_())

6. 性能优化技巧

技巧说明
缓存 QImage避免重复转换
使用 QPixmapQLabel.setPixmap 更快
缩小预览图img.resize((400,300)) 再转换
分离线程图像处理放子线程,避免卡 UI

示例:线程安全更新

from PyQt5.QtCore import QThread, pyqtSignal
import numpy as np

class Worker(QThread):
    finished = pyqtSignal(Image.Image)

    def __init__(self, img):
        super().__init__()
        self.img = img

    def run(self):
        # 模拟耗时处理
        time.sleep(1)
        arr = np.array(self.img)
        arr = arr + 50  # 提亮
        result = Image.fromarray(arr.clip(0, 255).astype('uint8'))
        self.finished.emit(result)

class MainWindow(QMainWindow):
    def __init__(self):
        super().__init__()
        self.label = QLabel(self)
        self.setCentralWidget(self.label)

        self.img = Image.open("photo.jpg").convert("RGB")
        self.worker = Worker(self.img)
        self.worker.finished.connect(self.update_image)
        self.worker.start()

    def update_image(self, pil_img):
        qimg = ImageQt.ImageQt(pil_img)
        self.label.setPixmap(QPixmap.fromImage(qimg))

7. 高级应用

7.1 图像编辑器(缩放 + 滤镜)

from PyQt5.QtWidgets import QPushButton, QVBoxLayout

class Editor(QMainWindow):
    def __init__(self):
        super().__init__()
        self.setWindowTitle("图像编辑器")
        self.img = Image.open("photo.jpg").convert("RGB")

        central = QWidget()
        layout = QVBoxLayout()

        self.label = QLabel()
        self.update_display()

        btn_blur = QPushButton("高斯模糊")
        btn_blur.clicked.connect(self.apply_blur)

        layout.addWidget(self.label)
        layout.addWidget(btn_blur)
        central.setLayout(layout)
        self.setCentralWidget(central)

    def update_display(self):
        qimg = ImageQt.ImageQt(self.img)
        self.label.setPixmap(QPixmap.fromImage(qimg).scaled(600, 400, transformMode=1))

    def apply_blur(self):
        self.img = self.img.filter(ImageFilter.GaussianBlur(5))
        self.update_display()

7.2 截图工具(结合 ImageGrab

from PIL import ImageGrab

class ScreenshotTool(QMainWindow):
    def __init__(self):
        super().__init__()
        btn = QPushButton("截图", self)
        btn.clicked.connect(self.capture)
        self.setCentralWidget(btn)

    def capture(self):
        img = ImageGrab.grab()  # 全屏截图
        qimg = ImageQt.ImageQt(img)
        label = QLabel()
        label.setPixmap(QPixmap.fromImage(qimg))
        label.show()

7.3 视频帧显示(OpenCV + PIL + Qt)

import cv2

class VideoPlayer(QMainWindow):
    def __init__(self):
        super().__init__()
        self.label = QLabel(self)
        self.setCentralWidget(self.label)

        self.cap = cv2.VideoCapture(0)
        self.timer = QTimer()
        self.timer.timeout.connect(self.update_frame)
        self.timer.start(30)

    def update_frame(self):
        ret, frame = self.cap.read()
        if ret:
            frame = cv2.cvtColor(frame, cv2.COLOR_BGR2RGB)
            img = Image.fromarray(frame)
            qimg = ImageQt.ImageQt(img)
            self.label.setPixmap(QPixmap.fromImage(qimg).scaled(640, 480))

8. 跨版本兼容(PyQt5 / PySide6)

def pil_to_qimage(pil_img):
    """自动适配 PyQt5 / PySide6"""
    try:
        from PyQt5.QtGui import QImage
    except ImportError:
        try:
            from PySide6.QtGui import QImage
        except ImportError:
            raise ImportError("需要 PyQt5 或 PySide6")

    return ImageQt.ImageQt(pil_img)

9. 常见问题 & 解决方案

问题原因解决
ImportError: cannot import name 'ImageQt'未安装 Qt 绑定pip install PyQt5
图像显示为黑屏颜色通道顺序错误.convert("RGB")
内存泄漏频繁转换不释放使用 QPixmap.cacheKey() 缓存
窗口闪烁频繁 setPixmap使用 QGraphicsView + QGraphicsPixmapItem

10. 官方文档

  • Pillow ImageQt:https://pillow.readthedocs.io/en/stable/reference/ImageQt.html
  • PyQt5 文档:https://www.riverbankcomputing.com/static/Docs/PyQt5/

一键运行示例:pil_qt_viewer.py

#!/usr/bin/env python3
import sys
from PIL import Image, ImageQt
from PyQt5.QtWidgets import QApplication, QLabel, QMainWindow

class Viewer(QMainWindow):
    def __init__(self, path):
        super().__init__()
        self.setWindowTitle(f"PIL Viewer - {path}")

        img = Image.open(path).convert("RGB")
        qimg = ImageQt.ImageQt(img)

        label = QLabel()
        label.setPixmap(QPixmap.fromImage(qimg))
        self.setCentralWidget(label)
        self.resize(img.size)

app = QApplication(sys.argv)
if len(sys.argv) < 2:
    print("用法: python pil_qt_viewer.py <image_path>")
    sys.exit(1)

window = Viewer(sys.argv[1])
window.show()
sys.exit(app.exec_())

使用

python pil_qt_viewer.py photo.jpg

总结:ImageQt 是 Pillow 与 Qt 的桥梁

功能推荐方式
显示图像ImageQt.ImageQt(img) → QPixmap
实时更新QTimer + setPixmap
大图预览img.resize() 先缩略
线程处理QThread + 信号

需要我帮你实现 图像标注工具、滤镜预览面板、批量处理 GUI、视频帧提取播放器 等完整项目吗?直接说需求,我给你完整可运行代码!

类似文章

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注