图像基础与OpenCV入门:图像读取/显示/保存、像素操作、色彩空间、图像属性
说实话,很多初学者一上来就追着深度学习跑,连图像在计算机里长什么样都没搞清楚。我个人觉得,这是个大坑。你想想看,连像素怎么存、颜色怎么表示都不懂,后面调模型参数的时候,出了问题你根本不知道从哪下手。
这一章,咱们就把地基打牢。我会带着你,从OpenCV最基础的操作开始,一步步把图像的本质摸清楚。
1. 图像读取、显示与保存
OpenCV读取图像,用的是 cv2.imread()。这个函数很直接,给它一个路径,它就给你返回一个数组。但这里有个坑,我当年刚入行时就踩过。
举个例子:
import cv2
# 读取图像
img = cv2.imread('cat.jpg')
# 显示图像
cv2.imshow('My Cat', img)
cv2.waitKey(0) # 等待按键
cv2.destroyAllWindows()
# 保存图像
cv2.imwrite('cat_copy.jpg', img)
cv2.waitKey(0) 这行代码,说白了就是让窗口一直等着,直到你按任意键才关闭。我曾经在项目里忘了加这行,结果窗口一闪而过,我还以为是代码写错了,排查了半天。
cv2.waitKey(1000) 表示等待1秒。
2. 像素操作
图像在计算机里,就是一个多维数组。对于一张彩色图像,它的形状是 (高度, 宽度, 通道数)。每个像素点,就是一个包含三个数值的列表,分别代表 B、G、R 的强度。
直接操作像素,是理解图像最直观的方式。我习惯用 NumPy 来操作,因为 OpenCV 的图像数据本身就是 NumPy 数组。
import cv2
import numpy as np
# 创建一个 300x300 的黑色图像
img = np.zeros((300, 300, 3), dtype=np.uint8)
# 修改某个像素为蓝色
img[100, 100] = [255, 0, 0] # BGR 格式
# 修改一块区域为绿色
img[50:150, 50:150] = [0, 255, 0]
cv2.imshow('Pixel Operation', img)
cv2.waitKey(0)
cv2.destroyAllWindows()
这里要注意,dtype=np.uint8 表示每个通道的值范围是 0-255。你想想看,如果超出这个范围,OpenCV 会自动截断,不会报错。嗯,这一点很容易被忽略。
3. 色彩空间
色彩空间,说白了就是颜色的表示方式。OpenCV 里最常用的有 BGR、RGB、HSV、灰度。我刚开始学的时候,总觉得 BGR 和 RGB 差不多,直到有一次做颜色识别,才发现区别大了去了。
3.1 BGR 与 RGB
BGR 是 OpenCV 的默认格式,而 RGB 是大多数其他库(比如 Matplotlib)的默认格式。转换很简单:
# 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 的转换。
3.2 灰度图
灰度图只有一个通道,每个像素值代表亮度。转换方法:
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
灰度图在很多任务中都能用,比如边缘检测、人脸识别。它去掉了颜色信息,只保留亮度,计算量小很多。
3.3 HSV 色彩空间
HSV 把颜色分解成色调(H)、饱和度(S)、明度(V)。这个空间特别适合做颜色分割,因为颜色信息集中在 H 通道上。
hsv = cv2.cvtColor(img, cv2.COLOR_BGR2HSV)
举个例子,你想提取图像中的红色区域。在 BGR 空间里,红色可能是 (0, 0, 255),但受光照影响,实际值会变化。而在 HSV 空间里,红色的 H 值范围是固定的,比如 0-10 和 170-180。这样分割起来就稳定多了。
4. 图像属性
图像属性包括形状、数据类型、像素数量等。这些信息在调试时非常有用。
import cv2
img = cv2.imread('cat.jpg')
# 获取图像属性
print('图像形状:', img.shape) # (高度, 宽度, 通道数)
print('数据类型:', img.dtype) # uint8
print('像素总数:', img.size) # 高度 * 宽度 * 通道数
# 单独获取高度、宽度、通道数
height, width, channels = img.shape
print(f'高度: {height}, 宽度: {width}, 通道数: {channels}')
img.shape 返回的是一个元组。如果是灰度图,它只有两个值(高度和宽度)。这一点要注意,否则在解包时可能会出错。
5. 综合示例:图像处理流水线
最后,咱们把今天学的知识串起来,做一个简单的图像处理流水线:读取图像、转为灰度、保存结果。
import cv2
# 1. 读取图像
img = cv2.imread('cat.jpg')
# 2. 转为灰度图
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
# 3. 显示原图和灰度图
cv2.imshow('Original', img)
cv2.imshow('Gray', gray)
# 4. 等待按键
cv2.waitKey(0)
# 5. 保存灰度图
cv2.imwrite('cat_gray.jpg', gray)
# 6. 释放窗口
cv2.destroyAllWindows()
这个例子虽然简单,但涵盖了图像处理的基本流程。你想想看,后面不管多复杂的项目,本质上都是在这个流程上做扩展。
好了,这一章的内容就到这里。下一章,咱们会深入图像的基本变换,比如缩放、旋转、裁剪。这些操作在实际项目中几乎天天用,到时候我会分享一些实战中的小技巧。