1. 计算机视觉基础:图像形成与表示、颜色空间、图像滤波与边缘检测

1.1 图像是怎么来的?——图像形成模型

做视觉这么多年,我经常跟新人说一句话:理解图像怎么来的,比理解怎么处理它更重要。你想想看,如果你连一张照片是怎么形成的都不清楚,后面那些滤波、检测、分割,说白了都是在瞎调参数。

图像形成,本质上是一个物理过程。光从光源出发,打到物体表面,反射后进入相机镜头,经过传感器采样,最终变成我们看到的像素矩阵。这里面有几个关键环节:

  • 光源:自然光(太阳)或人造光(灯泡),决定了场景的亮度和色温
  • 物体反射:不同材质反射率不同,金属反射强,布料反射弱
  • 镜头成像:小孔成像模型的升级版,引入了畸变、景深等现实问题
  • 传感器采样:CCD/CMOS把光信号转成电信号,再量化成数字值

核心公式(简化版):

像素值 = 光源强度 × 物体反射率 × 传感器灵敏度 + 噪声

嗯,这个公式虽然简单,但几乎所有图像处理算法都绕不开它。

我在项目中遇到过一件事:有一次做工业缺陷检测,白天晚上拍出来的图片亮度差异巨大,算法直接崩了。后来才发现,我们只考虑了物体反射率,完全没管光源变化。从那以后,我养成了一个习惯——做任何视觉项目,先搞清楚光照条件

1.2 图像的数学表示

图像在计算机里怎么存的?说白了就是一个二维数组。灰度图是单通道,每个像素0-255;彩色图是三个通道(RGB),每个通道也是0-255。

举个例子,一张640×480的彩色图像,它的形状是(480, 640, 3)。480行,640列,3个颜色通道。你想想看,这其实就是把三维空间的信息压缩到了二维平面上。

# 用Python表示一张图像
import numpy as np

# 创建一个100x100的红色图像
height, width = 100, 100
red_image = np.zeros((height, width, 3), dtype=np.uint8)
red_image[:, :, 0] = 255  # R通道设为255
red_image[:, :, 1] = 0    # G通道设为0
red_image[:, :, 2] = 0    # B通道设为0

我的小建议:刚入门时,别急着调库。自己手动写一个图像读取、显示、保存的流程,哪怕只用OpenCV的几行代码,也能帮你建立「图像就是数组」这个直觉。

1.3 颜色空间——不只是RGB

RGB是最常见的颜色表示方式,但它不是万能的。我个人习惯把颜色空间分成三类:

颜色空间 特点 典型应用
RGB 直观,硬件友好 显示、存储
HSV/HSL 色调、饱和度、亮度分离 颜色分割、目标跟踪
Lab 感知均匀,与设备无关 颜色匹配、图像增强

为什么会需要这么多颜色空间?我举个例子。你在做交通灯检测时,用RGB去提取红色,光照一变就完蛋。但换成HSV,只看H(色调)通道,红色就是红色,不管它亮还是暗。这就是颜色空间选择的重要性。

我曾经踩过的坑:有一次做肤色检测,直接用RGB阈值,结果在黄光下全偏了。后来换成YCbCr空间,只取Cb和Cr两个色度通道,效果立马好了。记住:做颜色相关任务,先想想哪个空间最合适

1.4 图像滤波——让图像变干净

滤波,说白了就是「邻居投票」。每个像素的值,由它周围像素共同决定。为什么要这么做?因为图像里有噪声,我们需要平滑掉那些「不和谐」的点。

常见的滤波方式有:

  • 均值滤波:取邻域平均值,简单粗暴,但会模糊边缘
  • 高斯滤波:加权平均,中心权重高,边缘权重低,效果更自然
  • 中值滤波:取中位数,对椒盐噪声特别有效
  • 双边滤波:同时考虑空间距离和像素差异,能保边去噪
# OpenCV中的滤波示例
import cv2
import numpy as np

img = cv2.imread('image.jpg')

# 高斯滤波
gaussian = cv2.GaussianBlur(img, (5, 5), 1.5)

# 中值滤波
median = cv2.medianBlur(img, 5)

# 双边滤波
bilateral = cv2.bilateralFilter(img, 9, 75, 75)

面试常问:高斯滤波的核大小和sigma怎么选?我的经验是:核大小取sigma的3倍左右,比如sigma=1.5,核大小取5×5。太小了去噪不够,太大了图像糊成一片。

1.5 边缘检测——找到图像的「骨架」

边缘是什么?说白了就是像素值发生剧烈变化的地方。你想想看,一张图像里最有信息量的部分,往往就是这些边缘——物体的轮廓、纹理的边界、光影的分界线。

边缘检测的核心思想是求导数。一阶导数的极大值对应边缘,二阶导数的过零点也对应边缘。常用的算子有:

  • Sobel算子:一阶导数,分水平和垂直方向
  • Laplacian算子:二阶导数,对噪声敏感
  • Canny边缘检测:多阶段优化,目前最常用的方法

Canny算法是我个人最喜欢的边缘检测方法。它做了四件事:

  1. 高斯滤波去噪
  2. 计算梯度幅值和方向
  3. 非极大值抑制(只保留梯度方向上的局部最大值)
  4. 双阈值检测(高阈值确定强边缘,低阈值连接弱边缘)
# Canny边缘检测
edges = cv2.Canny(img, threshold1=50, threshold2=150)

# 参数调优建议
# threshold1和threshold2的比例一般在1:2到1:3之间
# 我习惯先试(50, 150),效果不好再调

避坑指南:我曾经在项目里直接用Canny的默认参数,结果边缘断断续续的。后来发现,先做一次高斯滤波,再调低threshold1的值,边缘就连起来了。记住:预处理比算法本身更重要。

1.6 本章小结

这一章的内容,说白了就是视觉算法的「地基」。图像形成让你知道数据从哪来,颜色空间让你知道怎么表示,滤波让你知道怎么去噪,边缘检测让你知道怎么提取特征。这四个知识点,几乎贯穿了所有计算机视觉任务。

我个人建议:别急着跑深度学习模型。先把这些基础操作手写一遍,用Python的numpy实现均值滤波、Sobel边缘检测,哪怕慢一点,也能帮你建立扎实的直觉。面试的时候,面试官问这些基础问题,你如果能从物理原理讲到工程实践,那基本就稳了。

下一章我们会聊特征提取与描述子,也就是怎么从图像里找到「关键点」。到时候再细聊。