1

我写了一个小函数来将 ARGB 中的位图转换为灰度。转换本身效果很好,但结果是颠倒的。我找不到错误。

代码:#include #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);
}

这是图片:

基本图

转换后的图片,没有设置A--只有RGB: 不设置 Alpha-Value 的转换

转换后的图片,如代码所示(设置Alpha-Value: 通过设置 Alpha-Value 进行转换

嗯,我不知道,为什么他将“透明”设置为黑色......

4

2 回答 2

0

HBITMAP 可以引用以多种不同格式存储的位图。它可以是 DIBSECTION 或设备相关位图。其中任何一个都可以以多种方式表示像素值。请注意,GetObject 文档列出了两种不同的方式来获取有关 HBITMAP 的信息。

我的猜测是您的输入是一个 DIBSECTION,扫描线从上到下存储。当您请求 BITMAP(使用 GetObject)时,您会丢失一些格式信息,特别是图像是自下而上还是自上而下、是否具有 Alpha 通道以及通道的顺序(例如,BGRA V .ARGB)。BITMAP 不能像 DIBSECTION 那样表示格式细节。

处理像素数据后,您将使用 CreateBitmapIndirect 创建一个新位图。由于 BITMAP 结构不包含有关数据是自下而上还是自上而下的信息,因此它使用默认值,即自下而上。由于您(显然)从自上而下的像素数据开始,您已经有效地将图像颠倒过来。

您使用 alpha 通道的困难也可以通过以下事实来解释:当您尝试仅使用 BITMAP 描述格式时丢失了信息。如果颜色通道的顺序与 CreateBitmapIndirect 假定的默认顺序不同,那么您会看到这个问题。通过将 alpha 设置为与所有其他通道相同的灰度值,您有效地隐藏了您打乱了颜色通道顺序的事实。

一个办法

有几种不同的方法可以解决这个问题。这是一种可能的解决方案:

您可以使用 GetDIBits 让 Windows 为您提供指向您想要使用的格式的像素数据的指针,而不管其本机格式如何。然后,您可以让 Windows 使用 SetDIBits 将修改后的像素值转换回位图格式。

您必须填写 BITMAPINFO(有多种变体)来描述您期望的内存格式。您可以将此 BITMAPINFO 传递给 GetDIBits 和 SetDIBits。

于 2017-09-08T18:33:28.210 回答
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
}

结果:

真彩色屏幕截图:

真彩色屏幕截图

转换后的截图:

在此处输入图像描述

于 2017-09-09T10:54:37.620 回答