C++: Grayscale bitmap header and live painting + opencv image processing
我正在尝试显示来自单色相机(具有GenIcam标准的Adimec N5A / CXP)的实时图像。
从供应商处获得的示例(但在RGB 24中),我或多或少能够显示图像,但是色彩渲染非常奇怪(用颜色和阴影而不是灰度)。我想我在位图标头声明中做错了:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 | 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; } */ |
我在BITMAPINFO结构的bmiColors字段中发现" biClrUsed"应设置为256。然后,我不知道是否需要编写一个块来描述" bmiColors"。我想每个像素仅使用一个字节,而不是r,g和b分量。
然后再在程序中(在功能" OnPaint"中)使用功能" SetDIBitsToDevice"在先前创建的窗口中显示。首先检索图像指针:
1 | unsigned char *imagePtr = liveState.currentBuffer->getInfo<unsigned char *>(liveState.grabber, gc::BUFFER_INFO_BASE); |
然后显示图像:
1 | ::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容器有任何建议,我也会很高兴的:-)。
非常感谢!
看来你已经很近了。显示灰度图像的方法是使用调色板。这只是256个RGB条目,代表了黑白之间的所有阴影:
1 2 3 4 5 | 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; } |
首先,您需要分配足够的内存来容纳
1 | int32_t const bmi_size(sizeof(BITMAPINFOHEADER) + sizeof(RGBQUAD) * 256); |
分配结构。我使用
1 | BITMAPINFO* bmi(static_cast<BITMAPINFO*>(alloca(bmi_size))); |
您需要设置以下
1 2 3 4 5 6 | 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个输入选项板,因此
If this value is zero, the bitmap uses the maximum number of colors corresponding to the value of the
biBitCount member...
接下来,设置面板(基本上就是您的代码中被注释掉的部分)。
1 2 3 4 5 6 7 8 9 10 | 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; } } |
注意:上面的代码来自通用的调色板图像渲染功能。对于较小的调色板,它将黑色填充为未使用的颜色。我想可以将其重构为使用更少的条目,并将
现在,位图标题已准备就绪。在您的情况下,对
我使用
1 2 3 4 5 6 | HBITMAP bitmap = ::CreateDIBitmap(dc , &bmi->bmiHeader , CBM_INIT , data // Pointer to raw pixel data , bmi , DIB_RGB_COLORS); |