3、计算机视觉基础:图像表示与色彩空间、滤波与边缘检测、特征点提取

好,咱们进入正题。计算机视觉说白了,就是让机器看懂图像。但机器看到的不是「画面」,而是一堆数字。这一章,我会带你把这些数字背后的逻辑理清楚。

3.1 图像表示:从像素到矩阵

一张彩色图片,在计算机里就是三个二维矩阵的叠加。每个矩阵对应一个颜色通道——红、绿、蓝。每个像素的值在 0 到 255 之间,0 代表最暗,255 代表最亮。

举个例子,一张 640×480 的彩色图片,它的形状就是 (480, 640, 3)。480 是高度,640 是宽度,3 是通道数。灰度图就简单了,只有一个通道,形状是 (480, 640)。

我个人习惯用 OpenCV 读图,默认是 BGR 顺序,不是 RGB。这个坑我踩过好几次,后面会细说。

核心概念: 图像 = 矩阵 + 通道。理解这一点,后面的所有操作都是对矩阵做数学变换。

3.2 色彩空间:RGB 与 HSV

RGB 是最常用的色彩空间,但它有个问题——对光照变化特别敏感。你想想看,同一个物体,在强光和弱光下,RGB 值会差很多。这就导致做颜色识别时特别容易误判。

所以,我更喜欢用 HSV 色彩空间。H 是色调,S 是饱和度,V 是明度。色调基本不受光照影响,这就稳多了。

色彩空间 适用场景 我的经验
RGB 图像显示、存储 做颜色识别时慎用,光照一变就崩
HSV 颜色分割、目标检测 我项目中做交通灯识别,全靠 HSV 搞定

转换代码很简单,OpenCV 一行搞定:

import cv2
img = cv2.imread('image.jpg')
hsv = cv2.cvtColor(img, cv2.COLOR_BGR2HSV)
小技巧: HSV 的 H 范围是 0-179,不是 0-255。我第一次用的时候没注意,结果颜色死活分割不出来,排查了半天。

3.3 图像滤波:去噪与平滑

滤波的本质,就是用一个「窗口」在图像上滑动,对窗口内的像素做加权平均。最常见的三种:均值滤波、高斯滤波、中值滤波。

  • 均值滤波: 简单粗暴,所有像素权重一样。速度快,但会模糊边缘。
  • 高斯滤波: 中心权重高,边缘权重低。效果比均值好,我一般默认用这个。
  • 中值滤波: 取窗口内像素的中位数。对付椒盐噪声特别有效。

我曾经在一个项目中,摄像头有坏点,图像上全是白点。用中值滤波,一个 3×3 的窗口,直接搞定。高斯滤波反而越滤越花。

# 高斯滤波,核大小 5x5
blurred = cv2.GaussianBlur(img, (5, 5), 0)

# 中值滤波,核大小 5
median = cv2.medianBlur(img, 5)
注意: 滤波核大小必须是奇数。3、5、7 都行。偶数核会偏移中心,结果不对。

3.4 边缘检测:Sobel 与 Canny

边缘,就是图像中像素值剧烈变化的地方。怎么找?用导数。Sobel 算子就是计算一阶导数的近似值。

Sobel 分 X 方向和 Y 方向。X 方向检测垂直边缘,Y 方向检测水平边缘。我一般会两个方向都算,然后取绝对值相加。

sobel_x = cv2.Sobel(img, cv2.CV_64F, 1, 0, ksize=3)
sobel_y = cv2.Sobel(img, cv2.CV_64F, 0, 1, ksize=3)
sobel_combined = cv2.addWeighted(cv2.convertScaleAbs(sobel_x), 0.5,
                                 cv2.convertScaleAbs(sobel_y), 0.5, 0)

Canny 边缘检测就高级多了。它做了四步:去噪、算梯度、非极大值抑制、双阈值检测。效果比 Sobel 好很多,但参数需要调。

我个人习惯用 Canny 做预处理,然后 Sobel 做精细定位。双阈值怎么设?低阈值一般是高阈值的一半。比如高阈值 100,低阈值 50。

避坑指南: 我曾经在弱光环境下用 Canny,阈值设得太高,边缘全丢了。后来改成自适应阈值,才稳定下来。

3.5 特征点提取:SIFT 与 ORB

特征点,就是图像中「与众不同」的点。比如角点、斑点。这些点在不同视角、不同光照下都能被重复检测到,所以可以用来做图像匹配、目标跟踪。

SIFT 是经典中的经典。尺度不变、旋转不变、光照不变。但有个问题——它受专利保护,商用要付费。而且计算量很大,实时性差。

ORB 是 SIFT 的替代品。免费、速度快、效果也不错。我项目中做实时目标跟踪,基本都用 ORB。

算法 特点 适用场景
SIFT 精度高、尺度不变、专利限制 离线图像拼接、三维重建
ORB 速度快、免费、旋转不变 实时跟踪、移动端应用
# ORB 特征点提取
orb = cv2.ORB_create()
keypoints, descriptors = orb.detectAndCompute(img, None)

# 绘制特征点
img_with_kp = cv2.drawKeypoints(img, keypoints, None, color=(0,255,0))
我的建议: 如果做实时系统,优先用 ORB。如果做离线高精度匹配,用 SIFT。别纠结,选对工具比炫技重要。

3.6 本章知识体系

下面这张图,是我自己梳理的本章知识结构。你可以把它当作一张地图,随时回来对照。

计算机视觉基础:知识体系 图像表示 色彩空间 图像滤波 像素矩阵 + 通道 RGB / HSV 转换 均值 / 高斯 / 中值 边缘检测 特征点提取 Sobel 算子 / Canny 算法 SIFT(高精度) / ORB(实时) 目标:从像素到特征,为跟踪与检测打基础

嗯,这一章的内容就到这里。图像表示是地基,色彩空间是工具,滤波和边缘检测是预处理,特征点提取是核心。每一步都踩实了,后面做障碍物检测和跟踪才不会翻车。

可可精品资料库