2、图像基础操作:图像的读取、显示与保存、像素操作、色彩空间转换
好,咱们正式开始动手了。
这一章,说白了就是 OpenCV 的「基本功」。你想想看,不管多复杂的文档扫描流程,第一步永远是把图像读进来。读不对,后面全白搭。我个人习惯,拿到一张图,先看看它的像素值,再确认一下色彩空间——嗯,心里有底了,才敢往下走。
2.1 图像的读取、显示与保存
OpenCV 读取图像,用的是 cv2.imread()。这个函数看着简单,但坑不少。我刚开始用的时候,就吃过它的亏。
import cv2
# 读取图像
img = cv2.imread('document.jpg')
# 显示图像
cv2.imshow('Document', img)
cv2.waitKey(0)
cv2.destroyAllWindows()
# 保存图像
cv2.imwrite('output.jpg', img)
这里有个关键点:imread() 默认读取的是 BGR 格式。不是 RGB,是 BGR!
另外,imread() 的第二个参数可以指定读取方式:
| 参数 | 含义 |
|---|---|
cv2.IMREAD_COLOR |
默认,读取彩色图(BGR) |
cv2.IMREAD_GRAYSCALE |
读取为灰度图 |
cv2.IMREAD_UNCHANGED |
保留 Alpha 通道 |
显示图像时,waitKey(0) 的意思是「一直等待,直到用户按键」。这个 0 很关键——如果你写成 waitKey(1),窗口会闪一下就消失。嗯,这里要注意。
2.2 像素操作
图像是什么?说白了,就是一个二维数组。每个元素就是一个像素。彩色图的每个像素,又包含 B、G、R 三个通道的值。
我习惯把像素操作分成两类:读像素 和 写像素。
2.2.1 读取像素值
import cv2
import numpy as np
img = cv2.imread('document.jpg')
# 读取 (100, 200) 位置的像素
px = img[100, 200]
print(px) # 输出 [B, G, R] 值
# 只读取蓝色通道
blue = img[100, 200, 0]
print(blue)
你想想看,为什么是 [100, 200] 而不是 [200, 100]?因为 OpenCV 的坐标是 (行, 列),也就是 (y, x)。这一点和很多图像处理库不一样。我刚开始也经常搞混,后来干脆在代码里加了个注释:# 注意:先y后x。
2.2.2 修改像素值
# 将 (100, 200) 位置的像素设为白色
img[100, 200] = [255, 255, 255]
# 批量修改:将左上角 50x50 区域设为红色
img[0:50, 0:50] = [0, 0, 255]
img[:, :, 0] = 0 就行。我在处理高分辨率文档扫描图时,这个技巧能省下好几秒。
2.3 色彩空间转换
色彩空间转换,是文档扫描中绕不开的一步。为什么?因为很多 OCR 算法对灰度图或者二值图效果更好。你想想看,彩色图里那些花里胡哨的背景,对 OCR 来说全是噪音。
2.3.1 BGR 转灰度
这是最常用的转换。说白了,就是把彩色图变成黑白图。
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
灰度图只有一个通道,取值范围 0(黑)到 255(白)。
2.3.2 BGR 转 RGB
这个转换,我几乎每次做项目都会用到。因为 OpenCV 是 BGR,而很多其他库(比如 matplotlib、PIL)用的是 RGB。
rgb = cv2.cvtColor(img, cv2.COLOR_BGR2RGB)
2.3.3 其他常用转换
| 转换类型 | 代码 | 用途 |
|---|---|---|
| BGR → HSV | cv2.COLOR_BGR2HSV |
颜色分割、物体检测 |
| BGR → LAB | cv2.COLOR_BGR2LAB |
颜色校正、图像增强 |
| BGR → YUV | cv2.COLOR_BGR2YUV |
视频处理、压缩 |
我个人在文档扫描中,最常用的是 BGR→灰度。偶尔遇到光照不均匀的文档,我会先转成 LAB,然后对 L 通道做直方图均衡化——效果比直接处理 BGR 好很多。
2.4 实战小技巧
好,理论说完了,咱们来点实际的。我总结了几条写代码时的习惯,分享给你:
- 读完图先检查:
if img is None: print('图片没读进来')。路径写错了、文件损坏了,OpenCV 不会报错,只会返回 None。我吃过这个亏,debug 了半小时才发现是路径少了个斜杠。 - 显示图像时加个标题:
cv2.imshow('Original', img)。窗口多了容易搞混,标题能救命。 - 保存时注意格式:
cv2.imwrite('output.png', img)会保存为 PNG,无损压缩。如果是 JPEG,可以指定质量:cv2.imwrite('output.jpg', img, [cv2.IMWRITE_JPEG_QUALITY, 90])。 - 批量处理时用循环:比如你要把一整个文件夹的图片都转成灰度,写个 for 循环,配合
os.listdir(),几分钟搞定。
shape 属性。灰度图是 (h, w),彩色图是 (h, w, 3),带 Alpha 通道的是 (h, w, 4)。这个习惯帮我避免了很多低级错误。
嗯,这一章的内容就到这里。图像基础操作看着简单,但它是后面所有高级功能的地基。你想想看,如果连读图都读不对,后面的文档矫正、OCR 识别还怎么玩?
下一章,咱们会聊图像的几何变换——说白了,就是怎么把歪歪扭扭的文档照片给「掰正」了。到时候见。