如何在C / C ++中将12位图像转换为8位?

时间:2010-10-13 04:03:11

标签: c++ c image colors

好吧,所以我一直非常沮丧地尝试将12位缓冲区转换为8位缓冲区。 图像源是12位GrayScale(从JPEG2000解压缩),其颜色范围为0-4095。现在我必须将其减少到0-255。常识告诉我,我应该像这样简单地划分每个像素值。但是当我尝试这个时,图像太亮了。

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));
    }
}

现在我可以说需要进行一些对比度调整。任何人的想法?

非常感谢提前

5 个答案:

答案 0 :(得分:2)

实际上,只需要进行一些简单的对比度调整。一旦我在Photoshop中加载结果图像并进行自动对比,我就意识到了这一点......图像结果非常类似于预期的输出图像。 我找到了一个算法来做对比,并将其张贴在这里为了方便起见:

#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));


 }

答案 1 :(得分:0)

据我所知,主要问题是将12位值转换为8位值。

Range of 12-bit value = 0 - 4095 (4096 values)
Range of  8-bit value = 0 -  255 ( 256 values)

我会尝试将12位值x转换为8位值y

  1. 首先,首先缩小到范围0-1和
  2. 然后,扩大到0-256范围。
  3. 一些C-ish代码:

    uint16_t x = some_value; 
    uint8_t  y = (uint8_t) ((double) x/4096 ) * 256;
    

    <强>更新

    感谢Kriss的评论,我意识到我无视速度问题。由于浮动操作,上述解决方案可能比纯整数操作慢。

    然后我开始考虑另一个解决方案。如何使用y 8的最高有效位来构建x?换句话说,通过削减4最低有效位。

    y = x >> 4;
    

    这会有用吗?

答案 2 :(得分:0)

如果您只想删除底部的4个最低有效位,您可以执行以下操作:

unsigned int start_value = SOMEVALUE; // starting value
value = (value & 0xFF0 );             // drop bits 
unsigned char final_value =(uint8_t)value >> 4; //bit shift to 8 bits

注意“未签名”。您不希望签名位与您的值混淆。

答案 3 :(得分:0)

像这样:

// Image is stored in 'data'
unsigned short* I = (unsigned short*)data;

for(int i=0; i<imageSize; i++) {
// 'color' is the 8-bit value  
   char color = (char)((double)(255*I[i])/(double)(1<<12));
   /*...*/ 
}

答案 4 :(得分:-1)

狂野猜测:您的代码假设是一个大端机器(最重要的字节优先)。 Windows PC是小端的。所以也许试试

  shortValue = (shortArray[j+1]<<8);
  shortValue += (shortArray[j]);

如果确实是endiasness问题,那么您提供的代码只会削减每个值的4个最高位,并将其余部分扩展到强度范围。嗯,编辑,2秒后:不,那是一个思考。但是还是试试呢?

干杯&amp;第h。,

- Alf