You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在PyQt的QLabel中叠加图片实现洋葱皮效果

PyQt中使用QLabel实现洋葱皮效果

我尝试在PyQt中使用QLabel实现洋葱皮效果,如下简化示例中,加载了3张图片,使用QPainter将其绘制到标签上:

from PyQt5.QtWidgets import QApplication, QWidget, QGridLayout, QLabel
from PyQt5.QtCore import Qt, QPoint
from PyQt5.QtGui import QImage, QPixmap, QPainter
import sys
from pathlib import Path


class MainWindow(QWidget):
    def __init__(self):
        super().__init__()

        # -------------------------------------------------------------
        # 定义显示控件
        self.display = QLabel()

        # -------------------------------------------------------------
        # 导入帧素材
        frame_1 = QImage(str(Path(f'fixtures/test_onion_skin/frame_{1}.png')))
        frame_2 = QImage(str(Path(f'fixtures/test_onion_skin/frame_{2}.png')))
        frame_3 = QImage(str(Path(f'fixtures/test_onion_skin/frame_{3}.png')))    

        # -------------------------------------------------------------
        # 填充显示内容
        frame_1_scaled = frame_1.scaled(self.size(), Qt.KeepAspectRatio)
        frame_2_scaled = frame_2.scaled(self.size(), Qt.KeepAspectRatio)
        frame_3_scaled = frame_3.scaled(self.size(), Qt.KeepAspectRatio)

        base_pixmap = QPixmap(frame_1_scaled.size())

        painter = QPainter(base_pixmap)
        painter.drawImage(QPoint(), frame_3_scaled)
        painter.setOpacity(0.5)
        painter.drawImage(QPoint(), frame_2_scaled)
        painter.setOpacity(0.3)
        painter.drawImage(QPoint(), frame_1_scaled)
        painter.end()

        self.display.setPixmap(base_pixmap)

        # -------------------------------------------------------------
        # 设置布局
        layout = QGridLayout()
        layout.addWidget(self.display, 0, 0)
        self.setLayout(layout)


if __name__ == '__main__':
    app = QApplication(sys.argv)
    window = MainWindow()
    window.show()
    app.exec()

预期效果为最新帧完全不透明,更早的帧透明度逐级升高,但实际输出中三张图片均等混合,该问题看似简单,但搜索后暂未找到有效解决方案。

编辑
以下是用到的图片文件,很遗憾它们被自动转为了jpg格式,如果有更合适的导入方式欢迎告知。

编辑2
经过多次试验,决定做出妥协,允许基础图像存在一定混合效果。本次使用的是相机设备输出的原始图像,每张图像的背景都是非透明的。如果大家感兴趣可以参考如下代码:

from PyQt5.QtWidgets import QApplication, QWidget, QGridLayout, QLabel, QSizePolicy
from PyQt5.QtCore import Qt, QPoint
from PyQt5.QtGui import QImage, QPixmap, QPainter
import sys
from pathlib import Path


class MainWindow(QWidget):
    def __init__(self):
        super().__init__()
        # -------------------------------------------------------------
        # 定义图像绘制参数
        self.first_opacity = 1      # 首帧完全不透明,避免和背景混合
        self.falloff_value = 0.15   # 第二帧的透明度
        self.falloff_rate = 0.5     # 后续帧透明度的衰减系数

        # -------------------------------------------------------------
        # 定义显示控件
        self.display = QLabel()
        self.display.setSizePolicy(QSizePolicy.MinimumExpanding, QSizePolicy.MinimumExpanding)
        self.display.setMinimumSize(1, 1)

        # -------------------------------------------------------------
        # 导入帧素材
        self.images = []

        for i in range(1, 4, 1):
            self.images.append(QImage(str(Path(f'fixtures/test_onion_skin/frame_{i}.png'))))

        # -------------------------------------------------------------
        # 初始化显示内容
        self.update_display()

        # -------------------------------------------------------------
        # 设置布局
        layout = QGridLayout()
        layout.addWidget(self.display, 0, 0)
        self.setLayout(layout)

    def update_display(self):
        # -------------------------------------------------------------
        # 定义用于合并图像的基础画布
        base_pixmap = QPixmap(self.display.size())
        base_pixmap.fill(Qt.transparent)

        # -------------------------------------------------------------
        # 执行图像绘制流程
        painter = QPainter(base_pixmap)

        for (image, opacity) in zip(reversed(self.images), reversed(self.get_opacities(len(self.images)))):
            painter.setOpacity(opacity)
            painter.drawImage(QPoint(), image.scaled(base_pixmap.size(), Qt.KeepAspectRatio))

        painter.end()

        # -------------------------------------------------------------
        self.display.setPixmap(base_pixmap)

    def get_opacities(self, num_images):
        # -------------------------------------------------------------
        # 存储各帧透明度的列表
        opacities = [self.first_opacity]
        value = self.falloff_value

        # -------------------------------------------------------------
        # 计算多帧场景下的透明度
        if num_images > 1:
            num_decrements = num_images - 1

            for i in range(1, num_decrements + 1, 1):
                opacities.insert(0, value)
                value *= self.falloff_rate

        # -------------------------------------------------------------
        return opacities

    def resizeEvent(self, event):
        self.update_display()
        event.accept()


if __name__ == '__main__':
    app = QApplication(sys.argv)
    window = MainWindow()
    window.show()
    app.exec()

内容的提问来源于stack exchange,提问作者Transit12

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.09.24 14:24:05