简体   繁体   English

在Curses中两种颜色之间渐隐(Python)

[英]Fading between 2 colors in Curses (Python)

I'm trying to fade the background color of a Curses subwindow between 2 arbitrary RGB values passed to the setupColor() function in my code. 我试图在传递给我代码中的setupColor()函数的2个任意RGB值之间淡化Curses子窗口的背景色。

In some cases, the code behaves as expected and can satisfactorily fade between the colors, but most of the time it performs strangely. 在某些情况下,代码的行为符合预期,并且可以令人满意地在颜色之间淡入淡出,但是大多数情况下,它的执行效果很差。

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

This will fade the subwindow between black and aqua, and works nicely. 这将淡化黑色和浅绿色之间的子窗口,并且效果很好。

However, if I try to fade between say, yellow and purple, like so: 但是,如果我尝试在黄色和紫色之间淡入淡出,就像这样:

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

This will cycle between the 2 colors for the first few cycles, but seems to lose sync and eventually produces noticeably different colors then those passed to the function. 在最初的几个周期中,它将在两种颜色之间循环,但是似乎失去了同步性,最终产生的颜色与传递给函数的颜色明显不同。

As I based the original code on the Arduino LED Fade sketch, I searched to see if anyone had tried to do something similar with physical RGB LED's, which turned up this thread: c++ Fade between colors? 当我将原始代码建立在Arduino LED Fade草图的基础上时,我搜索是否有人试图对物理RGB LED进行类似的操作,从而发现了这个线程: c ++颜色之间的淡入淡出? (Arduino) . (Arduino)

The solution posted on the thread seems like it would be ideal for my needs, but I don't know C++ or JavaScript well enough to be able to follow, understand and port the code to Python. 线程上发布的解决方案似乎很适合我的需求,但是我对C ++或JavaScript的了解不深,无法跟踪,理解并将代码移植到Python。

Is it possible to adapt my code in order for the colors to fade properly, or is it worth scrapping it and starting over from scratch? 是否可以修改我的代码以使颜色正确地淡入淡出,还是值得对其进行剪贴并从头开始?

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)

I figured this one out myself in the end, it was a relatively simple (but hacky and inelegant) fix. 最后,我自己弄清楚了这个问题,它是一个相对简单(但又笨拙又不雅致)的修复程序。 I printed the output of each of the color channels (variables red,green and blue in the code above) at this point in the program: 我在程序中的这一点上打印了每个颜色通道的输出(上面代码中的变量红色,绿色和蓝色):

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

This is the output for the first three cycles of the program: 这是程序的前三个循环的输出:

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

As you can see, the green channel gradually drifts out of sync compared to the others, and the values for red and blue are slightly different to those passed to the setupColor() function. 如您所见,与其他通道相比,绿色通道逐渐不同步,并且红色和蓝色的值与传递给setupColor()函数的值略有不同。

The color value inaccuracy can be fixed by using if statements to directly set the values: 可以通过使用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

And the timing/synchronization issue can be fixed by using a single if statement to change the color fade direction. 通过使用单个if语句更改颜色淡入方向,可以解决定时/同步问题。 Instead of using a statement for each color like this... 而不是像这样对每种颜色使用声明...

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

...set all of them at once like this: ...像这样一次设置所有这些:

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

The eagle eyed will have probably spotted that if both maxGreen and minGreen are both set to 0 (eg, rgb(230,0,100) and rgb(100,0,200)), nothing will happen. 鹰眼可能已经发现,如果将maxGreen和minGreen都设置为0(例如rgb(230,0,100)和rgb(100,0,200)),则不会发生任何事情。 If you change green to a different color, it'll work fine. 如果将绿色更改为其他颜色,它将可以正常工作。

I doubt that it would be hard to add some logic to detect which color channels would work, but considering that this can be avoided simply by passing 1 instead of 0, I've not bothered. 我怀疑很难添加一些逻辑来检测哪些颜色通道有效,但是考虑到可以简单地通过传递1而不是0来避免这种情况,所以我没有打扰。

Another good move (efficiency wise) would be to dump all of the fade values into an array, and set the colors based on that, instead of going through the overhead of calculating the values each time. 另一个好的方法(从效率角度考虑)是将所有淡入淡出值都转储到一个数组中,并根据该值设置颜色,而不是每次都要花费计算值的开销。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM