0

Adalight LPD8806 gamma correction
Moderators: adafruit_support_bill, adafruit

Please be positive and constructive with your questions and comments.

Adalight LPD8806 gamma correction

by elmerfud on Mon Feb 27, 2012 11:55 pm

This is gamma correction code ripped directly out of the advancedLEDbeltKit.pde from the LPD8806 library. As the code comment states the pwm on the LPD8806 isn't visually linear. Personally I find this correct table very much improves the look. I figured I'd share the patch in case anyone else wants to try it out.


Code: Select all | TOGGLE FULL SIZE
diff --git a/Arduino/LEDstream_LPD8806/LEDstream_LPD8806.pde b/Arduino/LEDstream_LPD8806/LEDstream_LPD8806.pde
index 1fc79f0..9f995c6 100644
--- a/Arduino/LEDstream_LPD8806/LEDstream_LPD8806.pde
+++ b/Arduino/LEDstream_LPD8806/LEDstream_LPD8806.pde
@@ -178,7 +178,7 @@ void loop() {
       buffer[byteNum++] = c;          // Store in data buffer
       if(byteNum == 3) {              // Have a full LED's worth?
         while(byteNum > 0) {          // Issue data in LPD8806 order...
-          i = 0x80 | (buffer[byteOrder[--byteNum]] >> 1);
+          i = 0x80 | gamma(buffer[byteOrder[--byteNum]]);
           while(!(SPSR & _BV(SPIF))); // Wait for prior byte out
           SPDR = i;                   // Issue new byte
         }
@@ -230,3 +230,43 @@ static boolean timeout(
   return false; // No timeout
 }

+// Gamma correction compensates for our eyes' nonlinear perception of
+// intensity.  It's the LAST step before a pixel value is stored, and
+// allows intermediate rendering/processing to occur in linear space.
+// The table contains 256 elements (8 bit input), though the outputs are
+// only 7 bits (0 to 127).  This is normal and intentional by design: it
+// allows all the rendering code to operate in the more familiar unsigned
+// 8-bit colorspace (used in a lot of existing graphics code), and better
+// preserves accuracy where repeated color blending operations occur.
+// Only the final end product is converted to 7 bits, the native format
+// for the LPD8806 LED driver.  Gamma correction and 7-bit decimation
+// thus occur in a single operation.
+PROGMEM prog_uchar gammaTable[]  = {
+    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  1,  1,  1,  1,
+    1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  2,  2,  2,  2,
+    2,  2,  2,  2,  2,  3,  3,  3,  3,  3,  3,  3,  3,  4,  4,  4,
+    4,  4,  4,  4,  5,  5,  5,  5,  5,  6,  6,  6,  6,  6,  7,  7,
+    7,  7,  7,  8,  8,  8,  8,  9,  9,  9,  9, 10, 10, 10, 10, 11,
+   11, 11, 12, 12, 12, 13, 13, 13, 13, 14, 14, 14, 15, 15, 16, 16,
+   16, 17, 17, 17, 18, 18, 18, 19, 19, 20, 20, 21, 21, 21, 22, 22,
+   23, 23, 24, 24, 24, 25, 25, 26, 26, 27, 27, 28, 28, 29, 29, 30,
+   30, 31, 32, 32, 33, 33, 34, 34, 35, 35, 36, 37, 37, 38, 38, 39,
+   40, 40, 41, 41, 42, 43, 43, 44, 45, 45, 46, 47, 47, 48, 49, 50,
+   50, 51, 52, 52, 53, 54, 55, 55, 56, 57, 58, 58, 59, 60, 61, 62,
+   62, 63, 64, 65, 66, 67, 67, 68, 69, 70, 71, 72, 73, 74, 74, 75,
+   76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91,
+   92, 93, 94, 95, 96, 97, 98, 99,100,101,102,104,105,106,107,108,
+  109,110,111,113,114,115,116,117,118,120,121,122,123,125,126,127
+};
+
+// This function (which actually gets 'inlined' anywhere it's called)
+// exists so that gammaTable can reside out of the way down here in the
+// utility code...didn't want that huge table distracting or intimidating
+// folks before even getting into the real substance of the program, and
+// the compiler permits forward references to functions but not data.
+inline byte gamma(byte x) {
+  return pgm_read_byte(&gammaTable[x]);
+}
+
+

elmerfud
 
Posts: 20
Joined: Wed Feb 01, 2012 6:28 pm

Re: Adalight LPD8806 gamma correction

by pounce on Tue Feb 28, 2012 10:07 am

Reposting the code block to clean it up a little. Thanks for posting because I hadn't seen that bit of code before.

Code: Select all | TOGGLE FULL SIZE
// Gamma correction compensates for our eyes' nonlinear perception of
// intensity.  It's the LAST step before a pixel value is stored, and
// allows intermediate rendering/processing to occur in linear space.
// The table contains 256 elements (8 bit input), though the outputs are
// only 7 bits (0 to 127).  This is normal and intentional by design: it
// allows all the rendering code to operate in the more familiar unsigned
// 8-bit colorspace (used in a lot of existing graphics code), and better
// preserves accuracy where repeated color blending operations occur.
// Only the final end product is converted to 7 bits, the native format
// for the LPD8806 LED driver.  Gamma correction and 7-bit decimation
// thus occur in a single operation.
PROGMEM prog_uchar gammaTable[]  = {
    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  1,  1,  1,  1,
    1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  2,  2,  2,  2,
    2,  2,  2,  2,  2,  3,  3,  3,  3,  3,  3,  3,  3,  4,  4,  4,
    4,  4,  4,  4,  5,  5,  5,  5,  5,  6,  6,  6,  6,  6,  7,  7,
    7,  7,  7,  8,  8,  8,  8,  9,  9,  9,  9, 10, 10, 10, 10, 11,
   11, 11, 12, 12, 12, 13, 13, 13, 13, 14, 14, 14, 15, 15, 16, 16,
   16, 17, 17, 17, 18, 18, 18, 19, 19, 20, 20, 21, 21, 21, 22, 22,
   23, 23, 24, 24, 24, 25, 25, 26, 26, 27, 27, 28, 28, 29, 29, 30,
   30, 31, 32, 32, 33, 33, 34, 34, 35, 35, 36, 37, 37, 38, 38, 39,
   40, 40, 41, 41, 42, 43, 43, 44, 45, 45, 46, 47, 47, 48, 49, 50,
   50, 51, 52, 52, 53, 54, 55, 55, 56, 57, 58, 58, 59, 60, 61, 62,
   62, 63, 64, 65, 66, 67, 67, 68, 69, 70, 71, 72, 73, 74, 74, 75,
   76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91,
   92, 93, 94, 95, 96, 97, 98, 99,100,101,102,104,105,106,107,108,
  109,110,111,113,114,115,116,117,118,120,121,122,123,125,126,127
};

// This function (which actually gets 'inlined' anywhere it's called)
// exists so that gammaTable can reside out of the way down here in the
// utility code...didn't want that huge table distracting or intimidating
// folks before even getting into the real substance of the program, and
// the compiler permits forward references to functions but not data.
inline byte gamma(byte x) {
  return pgm_read_byte(&gammaTable[x]);
}

pounce
 
Posts: 82
Joined: Wed Nov 23, 2011 6:36 pm

Re: Adalight LPD8806 gamma correction

by adafruit on Tue Feb 28, 2012 11:58 am

thank you, would you like to post this as an issue or pull on github? it will help us greatly!

adafruit
 
Posts: 12151
Joined: Thu Apr 06, 2006 4:21 pm
Location: nyc

Re: Adalight LPD8806 gamma correction

by pburgess on Tue Feb 28, 2012 10:03 pm

elmerfud & pounce: not meaning to be a jerk for shooting down your pull request, especially after Phil specifically suggested the github approach, and I hope the explanation there clarifies the reasons.

Anyway...the Adalight code is already doing its own gamma correction. If it's not doing enough correction for your needs (e.g. mid-level brightness is still too much), this can be tweaked in Adalight.pde. Line 237 currently looks like this:
Code: Select all | TOGGLE FULL SIZE
f   = pow((float)i / 255.0, 2.8);

That 2.8 is the correction factor...larger numbers will intensify the gamma correction curve, dimming the midrange brightness level (while black & white are unaffected). So, if you're running the original LEDstream code on the Arduino (without the gamma table incorporated), you could instead try a larger value here, a la:
Code: Select all | TOGGLE FULL SIZE
f   = pow((float)i / 255.0, 3.3);

Hope that helps. And again, I appreciate your contribution and apologize if that came across as draconian. Rar!

pburgess
 
Posts: 4074
Joined: Sun Oct 26, 2008 2:29 am

Re: Adalight LPD8806 gamma correction

by elmerfud on Tue Feb 28, 2012 11:31 pm

I don't actaully use that sketch with Adalight :oops: :)

I didn't find the rejection draconian at all. It clearly wasn't inline with the direction you're taking the project.

Anyway, just for fun, plotting a few correction curves with Wolfram Alpha!

elmerfud
 
Posts: 20
Joined: Wed Feb 01, 2012 6:28 pm

Re: Adalight LPD8806 gamma correction

by pburgess on Wed Feb 29, 2012 1:47 am

Ah! Okay. In that case, in whatever code you're driving it from, you might either want to take a look in the Adalight source to see how the gamma correction is set up there...or, better yet, if you're using Processing on the host side, have a look at the WS2801 library used in the Adavision demos, since it already has some gamma table convenience functions. (Even if you're using the LPD8806 strip, since the LEDstream_LPD8806 sketch converts things from the prior protocol to the latter.)

pburgess
 
Posts: 4074
Joined: Sun Oct 26, 2008 2:29 am

Please be positive and constructive with your questions and comments.