前几天在一台CentOS系统上安装带解码功能的OpenCV,过程略曲折,特此记录安装过程中遇到的一些问题和解决方法,以备后续查阅。
因为需要使用OpenCV的解码功能,需要安装FFMPEG,FFMPEG安装过程见我之前的一篇博文:
安装带X264的ffmpeg
但是跟之前有些不一样的地方,就是需要打开libdc1394,因此在FFMPEG配置中需要加入 --enable-libdc1394。
但是在安装FFMPEG之前,需要提前安装libdc1394,我使用的源码安装,源码下载地址:
libdc1394源码下载地址
下载完成并解压后,进入libdc1394目录,./configure、make、make install即可。
libdc1394是一个为应用程序开发人员提供高级编程接口的库,它可以控制和捕获来自基于IEEE 1394摄像头的流,这些摄像头符合基于1394的数码相机规范(也称为IIDC或DCAM规范)。libdc1394还支持一些符合IIDC的USB摄像头。
libdc1394提供的功能包括:相机控制、视频采集、支持多摄像头/多适配器、支持多平台(Linux / OSX / Windows)、兼容IIDC 1.31、颜色空间转换函数、多重去贝叶斯算法等。
安装好libdc后,即可正常安装FFMPEG了。
最开始希望安装OpenCV-2.4.9,也是我们在工程中常用的一个版本,但是该版本在视频编码格式上与FFMPEG-4.0并不兼容(FFMPEG-4.0先入为主),因此重新下载了OpenCV-3.4.3的源码来安装,下载地址:
OpenCV源码地址
下载完成并解压缩后,即可配置编译选项了。首先,在opencv-3.4.3目录下建立一个新的目录用于存放编译产生的文件:
1. mkdir build
由于我们要使用FFMPEG进行解码,因此需要打开FFMPEG,设置cmake -D WITH_FFMPEG=ON。另外,如果系统编译器版本较低,可能不支持C++11,会出现配置失败的问题,因此,需要在配置时使能C++11:cmake -D ENABLE_CXX11=1。这样,最终的配置命令行如下:
2. cmake -D ENABLE_CXX11=1 -D CMAKE_BUILD_TYPE=Release -D CMAKE_INSTALL_PREFIX=/usr/local -D WITH_FFMPEG=ON ..
当然,以上是比较简单的设置,根据不同的需要,可以加入不同的参数。
以上命令行执行完成后,在执行结果中发现FFMPEG库后面都是OFF(或NO)的状态,也就是说opencv配置ffmpeg库未生效,这是怎么回事呢?经过分析并在网上查找解决方案,发现虽然系统中已经安装了FFMPEG,在OpenCV配置中也打开了FFMPEG选项,但是OpenCV并没有找到FFMPEG库的位置。查看OpenCV CMakeList.txt,可以看到对FFMPEG系列库状态的判断如下:
我们知道,在编译中如果不明确指定依赖库的头文件和库路径,就需要使用pkg-config来获取依赖库的信息。一般来讲,系统会默认在/usr/lib/pkgconfig,或者/usr/share/pkgconfig,或者环境变量PKG_CONFIG_PATH指定的目录下查找*.pc文件来确定依赖库的信息,但我们在安装FFMPEG时,是默认安装到了/usr/local/lib目录下,对应的pkgconfig也在这个目录下,但/usr/local/lib/pkgconfig并不在系统查找的范围之内,因此我们需要把该路径放在PKG_CONFIG_PATH中。具体操作方法:
vim /etc/profile
在文件末尾添加如下语句:
export PKG_CONFIG_PATH=/usr/local/lib/pkgconfig:$PKG_CONFIG_PATH
保存并退出文件后,执行如下语句使之生效:
source /etc/profile
以上操作完成后,再次运行OpenCV的配置命令(见编号为2的命令行),配置通过。
之后依次运行make、make install完成编译和安装。
3. make
4. make install
OpenCV安装完成后,我们来测试一下是否能够正常使用,主要是解码功能。写了一个简单的测试程序,测试从RTSP码流解码的功能:
#include
#include
using namespace std;
using namespace cv;
int main(int argc, char **argv)
{
Mat frame;
int64_t frame_num = 0;
VideoCapture capture;
capture.open("rtsp://admin:[email protected]:554/h264/ch1/main/av_stream");
if(!capture.isOpened())
{
printf("Open VideoCapture failed\n");
return -1;
}
printf("Open VideoCapture success! \n");
while(1)
{
capture.read(frame);
printf("frame col = %d, row = %d, frame number = %ld \n", frame.cols,
frame.rows, frame_num++);
}
return 0;
}
编译运行,解码24小时未出现异常。