1

我正在从我的 C# 代码动态加载 C++ 库。我想在大图像中找到小图像,将大图像转换为byte[]从物理路径读取的小图像。
当我打电话时,imdecodethenlarge_img总是返回0 colsand rows

C#

[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
private delegate ImageParams GetImageParams(IntPtr dataPtr, int size, string path);

// ...

byte[] largeImgByteArr = this.BitmapToByteArray(bmp);
IntPtr dataPtr = Marshal.AllocHGlobal(largeImgByteArr.Length);
Marshal.Copy(dataPtr, largeImgByteArr, 0, largeImgByteArr.Length);

C++

ImageParams GetImageParams(BYTE* largeImgBuf, int bufLength, const char* smallImgPath)
{
    Mat large_img_data(bufLength, 1, CV_32FC1, largeImgBuf);

    Mat large_img = imdecode(large_img_data, IMREAD_COLOR);
    Mat small_img = imread(smallImgPath, IMREAD_COLOR);

    int result_cols = large_img.cols - small_img.cols + 1;
    int result_rows = large_img.rows - small_img.rows + 1;

    Mat result;
    result.create(result_cols, result_rows, CV_32FC1);

    matchTemplate(large_img, small_img, result, CV_TM_SQDIFF_NORMED);
    normalize(result, result, 0, 1, NORM_MINMAX, -1, Mat());
}

我在这里做错了什么?
注意:我已检查图像路径是否正确且字节数组不为空。

编辑 1

我通过提供大图像稍微更改了我的代码,width并且height还摆脱imdecode并更改了类似这篇文章的内容。

ImageParams GetImageParams(BYTE* largeImgBuf, int height, int width, int bufLength, const char* smallImgPath)
{  
    // Mat large_img = imdecode(large_img_data, IMREAD_COLOR);
    Mat large_img = Mat(height, width, CV_8UC3, largeImgBuf);
    Mat small_img = imread(templPath, 1);

    /// ...
}

现在它返回行和列,但是在调用matchTemplate方法时会抛出异常:

在此处输入图像描述

4

2 回答 2

2

请记住,C# 中的位图结构使用数据填充(步幅值为 4),而 OpenCV 可能不会。尝试直接从字节数组创建 Mat 对象,但调整步长(步幅)值,因为它只是分配数据而没有任何所有权或重新分配。

编辑

这是一个如何从位图创建 OpenCV Mat 对象的示例。位图中的数据不会被复制,而只会被分配。PixelFormat 和 OpenCV mat 类型必须具有相应的单个元素大小(以字节为单位)。

cv::Mat ImageBridge::cvimage(System::Drawing::Bitmap^ bitmap){
    if(bitmap != nullptr){
        switch(bitmap->PixelFormat){
        case System::Drawing::Imaging::PixelFormat::Format24bppRgb:
            return bmp2mat(bitmap, CV_8UC3);
        case System::Drawing::Imaging::PixelFormat::Format8bppIndexed:
            return bmp2mat(bitmap, CV_8U);
        default: return cv::Mat();
        }
    }
    else
        return cv::Mat();
}


cv::Mat ImageBridge::bmp2mat(System::Drawing::Bitmap^ bitmap, int image_type){
    auto bitmap_data = bitmap->LockBits(
        System::Drawing::Rectangle(0, 0, bitmap->Width, bitmap->Height),
        System::Drawing::Imaging::ImageLockMode::ReadWrite,
        bitmap->PixelFormat);

    char* bmpptr = (char*)bitmap_data->Scan0.ToPointer();

    cv::Mat image(
        cv::Size(bitmap->Width, bitmap->Height),
        image_type,
        bmpptr,
        bitmap_data->Stride);

    bitmap->UnlockBits(bitmap_data);
    return image;
}

编辑 2

反向转换 - 这次来自 Mat 图像的数据被复制为 Bitmap 分配它自己的内存。

System::Drawing::Bitmap^ ImageBridge::bitmap(cv::Mat& image){
    if(!image.empty() && image.type() == CV_8UC3)
        return mat2bmp(image, System::Drawing::Imaging::PixelFormat::Format24bppRgb);
    else if(!image.empty() && image.type() == CV_8U)
        return mat2bmp(image, System::Drawing::Imaging::PixelFormat::Format8bppIndexed);
    else
        return nullptr;
}

System::Drawing::Bitmap^ ImageBridge::mat2bmp(cv::Mat& image, System::Drawing::Imaging::PixelFormat pixel_format){
    if(image.empty())
        return nullptr;

    System::Drawing::Bitmap^ bitmap = gcnew System::Drawing::Bitmap(image.cols, image.rows, pixel_format);

    auto bitmap_data = bitmap->LockBits(
        System::Drawing::Rectangle(0, 0, bitmap->Width, bitmap->Height),
        System::Drawing::Imaging::ImageLockMode::ReadWrite,
        pixel_format);

    char* bmpptr = (char*)bitmap_data->Scan0.ToPointer();
    int line_length = (int)image.step;
    int bmp_stride = bitmap_data->Stride;

    assert(!image.isSubmatrix());
    assert(bmp_stride >= 0);
    for(int l = 0; l < image.rows; l++){
        char* cvptr = (char*)image.ptr(l);
        int bmp_line_index = l * bmp_stride;

        for(int i = 0; i < line_length; ++i)
            bmpptr[bmp_line_index + i] = cvptr[i];
    }

    bitmap->UnlockBits(bitmap_data);

    return bitmap;
}

或者,如果您的 Mat 图像步长为 4,您可以使用非复制版本。

System::Drawing::Bitmap^ ImageBridge::bitmap2(cv::Mat& image){   
    System::Drawing::Bitmap^ bitmap;
    assert(!image.isSubmatrix());
    if(!image.empty() && image.type() == CV_8UC3){
        bitmap = gcnew System::Drawing::Bitmap(
            image.cols, image.rows,
            3 * image.cols,
            System::Drawing::Imaging::PixelFormat::Format24bppRgb,
            System::IntPtr(image.data));
    }
    else if(!image.empty() && image.type() == CV_8U){
        bitmap = gcnew System::Drawing::Bitmap(
            image.cols, image.rows,
            image.cols,
            System::Drawing::Imaging::PixelFormat::Format8bppIndexed,
            System::IntPtr(image.data));
    }
    return bitmap;
}
于 2016-08-22T10:09:47.300 回答
0

根据文档

该函数从内存中的指定缓冲区读取图像。如果缓冲区太短或包含无效数据,则返回空矩阵/图像。

尝试检查imdecode零件后的错误代码

#include <errno.h>

cout << errno;
于 2016-08-21T14:22:32.113 回答