1 在窗口HWND上显示CImage透明图片

在之前发表的文章:OpenCV – cv::Mat转换为CImage,支持透明通道图片转换 中我介绍了如何将OpenCV的cv::Mat转换为MFC的CImage结构,其中包含了带透明通道的cv::Mat转换为CImage的方法。本文将紧接上文,介绍如何将带alpha透明通道的CImage绘制到HWND上进行显示。

1.1 显示不带alpha透明通道的CImage

一般的,如果我们要将一个普通图片CImage显示到HWND上,一般会使用以下代码

bool RenderCvMatToHWnd::RenderMatToHWND(HWND hwnd, cv::Mat& frame)
{
    if (frame.empty())
        return false;

    // 获取HWND的DC
    HDC hDC = GetDC(hwnd);

    // 获取HWND宽高
    CRect rect;
    GetClientRect(hwnd, rect);
    int hwnd_width = rect.right - rect.left;
    int hwnd_height = rect.bottom - rect.top;

    // 获取合适尺寸的Mat
    cv::Mat fit_mat;
    bool res = GetFitMat(frame, fit_mat, hwnd_width, hwnd_height);

    if (!res)
        return false;

    // 转换为CImage
    CImage dst_cimage;
    res = ConvertMat2CImage(fit_mat, dst_cimage);
    if (!res)
        return false;

    // 显示到HWND上
    int offsetx = (hwnd_width - fit_mat.cols) / 2;           //调整偏移量  
    int offsety = (hwnd_height - fit_mat.rows) / 2;

    res = dst_cimage.Draw(hDC, offsetx, offsety, dst_cimage.GetWidth(), dst_cimage.GetHeight());  //图像显示

    ReleaseDC(hwnd, hDC);

    return true;
}

1.2 显示带alpha透明通道的CImage

但是如果CImage带alpha透明通道,我们需要进行以下转换才能正常显示,代码如下

    if (dst_cimage.GetBPP() == 32)
    {
        for (int i = 0; i < dst_cimage.GetWidth(); ++i)
        {
            for (int j = 0; j < dst_cimage.GetHeight(); ++j)
            {
                byte* pByte = (byte*)dst_cimage.GetPixelAddress(i, j);
                pByte[0] = pByte[0] * pByte[3] / 255;
                pByte[1] = pByte[1] * pByte[3] / 255;
                pByte[2] = pByte[2] * pByte[3] / 255;
            }
        }
    }

结合上述代码,完整的将带alpha透明通道的CImage显示到HWND的代码为

bool RenderCvMatToHWnd::RenderMatToHWND(HWND hwnd, cv::Mat& frame)
{
    if (frame.empty())
        return false;

    // 获取HWND的DC
    HDC hDC = GetDC(hwnd);

    // 获取HWND宽高
    CRect rect;
    GetClientRect(hwnd, rect);
    int hwnd_width = rect.right - rect.left;
    int hwnd_height = rect.bottom - rect.top;

    // 获取合适尺寸的Mat
    cv::Mat fit_mat;
    bool res = GetFitMat(frame, fit_mat, hwnd_width, hwnd_height);

    if (!res)
        return false;

    // 转换为CImage
    CImage dst_cimage;
    res = ConvertMat2CImage(fit_mat, dst_cimage);
    if (!res)
        return false;

    // 如果是透明通道图像则处理,显示透明图片
    if (dst_cimage.GetBPP() == 32)
    {
        for (int i = 0; i < dst_cimage.GetWidth(); ++i)
        {
            for (int j = 0; j < dst_cimage.GetHeight(); ++j)
            {
                byte* pByte = (byte*)dst_cimage.GetPixelAddress(i, j);
                pByte[0] = pByte[0] * pByte[3] / 255;
                pByte[1] = pByte[1] * pByte[3] / 255;
                pByte[2] = pByte[2] * pByte[3] / 255;
            }
        }
    }

    // 显示到HWND上
    int offsetx = (hwnd_width - fit_mat.cols) / 2;           //调整偏移量  
    int offsety = (hwnd_height - fit_mat.rows) / 2;

    res = dst_cimage.Draw(hDC, offsetx, offsety, dst_cimage.GetWidth(), dst_cimage.GetHeight());  //图像显示

    ReleaseDC(hwnd, hDC);

    return true;
}

通过上述代码可以将不带alpha透明通道的普通CImage和带alpha透明通道的CImage都可以显示到指定的HWND上。

参考