OpenCV 3.2 源码编译与 Python 绑定避坑指南
简介:OpenCV 3.2 面向计算机视觉、机器学习方向的 C++ 开发者与高校学生,提供该版本在 Windows 环境下编译、链接及二次开发所需的头文件与库文件,可用于图像处理、特征检测、目标识别、视频分析和相机标定等项目的环境搭建。压缩包共 178 个文件,其中 116 个 hpp 与 57 个 h 头文件构成主要接口声明,另有 3 个 dll 动态库和 2 个 lib 静态库,整体约 25.19MB,便于按模块查阅和工程引用。目前已有 752 人学习下载,说明其在 OpenCV 3.2 环境配置与版本适配场景中具有一定参考价值。资源涵盖 core、imgproc、videoio、calib3d、aruco 及 DNN 等模块的相关接口,读者可据此完成 Visual Studio 等工程的包含目录、库目录与依赖项配置,也可用于对照学习各模块的 C++ 接口组织方式,为图像滤波、特征匹配、目标检测和视频处理等实践提供底层支持。
1. 从一行 import 报错说起:opencv 3.2 的环境边界在哪
前阵子帮人复现一个老图像处理 Demo,代码里import cv2之后直接调cv2.SIFT(),机器上 apt 装的版本早就是 4.x,cv2.SIFT早就不在了,直接报属性不存在。退回去装opencv 3.2,源码包又卡在 Python 3.8 上编不过,cv2.cpp 一路报错,编译到一半就停。折腾两天才认清楚:3.2.0 是 2016 年底的版本,它认的 Python 是 2.7 和 3.5,编译器落在 gcc 4.8 到 5.4 最稳,SIFT、SURF 那批算法还在 opencv_contrib 的 xfeatures2d 里待着。
这类老环境在复现历史项目、跑老论文代码时非常常见,装不好就是编译中断、import 半途崩掉、摄像头打不开。这篇记的就是我重装 opencv 3.2 的完整过程:版本怎么配、cmake 怎么写、cv2.so 怎么放、出问题怎么救。
2. 装前把环境钉死:opencv 3.2 的版本搭配与依赖清单
opencv 3.2 这种老版本,最怕的不是命令写错,是环境没钉死。同一份源码,在 Python 3.5 上二十分钟编完,在 Python 3.8 上能报一堆 C API 找不到。所以动手之前先花十分钟把版本、依赖、目录三件事定下来,后面能省掉大半天。
2.1 三套组合:Python 2.7、Python 3.5 和纯 C++
先把三条常见路线摆出来,选一条走到底,别中途混着来。混着来最典型的翻车是:Python 2 的 cv2.so 和 Python 3 的装进同一个目录,然后import cv2时灵时不灵,这种玄学问题排查起来很费劲。
| 组合 | 系统 | Python | 编译器 | 适用场景 |
|---|---|---|---|---|
| A | Ubuntu 16.04 LTS | 2.7.12 | gcc 5.4 | 老代码、老脚本原样复现 |
| B | Ubuntu 16.04 LTS | 3.5.2 | gcc 5.4 | 新写的脚本,仍要用 xfeatures2d |
| C | Ubuntu 16.04 / CentOS 7 | 不启用 | gcc 5.4 / 4.8 | 只做 C++ 工程,不碰 Python 绑定 |
几个经验值。第一,Python 3.6 及以上别尝试编 opencv 3.2 的 Python 绑定,CPython 的 C API 在这几个小版本里改过,源码里的切片和字符串接口对不上,报错能拉一屏,常见做法是退回 3.5,或者干脆只编 C++ 部分。第二,numpy 也别装太新,3.2 时代的代码是按 numpy 1.11 上下写的,装到 1.20 以后容易出现类型判断上的兼容问题,装 2.x 基本必崩。第三,如果只是要 C++ 能力,BUILD_opencv_python3=OFF关掉绑定,能省掉一半的依赖麻烦。
Windows 那边情况简单些,opencv 3.2 官方提供自解压的预编译包,解压后把build\x64\vc14\bin塞进 PATH,工程里配好 include 和 lib 目录就行,不需要自己编。但预编译包不带 contrib 模块,要用 SIFT 还是得自己编,所以下面的流程在 Windows 上换成 CMake GUI 也能走通。
2.2 依赖包一次装齐:apt 与 yum 的差异
依赖最怕装一半,编到某个模块才发现缺库,又得从头来。我一般一次性装齐,按用途分四组记:编译工具、图像格式、视频编解码、GUI 与数学库。
# 编译工具链与构建工具 sudo apt-get update sudo apt-get install -y build-essential cmake git pkg-config # 图像格式支持:jpeg / png / tiff / jasper sudo apt-get install -y libjpeg8-dev libpng12-dev libtiff5-dev libjasper-dev # 视频编解码与摄像头采集 sudo apt-get install -y libavcodec-dev libavformat-dev libswscale-dev \ libv4l-dev libxvidcore-dev libx264-dev # GUI 与数学加速 sudo apt-get install -y libgtk2.0-dev libatlas-base-dev gfortran # Python 3.5 开发头文件与 numpy sudo apt-get install -y python3.5-dev python3-numpy每组的用途得说清楚,不然缺了不知道缺在哪。build-essential提供 gcc、g++、make,cmake 负责生成构建文件,pkg-config 决定后面 C++ 工程能不能用一条命令拿到编译参数。libjpeg8-dev、libpng12-dev、libtiff5-dev对应 imread 和 imwrite 的三种主流格式,缺了不会编译失败,但运行时会返回空 Mat,这种静默失败最难查。libjasper-dev是 JPEG2000 支持,某些新系统源里已经没有这个包,装不上就加-D WITH_JASPER=OFF关掉,不影响主要功能。
视频那组是关键。libavcodec-dev、libavformat-dev、libswscale-dev提供 FFmpeg 的编解码能力,缺了VideoCapture打不开 mp4,摄像头也可能读不出帧。libv4l-dev是 Linux 下摄像头采集的兼容层,笔记本上跑实时处理必须装。
GUI 这组里,libgtk2.0-dev决定imshow()能不能弹出窗口。opencv 3.2 默认走 GTK2,装成 GTK3 的话 cmake 会警告然后关掉 highgui 的窗口支持,程序能跑但看不到图。libatlas-base-dev提供 BLAS 加速,矩阵运算快一截;gfortran是 ATLAS 的编译依赖,漏了会链接报错。
CentOS 7 上换成 yum,包名对应关系是:gcc-c++换 build-essential,gtk2-devel换 libgtk2.0-dev,libjpeg-turbo-devel换 libjpeg8-dev,jasper-devel换 libjasper-dev,还要先yum install -y epel-release打开额外源,不然一堆包装不上。
2.3 源码包与目录规划
opencv 3.2 的源码我习惯放固定目录,编坏了直接删掉重来,不污染家目录。
# 建统一源码目录,权限交给自己 sudo mkdir -p /opt/src && sudo chown -R $USER:$USER /opt/src cd /opt/src # 主库固定拉 3.2.0 标签,别用 master git clone --branch 3.2.0 --depth 1 https://github.com/opencv/opencv.git opencv-3.2.0 # contrib 模块必须同版本,版本错位是编译失败的高发原因 git clone --branch 3.2.0 --depth 1 https://github.com/opencv/opencv_contrib.git opencv_contrib-3.2.0--branch 3.2.0锁死标签,--depth 1只拉最新一次提交,省一半下载时间。contrib 的版本必须和主库完全一致,3.2.0 对 3.2.0,差一个小版本都会在 cmake 阶段报模块接口不匹配。我见过有人主库拉 3.2、contrib 拉 3.4,编到 xfeatures2d 直接挂掉,回头查半天以为是编译器问题。
目录结构上,主库和 contrib 平级放,后面 cmake 里OPENCV_EXTRA_MODULES_PATH指到 contrib 的modules子目录,注意是modules不是 contrib 根目录,少写一层等于没配。
3. CMake 配置与编译:opencv 3.2 参数逐项拆解
源码躺好了,接下来是最容易出岔子的一段。cmake 这步不是敲完回车就完事,得看输出;make 这步不是并发拉满就快,得看内存。两件事都做对,后面安装和绑定基本是顺的。
3.1 一份能跑通的 cmake 命令
先把命令贴出来,再逐项解释。这套参数对应的是 2.1 里的组合 B:Ubuntu 16.04 + Python 3.5 + 带 contrib。
cd /opt/src/opencv-3.2.0 mkdir -p build && cd build cmake -D CMAKE_BUILD_TYPE=RELEASE \ -D CMAKE_INSTALL_PREFIX=/usr/local \ -D INSTALL_C_EXAMPLES=OFF \ -D INSTALL_PYTHON_EXAMPLES=ON \ -D OPENCV_EXTRA_MODULES_PATH=/opt/src/opencv_contrib-3.2.0/modules \ -D BUILD_EXAMPLES=OFF \ -D BUILD_TESTS=OFF \ -D WITH_CUDA=OFF \ -D WITH_QT=OFF \ -D WITH_GTK=ON \ -D WITH_FFMPEG=ON \ -D BUILD_opencv_python2=OFF \ -D BUILD_opencv_python3=ON \ -D PYTHON3_EXECUTABLE=/usr/bin/python3.5 \ -D PYTHON3_INCLUDE_DIR=/usr/include/python3.5m \ -D PYTHON3_LIBRARY=/usr/lib/x86_64-linux-gnu/libpython3.5m.so \ -D PYTHON3_NUMPY_INCLUDE_DIRS=/usr/lib/python3/dist-packages/numpy/core/include \ -D PYTHON3_PACKAGES_PATH=/usr/lib/python3/dist-packages \ .. 2>&1 | tee cmake.log命令来自源码根目录下的 build 子目录,所以最后是..。输出用tee存一份,编不过时不用往上翻终端。
参数取舍逐条说。CMAKE_BUILD_TYPE=RELEASE开优化,Debug 版本会大出好几倍,跑生产代码没必要。CMAKE_INSTALL_PREFIX=/usr/local是安装根,头文件落到/usr/local/include,库落到/usr/local/lib,Python 绑定落到/usr/lib/python3/dist-packages,这几个路径后面都要用到。
OPENCV_EXTRA_MODULES_PATH是 contrib 的入口,指向modules子目录。BUILD_TESTS=OFF和BUILD_EXAMPLES=OFF是省时间的关键,测试用例能占掉三成编译量,第一次装环境完全没必要编。
WITH_CUDA=OFF除非机器上真有能用的显卡和 CUDA 工具链,否则一定关掉。opencv 3.2 的 CUDA 支持对 cuda 版本很挑,编到cudaarithm报一堆模板错误是常态。WITH_QT=OFF是因为 Qt 版窗口要额外装 Qt5 开发包,用它不如用 GTK 省事;WITH_GTK=ON对应 apt 里装的 libgtk2.0-dev,两个都关掉的话imshow直接不可用。
PYTHON3_*这五个是 Python 绑定的命门。EXECUTABLE指解释器,INCLUDE_DIR指头文件目录,LIBRARY指libpython3.5m.so的完整路径,NUMPY_INCLUDE_DIRS指 numpy 的 C 头文件位置,PACKAGES_PATH指 cv2.so 的落地目录。路径写错不会报 cmake 错误,只会在输出里显示Python 3: NO,然后编完发现根本没有 cv2.so。
所以 cmake 跑完必须看输出,重点看三行:Python 3:后面是不是 YES 并带出版本号和路径;To be built:列表里有没有python3和xfeatures2d;FFMPEG:是不是 YES。这三行不对,后面不用编,改了参数重跑 cmake 只要几秒。
3.2 编译阶段:make -j 的数字怎么定
并发数是另一处容易翻车的地方。make -j拉满能把编译时间压到最短,也能让进程被系统直接杀掉,报一句internal compiler error: Killed,看着像编译器 bug,其实是内存不够。
# 先看核数与可用内存 nproc free -h # 保守起点:4 核 8G 内存用 -j4,内存紧张用 -j2 make -j4 2>&1 | tee build.log经验值是每个编译任务按 1GB 内存估。opencv 3.2 的dnn、imgproc这类模块编译时单进程能吃 1.5GB 上下,4G 内存的机器上make -j8基本必挂。报 Killed 就减并发,或者临时加个 swap 文件兜底,sudo fallocate -l 2G /swapfile建 2G 交换分区,编完再删掉。这个血泪经验值一条:宁可多花二十分钟,也别让编译跑到 80% 被杀掉重来。
编译时间参考,4 核 8G 的虚拟机上,关掉测试和示例、带 contrib、不带 CUDA,大约 25 到 40 分钟。如果十分钟就结束,多半是某个模块在 cmake 阶段被关掉了,回头翻 cmake.log 看To be built列表。
编译过程中的警告可以忽略,但 error 要立刻停。最常见的是 ffmpeg 相关头文件找不到,对应就是 2.2 里视频那组依赖没装全,补装后不用重新 cmake,直接再 make 即可,增量编译只编失败的那个模块。
3.3 安装与动态库路径
编完之后make install把产物复制到/usr/local,但系统默认不认这个路径下的动态库,不处理的话运行时报error while loading shared libraries: libopencv_core.so.3.2。这一步不能省。
sudo make install # 让系统动态链接器认识 /usr/local/lib sudo sh -c 'echo "/usr/local/lib" > /etc/ld.so.conf.d/opencv.conf' sudo ldconfig # 确认库已经被缓存到 sudo ldconfig -v | grep opencvldconfig读取/etc/ld.so.conf及其子目录下的配置,把库路径写入缓存。第三行能看到libopencv_core.so.3.2这类条目就说明注册成功。如果之前装过 apt 版的 opencv,/usr/lib/x86_64-linux-gnu下可能还留着一份 4.x 的库,ldconfig的搜索结果里两版并存时,链接顺序会决定实际用哪一版。稳妥做法是先apt-get remove掉旧包,或者用LD_LIBRARY_PATH=/usr/local/lib在运行时显式指定。
4. Python 绑定落地:让 cv2 稳定被 import 到的三种做法
C++ 库装好了,Python 侧还不一定能用。cv2.so 生成了但不在 sys.path 里,是新手最常见的一道墙。这章把「找文件、放对位置、验路径」三步走完。
4.1 先确认 cv2.so 到底生成了没有
别急着 import,先找文件。找不到文件说明 cmake 里的 PYTHON3 参数就没生效,再怎么折腾路径都没用。
# 在安装目录里找 Python 绑定产物 find /usr/local/lib -name "cv2*.so" # 看当前解释器的模块搜索路径 python3.5 -c "import sys; [print(p) for p in sys.path]"第一条命令正常应该输出类似/usr/local/lib/python3.5/dist-packages/cv2.so的结果。3.2 时代产物的文件名通常就是朴素的cv2.so,不像新版本带 ABI 后缀。搜不到的话,回 cmake.log 里搜Python 3,看是不是 NO,或者PYTHON3_PACKAGES_PATH指到了一个不存在的目录导致写不进去。
第二条命令列出 sys.path,确认目标目录在里面。Ubuntu 16.04 的 Python 3.5 一般包含/usr/lib/python3/dist-packages和/usr/local/lib/python3.5/dist-packages两条,如果安装路径不在这两条里,就得靠下一步处理。
4.2 软链进 site-packages(最省事)
我一般用软链,不复制。复制的话以后重编一次就得手动同步一次,容易忘。
# 把编译产物链到解释器能认的目录 sudo ln -sf /usr/local/lib/python3.5/dist-packages/cv2.so \ /usr/lib/python3/dist-packages/cv2.so # 验证 import 与版本 python3.5 -c "import cv2; print(cv2.__version__)"-s是软链,-f是存在就覆盖,两个一起用可以反复执行不出错。左边是实际产物,右边是 sys.path 里的目录。输出版本号3.2.0就通了。
不想动系统目录的话,用环境变量也行:
export PYTHONPATH=/usr/local/lib/python3.5/dist-packages:$PYTHONPATH写进~/.bashrc长期生效。缺点是换用户、换 shell、跑 cron 任务时环境变量不继承,容易出「我这儿明明能跑」的争议。团队协作的机器上,我还是倾向软链,路径写死在系统里,谁登进来都一样。
如果两个 Python 版本共存,务必确认软链指对了目录。python2.7和python3.5的 dist-packages 是两个不同目录,链错的表现是 Python 3 能 import、Python 2 报错,或者反过来。
4.3 pkg-config 与 C++ 工程引用
纯 C++ 工程不需要 cv2.so,但需要编译参数。opencv 3.2 装完后会在/usr/local/lib/pkgconfig下生成opencv.pc,pkg-config 靠它给出 include 和 lib 路径。
# 让 pkg-config 找到 opencv.pc export PKG_CONFIG_PATH=/usr/local/lib/pkgconfig:$PKG_CONFIG_PATH # 查看版本与编译参数 pkg-config --modversion opencv pkg-config --cflags --libs opencv第二条命令输出一串-I/usr/local/include/opencv ... -lopencv_core -lopencv_imgproc ...,把这串直接塞进 g++ 就能编。PKG_CONFIG_PATH同样建议写进/etc/profile.d/下的脚本,别只放在当前会话,不然换个终端又得重新 export。
写 CMake 工程的话更简单,find_package(OpenCV 3.2 REQUIRED)之后用${OpenCV_INCLUDE_DIRS}和${OpenCV_LIBS},版本号写 3.2 能挡住误用到 4.x 的情况。
5. 避坑记录:opencv 3.2 编译安装最容易翻车的五个地方
下面五条都是我自己撞过或者帮人救过的,按「现象 → 原因 → 解决」记,照着对号入座基本能定位。
5.1 ippicv 下载卡住,编译停在 30%
现象:make 跑到opencv_core附近卡住不动,日志里反复出现下载ippicv_linux_20151201.tgz的超时信息,十几分钟没进展。
原因:3.2 的构建脚本会在 cmake 阶段从外网拉 ippicv、ffmpeg 这类第三方二进制包,网络不稳就一直重试。
解决:手动下载对应的 tgz,放到源码目录的.cache/ippicv/下,文件名必须和脚本里写的一致,然后重新 cmake。或者 cmake 时加-D WITH_IPP=OFF直接关掉这套加速库,对功能没有影响,只是某些滤波运算慢一点。
5.2 make 被 Killed,报 internal compiler error
现象:编译到一半进程消失,终端留下c++: internal compiler error: Killed (program cc1plus)。
原因:并发数超过物理内存,系统 OOM killer 直接杀掉编译进程,看起来像编译器崩了。
解决:make -j2降并发,或者加 2G swap 兜底。别迷信-j$(nproc),虚拟机上 nproc 是 8 但内存只有 4G 的情况太常见了。
5.3 Python 3.6 及以上编不过 Python 绑定
现象:cmake 显示Python 3: YES,make 跑到opencv_python3模块时 cv2.cpp 报一堆标识符未声明。
原因:3.2 的绑定代码写于 CPython 3.5 时代,后续小版本调整过部分 C API 的签名和宏。
解决:装 3.5 的解释器和开发包,cmake 里把PYTHON3_EXECUTABLE、PYTHON3_INCLUDE_DIR、PYTHON3_LIBRARY三条全部指到 3.5 上,重新 cmake。不想退版本的话,就-D BUILD_opencv_python3=OFF只留 C++。
5.4 import cv2 报 undefined symbol
现象:import cv2抛ImportError: ... undefined symbol: _ZN2cv...,或者提示某个libopencv_*.so.3.2找不到。
原因:cv2.so 找到了,但它依赖的动态库版本不对,机器上残留了 apt 版 opencv 的旧库,链接时抢在前面。
解决:先apt-get remove掉python-opencv、libopencv-dev这类旧包,再sudo ldconfig刷新缓存,然后ldd cv2.so | grep opencv看每个依赖解析到哪个路径,确认全部指向/usr/local/lib。必要时用LD_LIBRARY_PATH=/usr/local/lib强制优先。
5.5 imshow 弹不出窗口,或摄像头读不到帧
现象:脚本跑到cv2.imshow直接报The function is not implemented,或者VideoCapture(0)返回 False。
原因:前者是 GTK 开发包缺失,cmake 阶段把 highgui 的 GUI 后端关掉了;后者是视频采集依赖没装全或者设备权限不够。
解决:sudo apt-get install libgtk2.0-dev pkg-config之后删掉 build 目录重新 cmake,看输出里GTK+ 2.x:是不是 YES。摄像头问题先ls /dev/video*确认设备存在,再sudo usermod -aG video $USER加权限,重新登录生效。
6. 装完怎么验:三条命令确认 opencv 3.2 真的跑通
装完不验,等于没装。我见过太多「编译成功」但一跑就崩的情况,下面三条从 Python、C++、功能能力三个层面各验一次,全部过了才算收工。
6.1 Python 侧:版本、路径、模块能力
import cv2 import numpy as np # 1. 版本与编译信息 print("version:", cv2.__version__) print("python bindings:", cv2.__file__) # 2. 基础图像运算:画个圆再转灰度 img = np.zeros((200, 300, 3), dtype=np.uint8) cv2.circle(img, (150, 100), 60, (0, 255, 0), -1) gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY) print("mean:", round(float(gray.mean()), 2)) # 3. 确认 contrib 里的 xfeatures2d 是否可用 sift = cv2.xfeatures2d.SIFT_create() kp = sift.detect(gray, None) print("keypoints:", len(kp))第一段输出3.2.0和 cv2.so 的绝对路径,路径必须指向你软链的那个位置,指到别处说明还有旧版本在抢。第二段验证 numpy 与 Mat 的互转链路,均值能打出来说明内存布局对得上。第三段是 3.2 这个版本的特色,SIFT 在 xfeatures2d 里,能创建出对象并检出关键点,说明 contrib 编进去了,这一步过不了就说明OPENCV_EXTRA_MODULES_PATH没配对。
6.2 C++ 侧:pkg-config 能否一条命令编过
#include <opencv2/opencv.hpp> #include <iostream> int main() { // 生成一张 300x200 的画布并画圆 cv::Mat img = cv::Mat::zeros(200, 300, CV_8UC3); cv::circle(img, cv::Point(150, 100), 60, cv::Scalar(0, 255, 0), -1); std::cout << "opencv version: " << CV_VERSION << std::endl; std::cout << "mat size: " << img.cols << "x" << img.rows << std::endl; cv::imwrite("out.png", img); return 0; }g++ verify.cpp -o verify $(pkg-config --cflags --libs opencv) ./verify ls -lh out.pngCV_VERSION是编译期宏,打出来的是头文件对应的版本,和运行时库版本不一致会暴露混装问题。能编过、能跑出3.2.0、能落地一个 png 文件,说明头文件、库、链接路径三处全对。
6.3 功能能力:视频与设备这两项单独看
# 查看编译期开启了哪些能力,重点看 FFMPEG 与 GUI python3.5 -c "import cv2; info=cv2.getBuildInformation(); print(info)" | grep -E "FFMPEG|GUI|GTK"输出里FFMPEG: YES和GUI: GTK两行是关键,缺了任意一项,视频和窗口相关的代码都跑不通。这两项在 cmake 阶段就定了,事后补不了,只能改参数重编,所以验的时候顺手看一眼getBuildInformation()的输出最保险。
最后是一个小习惯:把上面三条验证命令写成一个check_opencv.sh放在/opt/src下,以后每次重装或者换机器,先跑这个脚本再动项目代码。
从那以后我每次装完 opencv 都强制走一遍这套验证,不看到3.2.0和 keypoints 的数字就不往下写业务代码——之前有一次偷懒跳过,结果项目跑到半夜才发现 cv2.so 链的是旧版本,白白多花三小时。希望帮到你。
本文还有配套的精品资源,点击获取