从2D数组生成C++的16位灰度渐变图像

4

我目前尝试构建一个16位灰度的“渐变”图像,但我的输出看起来很奇怪,所以我显然没有正确理解。我希望有人能为我的问题提供一些帮助。我认为我写的“位图”是错误的?但我不确定。

#include "CImg.h"
using namespace std;

unsigned short buffer[1250][1250];

void fill_buffer()
{
    unsigned short temp_data = 0;
    for (int i =0;i < 1250; i++)
    {
        for (int j =0 ;j < 1250;j++)
        {
            buffer[i][j] = temp_data;
        }
        temp_data += 20;
    }
}

int main()
{
    fill_buffer();
    auto hold_arr = (uint8_t *)&buffer[0][0];
    cimg_library::CImg<uint8_t> img(hold_arr, 1250, 1250);
    img.save_bmp("test.bmp");
    return 0;
}

当前输出: 当前输出

函数不太可能期望一个伪装成 uint8_t* 指针的二维数组。请使用一维数组。此外,在16位格式中,您需要移动颜色并将它们组合以生成 uint16_t。实际上,您正在以24位格式保存图像,这就是为什么您会看到任何灰色的颜色。使用位图查看器并从位图文件中读取格式信息。请注意,24位格式对于渐变效果更好,而且只比16位略大。您可能希望使用24位或PNG格式。 - Barmak Shemirani
2个回答

5

你不能在BMP中存储16位灰度样本...请参见Wikipedia

BMP中的每像素16位选项允许您存储4位红色、4位绿色、4位蓝色和4位alpha,但不允许存储16位灰度。

24位格式允许您为红色、绿色和蓝色各存储1字节,但不允许存储16位灰度。

32位BMP允许您存储24位BMP加alpha。

您需要使用PNGNetPBM PGM格式或TIFF格式。PGM格式非常好,因为CImg可以在没有任何库的情况下写入它,并且您始终可以使用ImageMagick将其转换为其他任何格式,例如:

convert image.pgm image.png

或者

convert image.pgm image.jpg

这个可以工作:
#define cimg_use_png
#define cimg_display 0
#include "CImg.h"

using namespace cimg_library;
using namespace std;

unsigned short buffer[1250][1250];

void fill_buffer()
{
    unsigned short temp_data = 0;
    for (int i =0;i < 1250; i++)
    {
        for (int j =0 ;j < 1250;j++)
        {
            buffer[i][j] = temp_data;
        }
        temp_data += 65535/1250;
    }
}

int main()
{
    fill_buffer();
    auto hold_arr = (unsigned short*)&buffer[0][0];
    cimg_library::CImg<unsigned short> img(hold_arr, 1250, 1250);
    img.save_png("test.png");
    return 0;
}

enter image description here

请注意,当要求CImg写入PNG文件时,您需要使用以下命令(使用libpngzlib)进行编译:
g++-7 -std=c++11 -O3 -march=native -Dcimg_display=0 -Dcimg_use_png  -L /usr/local/lib -lm -lpthread -lpng -lz -o "main" "main.cpp"

仅做解释:

  • -std=c++11 只是设置 C++ 的标准
  • -O3 -march=native 仅仅是为了加速,不是严格要求的
  • -Dcimg_display=0 表示所有的 X11 头文件都没有被解析,所以编译更快——但这意味着您不能从程序中显示图像,因此它意味着你是“无头”的
  • -Dcimg_use_png 意味着你可以使用 libpng 读写 PNG 图像,而不需要安装 ImageMagick
  • -lz -lpng 意味着生成的代码将链接到 PNG 和 ZLIB 库。

“你不能在 BMP 文件中存储 16 位灰度样本。” 但是您可以以更低的颜色分辨率存储 16 位图像中的灰度,最高为 RGB555 或 RGB565。或者您可能是指此库不支持它。 - Barmak Shemirani
@BarmakShemirani 不,我的意思就是我说的那样。你不能在BMP中存储16位灰度样本。如果它以较低的分辨率如RGB555存在,它不再是16位灰度,而是5位。我同意你可以在16位BMP中存储灰度,但不能存储16位灰度,这就是我所说的。 - Mark Setchell
@BarmakShemirani 16位灰度图像能够在每个像素处存储65536种灰度级别,即2^16种。如果您只存储32种灰度级别,则无法成功存储16位灰度图像。 - Mark Setchell
只有256种灰度:RGB(0,0,0),RGB(1,1,1)... RGB(255,255,255)。16位位图最多可以存储31种这些灰色颜色,其中间必须跳过一大堆。无论如何,16位位图已经很老了,可能不受“CImg”的支持。 - Barmak Shemirani
@BarmakShemirani,是的,我刚刚看了一下CImg如何编写头文件,它将图像写成24位。 - user2316289
显示剩余2条评论

3
你遇到了8位和16位的问题。你正在写入16位的值,但是库将它们解释为8位。这就是可见的深色垂直条的解释。它在每个值的低字节和高字节之间交替处理,将它们视为两个单独的像素值。
"渐变百叶窗"效果的原因也是由于只考虑了低字节。它会在12个步骤中从0循环到240,然后在下一个步骤中溢出回到5,以此类推。
我不是专家,但一个好的起点可能是用替换,看看会产生什么影响。

你太棒了!使用uint16_t类型来替换掉垂直线是有道理的!我甚至不知道为什么要将数据转换为uint8_t类型。虽然没有解决“渐变百叶窗”问题,但这是朝着正确方向迈出的一步。 - user2316289
@user2316289 请尝试在能够告诉您位深度的图像应用程序中打开生成的bmp文件。可能bmp文件仅限于8位。我相信png和jpg文件能够存储16位图像。只要记住,我不是图像专家,所以我的说法可能有误。 ;) - dgnuff

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接