cv :: resize()因访问冲突错误而失败(由<struct at =“”null =“”>引起)

时间:2017-08-16 05:56:16

标签: 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#解决方案中得到的结果:

  

在0x00007FF8C8D9AA90(opencv_imgproc310d.dll)中抛出异常   使用dotNet.exe进行分类:0xC0000005:访问冲突读取   location 0x0000018B000F2000。

     

如果存在此异常的处理程序,则程序可能是安全的   继续进行。

当我调试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 = imgsample.size() = {width=256 height=378 } cv::Size_<int>num_channels_
img.channels()是3 sample.channels()为3 imshow() 当我使用<?xml version="1.0" encoding="UTF-8"?> <proxy name="sla_proxy_svc_vo2" startOnLoad="true" trace="disable" transports="http https" xmlns="http://ws.apache.org/ns/synapse"> <target> <inSequence> <log level="custom"> <property name="msg" value="*****INITIATING*****" /> </log> <payloadFactory media-type="xml"> <format> <soapenv:Envelope xmlns:echo="http://echo.services.core.carbon.wso2.org" xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/"> <soapenv:Body> <nstxt:text xmlns:nstxt="http://ws.apache.org/commons/ns/payload">grant_type=client_credentials&amp;client_id=G6Dk_3ZdrXOfPiuctufVq6GfTWoa&amp;client_secret=jxA8NTkEClE5xGUvGvvhVTDyXM4a</nstxt:text> </soapenv:Body> </soapenv:Envelope> </format> <args /> </payloadFactory> <log level="custom"> <property name="msg" value="*****BEFORE TOKEN SERVICE CALL*****" /> </log> <log level="full" /> <property name="HTTP_METHOD" scope="axis2" type="STRING" value="POST" /> <property name="messageType" scope="axis2" type="STRING" value="text/plain" /> <property name="ContentType" scope="axis2" type="STRING" value="text/plain" /> <property name="Accept" scope="axis2" type="STRING" value="application/json" /> <send> <endpoint> <http format="rest" method="post" trace="disable" uri-template="http://10.236.70.9:8281/token" /> </endpoint> </send> </inSequence> <outSequence> <log level="custom"> <property name="msg" value="******OUT SEQUENCE*******" /> </log> <log level="full" /> <send /> </outSequence> <faultSequence /> </target> </proxy> 显示img或sample时,会发出访问冲突异常。创建一个简单的黑色图像并在imshow()中显示它是好的。

1 个答案:

答案 0 :(得分:2)

感谢@ 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++侧的图像似乎已正确初始化,通道数,高度和宽度似乎都很好。
但是,当您尝试使用图像时,无论是通过调整图像还是使用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();
    }

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