如何从 C++ 中的 bmp 中删除绿屏?

How to remove green screen from bmp in c++?

所以我是 Direct2D 和图像处理领域的新手,现在有点不知所措。我有这张绿色背景的图片,我需要加载它。但是在将其显示到屏幕之前必须删除绿色背景(使用 C++ 色度键)。

到目前为止,我已经成功地将 jpg/bmp 文件中的 d2d 位图加载到屏幕上。抱歉,如果这是一个愚蠢的问题,但我在其他地方找不到太多信息。这是我正在尝试处理的图像。

所以我用来加载位图的步骤是,创建 WIC 工厂,创建能够将文件读入 WIC 的解码器,为 WIC 创建转换器并配置它。

最后一步是创建位图。

然后我用 RendetTarget->DrawBitmap() 方法传递适当的参数在屏幕上绘制它。

我现在唯一想不通的是如何去除下图中的绿屏。如果我的问题缺少一些必要的信息,请告诉我。任何帮助将不胜感激。

这是在屏幕上绘制位图的代码

gfx->GetRenderTarget()->DrawBitmap(
    bmp, //Bitmap we built from WIC
    D2D1::RectF(0, 0,
        bmp->GetSize().width, bmp->GetSize().height), 
    0.8f, // opacity
D2D1_BITMAP_INTERPOLATION_MODE::D2D1_BITMAP_INTERPOLATION_MODE_NEAREST_NEIGHBOR,

    D2D1::RectF(0, 0, bmp->GetSize().width, bmp->GetSize().height) //Source Rect
    );

这是我的可执行文件 (window) 的屏幕截图以及目前为止的内容。 Main Window

这是加载位图的代码

this->gfx = gfx;
bmp = NULL; 
HRESULT hr;


IWICImagingFactory *wicFactory = NULL;

hr = CoCreateInstance(
    CLSID_WICImagingFactory,
    NULL, 
    CLSCTX_INPROC_SERVER,
    IID_IWICImagingFactory, 

    (LPVOID*)&wicFactory); // pointer to the WICFactory

// decoder
IWICBitmapDecoder *wicDecoder = NULL;
hr = wicFactory->CreateDecoderFromFilename(
    filename, // filename passed as parameter
    NULL, 
    GENERIC_READ, 
    WICDecodeMetadataCacheOnLoad, 
    &wicDecoder); // pointer to the Decoder 


IWICBitmapFrameDecode* wicFrame = NULL;
hr = wicDecoder->GetFrame(0, &wicFrame); 


// create wic converter
IWICFormatConverter *wicConverter = NULL;

hr = wicFactory->CreateFormatConverter(&wicConverter);


hr = wicConverter->Initialize(
    wicFrame, 
    GUID_WICPixelFormat32bppPBGRA, 
    WICBitmapDitherTypeNone, 
    NULL, 
    0.0, 
    WICBitmapPaletteTypeCustom 
    );


// create bitmap
gfx->GetRenderTarget()->CreateBitmapFromWicBitmap(
    wicConverter, 
    NULL, 
    &bmp // destination bmp defined in header
);

此代码将在其上绘制一个背景和具有透明度的精灵。您所要做的就是加载一个透明的 png 文件。使用图像编辑器将位图转换为 png。这需要 Visual Studio Atl COM 类 CComPtr,但没有它你也可以做到。

#include <Windows.h>
#include <atlbase.h>
#include <d2d1.h>
#include <Wincodec.h>

HRESULT load_image(ID2D1HwndRenderTarget *target, 
    const wchar_t *filename, ID2D1Bitmap** bitmap)
{
    HRESULT hr = S_FALSE;
    CComPtr<IWICImagingFactory> factory;
    CComPtr<IWICBitmapDecoder> decoder;
    CComPtr<IWICBitmapFrameDecode> frame;
    CComPtr<IWICFormatConverter> converter;

    hr = CoCreateInstance(CLSID_WICImagingFactory, 
        NULL, CLSCTX_INPROC_SERVER, IID_IWICImagingFactory, (void**)&factory);
    if (FAILED(hr)) return hr;

    hr = factory->CreateDecoderFromFilename(filename, NULL, 
        GENERIC_READ, WICDecodeMetadataCacheOnLoad, &decoder);
    if(FAILED(hr)) return hr;

    hr = decoder->GetFrame(0, &frame);
    if(FAILED(hr)) return hr;

    hr = factory->CreateFormatConverter(&converter);
    if(FAILED(hr)) return hr;

    hr = converter->Initialize(frame, GUID_WICPixelFormat32bppPBGRA, 
        WICBitmapDitherTypeNone, NULL, 0.f, WICBitmapPaletteTypeMedianCut);
    if(FAILED(hr)) return hr;

    hr = target->CreateBitmapFromWicBitmap(converter, 0, bitmap);
    return hr;
}

void on_render(ID2D1HwndRenderTarget *render)
{
    render->BeginDraw();
    render->Clear(D2D1::ColorF(D2D1::ColorF::White));

    CComPtr<ID2D1Bitmap> background;
    if SUCCEEDED(load_image(render, L"c:\background.jpg", &background))
    {
        D2D1_SIZE_F size = background->GetSize();
        render->DrawBitmap(background, D2D1::RectF(0, 0, size.width, size.height));
    }

    CComPtr<ID2D1Bitmap> sprite;
    if SUCCEEDED(load_image(render, L"c:\transparent.png", &sprite))
    {
        D2D1_SIZE_F size = sprite->GetSize();
        render->DrawBitmap(sprite, D2D1::RectF(0, 0, size.width, size.height));
    }

    render->EndDraw();
}

TransparentBlt 是一个 GDI 函数,只能处理单一透明度。如果您打算使用 GDI 函数,那么也许您不需要 Direct2D 的复杂性!或者你可以使用 GDI+

if(msg == WM_PAINT)
{
    PAINTSTRUCT ps;
    HDC hdc = BeginPaint(hwnd, &ps);
    auto hbitmap = LoadImage(NULL, L"test.bmp", IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE);
    auto memdc = CreateCompatibleDC(hdc);
    auto oldbmp = SelectObject(memdc, hbitmap);

    BITMAP bm;
    GetObject(hbitmap, sizeof(bm), &bm);
    int w = bm.bmWidth;
    int h = bm.bmHeight;
    TransparentBlt(hdc, 0, 0, w, h, memdc, 0, 0, w, h, RGB(0, 255, 0));

    SelectObject(memdc, oldbmp);
    DeleteDC(memdc);
    DeleteObject(hbitmap);//<- edit
    EndPaint(hwnd, &ps);
    return 0;
}