【问题标题】:Problems with image types for template matching using OpenCV使用 OpenCV 进行模板匹配的图像类型问题
【发布时间】:2021-01-22 17:11:46
【问题描述】:

我在C++ 中使用OpenCV 在屏幕截图和磁盘中的图像之间执行模板匹配。我的屏幕截图似乎类型为CV_8UC4,但我的模板图像类型为CV_8UC3。这会导致matchTemplate 函数得到一个断言错误:

OpenCV(4.3.0) C:\...\opencv4\src\4.3.0-0c6047baf6.clean\modules\imgproc\src\templmatch.cpp:1104: error: (-215:Assertion failed) (depth == CV_8U || depth == CV_32F) && type == _templ.type() && _img.dims() <= 2 in function 'cv::matchTemplate'

为了解决这个问题,我尝试使用 convertTo 函数将两个 cv::Mats 转换为相同的类型:

screen_shot.convertTo(screen_shot, CV_8UC3);
template_image.convertTo(template_image, CV_8UC3);

令人惊讶的是,这“没有”。两个cv::Mats 的类型在调用后都不会被修改。为什么?

另一个尝试是修改屏幕截图创建代码以直接生成类型CV_8UC3。但是,这会使GetDIBits() 函数失败:

bool dump_window_screen_to_opencv_mat(const HWND window_handle, cv::Mat& output_mat)
{
    auto* const h_window_dc = GetDC(window_handle);
    auto* const h_window_compatible_dc = CreateCompatibleDC(h_window_dc);
    if (!h_window_compatible_dc)
    {
        return false;
    }

    if (!SetStretchBltMode(h_window_compatible_dc, COLORONCOLOR))
    {
        DeleteDC(h_window_compatible_dc);
        return false;
    }

    const auto window_resolution = // ...
    const auto loc_window_width = window_resolution.x;
    const auto loc_window_height = window_resolution.y;

    const auto h_bit_map = CreateCompatibleBitmap(h_window_dc, loc_window_width, loc_window_height);
    if (!h_bit_map)
    {
        DeleteDC(h_window_compatible_dc);
        return false;
    }

    BITMAPINFOHEADER bit_map_info_header;
    bit_map_info_header.biSize = sizeof(BITMAPINFOHEADER);
    bit_map_info_header.biWidth = loc_window_width;
    bit_map_info_header.biHeight = -loc_window_height;
    bit_map_info_header.biPlanes = 1;
    bit_map_info_header.biBitCount = 32;
    bit_map_info_header.biCompression = BI_RGB;
    bit_map_info_header.biSizeImage = 0;
    bit_map_info_header.biXPelsPerMeter = 0;
    bit_map_info_header.biYPelsPerMeter = 0;
    bit_map_info_header.biClrUsed = 0;
    bit_map_info_header.biClrImportant = 0;

    if (!SelectObject(h_window_compatible_dc, h_bit_map))
    {
        DeleteObject(h_bit_map);
        DeleteDC(h_window_compatible_dc);
        return false;
    }

    if (!StretchBlt(
        h_window_compatible_dc,
        0, 0,
        loc_window_width, loc_window_height,
        h_window_dc,
        0, 0,
        loc_window_width, loc_window_height,
        SRCCOPY))
    {
        DeleteObject(h_bit_map);
        DeleteDC(h_window_compatible_dc);
        return false;
    }

    output_mat.create(loc_window_height, loc_window_width, CV_8UC4); // <-- Here we can specify the image type

    const auto has_di_bits_succeeded = GetDIBits(
        h_window_dc,
        h_bit_map,
        0,
        loc_window_height,
        output_mat.data,
        reinterpret_cast<BITMAPINFO*>(&bit_map_info_header),
        DIB_RGB_COLORS);
    if (!has_di_bits_succeeded)
    {
        DeleteObject(h_bit_map);
        DeleteDC(h_window_compatible_dc);
        return false;
    }

    DeleteObject(h_bit_map);
    DeleteDC(h_window_compatible_dc);

    return true;
}

知道如何修复此代码以生成正确的图像类型,或者我可以尝试完全不同的方法吗?

opencv.org查看这个相关问题:
https://answers.opencv.org/question/236225

【问题讨论】:

    标签: c++ windows opencv winapi visual-c++


    【解决方案1】:

    rtype(第二个参数)的描述中的cv::Mat::convertTo规范中声明它是

    所需的输出矩阵类型,或者更确切地说,深度因为通道数与输入相同;如果 rtype 为负,则输出矩阵将与输入具有相同的类型。

    我不确定这是否是问题所在,但找不到任何其他解释。

    尝试使用cv::cvtColor 和适当的color code,在您的情况下是cv::COLOR_xxxA2xxx 之一,很可能是cv::COLOR_BGRA2BGR(或cv::COLOR_RGBA2RGB,没关系,因为它们是相等的,只有alpha 通道是删除)。或者如果您想将 Alpha 通道添加到最适合您的其他图像,则反之亦然。我主要使用它来将图像更改为灰度,如下所示:

    cv::Mat img_gray, image = imread(argv[1], cv::IMREAD_UNCHANGED);
    cv::cvtColor(image, img_gray, cv::COLOR_BGR2GRAY);
    

    【讨论】:

      猜你喜欢
      • 2014-12-18
      • 1970-01-01
      • 1970-01-01
      • 2016-03-03
      • 2013-10-27
      • 2011-07-26
      • 1970-01-01
      • 1970-01-01
      • 2016-03-21
      相关资源
      最近更新 更多