将 PNG 类型资源转换为 cv::Mat 时,CreateDIBSection ERROR_TAG_NOT_FOUND

问题描述 投票:0回答:2

我目前正在使用here找到的以下代码的修改版本来尝试将项目中的.png资源转换为HBITMAP,然后转换为cv::Map。

cv::Mat Resource2mat(const HMODULE hModule, const LPCSTR lpPNGName) {
    cv::Mat src;
    HRSRC found = FindResource(hModule, lpPNGName, "PNG");
    unsigned int size = SizeofResource(hModule, found);
    HGLOBAL loaded = LoadResource(hModule, found);
    void* resource_data = LockResource(loaded);

    /* Now we decode the PNG */
    vector<unsigned char> raw;
    unsigned long width, height;
    int err = decodePNG(raw, width, height, (const unsigned char*)resource_data, size);
    if (err != 0)
    {
        cout<<"\nError while decoding png splash: "<< err <<endl;
        return src;
    }

    // copy from the window device context to the bitmap device context
    BITMAPV5HEADER bmpheader = { 0 };
    bmpheader.bV5Size = sizeof(BITMAPV5HEADER);
    bmpheader.bV5Width = width;
    bmpheader.bV5Height = height;
    bmpheader.bV5Planes = 1;
    bmpheader.bV5BitCount = 32;
    bmpheader.bV5Compression = BI_BITFIELDS;
    bmpheader.bV5SizeImage = width * height * 4;
    bmpheader.bV5RedMask = 0x00FF0000;
    bmpheader.bV5GreenMask = 0x0000FF00;
    bmpheader.bV5BlueMask = 0x000000FF;
    bmpheader.bV5AlphaMask = 0xFF000000;
    bmpheader.bV5CSType = LCS_WINDOWS_COLOR_SPACE;
    bmpheader.bV5Intent = LCS_GM_BUSINESS;
    void* converted = NULL;
    HDC screen = GetDC(NULL);
    HBITMAP result = CreateDIBSection(screen, reinterpret_cast<BITMAPINFO*>(&bmpheader), DIB_RGB_COLORS, &converted, NULL, 0);
    cout << "Error Final: " << GetLastError() << endl;

    /* Copy the decoded image into the bitmap in the correct order */
    for (unsigned int y1 = height - 1, y2 = 0; y2 < height; y1--, y2++)
        for (unsigned int x = 0; x < width; x++)
        {
            *((char*)converted + 0 + 4 * x + 4 * width*y2) = raw[2 + 4 * x + 4 * width*y1]; // Blue
            *((char*)converted + 1 + 4 * x + 4 * width*y2) = raw[1 + 4 * x + 4 * width*y1]; // Green
            *((char*)converted + 2 + 4 * x + 4 * width*y2) = raw[0 + 4 * x + 4 * width*y1]; // Red
            *((char*)converted + 3 + 4 * x + 4 * width*y2) = raw[3 + 4 * x + 4 * width*y1]; // Alpha
        }

    GetDIBits(screen, result, 0, height, src.data, (BITMAPINFO *)&bmpheader, DIB_RGB_COLORS);

    cv::Mat Actual = src.clone();

    ReleaseDC(NULL, screen);
    /* Done! */
    return Actual;
}

我的 .rc 文件如下所示:

resources.h 条目如下所示


当运行代码并点击这一行时,我最终遇到了 2012 ( ERROR_TAG_NOT_FOUND ) 错误

HBITMAP result = CreateDIBSection(screen, reinterpret_cast<BITMAPINFO*>(&bmpheader), DIB_RGB_COLORS, &converted, NULL, 0);

通过在这行代码前后调用GetLastError()找到了它


这就是我在 int main() 中调用这个函数的方式:

HINSTANCE BotModuleHandle = GetModuleHandle(NULL);

cout << "Attempting to load a resource: " << endl;

cv::Mat S = Resource2mat(BotModuleHandle, MAKEINTRESOURCE(103));

提前致谢。

此外,任何有关将 PNG 资源转换为 cv::Mat 的更好方法的建议都非常感谢

c++ opencv bitmap png
2个回答
1
投票

如果您真正希望实现的是将资源图像加载到

cv::Mat
中,那么您可以使用更短的函数来完成:

cv::Mat Resource2mat(const HMODULE hModule, const LPCSTR lpPNGName)
{
    HRSRC found = FindResource(hModule, lpPNGName, "PNG");
    unsigned int size = SizeofResource(hModule, found);
    HGLOBAL loaded = LoadResource(hModule, found);
    void* resource_data = LockResource(loaded);

    return cv::imdecode(cv::_InputArray(static_cast<uchar*>(resource_data), size)
        , cv::IMREAD_UNCHANGED);
}

LockResource
为您提供一个指向包含 PNG 编码图像的缓冲区(字节数组)的指针(就好像您刚刚将 PNG 文件的内容读入数组一样)。
SizeofResource
给出该数组的大小(以字节为单位)。

OpenCV 提供了函数

cv::imdecode
,它可以从内存缓冲区中解码 PNG(和其他格式)图像。这里有一个小问题——我们需要在一个参数中传递指针和大小。为此,我们可以显式构造一个临时的
cv::_InputArray


整个测试程序:

#include <windows.h>
#include "resource.h"

#include <opencv2/opencv.hpp>


cv::Mat Resource2mat(const HMODULE hModule, const LPCSTR lpPNGName)
{
    HRSRC found = FindResource(hModule, lpPNGName, "PNG");
    CV_Assert(found);
    unsigned int size = SizeofResource(hModule, found);
    CV_Assert(size);
    HGLOBAL loaded = LoadResource(hModule, found);
    CV_Assert(size);
    void* resource_data = LockResource(loaded);
    CV_Assert(resource_data);

    return cv::imdecode(cv::_InputArray(static_cast<uchar*>(resource_data), size)
        , cv::IMREAD_UNCHANGED);
}

int main()
{
    HINSTANCE hModule = GetModuleHandle(NULL);
    cv::Mat image(Resource2mat(hModule, MAKEINTRESOURCE(IDB_PNG1)));
    cv::imshow("Resource image", image);
    cv::waitKey();

    return 0;
}

资源标题

resource.h
:

#define IDB_PNG1                        101

资源文件

pngres.rc
:

#include "resource.h"
#include "winres.h"

LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US
IDB_PNG1                PNG                     "resource.png"

运行此命令会给我一个正确显示图像的窗口:


0
投票

这在 Opencv c++ 应用程序中为我工作,我对代码进行了一些更改,因为它给出了错误:参数 const char* 与 LPCWSTR 不兼容。

#include <windows.h>
#include "resource.h"

#include <opencv2/opencv.hpp>
cv::Mat Resource2mat(const HMODULE hModule, const LPCWSTR lpPNGName)
{
  HRSRC found = FindResource(hModule, lpPNGName, L"PNG");
  CV_Assert(found);
  unsigned int size = SizeofResource(hModule, found);
  CV_Assert(size);
  HGLOBAL loaded = LoadResource(hModule, found);
  CV_Assert(size);
  void* resource_data = LockResource(loaded);
  CV_Assert(resource_data);

  return cv::imdecode(cv::_InputArray(static_cast<uchar*>(resource_data), size)
 , cv::IMREAD_COLOR);
}
int main()
{
  HINSTANCE hModule = GetModuleHandle(NULL);
  cv::Mat image(Resource2mat(hModule, MAKEINTRESOURCE(IDB_PNG1)));
  cv::imshow("Resource image", image);
  cv::waitKey();

 return 0;
}
© www.soinside.com 2019 - 2024. All rights reserved.