【问题标题】:Converting 12 bit color values to 8 bit color values C++将 12 位颜色值转换为 8 位颜色值 C++
【发布时间】:2016-10-09 11:39:02
【问题描述】:

我正在尝试将 12 位 RGGB 颜色值转换为 8 位 RGGB 颜色值,但使用我当前的方法会产生奇怪的结果。

从逻辑上讲,我认为简单地将 12 位 RGGB 划分为 8 位 RGGB 就可以了,而且非常简单:

// raw_color_array contains R,G1,G2,B in a bayer pattern with each element
// ranging from 0 to 4096
for(int i = 0; i < array_size; i++)
{
    raw_color_array[i] /= 16; // 4096 becomes 256 and so on
}

然而,在实践中这实际上是行不通的。例如,给定一张带有水和一块冰的小图像,您可以看到转换中实际发生的情况(最右边的图像)。

为什么会这样?以及如何在左侧获得相同(或接近)的图像,但改为 8 位值?谢谢!

编辑:离开@MSalters 的回答,我得到了质量更好的图像,但颜色仍然严重偏斜。我可以寻找哪些资源来将 12 位数据转换为 8 位数据而不会大幅降低质量?

【问题讨论】:

  • 您是否尝试过在通道上绘制直方图,看看您是否应该支持某些范围,而不是广泛开放的除以 16 的方法?
  • 你调试观察过raw_color_array的值吗?他们是你所期望的吗? raw_color_array 的数据类型是什么?你有舍入错误吗?
  • @ChrisO 实际上,我尝试的第一次迭代是查看直方图并猜测标准化方案。它产生了几乎相同的结果,但它不是一个可扩展的解决方案(例如,我需要为 14 位彩色图像重新执行此过程等等)。想知道这是否可能不带眼睛。
  • 因为您想将数据转换为不同的大小。您必须接受,当目标数据大小较小(从 12 位到 8 位)时,它会丢失一些数据。现在,要在转换后获得最接近的颜色强度匹配,您需要计算 12 位与目标转换之间的比率。我已经在答案中提出了公式。
  • 您说“RGB”,但代码显示“RGGB”。这可能是故意的(与“拜耳模式”结合使用是有意义的),但它可能很好地解释了为什么您的结果看起来偏绿。

标签: c++ image image-processing colors


【解决方案1】:

您的原始 12 位数据似乎不是线性比例。这对于图像来说很常见。对于非线性比例,不能使用除以 16 之类的线性变换。

sqrt(x*16) 这样的非线性变换也会给你一个 8 位的值。 std::pow(x, 12.0/8.0)

低梯度图像的一个已知问题是会出现条纹。如果您的图像具有原始值从 100 到 200 变化的区域,则 12 到 8 位的减少会将其缩小到少于 100 个不同的值。你得到四舍五入,并且通过天真的(本地)四舍五入你得到带。线性或非线性,然后会有一些输入 x 都映射到 y,还有一些映射到 y+1。这可以通过在浮点中进行转换来缓解,然后在舍入之前添加一个介于 -1.0 和 +1.0 之间的随机值。这有效地打破了能带结构。

【讨论】:

  • 谢谢! sqrt(x*16)std::pow(x, 12/8) 都比线性变换好得多。我的图像似乎变得灰绿了,但是有没有办法解决它?蓝色的海水因此变得更加微弱和绿色。
【解决方案2】:

在你澄清这个 12 位数据只针对一种颜色后,这是我的简单回答:

由于您想将其值转换为等效的 8 位,这显然意味着您丢失了一些数据(4 位)。这就是您没有得到相同输出的原因。

【讨论】:

  • 有问题的 12 位实际上表示 one 颜色的 12 位颜色值。就我而言,有 2^12 个可能的红色值,我想将其转换为 2^8 个可能的红色值。每个特定元素只代表一种颜色,颜色按照拜耳模式排列,红绿红第一行,绿蓝绿第二行
  • 无论您打算使用多少位数。我的回答的重点是,如果您要进行不同的范围或转换,则需要计算该目标范围的比率。我的答案中已经给出了公式。如果您想将 2^12 位转换为 2^8 位,如您所说,它仅代表一种颜色。然后获得最高可能的红色值并划分。 24(2X12) / 16(2^8) = 1.5 实际值 /1.5 是实际转换为 2^8 ex。 24 / 1.5 = 16 这也是 2^8 中的最高数字
  • 我不明白你为什么写 24(2 * 12) / 16(2^8) = 1.5。如果我想计算 12 位的最高最大值除以 8 位的最高最大值,那不是4096 (2^12) / 256 (2^8) = 16。 16 是我在 OP 中编写的代码示例中使用的
  • 对不起,我很困惑。您是正确的,它假设是 2 到 12 日和 2 到 16 日。使用 16 作为比率是正确的。我们可以得出结论,您获得不同输出的原因是因为我之前提到的转换中丢失了一些值。
【解决方案3】:

澄清后: 如果要保留实际的颜色值! 在 12 位图像中应用去马赛克,然后将结果数据缩放到 8 位。这样去马赛克造成的颜色损失会比以前的方法少。

【讨论】:

    【解决方案4】:

    您说您的 12 位代表一种颜色的 2^12 位。这是不正确的。您的图像中有红色、绿色和蓝色。查看直方图。我在命令行使用 ImageMagick 制作了这个:

    convert cells.jpg histogram:png:h.png
    

    如果您想要每像素 8 位,而不是尝试盲目/静态地将 3 位分配给绿色、2 位分配给红色和 3 位分配给蓝色,那么您最好使用 8 位调色板,这样您可以有 250 多种颜色的所有变化,而不是将自己限制在 8 种蓝色、4 种红色和 8 种绿色。所以,像这样:

    convert cells.jpg -colors 254 PNG8:result.png
    

    这是除原件之外的结果:

    上面的过程被称为“量化”,如果你想用 C/C++ 实现它,有一个写作here

    【讨论】:

    • 如果 RGB 位模式为 RGB 444,除以 16 并将结果重新解释为 RGB323 将丢弃所有 4 个蓝色位并将原始绿色通道的 3 个最低位重新解释为蓝色。不,这绝对不会发生。
    • 我只使用了 JPG,所以我可以实际显示图像,实际上图像是 .NEF 文件上的 0,1,1,2 图案。这意味着我仍然有2^12 每种颜色的位是吗?
    猜你喜欢
    • 2022-11-25
    • 1970-01-01
    • 2011-06-01
    • 2011-08-23
    • 2015-05-19
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多