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

如何在PyQt6中为图像创建蒙版并修改其颜色?

PyQt6实现图像蒙版与颜色修改的正确方案

问题背景

已有JavaScript实现的图像蒙版改色功能,现在需要在PyQt6中复刻相同效果。当前尝试createMaskFromColor仅得到黑白蒙版,无法实现目标效果。

原图

原图

JavaScript实现效果

JS实现效果

当前PyQt6代码问题

使用createMaskFromColor生成的蒙版是黑白的,无法叠加颜色实现JS中的效果。


解决方案:模拟Canvas的合成模式

PyQt6的QPainter支持类似Canvas的合成模式,可以通过以下步骤实现和JS一致的效果:

  1. 创建与图像尺寸一致的临时图像作为绘制画布
  2. 填充目标颜色到临时图像
  3. 使用CompositionMode_DestinationAtop模式绘制原图,保留图像Alpha通道区域的颜色
  4. 使用CompositionMode_Multiply模式再次绘制原图,增强细节
  5. 将最终合成的临时图像绘制到界面

修改后的完整代码

from sys import argv
from sys import exit as ex
from pathlib import Path
from PyQt6.QtWidgets import QApplication, QWidget, QSizePolicy, QVBoxLayout
from PyQt6.QtCore import Qt, QRectF, QTimer
from PyQt6.QtGui import QPaintEvent, QPainter, QImage, QPen, QColor, QBrush

class PaintWidget(QWidget):
    def __init__(self, parent=None) -> None:
        super().__init__()
        self.setSizePolicy(
            QSizePolicy(QSizePolicy.Policy.Expanding, QSizePolicy.Policy.Expanding)
        )
        # 加载并缩放图像(scaledToWidth返回新图像,需赋值)
        self.image_path = str(Path(Path(__file__).parent, "image.png"))
        self.image = QImage(self.image_path).scaledToWidth(150, Qt.TransformationMode.SmoothTransformation)
        self.target_color = QColor(255, 0, 0)  # 目标红色,可修改为任意颜色
        self.timer = QTimer(self)
        self.timer.timeout.connect(self.update)
        self.timer.start(17)

    def paintEvent(self, event: QPaintEvent | None) -> None:
        painter = QPainter(self)
        painter.setRenderHint(QPainter.RenderHint.Antialiasing)
        
        # 绘制背景
        painter.setPen(QPen(QColor(169, 169, 169), 0, Qt.PenStyle.SolidLine))
        painter.setBrush(QBrush(QColor(169, 169, 169), Qt.BrushStyle.SolidPattern))
        painter.drawRect(self.rect())

        # 创建临时图像作为合成画布
        temp_image = QImage(self.image.size(), QImage.Format.Format_ARGB32)
        temp_image.fill(Qt.GlobalColor.transparent)
        temp_painter = QPainter(temp_image)
        temp_painter.setRenderHint(QPainter.RenderHint.Antialiasing)

        # 步骤1:填充目标颜色
        temp_painter.fillRect(temp_image.rect(), self.target_color)

        # 步骤2:使用DestinationAtop模式绘制原图,保留图像区域的颜色
        temp_painter.setCompositionMode(QPainter.CompositionMode.CompositionMode_DestinationAtop)
        temp_painter.drawImage(0, 0, self.image)

        # 步骤3:使用Multiply模式再次绘制原图,增强细节(与JS逻辑一致)
        temp_painter.setCompositionMode(QPainter.CompositionMode.CompositionMode_Multiply)
        temp_painter.drawImage(0, 0, self.image)

        temp_painter.end()

        # 将合成后的图像绘制到界面
        rect = QRectF(0, 0, temp_image.width(), temp_image.height())
        painter.drawImage(rect, temp_image)

        return super().paintEvent(event)

class MainWindow(QWidget):
    def __init__(self) -> None:
        super().__init__()
        self.setup_ui()
        self.show()

    def setup_ui(self) -> None:
        self.showFullScreen()
        self.main_window_layout = QVBoxLayout()
        self.painter_widget = PaintWidget()
        self.main_window_layout.addWidget(self.painter_widget)
        self.setLayout(self.main_window_layout)

if __name__ == "__main__":
    app = QApplication(argv)
    main_window = MainWindow()
    ex(app.exec())

关键说明

  • 合成模式对应:
    • JS中的destination-atop对应PyQt的CompositionMode_DestinationAtop
    • JS中的multiply对应PyQt的CompositionMode_Multiply
  • 临时图像的作用:模拟Canvas的独立绘制环境,避免直接在界面画布操作导致的叠加问题
  • 图像缩放:scaledToWidth返回新图像,必须赋值给变量,否则原图像不会改变
  • 渲染提示:开启Antialiasing让图像边缘更平滑

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.30 00:04:53