OpenCV运行中告警提示“libpng warning: Application built with libpng-1.2.49 but running with 1.6.22”并崩溃
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!!!
- libpng warning: Application built with libpng-1.6.27 but running with 1.5.13
- 运行Xcode时,提示:An error was encountered while running (Domain = FBSOpenApplicationErrorDomain, Code = 4)
- 运行yum系统提示Existing lock /var/run/yum.pid: another copy is running as pid 3046
- Resource interpreted as Font but transferred with MIME type application/x-font-woff
- Resource interpreted as Document but transferred with MIME type application/json ...
- Resource interpreted as Document but transferred with MIME type application/json ...
- 运行Android Studio,一直提示:Error running app: Instant Run requires 'Tools | Android | Enable ADB integrat
- 在编译运行时,报出‘Your project contains errors,please fix them before running your application.’的提示框
- 红帽运行yum提示“This system is not registered with RHN”
- 在win20008上运行U890破解提示sorry,this application cannot run under a virtual machine
- 警告:Resource interpreted as Stylesheet but transferred with MIME type application/x-css
- 运行时,出现出错提示,“实时错误91,对象变量或with或块变量未设置”,如何解决?
- Hololens错误提示:can't be loaded because it was not built with the right version or build target.
- Resource interpreted as Document but transferred with MIME type application/json ...
- 转载:ADT安装好在Eclipse后运行模型Android提示Re-installation failed due to different application signatur
- eclipse svn “svn: SQLite compiled for *, but running with *”
- Wix CloseApplication 安装时提示xxx程序正在运行
- Resource interpreted as Stylesheet but transferred with MIME type application/x-css
- Resource interpreted as Document but transferred with MIME type application/json:
- 运行yum系统提示Existing lock /var/run/yum.pid: another copy is running as pid