【问题标题】:PyQt5 - HSV gradient not RGB gradientPyQt5 - HSV 渐变不是 RGB 渐变
【发布时间】:2020-03-23 13:38:00
【问题描述】:

我正在开发颜色选择器,并创建了一个混合颜色的面板。 面板的第一部分可以创建颜色的色调、色调和阴影,第二部分可以使用 2 种颜色进行混合。

但是我遇到了一个奇怪的情况,我在小部件上的渐变表示不反映它正在计算的实际颜色。 在这里你可以看到我使用“GREEN”和“PINK”并且渐变是相同的(RGB渐变?) 我通过使用 RGB 颜色空间计算顶栏的插值以及在 HSV 中插值的第二栏来实现这一点,这就是他们实际给出的结果。

这是我在托管我的代码的绘画程序上的渐变测试(上)与实际颜色混合器(下)的比较,它确实在 HSV 中显示。

如何在我的小部件上实现这种渐变过渡表示?

代码测试:

def paintEvent(self, event):
    green = QColor('#3c552c')
    pink = QColor('#d9bdcf')
    painter = QPainter(self)
    painter.setPen(QPen(Qt.black, 4, Qt.SolidLine))
    grad1 = QLinearGradient(20,20,190,20)
    grad1.setColorAt(0.0, green)
    grad1.setColorAt(1.0, pink)
    painter.setBrush(QBrush(grad1))
    painter.drawRect(10,10,200,200)

当前使用的代码:

def Mixer_Display(self):
    # Display Color with Tint, Tone, Shade
    mix_color_tint = str("background-color: qlineargradient(spread:pad, x1:0, y1:0, x2:1, y2:0, stop:0 rgb(%f, %f, %f), stop:1 rgb(255, 255, 255));" % (self.color_n_red, self.color_n_green, self.color_n_blue))
    self.layout.color_tint.setStyleSheet(mix_color_tint)
    mix_color_tone = str("background-color: qlineargradient(spread:pad, x1:0, y1:0, x2:1, y2:0, stop:0 rgb(%f, %f, %f), stop:1 rgb(127, 127, 127));" % (self.color_n_red, self.color_n_green, self.color_n_blue))
    self.layout.color_tone.setStyleSheet(mix_color_tone)
    mix_color_shade = str("background-color: qlineargradient(spread:pad, x1:0, y1:0, x2:1, y2:0, stop:0 rgb(%f, %f, %f), stop:1 rgb(0, 0, 0));" % (self.color_n_red, self.color_n_green, self.color_n_blue))
    self.layout.color_shade.setStyleSheet(mix_color_shade)
    # Display Gradients
    mix_gradient_1 = str("background-color: qlineargradient(spread:pad, x1:0, y1:0, x2:1, y2:0, stop:0 rgb(%f, %f, %f), stop:1 rgb(%f, %f, %f));" % (self.color_l1_red, self.color_l1_green, self.color_l1_blue, self.color_r1_red, self.color_r1_green, self.color_r1_blue))
    self.layout.gradient_1.setStyleSheet(mix_gradient_1)
    mix_gradient_2 = str("background-color: qlineargradient(spread:pad, x1:0, y1:0, x2:1, y2:0, stop:0 rgb(%f, %f, %f), stop:1 rgb(%f, %f, %f));" % (self.color_l2_red, self.color_l2_green, self.color_l2_blue, self.color_r2_red, self.color_r2_green, self.color_r2_blue))
    self.layout.gradient_2.setStyleSheet(mix_gradient_2)
    mix_gradient_3 = str("background-color: qlineargradient(spread:pad, x1:0, y1:0, x2:1, y2:0, stop:0 rgb(%f, %f, %f), stop:1 rgb(%f, %f, %f));" % (self.color_l3_red, self.color_l3_green, self.color_l3_blue, self.color_r3_red, self.color_r3_green, self.color_r3_blue))
    self.layout.gradient_3.setStyleSheet(mix_gradient_3)

【问题讨论】:

  • 你把“实际颜色混合器”带到哪里去了?
  • 它是别人的插件,我只是在上面挑了相同的颜色来显示颜色差异。
  • 所以这个人所做的可能是使用另一种颜色插值,可能基于 HSV 颜色空间。如果您知道该插件的来源,您可以在其代码中了解它是如何完成的。
  • 我不知道渐变是从哪里来的:\
  • 插件名称是什么?

标签: python-3.x pyqt5


【解决方案1】:

您可以通过向渐变添加额外颜色来模仿 HSV 渐变。看起来插件在两种颜色的色调、饱和度和值之间使用了线性插值,所以你可以这样做

from PyQt5 import QtWidgets
from PyQt5.QtCore import Qt
from PyQt5.QtGui import QColor, QPainter, QBrush, QLinearGradient, QPen
import numpy as np


class HSVColorBar(QtWidgets.QFrame):
    def __init__(self, c0, c1, parent=None):
        super().__init__(parent)
        self.c0 = c0
        self.c1 = c1

    @staticmethod
    def color_interpolator(col0, col1, factor):
        h0 = col0.hsvHueF()
        h1 = col1.hsvHueF()
        h1 -= round(h1-h0)
        hue = (h0*(1-factor) + h1*factor) % 1
        sat = col0.hsvSaturationF() * (1 - factor) + col1.hsvSaturationF() * factor
        val = col0.valueF() * (1 - factor) + col1.valueF() * factor
        return QColor.fromHsvF(hue, sat, val)

    def paintEvent(self, event):
        painter = QPainter(self)
        painter.setPen(QPen(Qt.black, 4, Qt.SolidLine))
        grad1 = QLinearGradient(0, 0, event.rect().width(), 0)
        # add intermediate colors to mimic hue mixing
        for i in np.linspace(0, 1, 10):
            grad1.setColorAt(i, self.color_interpolator(self.c0, self.c1, i))
        painter.setBrush(QBrush(grad1))
        painter.drawRect(event.rect())

if __name__ == "__main__":
    app = QtWidgets.QApplication([])
    green = QColor('#3c552c')
    pink = QColor('#d9bdcf')
    w = HSVColorBar(pink, green)
    w.show()
    app.exec()

截图

【讨论】:

  • 是否可以不使用 numpy 模块?它不适用于我正在使用的绘画程序
  • numpy 已经在大多数系统中可用,因为它是一个非常常用的模块。您可以“手动”执行相同的操作,但速度会慢得多。我能想到的唯一选择是自己做一个小的 Cython 模块进行插值。
  • 本例中,在for循环for i in np.linspace(0,1,10):中使用numpy的地方。您可以将其替换为 for i in range(11): i = i/10 ...
【解决方案2】:

受您的回答启发,我做了这样的事情。

主要:

# HSV Gradients
mix_hsv_g1 = self.style.HSV_Gradient(self.layout.hsv_g1.width(), self.color_hsv_l1, self.color_hsv_r1)
self.layout.hsv_g1.setStyleSheet(str(mix_hsv_g1))

模块:

def HSV_Gradient(self, width, color_left, color_right):
    # Colors
    left = [color_left[3], color_left[4], color_left[5]]
    right = [color_right[3], color_right[4], color_right[5]]
    # Conditions
    cond1 = right[0] - left[0]
    cond2 = (left[0] + 360) - right[0]
    cond3 = right[2] - left[1]
    cond4 = right[2] - left[2]
    # Style String
    slider_gradient = "background-color: qlineargradient(spread:pad, x1:0, y1:0, x2:1, y2:0, \n "
    "stop:%s rgb(%s, %s, %s), " % (0.000, color_left[0], color_left[1], color_left[2])
    unit = 1 / width
    for i in range(width):
        # Stop
        stop = round((i * unit), 3)
        # HSV Calculation
        if cond1 <= cond2:
            hue = left[0] + (stop * cond1)
        else:
            hue = left[0] - (stop * cond2)
            if hue <= 0:
                hue = hue + 360
            else:
                pass
        hue = hue / 360
        sat = (left[1] + (stop * cond3)) / 100
        val = (left[2] + (stop * cond4)) / 100
        # HSV to RGB Conversion
        rgb = colorsys.hsv_to_rgb(hue, sat, val)
        red = round(rgb[0]*255,3)
        green = round(rgb[1]*255,3)
        blue = round(rgb[2]*255,3)
        # String
        slider_gradient += "stop:%s rgb(%s, %s, %s), \n " % (stop, red, green, blue)
    slider_gradient += "stop:%s rgb(%s, %s, %s) ) " % (1.000, color_right[0], color_right[1], color_right[2])
    # Return StyleSheet String
    return slider_gradient

由于我使用绘制事件来控制自定义滑块,因此我想制作一个样式表来代替显示,因为计算似乎有点长。

结果:

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2022-01-19
    • 1970-01-01
    • 2016-04-21
    • 1970-01-01
    • 1970-01-01
    • 2015-03-22
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多