【问题标题】:How to remove green screen from bmp in c++?如何在c ++中从bmp中删除绿屏?
【发布时间】:2018-02-14 00:38:02
【问题描述】:

所以我是 Direct2D 和图像处理世界的新手,现在有点迷路了。我有这张绿色背景的图片,我需要加载。但是在将其显示到屏幕之前必须删除绿色背景(使用 c++ 色度键)。

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

所以我用来加载位图的步骤是,创建 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
    );

这是我的可执行文件(窗口)的屏幕截图以及我目前所做的。 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
);

【问题讨论】:

  • 换句话说,它似乎表明那里什么都没有,因为你没有放任何东西。
  • 您希望看到什么而不是绿色?分析该问题的答案,一切都会揭晓。
  • 我们需要查看更多代码。此 Direct2D 呈现目标是直接在您的顶级窗口上还是在子窗口上?
  • 您可以使绿色部分透明,但图像看起来不会很好。那个圆有一个光滑的圆周,这是由于抗锯齿。你仍然会看到一个微弱的绿色圆周。请改用具有多层透明度的 PNG 图像。我投票结束,因为您没有显示相关代码。

标签: c++ winapi image-processing direct2d


【解决方案1】:

此代码将在其上绘制具有透明度的背景和精灵。您所要做的就是加载具有透明度的 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;
}

【讨论】:

  • 非常感谢@BarkmakShemirani,这段代码帮了很多忙。 :)
  • 不客气。我在第二部分有错误,应该是DeleteObject(hbitmap),如编辑所示
猜你喜欢
  • 2019-01-14
  • 1970-01-01
  • 2017-03-11
  • 2019-02-10
  • 2019-04-30
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多