adafruit / Adafruit_CircuitPython_DotStar

Dotstarrin' away in CircuitPython land
MIT License
47 stars 38 forks source link

Built-in Gamma Correction to Dotstar and NeoPixel #21

Closed mcscope closed 5 years ago

mcscope commented 6 years ago

So when making anything that uses neopixels or dotstars, you may encounter issues with color giving unexpected results, and you might want to gamma correct your LEDs. Here's an adafruit learn about them. https://learn.adafruit.com/led-tricks-gamma-correction/the-issue

My suggestion is that we make this really easy to do, so that you can just pass gamma=True to a Dotstar/Neopixel strip when you construct it, and it will gamma correct every value. Here's what that might look like: dot = dotstar.DotStar(board.APA102_SCK, board.APA102_MOSI, 1, brightness=0.3, gamma=True)

If we do this, it should probably be done both in circuitpython dotstar and circutpython neopixel to keep the api the same.

The learn guide has a table of hardcoded gamma correction values, but I've used an algorithmic solution in my mcscope/liteup library. Probably the algorithmic correction takes less of a ram hit?

GAMMA_CORRECT_FACTOR = 2.8

def gamma_correct(led_val):
    max_val = (1 << 8) - 1.0
    corrected = pow(led_val / max_val, GAMMA_CORRECT_FACTOR) * max_val
    return int(min(255, max(0, corrected))))

it's a python implementation of the algorithm on the third page of the learn guide.

tannewt commented 6 years ago

I'm fine with adding this. I'd probably call it gamma_correct though. Would you do the math late like brightness?

On Wed, May 16, 2018 at 3:29 PM Christopher Beacham < notifications@github.com> wrote:

So when making anything that uses neopixels or dotstars, you may encounter issues with color giving unexpected results, and you might want to gamma correct your LEDs. Here's an adafruit learn about them. https://learn.adafruit.com/led-tricks-gamma-correction/the-issue

My suggestion is that we make this really easy to do, so that you can just pass gamma=True to a Dotstar/Neopixel strip when you construct it, and it will gamma correct every value. Here's what that might look like: dot = dotstar.DotStar(board.APA102_SCK, board.APA102_MOSI, 1, brightness=0.3, gamma=True)

If we do this, it should probably be done both in circuitpython dotstar and circutpython neopixel to keep the api the same.

The learn guide has a table of hardcoded gamma correction values, but I've used an algorithmic solution in my mcscope/liteup library. Probably the algorithmic correction takes less of a ram hit?

GAMMA_CORRECT_FACTOR = 2.8

def gamma_correct(led_val): max_val = (1 << 8) - 1.0 corrected = pow(led_val / max_val, GAMMA_CORRECT_FACTOR) * max_val return int(min(255, max(0, corrected))))

it's a python implementation of the algorithm on the third page of the learn guide.

— You are receiving this because you are subscribed to this thread. Reply to this email directly, view it on GitHub https://github.com/adafruit/Adafruit_CircuitPython_DotStar/issues/21, or mute the thread https://github.com/notifications/unsubscribe-auth/AADNqfkcnTiRKluvrNxH-DYI3ozyCTEhks5tzIwrgaJpZM4UB_D0 .

mcscope commented 6 years ago

I was imagining doing it in the __set_item__` call. I think brightness being calculated late makes sense because people might want to blink the strip and do something like:

strip.brightness=1
strip.show()
time.sleep(0.1)
strip.brightness=0.1
strip.show()

Now if we did the math for brightness in set_item, the above wouldn't work, it has to be done late. (well... we could do the math in set_item and then update the whole buffer in the brightness setter. Depends how much we care about that performance impact of doing the buffer every time),

I think people wouldn't want to turn on and off gamma correction the same way as they do brightness.

tannewt commented 6 years ago

Yeah, I agree it should be in the constructor. When would you apply the math to the pixel values? I think it has to be done late too which has the downsides of requiring more memory and time.

On Wed, May 16, 2018 at 3:45 PM Christopher Beacham < notifications@github.com> wrote:

I was imagining doing it in the set_item call. I think brightness being calculated late makes sense because people might want to blink the strip and do something like:

strip.brightness=1 strip.show() time.sleep(0.1) strip.brightness=0.1 strip.show()

Now if we did the math for brightness in set_item, the above wouldn't work, it has to be done late. (well... we could do the math in set_item and then update the whole buffer in the brightness setter. ),

I think people wouldn't want to turn on and off gamma correction the same way as they do brightness. Probably they either want it or they won't.

— You are receiving this because you commented. Reply to this email directly, view it on GitHub https://github.com/adafruit/Adafruit_CircuitPython_DotStar/issues/21#issuecomment-389659692, or mute the thread https://github.com/notifications/unsubscribe-auth/AADNqU-CsVS4tvATgoJA9oAsr6mhvRp6ks5tzI_0gaJpZM4UB_D0 .

mcscope commented 6 years ago

@tannewt see pull request

dhalbert commented 6 years ago

Calling pow() may be kind of expensive, which might be the original reason for the hardcoded values. Probably worth doing some timing tests.

Instead of passing True/False, you could also pass the correction factor (assuming not using precomputed values), with the default being 1.0 (right? that would lead to value**1, which could be checked for to save time).

ladyada commented 6 years ago

hiya FYI this is supported in fancy LED library https://github.com/adafruit/Adafruit_CircuitPython_FancyLED https://github.com/adafruit/Adafruit_CircuitPython_FancyLED/blob/master/examples/neopixel_rotate.py perhaps we could keep it there?

RedAnon commented 6 years ago

FancyLED is nice and works very well but the downside is the need for an additional library which is a bit of a pain on a memory constrained devices like Trinekts or Gemmas. Especially when you essentially use a very little subset of this features...

siddacious commented 6 years ago

Personally, I'm inclined to think that anyone who cares/knows about gamma correction probably wants to be using FancyLED anyways. If you're going to include gamma correction into CP you might as well include the whole kitchen sink which than starts to seem excessive.

I definitely like the original idea of making gamma correction easier to use but I think that can be better done by making it easier to find the FancyLED documentation. Something as simple as

If you're interested in fancy features for making your LEDs look even better, like gamma correction and color palettes, checkout the FancyLED library

in the dotstar or neopixel driver documentation, or other places where it's likely a person might be looking for something like that.

kattni commented 5 years ago

Looks like this can be closed based on discussion. Please reopen if needed.