3、图像基础与OpenCV入门:图像在计算机中的表示
各位同学,欢迎来到第三章。这一章我们聊聊图像在计算机里到底长什么样。说实话,很多初学者上来就调API,结果连图像是啥都没搞明白。我当年也踩过这个坑,调了半天代码,图像显示出来全是花的,后来才发现是通道顺序搞反了。
好,咱们从头说起。
3.1 图像在计算机中的表示
3.1.1 像素——图像的最小单元
你想想看,一张照片在电脑里是什么?说白了,就是一个巨大的数字矩阵。每个小格子就是一个像素(Pixel)。每个像素记录着那个位置的颜色信息。
举个例子,一张 640×480 的图像,就是 640 列、480 行的像素点阵。总共 307200 个像素。每个像素都有自己的颜色值。
核心概念:图像 = 矩阵。每个元素 = 像素。
3.1.2 通道——颜色的维度
一个像素怎么表示颜色?这就要说到通道了。
- 灰度图:1个通道。每个像素值 0~255,0是黑,255是白。
- 彩色图(RGB):3个通道。R(红)、G(绿)、B(蓝)。
- 带透明度的图(RGBA):4个通道。多了一个Alpha通道表示透明度。
我在项目中遇到过一个问题:用OpenCV读彩色图,结果用matplotlib显示出来颜色不对。后来才发现,OpenCV默认是BGR顺序,不是RGB。嗯,这里要注意,这是个经典坑。
避坑指南:OpenCV读取彩色图像时,通道顺序是BGR,不是RGB。显示前记得转换。
3.1.3 色彩空间——颜色的不同表达方式
除了RGB,还有别的色彩空间。常用的有:
| 色彩空间 | 说明 | 常见用途 |
|---|---|---|
| RGB | 红绿蓝三通道 | 显示器、相机 |
| HSV | 色调、饱和度、明度 | 颜色分割、物体跟踪 |
| GRAY | 单通道灰度 | 边缘检测、特征提取 |
| LAB | 亮度、绿红、蓝黄 | 颜色校正、图像增强 |
我个人习惯在做颜色相关的任务时,先用HSV。为什么?因为HSV把颜色和亮度分开了,做阈值分割特别方便。RGB里你想分割红色,R通道高、G和B低,但光照一变就全乱了。HSV里只看H通道就行,稳定得多。
3.2 OpenCV核心数据结构:Mat
OpenCV里最核心的数据结构就是Mat。说白了,Mat就是一个N维数组,专门用来存图像。
Mat里存了什么?
- 图像的宽、高
- 通道数
- 数据类型(比如CV_8UC3表示8位无符号、3通道)
- 像素数据本身
小技巧:Mat的data属性指向实际的像素内存。操作大图像时,注意深拷贝和浅拷贝的区别。直接用等号赋值是浅拷贝,修改一个会影响另一个。
3.3 图像读取、显示、保存
这部分是基本功,我直接上代码。
3.3.1 读取图像
import cv2
# 读取彩色图
img = cv2.imread('photo.jpg')
# 读取灰度图
img_gray = cv2.imread('photo.jpg', cv2.IMREAD_GRAYSCALE)
# 读取带透明通道的图
img_unchanged = cv2.imread('photo.jpg', cv2.IMREAD_UNCHANGED)
我曾经犯过一个错:路径里有中文,结果读出来是None。OpenCV的imread不支持中文路径。解决办法是用numpy先读,再解码。
3.3.2 显示图像
cv2.imshow('窗口标题', img)
cv2.waitKey(0) # 等待按键
cv2.destroyAllWindows()
waitKey(0)的意思是无限等待按键。如果你不写这行,窗口一闪就没了。嗯,这个坑我也踩过。
3.3.3 保存图像
cv2.imwrite('output.jpg', img)
保存时可以通过参数控制图片质量。比如JPEG的压缩质量:
cv2.imwrite('output.jpg', img, [cv2.IMWRITE_JPEG_QUALITY, 95])
注意:imwrite也支持中文路径?不支持。和imread一样的问题。建议用英文路径,或者用os.path处理。
3.4 图像属性获取
拿到图像后,我们经常需要知道它的基本信息。Mat对象提供了几个常用属性:
import cv2
img = cv2.imread('photo.jpg')
# 获取图像形状 (高, 宽, 通道数)
print(img.shape) # 例如 (480, 640, 3)
# 获取像素总数
print(img.size) # 480 * 640 * 3 = 921600
# 获取数据类型
print(img.dtype) # uint8
shape返回的是一个元组。灰度图只有两个值:(高, 宽)。彩色图有三个:(高, 宽, 通道数)。
我建议你拿到图像后,第一件事就是打印shape。这能帮你快速确认图像有没有正确加载,通道数对不对。
3.5 实战小例子
咱们来个小练习,把上面学的串起来:
import cv2
# 1. 读取图像
img = cv2.imread('cat.jpg')
# 2. 获取属性
h, w, c = img.shape
print(f'宽: {w}, 高: {h}, 通道: {c}')
# 3. 转成灰度图
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
# 4. 显示原图和灰度图
cv2.imshow('Original', img)
cv2.imshow('Gray', gray)
# 5. 保存灰度图
cv2.imwrite('cat_gray.jpg', gray)
cv2.waitKey(0)
cv2.destroyAllWindows()
这个例子虽然简单,但涵盖了图像处理的基本流程:读→处理→显示→保存。你想想看,后面所有的项目,本质上都是这个流程的扩展。
个人经验:刚开始学的时候,我建议你多打印shape和dtype。这能帮你建立对图像数据的直觉。等你熟练了,看一眼代码就知道数据长什么样。
好,这一章就到这里。下一章我们聊聊图像的基本操作——裁剪、缩放、旋转。这些是图像预处理的基础,也是实际项目里最常用的操作。
公众号:蓝海资料掘金营,微信deep3321