【发布时间】:2022-01-04 03:23:31
【问题描述】:
我正在尝试使用 PyQt 中的 QLabel 产生洋葱皮效果。在下面的简化示例中,使用 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__()
# -------------------------------------------------------------
# Define the display.
self.display = QLabel()
# -------------------------------------------------------------
# Import the frames
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')))
# -------------------------------------------------------------
# Populate the display
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)
# -------------------------------------------------------------
# Set the layout.
layout = QGridLayout()
layout.addWidget(self.display, 0, 0)
self.setLayout(layout)
if __name__ == '__main__':
app = QApplication(sys.argv)
window = MainWindow()
window.show()
app.exec()
理想情况下,最后一张图像会显示为完全不透明,而早期图像的透明度会越来越高。相反,我得到的输出是所有三个图像均等地混合在一起。这似乎是一个很容易解决的问题,但这次我的“Google Fu”并没有产生什么效果。
编辑
这里是图片文件。不幸的是,它们似乎已自动转换为 .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__()
# -------------------------------------------------------------
# Define values used for image painting.
self.first_opacity = 1 # Set first image to fully opaque so it does not blend into background.
self.falloff_value = 0.15 # The opacity of the second image.
self.falloff_rate = 0.5 # A factor used to decrement subsequent image transparencies.
# -------------------------------------------------------------
# Define the display.
self.display = QLabel()
self.display.setSizePolicy(QSizePolicy.MinimumExpanding, QSizePolicy.MinimumExpanding)
self.display.setMinimumSize(1, 1)
# -------------------------------------------------------------
# Import frames.
self.images = []
for i in range(1, 4, 1):
self.images.append(QImage(str(Path(f'fixtures/test_onion_skin/frame_{i}.png'))))
# -------------------------------------------------------------
# Set the display.
self.update_display()
# -------------------------------------------------------------
# Set the layout.
layout = QGridLayout()
layout.addWidget(self.display, 0, 0)
self.setLayout(layout)
def update_display(self):
# -------------------------------------------------------------
# Define the base pixmap on which to merge images.
base_pixmap = QPixmap(self.display.size())
base_pixmap.fill(Qt.transparent)
# -------------------------------------------------------------
# Preform paint cycle for images.
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):
# -------------------------------------------------------------
# Define a list to store image opacity values.
opacities = [self.first_opacity]
value = self.falloff_value
# -------------------------------------------------------------
# Calculate additional opacity values if more than one image is desired.
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()
【问题讨论】:
-
请分享.png
-
将 3 个文件压缩成一个 zip 文件,将其上传到 google drive、Dropbox 等服务,然后分享链接。你试过我的解决方案吗?在您的情况下,背景不统一,因此我的解决方案可能会失败。您可以使用其他工具编辑图像并删除背景吗?它还显示你得到什么以及你想得到什么
-
@eyllanesc 我尝试了您的解决方案,它很有帮助。谢谢!就我而言,我正在处理来自相机的图像,所以如果不进行大量的图像处理,我就无法真正改变它们。我决定使用一种允许与基本图像混合的解决方案。它适合我的目的。我会接受你的回答,以便我们结束这个问题。