python - Curses(Python)中两种颜色之间的淡入淡出

标签 python rgb ncurses curses

我试图在我的代码中传递给 setupColor() 函数的 2 个任意 RGB 值之间淡化 Curses 子窗口的背景颜色。

在某些情况下,代码的行为符合预期并且可以令人满意地在颜色之间淡化,但大多数时候它的表现很奇怪。

setupColor((0,0,0),(0,255,55))

这将使黑色和浅绿色之间的子窗口变淡,效果很好。

但是,如果我尝试在黄色和紫色之间淡化,就像这样:

setupColor((255,200,0),(200,0,200))

这将在前几个循环中在 2 种颜色之间循环,但似乎失去同步并最终产生与传递给函数的颜色明显不同的颜色。

当我将原始代码基于 Arduino LED Fade 草图时,我搜索了看是否有人尝试过对物理 RGB LED 做类似的事情,结果出现了这个帖子:c++ Fade between colors? (Arduino) .

线程上发布的解决方案似乎非常适合我的需求,但我对 C++ 或 JavaScript 的了解还不够深入,无法理解和将代码移植到 Python。

是否可以调整我的代码以使颜色正确褪色,或者是否值得放弃它并从头开始?

import curses,time
from curses import wrapper

def setupColor((red,green,blue),(red1,green1,blue1)):

    global color1,color2                                   #initialise globals for use later on in the program.
    global incrFloatRed,incrFloatGreen,incrFloatBlue
    global minRed,minGreen,minBlue,maxRed,maxGreen,maxBlue

    stepNumber = 60.00                 # number of steps within each color transition.

    color1 = (red,green,blue)         # clone the input tuples for use later on...
    color2 = (red1,green1,blue1)


    differenceRed = red - red1          # subtract each channel of color1 from color2,
    differenceGreen = green - green1    # this will return either a positive or negative float.
    differenceBlue = blue - blue1


    incrFloatRed = differenceRed / stepNumber        # divide the difference between the 2 colors by the 
    incrFloatGreen = differenceGreen / stepNumber    # step rate to obtain the color increments.
    incrFloatBlue = differenceBlue / stepNumber

    if red > red1:                            # if the red channel value of the 1st color is greater than 
            incrFloatRed = -incrFloatRed      # that of the 2nd, invert the increment (to allow
            maxRed = red                      # color subtraction), then set the top end of the range as 
            minRed = red1                     # red 1st channel and the bottom as red 2nd channel.
    else:                                     # Else, perform the inverse operation.
            incrFloatRed = abs(incrFloatRed)
            maxRed = red1
            minRed = red

    if green > green1:
            incrFloatGreen = -incrFloatGreen
            maxGreen = green
            minGreen = green1
    elif green < green1:
            incrFloatGreen = abs(incrFloatGreen)        
            maxGreen = green1
            minGreen = green

    if blue > blue1:
            incrFloatBlue = -incrFloatBlue
            maxBlue = blue
            minBlue = blue1
    else:
            incrFloatBlue = abs(incrFloatBlue)
            maxBlue = blue1
            minBlue = blue



def main(stdscr):
    global incrFloatRed,incrFloatGreen,incrFloatBlue

    setupColor((0,0,0),(0,255,255))

    red = color1[0]                #red,green and blue are the variables used to control the fade.
    green = color1[1]              #To begin with, they is set to the colors contained in the first 
    blue = color1[2]               #tuple that is passed to setupColor()



    label = stdscr.subwin(10,50,1,4)  # create a subwindow, draw a box around it, then add the string
    label.box()                       # "Hello, World!" to the subwindow at position row 1, column 1.
    label.addstr(1,1,"Hello, World!")
    curses.curs_set(0)                # Disable cursor visibility


    while True:




            red = red + incrFloatRed           # color = colorValue + colorIncrement
            green = green + incrFloatGreen
            blue = blue + incrFloatBlue

            if red <= minRed or red >= maxRed:   # if color is less than the start of the color range or
                    incrFloatRed = -incrFloatRed # greater than end of the color range, invert the color increment

            if green <= minGreen or green >= maxGreen:
                    incrFloatGreen = -incrFloatGreen

            if blue <= minBlue or blue >= maxBlue:
                    incrFloatBlue = -incrFloatBlue
                                                      # curses.init_color takes a tuple of rgb values as it's argument,
            cursesRed = int(int(red) / 0.255)         # but uses funky 1000-point intensity values, instead of the usual
            cursesGreen = int(int(green) / 0.255)     # 255. e.g. rgb(1000,0,0) for full intensity red, instead of
            cursesBlue = int(int(blue) / 0.255)       #           rgb(255,0,0).
                                                      # To convert between them, divide the integer of the color value float 
                                                      # by 0.255, then obtain the integer of the resulting float. 



            if cursesRed >=1000:                      # Sometimes a color value is set to greater
                    cursesRed = 1000                  # than 1k or less than 0. When a negative value or a value greater 
            if cursesGreen >=1000:                    # than 1k is passed to curses.init_color(), it will return ERR and
                    cursesGreen = 999                 # Curses will crash. 
            if cursesBlue >=1000:                     
                    cursesBlue = 999

            if cursesRed <=0:
                    cursesRed = 0
            if cursesGreen <=0:
                    cursesGreen = 0
            if cursesBlue <=0:
                    cursesBlue = 0


            curses.init_color(1,cursesRed,cursesGreen,cursesBlue) # reassign Curses color (1) to the RGB1K color of the current step... 

            curses.init_pair(1,255,1)                             # then create a color pair with the dynamic value (1) as 
                                                                  # the BG color, and white (255) as the FG. 



            label.bkgd(curses.color_pair(1)) # set the background of the label subwindow to the current color pair.. 
            label.refresh()                  # then refresh, so that we can see the change.

            time.sleep(0.02)                 # Take a little snooze, then do it all again. 


wrapper(main)

最佳答案

我最终自己解决了这个问题,这是一个相对简单(但又老套又不雅致)的修复方法。我在程序的此时打印了每个颜色 channel 的输出(上面代码中的变量红色、绿色和蓝色):

if red <= minRed or red >= maxRed:   
    outFile.write("Red : " + str(int(red)) + "|Green : " + str(int(green)) + "|Blue : " + str(int(blue)) + "\n")
    incrFloatRed = -incrFloatRed 

这是程序前三个周期的输出:

Red : 199|Green : 3  |Blue : 196
Red : 255|Green : 193|Blue : 0

Red : 199|Green : 9  |Blue : 196
Red : 255|Green : 186|Blue : 0

Red : 199|Green : 16 |Blue : 196
Red : 255|Green : 179|Blue : 0

如您所见,与其他 channel 相比,绿色 channel 逐渐偏离同步,红色和蓝色的值与传递给 setupColor() 函数的值略有不同。

颜色值不准确可以通过if语句直接设置值来修复:

while True:
        red = red + incrFloatRed           # color = colorValue + colorIncrement
        green = green + incrFloatGreen
        blue = blue + incrFloatBlue

        ##### Add the if statements after this ####

        if red < minRed:
            red = minRed
        if red > maxRed:
            red = maxRed

        if blue < minBlue:
            blue = minBlue
        if blue > maxBlue:
            blue = maxBlue

        if green < minGreen:
            green = minGreen
        if green > maxGreen:
            green = maxGreen

并且可以通过使用单个 if 语句更改颜色渐变方向来解决计时/同步问题。而不是像这样为每种颜色使用一个语句......

        if green <= minGreen or green >= maxGreen:
            incrFloatGreen = -incrFloatGreen 

...像这样一次设置所有这些:

        if green <= minGreen or green >=maxGreen:
            incrFloatRed = -incrFloatRed 
            incrFloatGreen = -incrFloatGreen
            incrFloatBlue = -incrFloatBlue   

眼尖的人可能已经发现,如果 maxGreen 和 minGreen 都设置为 0(例如,rgb(230,0,100) 和 rgb(100,0,200)),则什么也不会发生。如果将绿色更改为其他颜色,它会正常工作。

我怀疑添加一些逻辑来检测哪些颜色 channel 可以工作会很困难,但考虑到只需传递 1 而不是 0 就可以避免这种情况,我没有费心。

另一个好的举措(效率方面)是将所有淡入淡出值转储到一个数组中,并根据它设置颜色,而不是每次都计算这些值的开销。

关于python - Curses(Python)中两种颜色之间的淡入淡出,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/51713494/

相关文章:

image - 为什么图像的红色,绿色,蓝色 channel 分别是灰度(Matlab)?

c++ - 在另一个窗口中运行 ncurses 程序时,有什么方法可以使用 cout 进行调试吗?

c - 删除已在 ncurses 终端中打印的字符

python - Blender,使用提示命令将 .STL 转换为 .obj

python - 屏蔽 Y 数组以仅获取其 X1==X2 的值

python - matplotlib 调整颜色条

c - 如何正确将RGB颜色保存到ppm文件?

java - Windows 8 上 Java 8 Update 45 中的可能错误

python - 使用elasticsearch_dsl(Python)时如何指定文档类型?同样,如何指定几个索引?

haskell - 解释和编译的Haskell之间ncurses的区别?