1. 为什么 Ubuntu 20.04 LTS 上装 OpenCV 值得单独写一篇
Ubuntu 20.04 LTS 是个很特殊的存在。它发布于 2020 年 4 月,官方维护周期一直到 2025 年,而大量做计算机视觉、图像处理、机器人感知的团队,至今仍把它当作主力开发环境。原因不复杂:系统稳定、软件源成熟、驱动兼容性好,很多硬件厂商的 SDK 也是优先适配这个版本。OpenCV 作为计算机视觉领域最常用的开源库,几乎每个做图像处理的项目都绕不开它。但恰恰是"在 Ubuntu 20.04 上装 OpenCV"这件事,看起来简单,实际上坑不少。
我见过太多人在这件事上翻车。有人pip install opencv-python一行命令装完,跑起来发现视频读取报错;有人源码编译折腾一下午,最后卡在某个依赖找不到;还有人装完了 Python 能 import,但 C++ 项目死活链接不上。问题的根源在于:OpenCV 的安装方式不止一种,每种方式装出来的东西能力边界完全不同,而大多数人根本没搞清楚自己需要哪一种。
这篇内容就是要把这件事讲透。我会从安装方式的选择逻辑讲起,把 apt 安装、pip 安装、源码编译三条路各自的适用场景、具体操作、参数含义、踩坑点全部拆开说清楚。不管你是刚接触 Ubuntu 的新手,还是需要定制化编译的老手,都能在这里找到可以直接抄作业的方案。核心关键词就一个:Ubuntu 20.04 LTS 下 OpenCV 的安装,但我会把围绕它的依赖管理、版本选择、环境验证、问题排查一并讲完,让你装完之后是真的能用,而不是装完就完事。
先说一个基本判断:如果你只是想在 Python 里做点图像处理、跑个深度学习推理,pip 安装足够;如果你要做 C++ 开发、需要调用 CUDA 加速、或者要用到 OpenCV contrib 里的扩展模块(比如 SIFT、人脸识别相关算法),那基本得走源码编译。这个判断会贯穿全文,你带着它往下看就不会迷路。
2. 安装方式选型:三条路到底该走哪条
2.1 三种安装方式的本质区别
很多人把"装 OpenCV"当成一件事,其实它是三件不同的事。apt 装的是系统级预编译包,pip 装的是 Python 轮子(wheel),源码编译是你自己从头构建。这三者的区别不是"方便程度",而是"你能拿到什么"。
apt 方式(sudo apt install libopencv-dev python3-opencv)拿到的是 Ubuntu 官方仓库维护的版本。Ubuntu 20.04 仓库里默认是 OpenCV 4.2.0。这个版本稳定、依赖自动解决、装完系统里 C++ 和 Python 都能用。但它的短板很明显:版本偏旧,不带 contrib 扩展模块,不带 CUDA 支持,而且你没法控制编译选项。适合"我就想快速跑起来,不挑版本"的场景。
pip 方式(pip install opencv-python)拿到的是 PyPI 上预编译好的 wheel。它的优势是版本新、安装快、Python 里直接可用。但注意,pip 装的 OpenCV 只服务于 Python,你的 C++ 项目完全用不了它。而且默认的opencv-python包为了减小体积,砍掉了一些功能(比如某些视频编解码支持),需要opencv-contrib-python才能拿到扩展模块。适合"纯 Python 开发、不需要 C++ 接口"的场景。
源码编译是唯一能让你完全掌控的方式。你可以指定版本、开启 CUDA、编译 contrib 模块、裁剪不需要的部分。代价是耗时长(视机器性能,30 分钟到 2 小时不等)、依赖多、容易出错。适合"有明确定制需求"的场景。
2.2 一张表帮你快速决策
| 安装方式 | 版本 | C++ 支持 | Python 支持 | contrib 模块 | CUDA 加速 | 耗时 | 适用人群 |
|---|---|---|---|---|---|---|---|
| apt 安装 | 4.2.0 | 支持 | 支持 | 不支持 | 不支持 | 2 分钟 | 快速验证、教学 |
| pip 安装 | 最新 | 不支持 | 支持 | 可选 | 不支持 | 1 分钟 | 纯 Python 项目 |
| 源码编译 | 自选 | 支持 | 支持 | 支持 | 支持 | 30分钟+ | 定制化需求 |
这张表是我建议你保存下来的。每次纠结怎么装,先看这张表,对号入座。
2.3 选型背后的逻辑:别为了"新"而编译
我见过一种很常见的误区:觉得源码编译"更专业",于是不管三七二十一就上源码。结果花了两个小时编译完,发现自己根本用不到 contrib,也不需要 CUDA,纯属浪费时间。更糟的是,源码编译如果没配好,还可能污染系统环境,导致后面 apt 装的东西出问题。
反过来也有另一种误区:明明要做 C++ 项目,却用 pip 装了 OpenCV,然后发现find_package(OpenCV)找不到包,一脸懵。这就是没搞清楚 pip 装的 OpenCV 只对 Python 可见。
所以选型的核心逻辑是:先明确你的项目用什么语言、需不需要扩展模块、要不要 GPU 加速,再倒推安装方式。这个顺序不能反。下面我把三种方式的具体操作分别展开,你可以直接跳到你需要的那一节。
3. apt 方式:五分钟搞定的稳妥选择
3.1 具体操作步骤
apt 方式是最省心的,适合快速搭建环境。完整命令如下:
sudo apt update sudo apt install -y libopencv-dev python3-opencv第一行更新软件源索引,第二行安装 OpenCV 的开发库和 Python 绑定。libopencv-dev提供 C++ 头文件和库文件,python3-opencv提供 Python 的 cv2 模块。装完之后,系统里就有了 OpenCV 4.2.0。
验证 C++ 是否可用,可以写个最小测试:
pkg-config --modversion opencv4如果输出版本号(比如 4.2.0),说明 C++ 开发环境就绪。验证 Python:
python3 -c "import cv2; print(cv2.__version__)"输出 4.2.0 就对了。
3.2 为什么 apt 版本是 4.2.0
Ubuntu 20.04 冻结软件版本是在 2020 年初,当时 OpenCV 的最新稳定版就是 4.2.0。Ubuntu 的仓库策略是"稳定优先",一个 LTS 版本发布后,仓库里的主要软件版本基本不会大改,只打安全补丁。所以你在这个系统上通过 apt 装,永远只能拿到 4.2.0 这个系列。
这不是坏事。4.2.0 是个相当成熟的版本,主流的图像处理、特征检测、基础机器学习功能都有。真正缺的是 contrib 里的部分算法(比如 SIFT 在 4.2 里其实已经进主仓库了,但像 face 模块、xfeatures2d 里的部分内容还是缺)和 CUDA 支持。
3.3 实操心得:apt 方式的隐藏坑
第一个坑是 Python 版本。Ubuntu 20.04 默认的 python3 是 3.8,python3-opencv装的就是给 3.8 用的。如果你自己装了 conda 或者别的 Python 版本,import cv2可能会失败,因为 apt 装的 cv2 只对系统 Python 可见。这时候要么用系统 Python,要么走 pip 方式。
第二个坑是头文件路径。apt 装的 OpenCV 头文件在/usr/include/opencv4/,库文件在/usr/lib/x86_64-linux-gnu/。用 CMake 的时候,find_package(OpenCV REQUIRED)一般能自动找到,但如果你的 CMakeLists 写得有问题,可能需要手动指定OpenCV_DIR。
第三个坑是版本冲突。如果你之前用 pip 装过 opencv-python,再 apt 装一遍,Python 里 import 的到底是哪个版本就说不准了。建议二选一,别混着来。我个人的做法是:系统级用 apt,项目级用虚拟环境加 pip,物理隔离。
提示:apt 方式装完后,如果 Python 里 import cv2 报
ImportError: libGL.so.1: cannot open shared object file,装一下sudo apt install libgl1-mesa-glx就好。这是服务器环境最常见的问题,因为服务器通常不装图形库。
4. pip 方式:Python 开发者的快速通道
4.1 包的选择:opencv-python 还是 opencv-contrib-python
pip 安装 OpenCV 有几个包名,容易搞混,我列一下:
opencv-python:主模块,基础功能opencv-contrib-python:主模块加 contrib 扩展opencv-python-headless:无 GUI 版本,适合服务器opencv-contrib-python-headless:无 GUI 加 contrib
选择逻辑很简单:需要 contrib 里的算法(比如某些特征匹配、追踪算法)就选带 contrib 的;服务器上没有图形界面就选 headless 的。如果你不确定,选opencv-contrib-python最保险,功能最全。
安装命令:
pip install opencv-contrib-python如果你用虚拟环境(强烈建议),先激活环境再装:
python3 -m venv cv_env source cv_env/bin/activate pip install opencv-contrib-python4.2 版本锁定:别让自动升级坑了你
pip 默认装最新版。OpenCV 的版本迭代挺快,最新版有时候会有兼容性问题。生产环境建议锁定版本:
pip install opencv-contrib-python==4.5.5.644.5.5.64 是个很稳的版本,我很多项目都用它。锁版本的好处是环境可复现,换台机器装出来一模一样。这个习惯在做项目交付的时候特别重要,不然别人复现你的结果时,可能因为版本差异跑出不同结果。
4.3 实操心得:pip 方式的三个注意点
第一,pip 装的 OpenCV 和 apt 装的会打架。如果你系统里已经有 apt 装的 cv2,pip 装的时候可能会提示已存在。这时候要么用虚拟环境隔离,要么pip install --force-reinstall强制覆盖。我建议前者。
第二,headless 版本没有cv2.imshow。如果你在服务器上装了 headless,然后写代码调imshow,会直接报错。这不是 bug,是设计如此。服务器上做可视化,要么存成图片文件,要么用其他方式传出来看。
第三,pip 装的 OpenCV 不带 CUDA。PyPI 上的 wheel 是通用编译的,不含 GPU 支持。想在 Python 里用 CUDA 加速的 OpenCV,只能源码编译。这一点很多人不知道,以为 pip 装完就能用 GPU,结果发现cv2.cuda.getCudaEnabledDeviceCount()返回 0。
注意:如果你同时需要 Python 和 C++ 接口,pip 方式满足不了你,必须走源码编译或者 apt。pip 装的 OpenCV 对 C++ 完全不可见。
5. 源码编译:定制化需求的唯一出路
5.1 编译前的依赖准备
源码编译最容易卡在依赖上。Ubuntu 20.04 上编译 OpenCV 需要的依赖,我整理成一条命令,直接复制执行:
sudo apt install -y build-essential cmake git pkg-config \ libjpeg-dev libtiff-dev libpng-dev \ libavcodec-dev libavformat-dev libswscale-dev libv4l-dev \ libxvidcore-dev libx264-dev \ libgtk-3-dev libatlas-base-dev gfortran \ python3-dev python3-numpy这些依赖各有用途:build-essential提供编译器和 make,cmake是构建工具,libjpeg/libtiff/libpng是图像格式支持,libavcodec系列是视频编解码支持,libgtk-3-dev是 GUI 支持(imshow依赖它),libatlas-base-dev是数学运算加速,python3-dev是 Python 绑定编译需要。
如果你想开 CUDA,还得装 CUDA Toolkit 和 cuDNN。这部分涉及显卡驱动,不同硬件情况不同,我这里不展开,但记住一点:CUDA 版本要和你的显卡驱动匹配,装之前先nvidia-smi看一下驱动支持的 CUDA 版本上限。
5.2 下载源码与配置编译选项
从官方仓库克隆源码,注意要同时克隆主仓库和 contrib 仓库:
git clone https://github.com/opencv/opencv.git git clone https://github.com/opencv/opencv_contrib.git想编译特定版本就切分支,比如:
cd opencv git checkout 4.5.5 cd ../opencv_contrib git checkout 4.5.5然后创建构建目录,用 cmake 配置:
cd opencv mkdir build && cd build cmake -D CMAKE_BUILD_TYPE=RELEASE \ -D CMAKE_INSTALL_PREFIX=/usr/local \ -D OPENCV_EXTRA_MODULES_PATH=../../opencv_contrib/modules \ -D WITH_CUDA=OFF \ -D BUILD_EXAMPLES=OFF \ -D BUILD_opencv_python3=ON \ ..这里每个参数都有讲究。CMAKE_INSTALL_PREFIX=/usr/local指定安装路径,装完头文件在/usr/local/include/opencv4,库在/usr/local/lib。OPENCV_EXTRA_MODULES_PATH指向 contrib 模块路径,开了这个才能用扩展算法。WITH_CUDA=OFF是关掉 CUDA,你要开就改成 ON,但前提是 CUDA 环境配好了。BUILD_EXAMPLES=OFF关掉示例编译,省时间。
5.3 编译与安装
配置完成后开始编译。用nproc查看 CPU 核心数,然后并行编译:
make -j$(nproc)-j后面跟核心数,比如 8 核就make -j8。并行编译能大幅缩短时间,但注意内存占用也会上去。如果编译过程中报内存不足(OOM),把并行数降下来,比如make -j4。
编译完成后安装:
sudo make install sudo ldconfigldconfig是刷新动态链接库缓存,让系统能找到新装的库。这一步很多人会忘,忘了之后运行程序会报找不到库。
5.4 编译参数的选择逻辑
编译参数不是随便填的,每个都影响最终产物。我挑几个关键的说说。
BUILD_opencv_python3=ON决定是否编译 Python 绑定。如果你只用 C++,可以关掉省时间。但注意,如果你用 conda 环境,Python 绑定的路径可能不对,需要额外指定PYTHON3_EXECUTABLE、PYTHON3_INCLUDE_DIR、PYTHON3_LIBRARY等参数。
WITH_CUDA=ON开启 CUDA 支持,但开了之后编译时间会显著增加,而且如果 CUDA 环境有问题,编译会直接失败。建议第一次编译先关掉,确认基础编译能过,再开 CUDA 重编。
OPENCV_GENERATE_PKGCONFIG=ON生成 pkg-config 文件,方便 C++ 项目用pkg-config找库。这个默认可能是关的,建议打开。
BUILD_TESTS=OFF和BUILD_PERF_TESTS=OFF关掉测试编译,能省不少时间。除非你要跑 OpenCV 自己的测试,否则没必要编。
5.5 实操心得:源码编译的避坑指南
第一个坑是 contrib 版本不匹配。主仓库和 contrib 仓库的版本必须一致,否则编译会报错。切分支的时候两个都要切。
第二个坑是 Python 绑定装到了错误的位置。如果你用系统 Python,装完在/usr/local/lib/python3.8/dist-packages/下能找到 cv2。如果你用 conda,可能装到了系统 Python 的路径,conda 环境里 import 不到。解决办法是编译时明确指定 conda 环境的 Python 路径。
第三个坑是编译内存不足。OpenCV 编译很吃内存,尤其是开了 CUDA 之后。8G 内存的机器建议make -j2甚至make -j1。我见过有人make -j16直接把机器搞死机的。
第四个坑是装完之后和 apt 版本冲突。如果你之前 apt 装过 OpenCV,源码编译装到/usr/local后,系统里会有两个版本。CMake 找的时候可能找到旧的那个。解决办法是在 CMakeLists 里明确指定OpenCV_DIR=/usr/local/lib/cmake/opencv4。
提示:源码编译装完后,如果 Python 里 import cv2 报错,先检查
python3 -c "import sys; print(sys.path)",看/usr/local/lib/python3.8/dist-packages在不在路径里。不在的话,手动加一下或者用pip install -e的方式链接。
6. 安装后的验证与常见问题排查
6.1 完整的验证清单
装完 OpenCV 别急着写业务代码,先跑一遍验证。我习惯用下面这个脚本,一次性检查所有关键能力:
import cv2 import numpy as np print("OpenCV version:", cv2.__version__) print("CUDA enabled:", cv2.cuda.getCudaEnabledDeviceCount() if hasattr(cv2, 'cuda') else "N/A") # 测试基础图像操作 img = np.zeros((100, 100, 3), dtype=np.uint8) img[:] = (255, 0, 0) gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY) print("Basic operation OK, gray shape:", gray.shape) # 测试 contrib 模块(如果装了) try: sift = cv2.SIFT_create() print("SIFT available") except AttributeError: print("SIFT not available") # 测试视频编解码 try: fourcc = cv2.VideoWriter_fourcc(*'mp4v') print("Video codec OK") except Exception as e: print("Video codec issue:", e)这个脚本能帮你快速判断装出来的 OpenCV 到底有哪些能力。CUDA 那行如果返回 0,说明没开 GPU 支持。SIFT 那行如果报错,说明没装 contrib 或者版本太老。
6.2 常见问题速查表
| 问题现象 | 可能原因 | 解决方法 |
|---|---|---|
| import cv2 报 libGL.so.1 找不到 | 缺图形库 | sudo apt install libgl1-mesa-glx |
| import cv2 报 libgthread 找不到 | 缺 glib 库 | sudo apt install libglib2.0-0 |
| C++ 编译报找不到头文件 | 路径没配 | CMake 里指定 OpenCV_DIR |
| 运行时报找不到 .so | 链接缓存没刷新 | sudo ldconfig |
| Python 里 cv2 版本不对 | 多版本冲突 | 检查 sys.path,清理旧版本 |
| imshow 报错 | headless 版本 | 换非 headless 包或改用存图 |
| CUDA 设备数为 0 | 编译没开 CUDA | 重新编译加 WITH_CUDA=ON |
| 编译 OOM | 并行数太高 | 降低 make -j 数值 |
6.3 排查思路:从报错信息倒推
排查 OpenCV 问题有个通用思路:先看报错发生在哪个阶段。是 import 阶段、编译阶段还是运行阶段。
import 阶段报错,基本都是动态库找不到。用ldd命令看 cv2 依赖哪些库,哪个显示 not found 就装哪个。比如:
ldd /usr/local/lib/python3.8/dist-packages/cv2/python-3.8/cv2.cpython-38-x86_64-linux-gnu.so | grep "not found"编译阶段报错,看 CMake 的输出。CMake 配置完会打印一份摘要,列出哪些模块会编译、哪些依赖找到了、哪些没找到。仔细看这份摘要,能发现大部分问题。比如 Python 那几行如果显示 NO,说明 Python 绑定不会编译。
运行阶段报错,看具体函数。比如cv2.VideoCapture打不开视频,可能是编解码器没装;cv2.imshow报错,可能是 GUI 支持没编进去。
6.4 实操心得:多版本共存的管理
有时候你确实需要多个 OpenCV 版本共存,比如一个项目用 4.2,另一个用 4.5。这时候推荐用虚拟环境隔离 Python 版本,C++ 版本则通过 CMake 的OpenCV_DIR指定。
Python 侧,每个项目一个 venv,各自 pip 装各自的版本,互不干扰。C++ 侧,把不同版本装到不同前缀(比如/opt/opencv-4.2和/opt/opencv-4.5),项目 CMakeLists 里指定用哪个。
这种管理方式虽然麻烦点,但能彻底避免版本冲突。我做过一个项目同时依赖两个 OpenCV 版本,就是这么处理的,跑了大半年没出过问题。
7. 一些容易被忽略的细节
7.1 关于 Python 路径的那些事
Ubuntu 20.04 上 Python 路径有点绕。系统自带 python3.8,路径在/usr/bin/python3。如果你装了 conda,conda 的 python 在~/miniconda3/bin/python。apt 装的 cv2 只对系统 python 可见,pip 装的 cv2 对当前激活环境的 python 可见。
判断当前 python 用的是哪个 cv2,可以这样:
import cv2 print(cv2.__file__)输出的路径能告诉你它从哪加载的。如果路径在/usr/lib/python3/dist-packages/,那是 apt 装的;如果在虚拟环境的 site-packages 里,那是 pip 装的;如果在/usr/local/lib/python3.8/dist-packages/,那是源码编译装的。
7.2 关于编译时间的预期管理
源码编译 OpenCV 的时间差异很大。纯 CPU 编译、不开 contrib、不开 CUDA,8 核机器大概 15 到 20 分钟。开了 contrib 大概 25 分钟。开了 CUDA 可能 1 小时以上。如果机器核心少、内存小,时间还要翻倍。
我的建议是:第一次编译先做最小配置,确认流程能跑通,再逐步加功能重编。别一上来就全开,失败了都不知道哪出的问题。
7.3 关于版本选择的建议
OpenCV 4.x 系列里,4.2、4.5、4.8 是比较稳的几个版本。4.2 是 Ubuntu 20.04 的默认,4.5.5 是我个人最推荐的(功能全、bug 少),4.8 比较新,部分 API 有变化。
如果你没有特殊需求,源码编译建议选 4.5.5。这个版本在稳定性、功能完整性、社区支持之间平衡得最好。太老的版本缺功能,太新的版本可能有兼容性问题。
7.4 关于卸载和清理
装错了想重来,得先清理干净。apt 装的用sudo apt remove libopencv-dev python3-opencv卸载。pip 装的用pip uninstall opencv-python opencv-contrib-python。源码编译装的比较麻烦,因为make install没有对应的 uninstall,得手动删/usr/local下的相关文件,或者用make install_manifest.txt里记录的路径逐个删。
这也是为什么我建议源码编译装到独立前缀(比如/opt/opencv-4.5.5),而不是默认的/usr/local。独立前缀卸载的时候直接删目录就行,干净利落。
8. 最后分享几个实战技巧
装 OpenCV 这件事,说到底是个"匹配需求"的活。我这些年踩过的坑,大部分都不是技术难题,而是"用了不对的方式"。所以最后再强调几个实战中特别有用的点。
第一,先想清楚再动手。花两分钟想清楚你的项目用什么语言、要不要 contrib、要不要 GPU,比花两小时编译完发现不对要划算得多。选型那节的表格,建议你每次装之前都过一遍。
第二,虚拟环境是好朋友。Python 项目一律用 venv 或 conda 隔离,别往系统 Python 里乱装东西。系统 Python 保持干净,只放 apt 装的基础包。这样出问题的时候好排查,重装的时候也好清理。
第三,编译日志要留着。源码编译的时候,把 cmake 的输出和 make 的输出重定向到文件里存着。出问题的时候翻日志,比重新跑一遍快得多。我习惯用cmake ... 2>&1 | tee cmake.log和make -j8 2>&1 | tee make.log。
第四,验证脚本要常备。上面那个验证脚本,我建议你存成check_opencv.py,每次装完新环境跑一遍。它能帮你快速确认环境是否可用,省得写业务代码写到一半才发现环境有问题。
第五,别迷信最新版。OpenCV 的版本迭代快,但新版本不一定适合你。生产环境用经过验证的稳定版本,比追新更重要。4.5.5 这个版本我用了很久,各种场景都验证过,推荐给你。
这套流程我在不同机器上重复过很多次,从笔记本到服务器,从纯 CPU 到带 GPU 的工作站,基本都能覆盖。你按自己的需求对号入座,选对应的方式操作就行。装完之后跑一遍验证脚本,确认没问题再开始写代码,能省掉后面很多麻烦。