OpenCV拾趣(一)——构建自己的OpenCV SDK

本篇简介

谈起一套工具的使用,首先需要的就是这套工具的安装。因为这个系列的研究所使用的开发系统为Ubuntu16.04,而官方目前没有提供3.3版本的安装包,因此需要自己从源码进行编译。

既然都已经必须从源码编译了,不妨添加一些基础安装包里没有包含的高级模块,打造一个功能更为全面的SDK。

编写构建脚本

在从源码构建一套工具时,因为系统环境差异等各方面的因素,往往会出现一些预料之外的情况导致构建失败,很少能一次就构建成功。因此,我个人习惯编写简单的脚本进行构建,以减少构建失败时重复敲打命令的工作。

首先规划一下构建环境的目录结构:

simpleCV  
   |  
   +-->tools:工具文件夹  
   |   |  
   |   +-->build_cv:构建脚本  
   |    
   +-->opencv_git:官方代码库文件夹  
   |   |  
   |   +-->opencv:官方opencv基础库源码  
   |   |  
   |   +-->opencv_contrib:官方contrib源码  
   |  
   +-->sdk  
       |  
       +-->opencv:构建目录,避免污染源码库环境  
       |  
       +-->opencv_release:发布目录,也就是最终使用的sdk  

然后大致划分一下构建的步骤:

  1. 从官方的git repo里拉取最新的源码
  2. 安装依赖
  3. 准备构建环境
  4. 执行cmake和make进行构建
  5. 部署额外的库文件

接下来开始编写脚本。先编写一个基本的脚本框架:

#!/bin/bash
# 全局变量
ROOT_DIR=$(pwd)/..
GIT_DIR=${ROOT_DIR}/opencv_git
SDK_DIR=${ROOT_DIR}/sdk
BUILD_DIR=${SDK_DIR}/opencv
RELEASE_DIR=${SDK_DIR}/opencv_release
VERSION=3.3.1
HTTP_PROXY_PROP=127.0.0.1:8123

# 执行入口
#update_opencv_src &&
#   install_dependencies &&
#   prepare_src_codes &&
#   exec_cmake &&
#   exec_make &&
#   deploy_extra_libs

其中:

  • 全局变量:定义了前面规划的目录结构、准备编译的opencv版本和代理设置
  • 执行入口部分:按照上面划分的步骤,把每一步都包成一个函数,构建的时候如果出错了,可以把前面已经成功的步骤注释掉,只调试出问题的步骤。(现在因为函数都还没有编写,所以暂时先注释起来。)

下面就来编写各个步骤的函数:

1. 拉取最新源码

目前官方的最新代码分为基础包和contrib包,其中contrib包囊括了一些技术较新,但是因为各种原因还没有集成在默认OpenCV中的功能。

这两个包分别对应官方github的opencv和opencv_contrib这两个repo,且这两个repo的版本号是基本一致的。例如本系列使用的3.3.1版本opencv,只需要将两个库均切换到3.3.1标签即可。

下面是拉取最新源码的脚本:

update_opencv_src() {
    echo "Updating soruce code..."
    local src_dirs=(${GIT_DIR} ${SDK_DIR})
    ensure_dirs ${src_dirs[@]}
    cd ${GIT_DIR}
    if [[ -d ${GIT_DIR}/opencv/.git ]]; then
        git pull
    else
        git clone https://github.com/opencv/opencv.git
    fi
    if [[ -d ${GIT_DIR}/opencv_contrib ]]; then
        git pull
    else
        git clone https://github.com/opencv/opencv_contrib
    fi
    cd ${GIT_DIR}/opencv
    git checkout ${VERSION}
    cd ${GIT_DIR}/opencv_contrib
    git checkout ${VERSION}
}

这里面用到了一个确保关键目录存在的工具函数

ensure_dirs() {
    local targets=$@
    for target in ${targets[@]}; do
        echo -n "checking ${target}..."
        if [[ ! -d ${target} ]]; then
            mkdir -p ${target}
        fi
        echo "OK!"
    done
}

2.安装依赖

3.3.1需要安装的依赖参见下面的安装依赖函数。值得注意的是有些依赖包可能会安装得比较缓慢,有条件的话可以设置一下代理。下面的脚本里也包含了对代理设置的判断:

install_dependencies() {
    echo "Installing dependencies..."
    if [[ -n ${HTTP_PROXY_PROP} ]]; then
        export http_proxy=http://${HTTP_PROXY_PROP}
        export https_proxy=https://${HTTP_PROXY_PROP}
    fi

    sudo apt install -y libjpeg8-dev libjasper-dev libpng12-dev &&
        sudo apt install -y libtiff5-dev &&
        sudo apt install -y libavcodec-dev libavformat-dev libswscale-dev libdc1394-22-dev &&
        sudo apt install -y libxine2-dev libv4l-dev &&
        sudo apt install -y libgstreamer0.10-dev libgstreamer-plugins-base0.10-dev &&
        sudo apt install -y qt5-default libgtk2.0-dev libtbb-dev &&
        sudo apt install -y libatlas-base-dev &&
        sudo apt install -y libfaac-dev libmp3lame-dev libtheora-dev &&
        sudo apt install -y libvorbis-dev libxvidcore-dev &&
        sudo apt install -y libopencore-amrnb-dev libopencore-amrwb-dev &&
        sudo apt install -y x264 v4l-utils &&
        sudo apt install -y python-dev python-pip python3-dev python3-pip

    if [[ -n ${HTTP_PROXY_PROP} ]]; then
        sudo -H pip2 --proxy ${HTTP_PROXY_PROP} install -U pip numpy &&
            sudo -H pip3 --proxy ${HTTP_PROXY_PROP} install -U pip numpy
    else
        sudo -H pip2 install -U pip numpy &&
            sudo -H pip3 install -U pip numpy
    fi
}

3. 准备构建环境

为了避免污染源码库,可以单独搭建一个构建环境,将两个源码库中的源码合并在一起,然后在新搭建的构建环境中进行构建:

prepare_src_codes() {
    echo "Preparing build environment..."
    if [[ -d ${BUILD_DIR} ]]; then
        rm -rf ${BUILD_DIR}
    fi
    mkdir ${BUILD_DIR}
    cd ${GIT_DIR}/opencv
    local src_modules=(3rdparty apps cmake data doc include modules platforms samples)
    for module in ${src_modules[@]}; do
        echo "copying opencv/${module}..."
        cp -Rf ${module} ${BUILD_DIR}/${module}
    done

    cp -Rf CMakeLists.txt ${BUILD_DIR}
    cp -Rf LICENSE ${BUILD_DIR}

    if [[ -d ${BUILD_DIR}/contrib ]]; then
        rm -rf ${BUILD_DIR}/contrib
    fi
    mkdir ${BUILD_DIR}/contrib
    cd ${GIT_DIR}/opencv_contrib
    local contrib_modules=(doc modules samples)
    for module in ${contrib_modules[@]}; do
        echo "copying opencv_contrib/${module}..."
        cp -Rf ${module} ${BUILD_DIR}/contrib/${module}/
    done
}

4. 执行cmake

准备好构建环境后,就可以尝试进行编译了。官方的源码已经提供了CMakeList.txt,所以最简单的办法就是直接使用cmake作为编译工具。

这里需要特别注意两点:

  1. 请保持网络畅通。官方设置的编译过程中会下载一些所需的依赖库,如果下载失败导致cmake执行失败,可以尝试多执行几次。
  2. 请确保系统中的cmake包含https支持。这里面有个比较坑的地方,就是一些重要的依赖库需要使用https下载,而下载失败cmake不会报错,会跳过继续执行,但是在后面执行make的时候会报一些诸如找不到cuda.hpp之类的诡异错误。如果发现所使用的cmake不包含https支持,可以重新编译一下cmake。具体可以参考下面的参考链接3

——综合上面两点,还是和前面安装依赖包时一样,有条件的话推荐在这一步使用一下代理。

言归正传,官方的CMakeList中提供了非常多的选项,可以通过在cmake后添加-D标签进行控制,下面的脚本仅挑选了我认为有用的模块,如果有其他进一步的需要可以参考CMakeList中的设置进行调整。

为了方便调试,这个函数还添加了一个--clean的参数来清理构建目录,如果需要的话在执行入口的exec_cmake后面加上--clean即可:

exec_cmake() {
    echo "Executing cmake..."
    cd ${BUILD_DIR}
    if [[ -d build ]]; then
        if [[ $1 -eq "--clean" ]]; then
            rm -rf build/
        fi
    else
        mkdir build
    fi
    cd build
    cmake -D CMAKE_BUILD_TYPE=RELEASE \
        -D CMAKE_INSTALL_PREFIX=${RELEASE_DIR} \
        -D INSTALL_C_EXAMPLES=ON \
        -D INSTALL_PYTHON_EXAMPLES=ON \
        -D WITH_TDD=ON \
        -D WITH_V4L=ON \
        -D WITH_QT=ON \
        -D WITH_OPENGL=ON \
        -D OPENCV_EXTRA_MODULES_PATH=${BUILD_DIR}/contrib/modules \
        -D BUILD_EXAMPLES=ON ..
}

5. 执行make

执行到这一步基本上就没什么问题了。需要注意的就是上面一步所说的,如果cmake的https支持缺失的话,可能会报一些奇怪的错,如果构建执行make的时候报了什么错,请检查一下所使用的cmake。

exec_make() {
    "Making..."
    cd ${BUILD_DIR}/build
    local core_cnt=$(nproc)
    make -j${core_cnt} && make install
}

6. 部署额外的库文件

在使用编译好的sdk时,根据cmake设置的不同,可能会有一些动态库需要额外部署到sdk中以方便链接时使用。下面是部署libippicv到sdk路径下的脚本:

deploy_extra_libs() {
    #libippicv
    echo -n "Deploying libippicv..."
    local lib_ippicv_path=$(find ${BUILD_DIR}/build/3rdparty/ippicv -name "libippicv.a")
    if [[ -n ${lib_ippicv_path} ]];then
        cp ${lib_ippicv_path} ${RELEASE_DIR}/lib && echo "OK" || echo "FAILED!"
    else
        echo "FAILED!libippicv not found!"
    fi
    
}

至此,sdk就构建完成了。(>>查看完整脚本

下一步的尝试是使用这个sdk结合Qt进行开发。具体请参见下一节
>>返回系列索引

参考链接

  1. OpenCV 3 - 编译更强大的OpenCV:windows环境下拓展和编译opencv的系列教程
  2. Install OpenCV on Ubuntu:Ubuntu上安装opencv的教程,列举了所需的依赖包
  3. CMake缺失https下载支持导致的错误讨论
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 160,706评论 4 366
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 68,002评论 1 301
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 110,462评论 0 250
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 44,375评论 0 216
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 52,763评论 3 294
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,849评论 1 224
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 32,033评论 2 317
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,768评论 0 204
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,490评论 1 246
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,734评论 2 253
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 32,204评论 1 264
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,566评论 3 260
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 33,227评论 3 241
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,137评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,934评论 0 201
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,926评论 2 283
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,774评论 2 274