OpenCV 核心概念

FreeGuideOnline 最新 2026-07-15

python import cv2 img = cv2.imread('example.jpg') print(img.shape) # (高, 宽, 通道数) print(img.dtype) # 数据类型,例如 uint8


了解 `shape` 和 `dtype` 是编写健壮图像处理代码的第一步。

## 2. 像素与颜色空间

### 2.1 像素值的含义
在 OpenCV 中,默认读取的图像是 **BGR 格式**(蓝、绿、红),而非更常见的 RGB。这是一点重要的历史遗留差异,操作时需特别留意。

- 对于 8 位图像,B、G、R 三个通道的取值范围均为 0 - 255。
- 对于灰度图像,只有一个通道,直接表示亮度。

### 2.2 常用颜色空间转换
颜色空间是组织和描述色彩的方式。除了 BGR,以下三种空间在计算机视觉任务中非常实用:

- **灰度 (GRAY)**:将彩色图转为单通道亮度图,常用于边缘检测、阈值处理等。
- **HSV**:色相(H)、饱和度(S)、明度(V)。适合用于颜色分割(例如提取某一特定颜色的物体)。
- **Lab**:更接近人眼感知,L 通道表示亮度,a 和 b 表示颜色对立维度。

转换方法:

```python
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
hsv  = cv2.cvtColor(img, cv2.COLOR_BGR2HSV)

熟练掌握颜色空间转换是进行复杂视觉任务的基础。

3. 图像的基本 I/O:读取、显示与保存

这是每个 OpenCV 程序的起点和终点。

3.1 读取图像

img = cv2.imread('path/to/image.jpg')

如果路径错误,imgNone。实际项目中务必检查返回值。

3.2 显示图像

cv2.imshow('Window Title', img)
cv2.waitKey(0)          # 等待按键,0 表示无限等待
cv2.destroyAllWindows()

3.3 保存图像

cv2.imwrite('output.png', img)

imwrite 会根据文件扩展名自动选择压缩格式。

4. 区域操作与 ROI(感兴趣区域)

很多任务不需要处理整幅图像,而只关心某个局部。OpenCV 通过切片(numpy 数组操作)直接提取 ROI。

# 假设 img 是一张 BGR 图像
roi = img[100:300, 200:400]   # 提取行 100~300,列 200~400 的区域

对 ROI 的修改会直接反映到原图上,因为它们共享同一块数据内存。如果想要独立副本,需使用 .copy() 方法。

ROI 常用于人脸检测、目标跟踪等场景中的局部处理。

5. 基本图像操作

5.1 算术运算与亮度调节

图像之间可以直接使用 +- 运算符,但更好的方式是使用 cv2.add()cv2.subtract(),因为它们会自动进行饱和运算(超过 255 时截断为 255,低于 0 时截断为 0,防止溢出)。

bright = cv2.add(img, 50)        # 整体提亮
dark   = cv2.subtract(img, 50)   # 整体变暗

5.2 图像混合

将两幅图像按权重叠加:

blend = cv2.addWeighted(img1, 0.7, img2, 0.3, 0)

5.3 按位操作

cv2.bitwise_and()cv2.bitwise_or() 等操作通常与掩膜(mask)配合使用,实现图像的局部替换或提取。

6. 阈值处理:图像的二值化

阈值(Threshold)是将灰度图转换为二值图的关键操作,广泛用于物体分割和轮廓检测。

6.1 简单阈值

ret, thresh = cv2.threshold(gray, 127, 255, cv2.THRESH_BINARY)

所有灰度值大于 127 的像素设为 255(白色),其余设为 0(黑色)。

6.2 自适应阈值与 Otsu

  • 自适应阈值 适合光照不均匀的图像,阈值由像素周围区域计算得出。
  • Otsu 阈值 自动计算最佳全局阈值,适合前景与背景有明显双峰直方图的图像。
th_otsu = cv2.threshold(gray, 0, 255, cv2.THRESH_BINARY + cv2.THRESH_OTSU)

7. 图像平滑与滤波

在消除噪声、提取轮廓前,常常需要对图像进行平滑处理。

7.1 均值滤波

用一块区域内的像素平均值替换中心像素,速度快但会模糊边缘。

blur = cv2.blur(img, (5,5))

7.2 高斯滤波

权重按照高斯分布分配,中心像素权重更高,去噪的同时更好地保留边缘信息。

gauss = cv2.GaussianBlur(img, (5,5), 0)

7.3 中值滤波

用区域内像素中值替换中心值,对椒盐噪声效果显著。

median = cv2.medianBlur(img, 5)

8. 边缘检测:Canny 算法

边缘是指图像中亮度变化剧烈的区域。Canny 边缘检测是一种经典的多级算法,使用方便且效果稳定。

edges = cv2.Canny(image, threshold1, threshold2)
  • threshold1threshold2 是两个滞后阈值,边缘梯度高于高阈值时确定为边缘,低于低阈值时舍弃,介于两者之间的则根据连接情况判断。

通常在执行 Canny 之前,会先用高斯滤波平滑图像,以减少噪声产生的伪边缘。

9. 轮廓:形状分析与目标检测的基石

轮廓是一系列连续的边缘点,可以表示物体的外边界。

9.1 查找轮廓

contours, hierarchy = cv2.findContours(thresh, cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE)
  • thresh 是一幅二值图像(通常来自阈值或边缘检测输出)。
  • 返回的 contours 是一个列表,每个元素是一组点坐标。

9.2 绘制轮廓

cv2.drawContours(img, contours, -1, (0,255,0), 3)

9.3 轮廓特征提取

对于每个轮廓,可以计算面积、周长、外接矩形、质心等:

area = cv2.contourArea(cnt)
x, y, w, h = cv2.boundingRect(cnt)

这些特征是进行形状识别、物件计数的核心手段。

10. 视频处理入门

OpenCV 同样可以处理视频流(来自文件或摄像头),其核心概念与图像处理完全一致——视频本质上是一帧一帧的图像序列。

10.1 捕捉视频

cap = cv2.VideoCapture(0)          # 0 表示默认摄像头
while cap.isOpened():
    ret, frame = cap.read()
    if not ret:
        break
    # 在此对 frame 进行图像处理
    cv2.imshow('frame', frame)
    if cv2.waitKey(1) & 0xFF == ord('q'):
        break
cap.release()
cv2.destroyAllWindows()