扫一扫
分享文章到微信
扫一扫
关注官方公众号
至顶头条
在编写图像识别模块时,遇到了一个莫名的大问题,(如代码所示)
以下是引用片段: unsigned char *image0, *image1; image0 = get_image(...); image1 = get_image(...); |
以上代码是从摄像头连续拍摄两张照片,但奇怪的是,拍摄完毕时发现,image0保存的图片内容和image1的内容竟然完全相同!!!!太不可思议了。首先,通过如下代码排除了摄像头的问题:
以下是引用片段: image0 = get_image(...); put__image_jpeg(out0, image0...); image1 = get_image(...); put_image_jpeg(out1, image1...); |
以上代码的含义是在摄像头拍摄下图片后立即保存为jpeg文件,这样我就能检测两张图片是否内容相同,不出所料,检测结果显示两个jpeg文件的图片内容是完全不同的。但即使是这样,在以上操作后,依旧发现image0和image1指向的图片内容相同。似乎是中邪了,保存的jpeg文件内容不同,但是指针指向的却是相同的内容(都是image1的内容,也就是后一张图片)。然后想着,是不是在获取image1的同时,把image0的内存区域给覆盖了,这个是很有可能的,那么这个问题就100%出在get_image函数中。打开这个函数的定义发现:
以下是引用片段: char *map; ... map = malloc(...); ... return (map); |
这个就和我想的不一样了,这个函数非常正确,它在获取摄像头的图像时,是采用了动态内存分配,并且返回内存区域的首地址,这样的话,就根本不可能会出现内存覆盖的现象。至此,这个问题一直困扰了我半个星期,一点进展都没有,大脑一团浆糊,唯一想的就是中邪了。
然后,就在n天后,吃饱了撑的,在校园里走着,忽然脑袋里想起了我们在用户空间中的内存地址都是虚拟内存地址,也就是需要通过内存映射,才能够访问到物理地址的。那么这样的映射关系到底是什么关系呢?第一个闪现的就是一一映射,也就是说只允许唯一的虚拟地址去映射唯一的物理地址。那么到底有没有其它的可能性呢?一对多?这个马上被否定了,因为假如一个虚拟地址能够映射多个物理地址的话,根本是不可能实现的,因为操作系统无法分清某一时刻这个虚拟地址到底要映射到哪个物理地址上。那么多对一呢?也就是说多个虚拟地址可以映射到唯一的物理地址上?也就是说通过不同的虚拟地址,我们可以访问同一个物理地址。这个可行。忽然间就豁然开朗,考虑到项目上出的那个奇怪的问题,会不会是image0和image1同时映射到了相同的物理地址上?
这个问题如何验证,似乎非常难办,其实到现在还没想到比较快捷的方法,第一个是用内核调试,在内核空间中,应该可以跟踪虚存管理的细节;第二个是源码入手,假如问题成立的话,那么这个相同的物理地址应该就是用来暂存摄像头获取的图像信息的,那么这个要么在V4L接口中实现,要么在摄像头驱动中实现。
但是由于时间关系,没能确实的验证,但是基于这个猜想,我却很容易的想出了解决问题的办法,就是内存块复制。代码如下:
以下是引用片段: image0 = get_image(...); image0_tmp = (unsigned char *)malloc(image_size); memset(image0_tmp, 0, image_size); memcpy(image0_tmp, image0, image_size); free(image0); image1 = get_image(...); |
首先抓取image0,然后将其指向的图像信息,通过memcpy手动复制到另一块分配好的内存区域中,然后再次抓取image1,这样的话,两张图片就这样保存下来了(第一张在image0_tmp中,第二张在image1中)。至此,问题得以圆满解决。
如果您非常迫切的想了解IT领域最新产品与技术信息,那么订阅至顶网技术邮件将是您的最佳途径之一。
现场直击|2021世界人工智能大会
直击5G创新地带,就在2021MWC上海
5G已至 转型当时——服务提供商如何把握转型的绝佳时机
寻找自己的Flag
华为开发者大会2020(Cloud)- 科技行者