【问题标题】:C++: Grayscale bitmap header and live painting + opencv image processingC++:灰度位图头和实时绘画+opencv图像处理
【发布时间】:2018-09-22 17:38:10
【问题描述】:

我正在尝试显示来自单色相机(Adimec N5A/CXP,采用 GenIcam 标准)的实时图像。

来自供应商的示例(但在 RGB 24 中),我或多或少能够显示图像,但颜色渲染非常奇怪(颜色和阴影而不是灰度)。我想我在位图标题声明中做错了:

    bitmapInfo = (LPBITMAPINFO)malloc(sizeof(BITMAPINFOHEADER) + sizeof(RGBQUAD));
    bitmapInfo->bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
    bitmapInfo->bmiHeader.biPlanes = 1;
    bitmapInfo->bmiHeader.biBitCount = 8; // 24
    bitmapInfo->bmiHeader.biCompression = BI_RGB;
    bitmapInfo->bmiHeader.biSizeImage = 0;
    bitmapInfo->bmiHeader.biXPelsPerMeter = 0;
    bitmapInfo->bmiHeader.biYPelsPerMeter = 0;
    bitmapInfo->bmiHeader.biClrUsed = 256;
    bitmapInfo->bmiHeader.biClrImportant = 0;
    bitmapInfo->bmiHeader.biWidth = (LONG)width;
    bitmapInfo->bmiHeader.biHeight = -(LONG)height;
    /*
    RGBQUAD* bmiColors = (RGBQUAD*)(bitmapInfo->bmiColors);
    for (size_t index = 0; index < 256; ++index)
    {
        bmiColors[index].rgbBlue = (BYTE)index;
        bmiColors[index].rgbGreen = (BYTE)index;
        bmiColors[index].rgbRed = (BYTE)index;
        bmiColors[index].rgbReserved = 0;
    }
    */

我在bmiColors field of BITMAPINFO structure发现'biClrUsed'应该设置为256。然后我不知道我是否需要写一个块来描述'bmiColors'。我想每个像素只使用一个字节而不是 r、g 和 b 分量。

然后在程序中(在函数“OnPaint”中),它使用函数“SetDIBitsToDevice”在先前创建的窗口中显示。首先检索图像指针:

unsigned char *imagePtr = liveState.currentBuffer->getInfo<unsigned char *>(liveState.grabber, gc::BUFFER_INFO_BASE);

然后显示图片:

::SetDIBitsToDevice(dc, 0, 0, (DWORD)liveState.width, (DWORD)liveState.height, 0, 0, 0, (UINT)liveState.height, imagePtr, liveState.bitmapInfo, DIB_RGB_COLORS);

我不知道该放什么而不是 DIB_RGB_COLORS 作为最后一个参数。我只找到了这个参数的另一个值,即 DIB_PAL_COLORS。我想应该有灰度选项?

这是我程序的第一步...如果您对如何将图像指针推送到 opencv 容器有任何建议,我也会非常高兴:-)。

提前非常感谢!

【问题讨论】:

  • 我使用调色板显示灰度图像(生成非常简单)。快速粘贴我的代码,因为我即将出发:pastebin.com/Yz0cQYT8——数据指针是原始的cv::Mat 有效负载。我回来后会写一个答案。 (那里可能有一些 WTL 位,但无论如何这与 WinAPI 非常接近)
  • 嗨,丹,我可以请你帮忙吗?如何使用 cv::Mat 从内存缓冲区加载图像?我想我应该使用 cv::imdecode,但我不能。我猜缓冲区类型有问题。 'Mat srcImg = imdecode(imagePointer, 0);'
  • 内存缓冲区中有什么?原始图像数据(如上)?还是以 PNG、JPEG 或类似的格式编码图像数据?
  • 如果它已经是原始图像数据,那么你使用this cv::Mat constructor(注意它不会复制数据,你有责任确保指针保持有效,只要@987654329 @包装它的生活)

标签: c++ opencv image-processing bitmap visual-studio-2017


【解决方案1】:

看来你们已经很亲近了。显示灰度图像的方法是使用调色板。这只是代表黑色和白色之间所有阴影的 256 个 RGB 条目:

std::vector<RGBQUAD> pal(256);
for (int32_t i(0); i < 256; ++i) {
    pal[i].rgbRed = pal[i].rgbGreen = pal[i].rgbBlue = i;
    pal[i].rgbReserved = 0;
}

首先,您需要分配足够的内存来保存BITMAPINFOHEADER 以及定义要使用的调色板的256 个RGBQUAD 条目。

int32_t const bmi_size(sizeof(BITMAPINFOHEADER) + sizeof(RGBQUAD) * 256);

分配结构。我使用_alloca 将其放入堆栈,因此无需担心清理。

BITMAPINFO* bmi(static_cast<BITMAPINFO*>(alloca(bmi_size)));

BITMAPINFOHEADER的以下成员需要设置,其余的可以保留为零。

bmi->bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
bmi->bmiHeader.biWidth = static_cast<LONG>(width);
bmi->bmiHeader.biHeight = static_cast<LONG>(-height);
bmi->bmiHeader.biPlanes = 1;
bmi->bmiHeader.biBitCount = 8;
bmi->bmiHeader.biCompression = BI_RGB;

注意:由于我们有一个完整的 256 条目调色板,biClrUsed 可以设置为 0。来自docs

如果此值为零,则位图使用与biBitCount 成员的值对应的最大颜色数...

接下来,设置调色板(基本上就是您的代码中被注释掉的部分)。

for (uint32_t i(0); i < 256; ++i) {
    if (pal.size() > i) {
        bmi->bmiColors[i] = pal[i];
    } else {
        bmi->bmiColors[i].rgbRed
            = bmi->bmiColors[i].rgbGreen
            = bmi->bmiColors[i].rgbBlue
            = bmi->bmiColors[i].rgbReserved = 0;
    }
}

注意:上面的代码来自一个通用的调色板图像渲染函数。对于较小的调色板,它用黑色填充未使用的颜色。我想这可以重构为使用更少的条目以及将biClrUsed 设置为适当的值。

现在位图标题已准备就绪。在您的情况下,对 SetDIBitsToDevice 的调用仍将使用 DIB_RGB_COLORS,因为 “颜色表包含文字 RGB 值。”

我使用 CreateDIBitmap 创建一个 DDB,稍后我可以使用 BitBlt 渲染它。

HBITMAP bitmap = ::CreateDIBitmap(dc
    , &bmi->bmiHeader
    , CBM_INIT
    , data // Pointer to raw pixel data
    , bmi
    , DIB_RGB_COLORS);

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2011-12-25
    • 2012-06-13
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-04-05
    • 2015-02-03
    • 1970-01-01
    相关资源
    最近更新 更多