cv :: resize()失败,并出现访问冲突错误(由< struct in NULL>引起)
This is a followup question from this one,
I'm trying to do a simple resize using opencv which ends up crashing!
This is the example code which the access violation occurs:
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#解决方案中得到的:
This is what I get in my C# solution when debugging :
在以下位置抛出异常:0x00007FF8C8D9AA90(opencv_imgproc310d.dll) 使用dotNet.exe进行分类:0xC0000005:读取访问冲突 位置0x0000018B000F2000.
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(<struct at NULL>
):
When I debug into the opencv code, I can see that sz
is a null struct(<struct at NULL>
) :
template<typename _Tp> inline
Size_<_Tp>::Size_(const Size_& sz)
: width(sz.width), height(sz.height) {}
这显然会导致访问冲突!.
and this clearly causes the access violation!.
这是怎么了?我该怎么办?
What is wrong here and what should I do ?
更新:
更多信息: 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或示例时,将发出访问冲突异常.创建一个简单的黑色图像并将其显示在imshow()中是可以的.
Update :
More information :sample.size()
is as exactly as img.size()
since the last else
clause is executed and thus sample = img
.sample.size() = {width=256 height=378 } cv::Size_<int>
num_channels_
is 3img.channels()
is 3 so is sample.channels()
When I use imshow()
to display either img or sample, the access violation exception is issued. creating a simple black image and displaying it in imshow() is fine though.
由于@Micka在评论中的建议,我发现原因首先是由于发送到preprocess
方法的图像而不是resize
方法本身.
进一步的调试证明了@Micka对C#
侧错误代码的怀疑.
我最初是在C#
端写的:
Thanks to @Micka's suggestions in the comments, I found out the cause was first due to the image that was sent to the preprocess
method and not the resize
method by itself.
Further debugging proved @Micka's suspicion about the faulty code on C#
side.
I was originally wrote in the C#
side :
[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()
来显示图像时,它会使应用程序崩溃并给出访问冲突异常,该错误与调整大小时发生的错误相同,并发布在问题中. .
看着答案,我更改了负责将图像传递到dll
的C#代码.新代码如下:
This proved to be plain wrong, or at the very least buggy. Using this code, the image on the C++
side seemed to have been initialized properly, the number of channels, the height, and width all seemed fine.
But the moment you attempt to use the image, either by resizing it or even showing it using imshow()
, it would crash the application and be giving an access violation exception, the very same error that happened when resizing and is posted in the question.
Looking at this answer, I changed the C# code responsible for handing the image to the dll
. the new code is as follows :
//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 ++代码:
and the C++ code in the DLL :
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();
}
并纠正了我以前遇到的所有访问冲突.
and doing so rectified all access violations I was getting previously.