Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to Convert a 12-bit Image to 8-bit in C/C++?

Tags:

c++

c

image

colors

All right, so I have been very frustrated trying to convert a 12-bit buffer to an 8-bit one. The image source is a 12-bit GrayScale (decompressed from JPEG2000) whose color range goes from 0-4095. Now I have to reduce that to 0-255. Common sense tells me that I should simply divide each pixel value like this. But when I try this, the image comes out too light.

void 
TwelveToEightBit(
    unsigned char * charArray,
    unsigned char * shortArray,
    const int num )
{

    short shortValue  = 0; //Will contain the two bytes in the shortArray.
    double doubleValue  = 0; //Will contain intermediary calculations.

    for( int i = 0, j =0; i < num; i++, j +=2 )
    {
        // Bitwise manipulations to fit two chars onto one short.
        shortValue = (shortArray[j]<<8);
        shortValue += (shortArray[j+1]);

        charArray[i] = (( unsigned char)(shortValue/16));
    }
}

Now I can tell that there needs to be some contrast adjustments. Any ideas anyone?

Many Thanks in advance

like image 233
Sir Wellington Avatar asked Oct 20 '25 12:10

Sir Wellington


1 Answers

In actuality, it was merely some simple Contrast adjustments that needed to be made. I realized this as soon as I loaded up the result image in Photoshop and did auto-contrast....the image result would very closely resemble the expected output image. I found out an algorithm that does the contrast and will post it here for other's convenience:

#include <math.h>

 short shortValue  = 0; //Will contain the two bytes in the shortBuffer.
 double doubleValue  = 0; //Will contain intermediary calculations.

 //Contrast adjustment necessary when converting
 //setting 50 as the contrast seems to be real sweetspot.
 double contrast = pow( ((100.0f + 50.0f) / 100.0f), 2); 

 for ( int i = 0, j =0; i < num; i++, j += 2 )
 {

  //Bitwise manipulations to fit two chars onto one short.
  shortValue = (shortBuffer[j]<<8);
  shortValue += (shortBuffer[j+1]);

  doubleValue = (double)shortValue;

  //Divide by 16 to bring down to 0-255 from 0-4095 (12 to 8 bits)
  doubleValue /= 16;

  //Flatten it out from 0-1
  doubleValue /= 255;
  //Center pixel values at 0, so that the range is -0.5 to 0.5
  doubleValue -= 0.5f;
  //Multiply and just by the contrast ratio, this distances the color
  //distributing right at the center....see histogram for further details
  doubleValue *= contrast;

  //change back to a 0-1 range
  doubleValue += 0.5f;
  //and back to 0-255
  doubleValue *= 255;


  //If the pixel values clip a little, equalize them.
  if (doubleValue >255)
   doubleValue = 255;
  else if (doubleValue<0)
   doubleValue = 0;

  //Finally, put back into the char buffer.
  charBuffer[i] = (( unsigned char)(doubleValue));


 }
like image 78
Sir Wellington Avatar answered Oct 23 '25 02:10

Sir Wellington