2、图像基础与OpenCV入门:图像读取、显示、保存、色彩空间转换(BGR、灰度、HSV)、图像属性
好,我们正式开始动手了。这一章,我会带你走一遍OpenCV最基础的操作——说白了就是怎么把一张图片请进内存,怎么看它一眼,怎么改改它的颜色,最后再把它存回去。这些操作在车牌识别里会反复出现,所以别嫌简单,基础打牢了后面才不慌。
2.1 图像读取:imread() 的玄机
在OpenCV里,读取图像用的是 cv2.imread()。这个函数有两个参数:第一个是图片路径,第二个是读取模式。模式有三种最常用的:
| 模式 | 标志 | 说明 |
|---|---|---|
| 彩色 | cv2.IMREAD_COLOR 或 1 |
默认模式,读取为BGR三通道彩色图 |
| 灰度 | cv2.IMREAD_GRAYSCALE 或 0 |
读取为单通道灰度图 |
| 不变 | cv2.IMREAD_UNCHANGED 或 -1 |
包含Alpha通道(透明度) |
我个人习惯用数字标志,因为写起来快。但团队协作时建议用常量名,可读性更好。
import cv2
# 读取彩色图像
img_color = cv2.imread('car_plate.jpg', 1)
# 读取灰度图像
img_gray = cv2.imread('car_plate.jpg', 0)
# 读取包含Alpha通道的图像
img_unchanged = cv2.imread('car_plate.jpg', -1)
如果图片不存在,imread() 不会报错,而是返回 None。所以读取后最好检查一下:
if img is None:
print("图片没找到,检查路径!")
exit()
2.2 图像显示:imshow() 与窗口管理
显示图像用 cv2.imshow()。它创建一个窗口,把图像怼进去。配合 cv2.waitKey() 和 cv2.destroyAllWindows() 一起用。
cv2.imshow('车牌原图', img_color)
cv2.waitKey(0) # 等待按键,0表示无限等待
cv2.destroyAllWindows()
waitKey() 的参数是毫秒数。如果设为0,程序会一直停在那里,直到你按任意键。这个函数还会返回按键的ASCII码,后面做交互时会用到。
imshow() 可能会卡住。我建议用 cv2.imshow() 配合 cv2.waitKey(1) 来刷新窗口,或者干脆用matplotlib来显示。
2.3 图像保存:imwrite() 的格式秘密
保存图像用 cv2.imwrite()。第一个参数是保存路径,第二个参数是图像数据。OpenCV会根据文件扩展名自动选择编码格式。
cv2.imwrite('output.jpg', img_color)
cv2.imwrite('output.png', img_color)
保存JPG时可以控制质量:
cv2.imwrite('output_high.jpg', img_color, [cv2.IMWRITE_JPEG_QUALITY, 95])
质量范围是0-100,默认95。数值越大,文件越大,画质越好。车牌识别时我一般用95以上,因为车牌上的字符边缘不能有太多压缩伪影。
2.4 色彩空间转换:BGR、灰度、HSV
OpenCV默认读取的是BGR格式,不是我们熟悉的RGB。这一点特别容易搞混。我第一次用OpenCV显示图片时,发现颜色偏蓝,查了半天才发现是通道顺序的问题。
转换色彩空间用 cv2.cvtColor():
# BGR 转灰度
gray = cv2.cvtColor(img_color, cv2.COLOR_BGR2GRAY)
# BGR 转 HSV
hsv = cv2.cvtColor(img_color, cv2.COLOR_BGR2HSV)
# HSV 转 BGR
bgr = cv2.cvtColor(hsv, cv2.COLOR_HSV2BGR)
为什么车牌识别要用HSV?因为HSV把颜色信息(Hue)和亮度(Value)分开了。蓝色车牌在HSV空间里,H值集中在100-130之间。这样我们就能通过阈值直接提取蓝色区域,不受光照影响。
2.5 图像属性:shape、dtype、size
图像在OpenCV里就是一个NumPy数组。我们可以通过属性来了解它的结构:
print("图像形状:", img_color.shape) # (高度, 宽度, 通道数)
print("数据类型:", img_color.dtype) # uint8
print("像素总数:", img_color.size) # 高 * 宽 * 通道数
举个例子,一张1080x1920的彩色图:
shape返回(1080, 1920, 3)dtype返回uint8(0-255的整数)size返回1080 * 1920 * 3 = 6,220,800
灰度图只有两个维度:(1080, 1920)。这一点在处理时要特别注意,因为很多函数要求输入是单通道或三通道。
2.6 实战小练习:读取车牌并转换
我们来写一个完整的例子,把今天学的串起来:
import cv2
# 1. 读取车牌图像
plate = cv2.imread('blue_plate.jpg')
if plate is None:
print("图片加载失败")
exit()
# 2. 显示原图
cv2.imshow('原图', plate)
# 3. 转灰度
gray_plate = cv2.cvtColor(plate, cv2.COLOR_BGR2GRAY)
cv2.imshow('灰度图', gray_plate)
# 4. 转HSV
hsv_plate = cv2.cvtColor(plate, cv2.COLOR_BGR2HSV)
cv2.imshow('HSV图', hsv_plate)
# 5. 保存灰度图
cv2.imwrite('gray_plate.jpg', gray_plate)
# 6. 打印属性
print("原图属性:", plate.shape)
print("灰度图属性:", gray_plate.shape)
cv2.waitKey(0)
cv2.destroyAllWindows()
运行这段代码,你会看到三个窗口依次弹出。按任意键关闭。灰度图保存到了当前目录。
嗯,这一章的内容就到这里。图像读取、显示、保存、色彩空间转换、图像属性——这些是OpenCV的“呼吸”和“心跳”。后面每一章都会用到它们。下一章我们聊聊图像预处理,那是车牌识别里最花功夫的部分。
公众号:蓝海资料掘金营,微信deep3321