找了两个小时的问题,记录一下, 在ROS下usb_cam节点下添加了新的去畸变函数,并将其发布成topic,但是在实际运行的时候,有时候会出现段错误,debug模式提示如下:
__memcpy_avx_unaligned () at ../sysdeps/x86_64/multiarch/memcpy-avx-unaligned.S:238
可以定位到我代码中的memcpy()函数, 其实是ROS下的sensor_msgs::fillmage()的
memcpy(&image.data[0], data_arg, st0);
用gdb调试了解到,这里是将data_arg中的内容拷贝到image.data中时,出现data_arg这块内存无法访问, 而data_arg其实是一个cv::Mat的data;
由此定位到了这段函数:
void UsbCam::undistort_image()
{
cv::Mat ori_img,dst_img;
int img_size;
if(monochrome_){
ori_img=cv::Mat(image_->height,image_->width,CV_8UC1,image_->image);
img_size = image_->width*image_->height;
}else
{
ori_img=cv::Mat(image_->height,image_->width,CV_8UC3,image_->image);
img_size = image_->width*image_->height*3;
}
cv::remap(ori_img,dst_img,mat_mapx,mat_mapy,cv::INTER_LINEAR);
undistort_image_->width = dst_img.cols;
undistort_image_->height = dst_img.rows;
undistort_image_->image = reinterpret_cast<char*>(dst_img.data);
if(dst_img.empty())
ROS_INFO_STREAM("dst_img is empty ");
}
上面的函数定义了 ori_img 和 dst_img两个cv::Mat, 对ori_img在赋值之后进行了去畸变操作,去畸变后的图像保存在dst_img中,随后又将dst_img的图像数据,即data保存到undistort_image->image中,但是这里的保存仅仅是将undistort_image->image的指针指向了ori_img.data的地址,并没有进行内存的拷贝,同时dst_img又是这个函数的局部变量,在退出该函数的时候cv::Mat的析构函数会自动释放dst_img对应的内存,因此,等到外面在访问这块内存进行memcpy的操作时,会出现访问不到内存,导致memcpy出错。
这里的修改方式为将
undistort_image_->image = reinterpret_cast<char*>(dst_img.data);
修改为:
memcpy(&undistort_image_->image[0], dst_img.data, img_size);
将内存通过memcpy拷贝进来,从而避免dst_img的内存被释放时,也相当于释放了undistort_image->image对应的内存; 同时我的undistort_image->image因为是事先申请好了一块内存的, 就应该进行这样的深拷贝,而不是直接将将指针指向对应的地址;
关于深拷贝和浅拷贝参考C++的深拷贝和浅拷贝; 对于像cv::Mat这样的类,其中的data中的数据(指针类型),只有执行深拷贝,才能保证新保存的数据与Mat中的data相互独立,否则,一旦元数据被释放,新保存的数据也不存在了;
当然,我这里的根源问题,并不在于memcpy(), 而是在于错误地将指针指向局部变量的内存地址, 如果有小伙伴在使用memcpy()时出现了问题,也可以试一下将memcpy()替换掉,自己写一个for循环进行拷贝,看一下还会不会有错;
这是我中间的debug过程,发出来分享一下:
image.data.resize(st0);
image.data.clear();//将我原来为image.data申请的内存先清除掉
char *pdata = (char *)data_arg;//做一个类型转换,不重要
printf("image.data = %d %d %d \n", &image.data[0], image.data.capacity(), data_arg);
for (size_t i = 0; i < st0; i++)
{
image.data.push_back((char)pdata[i]);//替换memcpy(),自己手动copy
}
不一定能解决问题,但是可以作为一个Debug的思路。
:)