Peanuts
OpenCV 速查手册
2062 字
10 分钟
OpenCV 速查手册
面向传统计算机视觉与 RoboMaster 视觉入门的 OpenCV 快速参考。
主要基于 OpenCV 4.x,C++ 为主,同时补充 Python 常用写法。
建议收藏的官方资源:
目录
- 安装与环境
- 常见模块与头文件
- 核心数据结构
- cv::Mat 详解
- 图像与视频 I/O
- 颜色空间与通道操作
- 几何变换与滤波
- 二值化与阈值
- 形态学操作
- 边缘检测
- 轮廓与几何拟合
- 绘制与可视化
- 传统视觉 Detector 思路(灯条 / 装甲板)
- 常用速查表
- 实用 Tips 与常见陷阱
1. 安装与环境
Ubuntu(推荐新人方式)
sudo apt updatesudo apt install -y libopencv-dev pkg-config cmake g++验证:
pkg-config --modversion opencv4pkg-config --cflags --libs opencv4CMake 最小工程示例
cmake_minimum_required(VERSION 3.16)project(opencv_demo LANGUAGES CXX)set(CMAKE_CXX_STANDARD 17)set(CMAKE_CXX_STANDARD_REQUIRED ON)
find_package(OpenCV REQUIRED)add_executable(opencv_demo main.cpp)target_include_directories(opencv_demo PRIVATE ${OpenCV_INCLUDE_DIRS})target_link_libraries(opencv_demo PRIVATE ${OpenCV_LIBS})编译运行:
mkdir -p build && cd buildcmake ..cmake --build . -j./opencv_demo ../test.jpgPython
pip install opencv-python # 或 opencv-contrib-pythonimport cv2print(cv2.__version__)2. 常见模块与头文件
| 模块 | 头文件 | 主要用途 |
|---|---|---|
| Core | opencv2/core.hpp | Mat、Point、Rect、Scalar、矩阵运算 |
| Imgcodecs | opencv2/imgcodecs.hpp | imread / imwrite |
| HighGUI | opencv2/highgui.hpp | imshow、waitKey、Trackbar |
| Imgproc | opencv2/imgproc.hpp | 颜色、滤波、阈值、形态学、轮廓、绘图 |
| VideoIO | opencv2/videoio.hpp | VideoCapture |
新人可直接:
#include <opencv2/opencv.hpp>3. 核心数据结构
| 类型 | 含义 | 常见用途 |
|---|---|---|
cv::Mat | 多维稠密数组 | 图像、Mask、中间结果 |
cv::Point / Point2f | 二维点 | 像素坐标、中心、角点 |
cv::Point3f | 三维点 | PnP、空间几何 |
cv::Size / Size2f | 宽高 | 图像尺寸、核尺寸 |
cv::Rect / Rect2f | 水平矩形 | ROI、Bounding Box |
cv::Scalar | 最多 4 个标量 | 颜色、阈值、初始化 |
cv::Vec3b | 3 个 uchar | 读取 BGR 像素 |
cv::RotatedRect | 旋转矩形 | 灯条、细长目标拟合 |
cv::Moments | 矩 | 面积、质心 |
常用构造
cv::Point p(100, 50);cv::Point2f pf(100.5f, 50.2f);cv::Size sz(1280, 1024); // width, heightcv::Rect rect(100, 80, 300, 200); // x, y, width, heightcv::Scalar green(0, 255, 0); // BGRcv::RotatedRect rr(cv::Point2f(300, 200), cv::Size2f(40, 120), 20.0f);注意坐标系:图像原点在左上角,x 向右,y 向下。Mat.at(row, col) = at(y, x)。
4. cv::Mat 详解
常见类型
| 类型 | 含义 | 场景 |
|---|---|---|
CV_8UC1 | 8-bit 无符号 1 通道 | 灰度 / 二值 |
CV_8UC3 | 8-bit 无符号 3 通道 | BGR 彩色 |
CV_16UC1 | 16-bit 无符号 1 通道 | 深度图 |
CV_32FC1 | 32-bit float 1 通道 | 浮点计算 |
属性查看
std::cout << image.rows << " " << image.cols << " " << image.channels() << " " << image.type() << " " << image.empty() << std::endl;浅拷贝 vs 深拷贝
cv::Mat a = image; // 共享数据(引用计数)cv::Mat b = image.clone(); // 深拷贝image.copyTo(b); // 显式深拷贝像素访问
// 灰度uchar v = gray.at<uchar>(y, x);
// BGRcv::Vec3b pixel = image.at<cv::Vec3b>(y, x);uchar b = pixel[0], g = pixel[1], r = pixel[2];
// 高性能按行遍历for (int y = 0; y < gray.rows; ++y) { uchar* row = gray.ptr<uchar>(y); for (int x = 0; x < gray.cols; ++x) { // 使用 row[x] }}ROI
cv::Rect roi_rect(x, y, w, h);cv::Mat roi = image(roi_rect); // 视图cv::Mat roi_copy = image(roi_rect).clone(); // 独立5. 图像与视频 I/O
图像
cv::Mat color = cv::imread(path, cv::IMREAD_COLOR); // BGRcv::Mat gray = cv::imread(path, cv::IMREAD_GRAYSCALE);if (color.empty()) { /* 失败处理 */ }cv::imwrite("out.jpg", color);img = cv2.imread(path, cv2.IMREAD_COLOR)cv2.imwrite("out.jpg", img)显示
cv::imshow("win", image);int key = cv::waitKey(0); // 0 = 永久等待if (key == 27) { /* ESC */ }cv::destroyAllWindows();视频 / 摄像头
cv::VideoCapture cap(path_or_index);if (!cap.isOpened()) { /* 错误 */ }cv::Mat frame;while (cap.read(frame)) { // 处理 frame cv::imshow("frame", frame); if (cv::waitKey(1) == 27) break;}6. 颜色空间与通道操作
常用转换
cv::cvtColor(src, gray, cv::COLOR_BGR2GRAY);cv::cvtColor(src, hsv, cv::COLOR_BGR2HSV);cv::cvtColor(src, rgb, cv::COLOR_BGR2RGB); // 注意:matplotlib 等需要HSV 注意:OpenCV 中 H 范围为 0179(不是 0360)。
通道分离 / 合并
std::vector<cv::Mat> chs;cv::split(image, chs); // chs[0]=B, [1]=G, [2]=Rcv::merge(chs, merged);颜色阈值 Mask(inRange)
cv::Scalar lower(90, 80, 80); // HSV 蓝示例cv::Scalar upper(130, 255, 255);cv::Mat mask;cv::inRange(hsv, lower, upper, mask);
cv::Mat selected;cv::bitwise_and(image, image, selected, mask);传统 RM 中也常用通道差(如 B - R)增强灯条对比度。
7. 几何变换与滤波
resize
cv::resize(src, dst, cv::Size(640, 480), 0, 0, cv::INTER_LINEAR);// 或按比例cv::resize(src, dst, cv::Size(), 0.5, 0.5, cv::INTER_AREA);常用滤波
cv::GaussianBlur(src, dst, cv::Size(5, 5), 1.2);cv::medianBlur(src, dst, 5); // 对椒盐噪声好cv::blur(src, dst, cv::Size(5, 5)); // 均值cv::bilateralFilter(src, dst, 9, 75, 75); // 保边其他:
cv::flip(src, dst, 1); // 1=水平, 0=垂直, -1=两者cv::rotate(src, dst, cv::ROTATE_90_CLOCKWISE);cv::normalize(src, dst, 0, 255, cv::NORM_MINMAX, CV_8U);8. 二值化与阈值
固定阈值
cv::threshold(gray, binary, 180, 255, cv::THRESH_BINARY);// 常用类型:THRESH_BINARY, THRESH_BINARY_INV, THRESH_OTSU, THRESH_TOZERO自适应阈值
cv::adaptiveThreshold(gray, binary, 255, cv::ADAPTIVE_THRESH_GAUSSIAN_C, cv::THRESH_BINARY, 11, 2);固定阈值简单可解释,但对光照变化敏感;自适应更适合局部亮度不均场景。实际工程需用真实数据验证。
9. 形态学操作
cv::Mat kernel = cv::getStructuringElement(cv::MORPH_RECT, cv::Size(3, 3));// 或 MORPH_ELLIPSE, MORPH_CROSS
cv::erode(binary, eroded, kernel);cv::dilate(binary, dilated, kernel);
cv::morphologyEx(binary, opened, cv::MORPH_OPEN, kernel); // 去小白噪点cv::morphologyEx(binary, closed, cv::MORPH_CLOSE, kernel); // 填小黑洞、连接断裂| 操作 | 效果 |
|---|---|
| Erode | 白区域收缩,去细小突出 |
| Dilate | 白区域扩张,填裂缝 |
| Open | 先腐蚀后膨胀,去小噪点 |
| Close | 先膨胀后腐蚀,连接目标 |
形态学不是必须步骤,只有在数据中能稳定解决问题时才加入。
10. 边缘检测
cv::Canny(gray_or_blurred, edges, 80, 160);Canny 对梯度敏感,常配合 GaussianBlur 使用。RM 灯条检测中若颜色/亮度二值化已足够干净,可直接找轮廓,不必强行加入 Canny。
11. 轮廓与几何拟合
findContours
std::vector<std::vector<cv::Point>> contours;std::vector<cv::Vec4i> hierarchy;
cv::findContours(binary, contours, hierarchy, cv::RETR_EXTERNAL, // 只外层 cv::CHAIN_APPROX_SIMPLE); // 压缩共线点常用模式:
RETR_EXTERNAL:只最外层RETR_TREE:完整层级CHAIN_APPROX_NONE:保留所有点CHAIN_APPROX_SIMPLE:压缩
常用轮廓属性
double area = cv::contourArea(contours[i]);double peri = cv::arcLength(contours[i], true);cv::Rect bbox = cv::boundingRect(contours[i]);cv::RotatedRect rrect = cv::minAreaRect(contours[i]);cv::Moments m = cv::moments(contours[i]);cv::Point2f center(m.m10 / m.m00, m.m01 / m.m00);近似多边形
std::vector<cv::Point> approx;cv::approxPolyDP(contours[i], approx, 0.02 * peri, true);绘制轮廓
cv::drawContours(debug, contours, -1, cv::Scalar(0, 255, 0), 2);RotatedRect 使用
cv::Point2f vertices[4];rrect.points(vertices);// 可转成自己的 Light 结构,统一长边/短边/倾角定义12. 绘制与可视化
cv::line(img, pt1, pt2, color, thickness);cv::rectangle(img, rect, color, thickness); // thickness < 0 填充cv::circle(img, center, radius, color, thickness);cv::putText(img, text, org, cv::FONT_HERSHEY_SIMPLEX, scale, color, thickness);cv::fillPoly(img, {pts}, color);颜色顺序始终是 BGR。
13. 传统视觉 Detector 思路(灯条 / 装甲板)
一套简化流水线(来自 RoboMaster 实践):
Image → Preprocess → Binary / Feature → Contours → Light Candidates → Armor Pairs → 2D Corners最终输出示例:
struct Armor { cv::Point2f center; std::array<cv::Point2f, 4> corners;};典型步骤概览
- 预处理:灰度 / HSV / 通道差 + 滤波
- 二值化 / Mask:固定阈值或 inRange,得到亮灯条区域
- 形态学(可选):开运算去噪、闭运算连接
- 找轮廓:
findContours+ 面积、长宽比、角度筛选 → 得到 Light 候选 - 配对:根据两灯条距离、角度差、高度比等先验规则组成装甲板
- 几何:
minAreaRect或四点拟合得到 corners 与 center
核心原则:
- OpenCV 只是工具,真正的“哪个是灯条、哪两根能组成装甲板”需要根据目标先验自己写判据。
- 保持每一步可解释、可调试(输出中间图)。
- 参数必须用真实赛场数据验证,而不是“感觉高级”。
14. 常用速查表
图像读取标志
| 标志 | 含义 |
|---|---|
IMREAD_COLOR | 3 通道 BGR |
IMREAD_GRAYSCALE | 单通道灰度 |
IMREAD_UNCHANGED | 原样(含 alpha) |
插值方式
| 标志 | 场景 |
|---|---|
INTER_LINEAR | 通用放大 |
INTER_AREA | 缩小推荐 |
INTER_NEAREST | 最近邻(快) |
INTER_CUBIC | 高质量放大 |
常见颜色常量(BGR)
cv::Scalar(255, 0, 0) // 蓝cv::Scalar(0, 255, 0) // 绿cv::Scalar(0, 0, 255) // 红cv::Scalar(0, 255, 255) // 黄cv::Scalar(255, 255, 255) // 白cv::Scalar(0, 0, 0) // 黑15. 实用 Tips 与常见陷阱
- 永远检查 empty():
imread/VideoCapture失败不会抛异常。 - BGR 不是 RGB:与 matplotlib、Pillow 交互时记得转换。
- 浅拷贝陷阱:修改 ROI 或赋值后的 Mat 可能影响原图,需要独立数据时用
clone()。 - at(y, x):行列顺序与日常 (x, y) 习惯相反。
- HSV 范围:H 是 0~179。
- 不要盲目堆函数:每加一步就增加参数和失败模式,用数据验证必要性。
- 调试友好:中间结果全部
imshow或imwrite,方便调参。 - 性能:大图循环优先
ptr,避免频繁at;正式程序少依赖 GUI。 - 版本差异:以当前安装版本官方文档为准。
- 从工具到算法:学会 API 只是第一步,真正的 Detector 需要目标先验与可解释的规则。
附录:最小可运行示例(C++)
#include <opencv2/opencv.hpp>#include <iostream>
int main(int argc, char** argv) { if (argc < 2) { std::cerr << "Usage: " << argv[0] << " <image>\n"; return 1; } cv::Mat image = cv::imread(argv[1], cv::IMREAD_COLOR); if (image.empty()) return 1;
cv::Mat gray, blurred, binary; cv::cvtColor(image, gray, cv::COLOR_BGR2GRAY); cv::GaussianBlur(gray, blurred, cv::Size(5, 5), 1.2); cv::threshold(blurred, binary, 180, 255, cv::THRESH_BINARY);
std::vector<std::vector<cv::Point>> contours; cv::findContours(binary, contours, cv::RETR_EXTERNAL, cv::CHAIN_APPROX_SIMPLE);
cv::Mat debug = image.clone(); cv::drawContours(debug, contours, -1, cv::Scalar(0, 255, 0), 2);
cv::imshow("original", image); cv::imshow("binary", binary); cv::imshow("debug", debug); cv::waitKey(0); return 0;}文档版本:2026-09
参考来源:OpenCV 官方文档 + Zhejiang University RoboMaster Vision 传统视觉教程
使用建议:边读边编译,修改参数观察结果,逐步把基础 API 组合成完整 Detector。
祝调试顺利!
支持与分享
如果这篇文章对你有帮助,欢迎分享给更多人或投喂支持!
相关文章 智能推荐
1
PnP 位姿解算学习笔记
笔记本 2026-09-12
2
ROS 2 速查手册
笔记本 2026-09-11
3
ROS 2 速查手册(进阶)
笔记本 2026-09-11
4
OpenCode 学习笔记
笔记本 2026-08-31
5
2025 NECCS 笔记
笔记本 一些笔记
随机文章 随机推荐
无穷量?