您的位置:首页 > 产品设计 > UI/UE

OpenCV运行中告警提示“libpng warning: Application built with libpng-1.2.49 but running with 1.6.22”并崩溃

2018-09-03 18:17 239 查看

OpenCV运行中告警提示“libpng warning: Application built with libpng-1.2.49 but running with 1.6.22”并崩溃

一、问题描述

最近项目需要使用OpenCV在地图图片(png格式)上添加比例尺,于是采用编译源码的方式获得了OpenCV的所有库。将OpenCV库添加到自己的项目后,编译、链接均正常。但是在CentOS系统上,程序运行过程中调用cv::imdecode()函数后控制台输出告警信息:“libpng warning: Application built with libpng-1.2.49 but running with 1.6.22”。 但此时程序并没有crash,而是在后面调用cvPutText()函数时输出报错信息“Unknown array type in function cvarrToMat”后core dump. 相同的代码在macOS上运行正常,没有出现告警信息,也没有crash,仅在centOS上出现问题。代码段如下:

std::vector<char> vecBuffer(pngBuffer.get(), pngBuffer.get() + bufferSize);
cv::_InputArray arrayBuffer(vecBuffer);
//将缓冲区中的png图片数据解析到Mat对象中
cv::Mat image = cv::imdecode(arrayBuffer, CV_LOAD_IMAGE_COLOR);
... ...  //在图片上绘制比例尺(省略)
//在比例尺上写入比例系数,centOS系统上调用该函数时core dump
cvPutText(&image, text.c_str(), textPos, &font, textColor);

做个广告,欢迎访问免费的在线电影网站:一号影院

二、问题排查

1、调试源码发现,cvPutText()函数崩溃是因为cv::imdecode()所返回的image对象中的data为空,并传给了cvPutText()函数(代码如上所示)。cvPutText()函数内部调用cvarrToMat()函数时无法判断数据类型而主动抛出了异常。
由此可见问题的原因是cv::imdecode()函数的不正常返回值导致的,接下来进一步查找cv::imdecode()返回空对象的原因。

2、单步进入cv::imdecode()函数发现,该函数解析传入的图片数据时,需要调用libpng的png_create_read_struct()函数,而该函数返回了空指针(代码如下所示),同时输出了上述告警信息“libpng warning: Application built with libpng-1.2.49 but running with 1.6.22”。由于返回的png_ptr为空,因此主调函数cv::imdecode()自然也会返回空的Mat对象,最终导致后面的core dump. 考虑到png_create_read_struct()函数返回空指针与上述告警信息同时出现,因此怀疑问题的原因是linpng库的版本不对导致问题出现。

bool  PngDecoder::readHeader()  //OpenCV源码
{
volatile bool result = false;
close();
//下面这行返回了空指针(读取png数据失败)
png_structp png_ptr = png_create_read_struct( PNG_LIBPNG_VER_STRING, 0, 0, 0 );
if( png_ptr )
{
... ... //省略部分代码<
277e1
/span>
result = true;
}

if( !result )
close();

return result;
}

3、在我的centOS环境上,/user/lib64目录下确实装的有libpng的库,编译OpenCV时也确实链接到了这个库上,ldd命令发现,运行阶段也是load这个库,也就是说,正是因为这个库的版本不对,才导致了core dump. 但是,更奇怪的问题是我的macOS上根本没有安装过任何版本的libpng,但是编译链接阶段没有任何报错,运行竟然也正常,并且运行阶段并不依赖、也不加载libpng的库。那么唯一的解释是OpenCV源码中包含了libpng的代码。查看OpenCV源码,果然在里面找到了libpng的源码(3rdparty/libpng目录)。现在,问题原因越来越清晰:在mac上编译OpenCV时,编译了内建的libpng,运行阶段自然执行的是内建的libpng的代码,因此程序运行正常;而在centOS上编译时,却是链接到系统已有的库中,运行阶段也是执行的系统已有库中里的程序。而centOS上已有的libpng库版本太老,与我的png数据不兼容,运行时,该库里的png_create_read_struct()函数无法解析我的png数据而返回了空指针。

4、最后的问题是,为什么在mac上编译时会将OpenCV自带的libpng编译成内建的,而在centOS上却要依赖系统的libpng库??看来这一切的答案要在cmake的组态档中寻找了。打开OpenCV/CMakeLists.txt 文件,马上就发现了端倪(如下图):

看到了吧?苹果系统下是要“build png”的!!而centOS下不用“build png”,自然是链接到系统的库了!

再来看看这里定义的 BUILD_PNG 是怎么使用的:

明白了吗?这里是说,当 BUILD_PNG 值为ON的时候,则编译内建的libpng;当 BUILD_PNG 值为 OFF的时候,先在系统中查找libpng, 若系统中已安装libpng,则依赖它,若找不到libpng,则编译一个内建的libpng. 值得一提的是,这里编译的内建libpng是先编译成了静态库,然后在链接阶段把它链接到OpenCV的动态库中,这样一来,运行阶段是不需要再依赖libpng的。
好了,既然知道BUILD_PNG用于控制“编译内建libpng”或“依赖系统libpng”,那么我们只要在编译OpenCV的时候,将BUILD_PNG设置为ON,即可强制编译OpenCV自带的libpng,而不受系统中libpng的影响。这样一来,就不会有版本不匹配的问题了,所以解决办法是:

三、解决办法

方法一:
编译OpenCV时,在执行cmake命令时加上参数: -D BUILD_PNG=ON
即:
cmake -D BUILD_PNG=ON -D CMAKE_BUILD_TYPE=DEBUG -D CMAKE_INSTALL_PREFIX=/usr/local/opencv-3.4.1 …

方法二:
将系统中已存在的libpng库换成与OpenCV自带的libpng同版本的libpng库即可。但是这种方法不是很优雅,而且操作起来比较麻烦,需要自己下载或者编译新版本的libpng库,所以不推荐。

四、效果

看到下图右上角的比例尺了吗? Celebrate!!!

内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: 
相关文章推荐