2、图像基础操作:图像的读取、显示、保存,像素操作,色彩空间转换
好,咱们正式开始动手了。
这一章,说白了就是 OpenCV 的「基本功」。你想想看,不管后面要做多复杂的目标检测、多炫酷的跟踪算法,第一步永远是把图像弄进来、看一眼、存起来。然后才能谈得上处理。
我个人习惯,拿到一张图,先做三件事:读进来、显示出来、检查一下像素值。这三步走顺了,心里才有底。
2.1 图像的读取:imread() 的坑与妙用
读取图像,用的是 cv2.imread()。这函数看着简单,但我在项目中遇到过不少坑。
import cv2
# 默认以彩色模式读取
img = cv2.imread('cat.jpg')
# 以灰度模式读取
img_gray = cv2.imread('cat.jpg', cv2.IMREAD_GRAYSCALE)
# 读取包含透明通道的图像
img_unchanged = cv2.imread('cat.png', cv2.IMREAD_UNCHANGED)
这里有个关键点,很多人一开始不知道——OpenCV 默认读取的是 BGR 格式,不是 RGB。嗯,这里要注意,后面做色彩空间转换时会用到。
另外,imread() 如果读不到文件,不会抛异常,而是返回 None。所以安全写法是:
img = cv2.imread('cat.jpg')
if img is None:
print("图片没读到,检查路径!")
exit()
2.2 图像的显示:imshow() 与窗口管理
读进来了,总得看一眼吧?用 cv2.imshow()。
cv2.imshow('My Window', img)
cv2.waitKey(0) # 等待按键
cv2.destroyAllWindows()
为什么会这样?waitKey(0) 的意思是无限等待键盘输入。你不加这一行,窗口一闪就没了。我刚开始学的时候,窗口闪一下消失,还以为代码写错了。
cv2.WINDOW_NORMAL 标志:
cv2.namedWindow('My Window', cv2.WINDOW_NORMAL)
cv2.imshow('My Window', img)
这样窗口就可以用鼠标拖拽缩放了。
2.3 图像的保存:imwrite() 的格式控制
处理完了,得存起来。用 cv2.imwrite()。
cv2.imwrite('output.jpg', img)
# 控制 JPEG 质量(0-100,默认95)
cv2.imwrite('output_high.jpg', img, [cv2.IMWRITE_JPEG_QUALITY, 95])
# 控制 PNG 压缩级别(0-9,默认3)
cv2.imwrite('output_lossless.png', img, [cv2.IMWRITE_PNG_COMPRESSION, 0])
我个人习惯,做实验时用 PNG 保存,因为无损。最终交付时再用 JPEG 压缩,节省空间。
2.4 像素操作:图像的「细胞」
图像是什么?说白了就是一个多维数组。每个像素点就是一个数值。
对于灰度图,每个像素是 0-255 的数值。0 是黑,255 是白。
对于彩色图,每个像素是三个数值(B、G、R)。
# 获取像素值
pixel = img[100, 200] # 第100行,第200列的像素
print(pixel) # 彩色图返回 [B, G, R]
# 修改像素值
img[100, 200] = [255, 0, 0] # 改成蓝色
# 获取单通道值
blue_value = img[100, 200, 0] # 第0通道(B通道)
我记得有一次做目标检测的标注,画矩形框时死活对不上位置。查了半天,才发现是行列顺序搞反了。从那以后,我每次写像素操作都会默念一遍:先 y 后 x,先行后列。
2.5 色彩空间转换:BGR、RGB、HSV、灰度
这是图像处理里最基础也最重要的操作之一。
2.5.1 BGR 与 RGB
前面说了,OpenCV 默认是 BGR。但很多其他库(比如 matplotlib)用的是 RGB。所以显示时经常需要转换。
# BGR 转 RGB
img_rgb = cv2.cvtColor(img, cv2.COLOR_BGR2RGB)
# RGB 转 BGR
img_bgr = cv2.cvtColor(img_rgb, cv2.COLOR_RGB2BGR)
你想想看,如果你用 matplotlib 显示 OpenCV 读进来的图,颜色会偏蓝偏黄。就是因为 BGR 和 RGB 的通道顺序反了。
2.5.2 BGR 转灰度
灰度图只有亮度信息,没有颜色。很多算法(比如边缘检测、人脸识别)第一步就是转灰度,因为数据量小、处理快。
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
灰度转换的公式是:Gray = 0.299*R + 0.587*G + 0.114*B。嗯,人眼对绿色最敏感,所以绿色权重最高。
2.5.3 BGR 转 HSV
HSV 色彩空间,说白了就是把颜色拆成三部分:色调(H)、饱和度(S)、明度(V)。
为什么用 HSV?因为它在做颜色分割时特别好用。比如你要从一张图里找出红色的物体,在 BGR 空间里很难界定「什么是红」,但在 HSV 空间里,只需要设定 H 的范围就行。
hsv = cv2.cvtColor(img, cv2.COLOR_BGR2HSV)
# HSV 范围(OpenCV 中):
# H: 0-179
# S: 0-255
# V: 0-255
cv2.inRange() 配合 HSV 做掩码,效果比 BGR 好得多。比如检测红色:
lower_red = np.array([0, 50, 50])
upper_red = np.array([10, 255, 255])
mask = cv2.inRange(hsv, lower_red, upper_red)
2.6 综合示例:一个完整的图像处理流程
来,咱们把今天学的串起来。写一个完整的例子:
import cv2
import numpy as np
# 1. 读取图像
img = cv2.imread('cat.jpg')
if img is None:
print("图片没读到")
exit()
# 2. 显示原始图像
cv2.imshow('Original', img)
# 3. 转灰度并显示
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
cv2.imshow('Gray', gray)
# 4. 转 HSV 并显示
hsv = cv2.cvtColor(img, cv2.COLOR_BGR2HSV)
cv2.imshow('HSV', hsv)
# 5. 修改像素:在图像中心画一个蓝色方块
h, w = img.shape[:2]
center_y, center_x = h // 2, w // 2
img[center_y-10:center_y+10, center_x-10:center_x+10] = [255, 0, 0]
# 6. 保存修改后的图像
cv2.imwrite('cat_modified.jpg', img)
cv2.waitKey(0)
cv2.destroyAllWindows()
这个例子虽然简单,但涵盖了读取、显示、转换、像素操作、保存这五个核心步骤。你把它跑通了,图像基础操作就算入门了。
2.7 本章小结
| 操作 | 函数 | 注意事项 |
|---|---|---|
| 读取 | cv2.imread() | 路径不能有中文,返回 None 时不报错 |
| 显示 | cv2.imshow() | 必须配合 waitKey(),否则窗口一闪而过 |
| 保存 | cv2.imwrite() | JPEG 有损,PNG 无损 |
| 像素操作 | img[y, x] | 先 y 后 x,先行后列 |
| 色彩转换 | cv2.cvtColor() | OpenCV 默认 BGR,HSV 中 H 范围 0-179 |
嗯,这一章的内容就这些。说白了就是四个字:读、显、存、转。把这四个字练熟了,后面的章节你会走得很顺。
下一章,咱们聊聊图像的几何变换——缩放、旋转、仿射变换。到时候你会发现,像素操作和色彩空间转换的知识全都能用上。