c++ - cv::resize() 因访问冲突错误而失败(由 <struct at NULL> 引起)

标签 c++ opencv

这是 this one 的后续问题,
我正在尝试使用 opencv 进行简单的调整大小,但最终崩溃了!
这是发生访问冲突的示例代码:

void Classifier::Preprocess(const cv::Mat& img, std::vector<cv::Mat>* input_channels)
{
    /* Convert the input image to the input image format of the network. */
    cv::Mat sample;
    if (img.channels() == 3 && num_channels_ == 1)
        cv::cvtColor(img, sample, cv::COLOR_BGR2GRAY);
    else if (img.channels() == 4 && num_channels_ == 1)
        cv::cvtColor(img, sample, cv::COLOR_BGRA2GRAY);
    else if (img.channels() == 4 && num_channels_ == 3)
        cv::cvtColor(img, sample, cv::COLOR_BGRA2BGR);
    else if (img.channels() == 1 && num_channels_ == 3)
        cv::cvtColor(img, sample, cv::COLOR_GRAY2BGR);
    else
        sample = img;

    //resize image according to the input
    cv::Mat sample_resized;
    Size size(input_geometry_.width,input_geometry_.height );

    if (sample.size() != input_geometry_)
        cv::resize(sample, sample_resized, size);
    else
        sample_resized = sample;

    //...
}

这是我在调试时在 C# 解决方案中得到的:

Exception thrown at 0x00007FF8C8D9AA90 (opencv_imgproc310d.dll) in Classification Using dotNet.exe: 0xC0000005: Access violation reading location 0x0000018B000F2000.

If there is a handler for this exception, the program may be safely continued.

当我调试 opencv 代码时,我可以看到 sz 是一个空结构(<struct at NULL>):

template<typename _Tp> inline
Size_<_Tp>::Size_(const Size_& sz)
    : width(sz.width), height(sz.height) {}

这显然会导致访问冲突!

这里出了什么问题,我该怎么办?

更新:
更多信息:
sample.size()img.size() 一样,因为最后一个 else 子句被执行,因此 sample = img
sample.size() = {width=256 height=378 } cv::Size_<int>
num_channels_ 为 3
img.channels() 是 3 所以 sample.channels()
当我使用 imshow() 显示 img 或 sample 时,会发出访问冲突异常。创建一个简单的黑色图像并在 imshow() 中显示它是可以的。

最佳答案

感谢@Micka 在评论中的建议,我发现原因首先是由于发送到 preprocess 方法而不是 resize 方法的图像本身。
进一步的调试证实了@Micka 对C# 端错误代码的怀疑。 我原来是在C#这边写的:

[DllImport(@"CDll2.dll", CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi)]
static extern void Classify_image(byte[] img, uint height, uint width, byte[] out_result, out int out_result_length, int top_n_results = 2);

private string Classify(Bitmap img, int top_n_results)
{
    byte[] result = new byte[200];
    int len;
    var img_byte = (byte[])(new ImageConverter()).ConvertTo(img, typeof(byte[]));

    Classify_image(img_byte, (uint)img.Height, (uint)img.Width,res, out len, top_n_results);

    return  ASCIIEncoding.ASCII.GetString(result);
}

这是 dll 部分的代码:

CDLL2_API void Classify_image(unsigned char* img_pointer, unsigned int height, unsigned int width, char* out_result, int* length_of_out_result, int top_n_results)
    {
        auto classifier = reinterpret_cast<Classifier*>(GetHandle());
        cv::Mat img = cv::Mat(height, width, CV_32FC3, (void*)img_pointer);

        std::vector<Prediction> result = classifier->Classify(img, top_n_results);

        //misc code...
        *length_of_out_result = ss.str().length();
    }

这被证明是完全错误的,或者至少是错误的。使用此代码,C++ 端的图像似乎已正确初始化, channel 数、高度和宽度似乎都正常。
但是当您尝试使用图像时,无论是通过调整图像大小还是使用 imshow() 显示图像,它都会使应用程序崩溃并给出访问冲突异常,这与调整大小并张贴在问题中。
看着这个answer ,我更改了负责将图像传递给 dll 的 C# 代码。新代码如下:

//Dll import 
[DllImport(@"CDll2.dll", CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi)]
static extern void Classify_Image(IntPtr img, uint height, uint width, int step, byte[] out_result, out int out_result_length, int top_n_results = 2);

//...
//main code 

Bitmap img = new Bitmap(txtImagePath.Text);
BitmapData bmpData = img.LockBits(new Rectangle(0, 0, img.Width, img.Height),  ImageLockMode.ReadWrite,  img.PixelFormat);
result = Classify_Image(bmpData.Scan0, (uint)bmpData.Height, (uint)bmpData.Width, bmpData.Stride, res, out len, top_n_results);
img.UnlockBits(bmpData); //Remember to unlock!!!

和 DLL 中的 C++ 代码:

CDLL2_API void Classify_Image(unsigned char* img_pointer, unsigned int height, unsigned int width, int step, char* out_result, int* length_of_out_result, int top_n_results)
    {
        auto classifier = reinterpret_cast<Classifier*>(GetHandle());

        cv::Mat img = cv::Mat(height, width, CV_8UC3, (void*)img_pointer, step);

        std::vector<Prediction> result = classifier->Classify(img, top_n_results);

        //...
        *length_of_out_result = ss.str().length();
    }

这样做纠正了我之前遇到的所有访问冲突。

关于c++ - cv::resize() 因访问冲突错误而失败(由 <struct at NULL> 引起),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/45706018/

相关文章:

c++ - 将派生类 unique_ptr 的所有权转移到其抽象基类 unique_ptr

OpenCV Transformationmatrix : affine vs. 透视变形

opencv - 无法向 opencv 添加额外模块(opencv_contrib)

OpenCV 默认存储格式

c++ - 用 node::Buffer 包装现有内存

c++ - 计时器精度 : c clock( ) vs. WinAPI 的 QPC 或 timeGetTime( )

python-3.x - 查找图像中圆的质心和颜色值

c++ - 从 OpenCV Mat 中获取值(value)

c++ - 具有坐标、法线和颜色的交错 VBO

c++ - 在有向图中通过 bfs 搜索显示最短路径