我写了一个小函数来将ARGB中的位图转换为灰度。转换本身效果很好,但结果是颠倒的。 我找不到错误。
代码: #包括 #include
inline BYTE GrayScaleValue(BYTE* r, BYTE* g, BYTE* b) { return /*ceil*/(0.21f * (*r) + 0.72f * (*g) + 0.07f * (*b)); }
extern "C" __declspec(dllexport) HBITMAP ConvertToMonocrom(HBITMAP bmp) {
INT x = 0, y = 0;
char Gray;
BITMAP bm;
GetObject(bmp, sizeof(BITMAP), (LPSTR)&bm);
BYTE * pImgByte = (BYTE *)bm.bmBits;
INT iWidthBytes = bm.bmWidth * 4;
for (y = 0; y < bm.bmHeight; y++) {
for (x = 0; x < bm.bmWidth; x++) {
Gray = GrayScaleValue(&pImgByte[y * iWidthBytes + x * 4 + 3], &pImgByte[y * iWidthBytes + x * 4 + 2], &pImgByte[y * iWidthBytes + x * 4 + 1]);
pImgByte[y * iWidthBytes + x * 4] = Gray;
pImgByte[y * iWidthBytes + x * 4 + 1] = Gray;
pImgByte[y * iWidthBytes + x * 4 + 2] = Gray;
pImgByte[y * iWidthBytes + x * 4 + 3] = Gray;
}
}
return CreateBitmapIndirect(&bm);
}
这是图片:
嗯,我不知道,为什么他将“透明”设置为黑色...
答案 0 :(得分:0)
HBITMAP可以引用以多种不同格式存储的位图。它可以是DIBSECTION或依赖于设备的位图。其中任何一个都可以以各种方式表示像素值。请注意,GetObject documentation列出了两种获取HBITMAP信息的方法。
我的猜测是你的输入是一个DIBSECTION,扫描线从上到下存储。当您要求BITMAP(使用GetObject)时,您会丢失一些格式信息,特别是图像是自下而上还是自上而下,是否具有Alpha通道以及通道的顺序(例如,BGRA V) 。ARGB)。 BITMAP不能表示与DIBSECTION一样多的格式细节。
操作像素数据后,您将使用CreateBitmapIndirect创建新的位图。由于BITMAP结构不包含有关数据是自下而上还是自上而下的信息,因此它使用默认值,即自下而上。由于您(显然)从自上而下的像素数据开始,您可以有效地颠倒图像。
您在使用Alpha通道时遇到的困难也可以解释为当您尝试使用BITMAP描述格式时丢失了信息。如果颜色通道的顺序与CreateBitmapIndirect假定的默认顺序不同,那么您将看到这个问题。通过将alpha设置为与所有其他通道相同的灰度值,您可以有效地隐藏您已经扰乱了颜色通道顺序的事实。
有几种不同的方法可以解决这个问题。这是一个可能的解决方案:
您可以要求Windows使用GetDIBits为您提供指向您要使用的格式的像素数据的指针,而不管其原生格式如何。然后,您可以让Windows将修改后的像素值转换回使用SetDIBits的位图格式。
您必须填写BITMAPINFO(有几种变体)来描述您期望的内存格式。您将此BITMAPINFO传递给GetDIBits和SetDIBits。
答案 1 :(得分:0)
Adrian McCarthy向我们展示了更好的解决方案,但我需要几天的时间来阅读有关DIB的内容。我需要一个快速的解决方案,并通过再次颠倒位图来获得它。
关于如何将HBITMAP从TrueColor转换为GrayScale的问题经常在互联网上找到并且答案并不令人满意,我现在想要发布我的代码:
#include <stdio.h>
#include <Windows.h>
#include <math.h>
inline BYTE GrayScaleValue(BYTE* r, BYTE* g, BYTE* b) { return /*ceil*/(0.21f * (*r) + 0.72f * (*g) + 0.07f * (*b)); }
extern "C" __declspec(dllexport) HBITMAP ConvertToMonocrom(HBITMAP bmp) {
#pragma region Local variables
INT x = 0, y = 0;
char Gray;
BITMAP bm;
#pragma endregion
#pragma region Activating HBITMAP
GetObject(bmp, sizeof(BITMAP), (LPSTR)&bm);
#pragma endregion
#pragma region Assigning pointer
BYTE * pImgByte = (BYTE *)bm.bmBits;
BYTE* fpImgByte = (BYTE*)malloc(bm.bmHeight * bm.bmWidth * sizeof(BYTE));
if (fpImgByte == nullptr) { printf("ERROR: Unable to allocate memory for buffer array!"); return nullptr; }
INT iWidthBytes = bm.bmWidth * 4;
#pragma endregion
#pragma region TrueColor to GrayScale
for (y = 0; y < bm.bmHeight; y++) {
for (x = 0; x < bm.bmWidth; x++) {
Gray = GrayScaleValue(&pImgByte[y * iWidthBytes + x * 4 + 3], &pImgByte[y * iWidthBytes + x * 4 + 2], &pImgByte[y * iWidthBytes + x * 4 + 1]);
fpImgByte[y * bm.bmWidth + x] = Gray;
}
}
#pragma endregion
#pragma region Flipping bitmap
for (y = 0; y < bm.bmHeight; y++) {
for (x = 0; x < bm.bmWidth; x++) {
Gray = fpImgByte[(bm.bmHeight - y - 1)*bm.bmWidth + x];
pImgByte[y * iWidthBytes + x * 4] = Gray;
pImgByte[y * iWidthBytes + x * 4 + 1] = Gray;
pImgByte[y * iWidthBytes + x * 4 + 2] = Gray;
pImgByte[y * iWidthBytes + x * 4 + 3] = Gray;
}
}
#pragma endregion
#pragma region Releasing memory
free(fpImgByte);
#pragma endregion
#pragma region Returning converted bitmap
return CreateBitmapIndirect(&bm);
#pragma endregion
}
结果:
TrueColor中的屏幕截图:
转换后的屏幕截图: