简体   繁体   English

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

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

All right, so I have been very frustrated trying to convert a 12-bit buffer to an 8-bit one. 好吧,因此尝试将12位缓冲区转换为8位缓冲区令我非常沮丧。 The image source is a 12-bit GrayScale (decompressed from JPEG2000) whose color range goes from 0-4095. 图像源是一个12位灰度(从JPEG2000解压缩),其颜色范围为0-4095。 Now I have to reduce that to 0-255. 现在我必须将其减少到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 提前谢谢了

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. 我将结果图像加载到Photoshop中并进行自动对比后,就意识到了这一点。图像结果与预期的输出图像非常相似。 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));


 }

if you just want to drop the bottom 4 least significant bits you can do the following: 如果只想删除最低的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

Note the "unsigned". 注意“未签名”。 You don't want the signed bit mucking with your values. 您不希望签名与您的值混为一谈。

Like this: 像这样:

// 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));
   /*...*/ 
}

The main problem, as I understand, is to convert a 12-bit value to a 8-bit one. 据我了解,主要问题是将12位值转换为8位值。

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

I would try to convert a 12-bit value x to a 8-bit value y 我会尝试将12位值x转换为8位值y

  1. First, scale down first to the range 0-1, and 首先,先缩小到0-1的范围,然后
  2. Then, scale up to the range 0-256. 然后,放大到0-256的范围。

Some C-ish code: 一些C-ish代码:

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

Update 更新资料

Thanks to Kriss 's comment, I realized that I disregarded the speed issue. 感谢Kriss的评论,我意识到我不理会速度问题。 The above solution, due to floating operations, might be slower than pure integer operations. 由于浮动运算,上述解决方案可能比纯整数运算要慢。

Then I started considering another solution. 然后,我开始考虑另一种解决方案。 How about constructing y with the 8 most significant bits of x ? x8最高有效位构造y怎么样? In other words, by trimming off the 4 least significant bits. 换句话说,通过修剪4最低有效位。

y = x >> 4;

Will this work? 这样行吗?

Wild guess: your code assumes a big-endian machine (most significant byte first). 大胆的猜测:您的代码假定使用大端机(最高有效字节在前)。 A Windows PC is little-endian. Windows PC是低端的。 So perhaps try 所以也许尝试

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

If indeed endiasness is the problem then the code you presented would just shave off the 4 most significant bits of every value, and expand the rest to the intensity range. 如果确实存在问题,那么您提供的代码将仅去除每个值的4个最高有效位,并将其余的扩展到强度范围。 Hm, EDIT, 2 secs later: no, that was a thinko. 嗯,编辑,两秒钟后:不,那是个想法。 But try it anyway? 但是还是尝试一下吗?

Cheers & hth., 干杯,……

– Alf –阿尔夫

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

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