1. 图像处理基础:像素与色彩空间、图像数字化与存储格式、OpenCV环境搭建与基本操作
各位同学好,欢迎来到《图像处理算法优化与摄像头调优》的第一章。
说实话,我见过太多人一上来就调算法、跑模型,结果连一张图片在内存里长什么样都说不清楚。这就像盖楼不打地基——迟早要塌。今天咱们就把这块地基夯实了。
1.1 像素——图像的最小单元
一张数字图像,说白了就是一个二维数组。数组里的每个元素,就是一个像素。
我习惯把像素想象成马赛克瓷砖。你离远了看,是一幅完整的画;凑近了看,就是一个个小方块。每个小方块都有自己的颜色值。
核心概念:像素是图像的基本采样单元。每个像素存储一个数值(灰度图)或一组数值(彩色图),代表该位置的亮度或颜色信息。
举个例子,一张 640×480 的灰度图,就是 640 列、480 行的矩阵。每个格子存一个 0~255 的整数,0 代表纯黑,255 代表纯白。就这么简单。
我的经验:做嵌入式视觉时,我经常把图像分辨率记成「宽×高×通道数」。比如 640×480×3 就是一张彩色图。这个习惯帮我避免了很多内存越界的坑。
1.2 色彩空间——计算机怎么「看」颜色
人眼感知颜色靠的是三种视锥细胞。计算机呢?它靠的是色彩空间模型。
1.2.1 RGB 色彩空间
最常用的就是 RGB。红、绿、蓝三个通道,每个通道 0~255,组合出 1600 多万种颜色。显示器、摄像头传感器,基本都是 RGB 的天下。
但 RGB 有个问题——它跟人眼的感知方式不太匹配。你调高红色分量,人眼感觉到的亮度变化并不线性。这就引出了下一个模型。
1.2.2 YUV / YCbCr 色彩空间
YUV 把亮度(Y)和色度(U、V)分开。这个设计很聪明——人眼对亮度敏感,对颜色不敏感。所以视频压缩时可以多保留 Y 的信息,少保留 UV 的信息,画质损失不大。
我记得第一次做摄像头驱动时,发现采集到的数据是 YUYV 格式,直接当 RGB 显示,颜色全乱套了。嗯,从那以后我再也不敢忽略色彩空间转换了。
1.2.3 HSV 色彩空间
HSV 把颜色拆成色调(H)、饱和度(S)、明度(V)。做颜色识别时特别好用——你想找红色物体,直接限定 H 的范围就行,不受光照变化影响。
| 色彩空间 | 通道含义 | 典型应用 | 我的建议 |
|---|---|---|---|
| RGB | 红、绿、蓝 | 显示、传感器原始数据 | 做显示用,做分析别用 |
| YUV/YCbCr | 亮度、蓝色差、红色差 | 视频编码、摄像头输出 | 嵌入式摄像头默认格式 |
| HSV | 色调、饱和度、明度 | 颜色识别、图像分割 | 颜色检测首选 |
| 灰度 | 单通道亮度 | 边缘检测、二值化 | 省内存、速度快 |
1.3 图像数字化与存储格式
模拟信号怎么变成数字图像?这个过程叫数字化,包含两步:采样和量化。
- 空间采样:决定图像的分辨率。采样越密,细节越多,文件也越大。
- 幅度量化:决定每个像素的位深。8 位就是 256 级灰度,10 位就是 1024 级。
你想想看,一张 12 位深度的 RAW 图,比 8 位的 JPEG 包含更多细节。但代价是文件体积翻倍。这就是为什么专业相机拍 RAW,手机默认拍 JPEG——存储和画质的取舍。
1.3.1 常见图像存储格式
| 格式 | 压缩方式 | 特点 | 适用场景 |
|---|---|---|---|
| BMP | 无压缩 | 文件大,读取快 | 学习调试用 |
| JPEG | 有损压缩 | 文件小,有块效应 | 网络传输、存储 |
| PNG | 无损压缩 | 支持透明通道 | UI、图标、需要保真的场景 |
| RAW | 传感器原始数据 | 未处理,位深高 | 专业摄影、ISP 调试 |
避坑指南:我曾经在项目中直接用 JPEG 做边缘检测,结果压缩带来的块效应导致检测结果全是假边缘。后来换成 PNG 或 BMP 就正常了。记住——有损压缩会破坏像素的原始关系,做图像分析时尽量用无损格式。
1.4 知识体系总览
下面这张图把本章的核心知识点串起来了。你可以把它当作整个课程的「地图」——后面每一章都会在这张图上展开。
1.5 OpenCV 环境搭建与基本操作
理论说完了,咱们来点实际的。OpenCV 是图像处理领域最常用的库,没有之一。我这些年做过的项目,从手机摄像头调优到工业检测,几乎都离不开它。
1.5.1 安装 OpenCV
Python 环境下,安装就一行命令:
pip install opencv-python opencv-contrib-python
如果你用 C++,建议从源码编译,这样能开启优化选项。我个人习惯在 Linux 下编译时加上 -DCMAKE_BUILD_TYPE=RELEASE 和 -DWITH_TBB=ON,速度能快不少。
小技巧:安装后运行 python -c "import cv2; print(cv2.__version__)" 验证。如果看到版本号,说明装好了。
1.5.2 读取、显示、保存图像
这是 OpenCV 最基础的三板斧。看代码:
import cv2
# 读取图像
img = cv2.imread('lena.jpg')
# 显示图像
cv2.imshow('My Image', img)
cv2.waitKey(0) # 等待按键
cv2.destroyAllWindows() # 关闭窗口
# 保存图像
cv2.imwrite('output.jpg', img)
这里有个坑——imread 默认以 BGR 顺序读取,不是 RGB。我第一次用 OpenCV 时,用 matplotlib 显示图像,颜色全偏蓝。后来才反应过来,OpenCV 的默认色彩空间是 BGR。
重要提醒:OpenCV 使用 BGR 顺序!如果你用其他库(如 matplotlib)显示,记得先转换:img_rgb = cv2.cvtColor(img, cv2.COLOR_BGR2RGB)。
1.5.3 访问和修改像素
图像在 OpenCV 里就是 NumPy 数组。访问像素就像操作矩阵:
import cv2
import numpy as np
# 创建一个 300x300 的红色图像
img = np.zeros((300, 300, 3), dtype=np.uint8)
img[:, :] = (0, 0, 255) # BGR 顺序,所以 (0,0,255) 是红色
# 访问 (100, 100) 处的像素
(b, g, r) = img[100, 100]
print(f"B:{b}, G:{g}, R:{r}")
# 修改某个区域
img[50:150, 50:150] = (255, 0, 0) # 蓝色方块
你想想看,掌握了像素级别的操作,后面做滤波、边缘检测、形态学处理,其实都是在操作这些数值。
1.5.4 色彩空间转换
前面讲了那么多色彩空间,现在用代码实现一下:
import cv2
img = cv2.imread('lena.jpg')
# 转灰度
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
# 转 HSV
hsv = cv2.cvtColor(img, cv2.COLOR_BGR2HSV)
# 转 YUV
yuv = cv2.cvtColor(img, cv2.COLOR_BGR2YUV)
做颜色识别时,我几乎只用 HSV。比如检测红色:
import cv2
import numpy as np
img = cv2.imread('red_ball.jpg')
hsv = cv2.cvtColor(img, cv2.COLOR_BGR2HSV)
# 红色在 HSV 中的范围
lower_red = np.array([0, 50, 50])
upper_red = np.array([10, 255, 255])
mask = cv2.inRange(hsv, lower_red, upper_red)
cv2.imshow('Red Mask', mask)
cv2.waitKey(0)
核心要点:色彩空间转换是图像预处理的第一步。选对色彩空间,后续处理事半功倍。做检测用 HSV,做压缩用 YUV,做显示用 RGB——这是铁律。
1.6 本章小结
这一章我们走完了图像处理的「第一公里」:
- 理解了像素是图像的基本单元
- 掌握了RGB、YUV、HSV三种色彩空间的特点和用途
- 明白了数字化的两个关键步骤:采样和量化
- 区分了BMP、JPEG、PNG、RAW等存储格式的适用场景
- 搭建了OpenCV环境,学会了读写显示和像素操作
这些基础看似简单,但我在实际项目中见过太多人在这里栽跟头。色彩空间搞错、像素位深忽略、格式选错——每一个都是实打实的 bug。希望你能把这些基础打牢,后面的路会顺畅很多。