如何在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
相关产品推荐
相关产品推荐

