学习 OpenCV 之前需要先安装使用的库:
pip install opencv-python==3.4.18.65 -i https://pypi.tuna.tsinghua.edu.cn/simple
pip install opencv-contrib-python==3.4.18.65 -i https://pypi.tuna.tsinghua.edu.cn/simple
pip install numpy==1.26.4 -i https://pypi.tuna.tsinghua.edu.cn/simple
OpenCV 更偏向于一个计算机视觉算法库,专注于图像的处理和分析。它不同于通用的深度学习框架(如 TensorFlow、PyTorch),后者主要用于模型的训练。在实际项目中,两者常结合使用:用 OpenCV 进行数据预处理,再用深度学习模型进行推理。
简单来说,OpenCV 为计算机视觉提供了从基础到高级的"乐高积木",让开发者能高效地搭建各种"看"世界的应用。
作为对图像处理和分析特化的算法库,我们得先去读取电脑中的图片或者视频。假设我的文件夹里含有 1.jpg 这个图片,可以用以下代码读取:
import cv2 # 读取的格式是 BGR numpy import numpy as np a = cv2.imread('1.jpg')这时候 a 里面是 numpy 数组,存储了读取的图像的像素值,大概长这样子:
[[[184 64 22] [184 64 22] [184 64 22] ... [206 146 110] [206 146 110] [206 146 110]] [[185 66 21] [184 64 22] [184 64 22] ...可以使用以下代码显示图片:
cv2.imshow('1', a) # 显示图片。显示图片的名称,显示的图片数据。如注释所说,我们可以使用 imshow 来显示图片,括号内前面是图片名,后面是存储图片数据的数组变量。之后便引入图片显示的时间长短,一般我们需要图片一直存在,但输入上述的代码会出现两个结果:
一闪而过(最常见):程序执行完
cv2.imshow()后,紧接着脚本就运行结束了。Python 进程退出时会自动回收所有内存和窗口资源,所以你几乎看不到图像窗口,或者看到它出现一瞬间就消失了。卡死/无响应(部分环境):由于没有调用
waitKey去"刷新" GUI 事件循环,窗口可能无法正常渲染,直接显示为"未响应"的白色/灰色框。
所以在这下面必须加上一句能控制图片出现时间的代码:
cv2.waitKey(0)默认值为 0,写零表示没有倒计时,图片一直存在,而它的单位是毫秒(ms),也就是说在括号内写 1000 也只有一秒的显示时间。在这之后我们需要进行退出,那需要释放内存:
cv2.destroyAllWindows() # 关闭所有打开的窗口并释放所有相关内存。对于简单的程序不需要调用这些函数,应用程序的所有资源和窗口在退出时都会由操作系统自动关闭。在这之后我们可以对之前的图片进行一些操作输出一些信息:
# 调试时观察 shape、dtype、size 属性 print("图像形状 (shape): ", a.shape) # 高、宽、通道数 print("图像数据类型 (dtype): ", a.dtype) # 无符号 8 位整数,用于表示像素值的范围在 0 到 255 之间 print("图像大小 (size): ", a.size) # 表示图像的总像素数,即图像的高度乘以宽度乘以通道数大概输出为:
图像形状 (shape): (834, 1024, 3) 图像数据类型 (dtype): uint8 图像大小 (size): 2562048灰度操作
将彩色图像转为灰度图,是为了在保留关键结构和纹理信息的同时,大幅降低数据复杂度,从而提高处理速度和算法鲁棒性。
更具体地说,有以下几个核心原因:
1. 🚀 计算效率更高(速度与内存)
彩色图像通常是3 通道(RGB 或 BGR),而灰度图只有1 通道。
数据量减少 2/3:处理一张灰度图所需的计算量和内存仅为彩色的 1/3。
推理更快:在实时处理(如视频流、嵌入式设备)中,减少通道数能显著提升帧率。
2. 🎯 聚焦核心特征(忽略颜色干扰)
很多计算机视觉任务关注的是物体的形状、轮廓、纹理和明暗变化,而非颜色本身。
例如,在边缘检测(如 Canny 算子)或特征提取(如 SIFT、ORB)中,算法主要依赖梯度(亮度的变化)。颜色信息往往是多余的,甚至可能引入噪声(比如相同颜色的物体与背景混淆)。
OCR(文字识别):识别黑白印刷体文字时,颜色完全无用,灰度化后算法能更专注于笔画形状。
3. 📉 降低过拟合风险(机器学习/深度学习)
在训练深度学习模型时,输入彩色图像意味着模型要学习 3 倍于灰度的参数。
如果训练数据中颜色与标签存在偶发关联(例如,"苹果"大多是红色),模型可能会过度依赖颜色,而忽略形状。灰度化可以迫使模型关注更本质的纹理和结构,从而提高泛化能力。
4. 🔧 算法原生要求(历史与数学原因)
许多经典的计算机视觉算法(如直方图均衡化、二值化、形态学操作)本身就是基于亮度(强度)设计的。如果输入彩色图,通常需要先将彩色分量加权转换为灰度值,否则算法无法直接处理多维数据。
综上所述,灰度图还是很有必要的,我们通常用以下代码进行图片灰度化的操作:
b = cv2.imread(r'./1.jpg', cv2.IMREAD_GRAYSCALE)代码对 1.jpg 进行读取并将其灰度化。在进行灰度化之前也可能对图片的大小存疑,是不是也可以改变其大小:
c = cv2.imread('1.jpg') d = c[230:580, 300:600] # 读取位置 cv2.imshow('yuantu', c) cv2.imshow('qiepian', d)开头也讲了 OpenCV 也可以对视频进行操作:
video_capture = cv2.VideoCapture("2.mp4")可通过以上代码对视频文件进行读取,同样也能对视频的颜色进行更改:
frame = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)GRAY 为颜色,可更改为其他颜色。上面提到彩色是三通道的,灰度是单通道的,代码中可以将三个通道拆开来分开灰度化:
三个单通道灰度图
cv2.imshow('b', b)→ 显示B(蓝色)通道的灰度图cv2.imshow('g', g)→ 显示G(绿色)通道的灰度图cv2.imshow('r', r)→ 显示R(红色)通道的灰度图
每个窗口都是一张单通道图像,像素值代表该通道的强度(0~255),显示为灰度。
合并后的彩色图
cv2.imshow('result3', img)→ 将a1(B 通道)、a2(G 通道)、a3(R 通道)重新合并为 BGR 彩色图像。
由于a1, a2, a3正是原始图像a的三个通道,所以合并后的图像与原始图像完全一致。
🎯 作用与意义
教学演示:帮助你直观理解彩色图像由三个独立通道组成,每个通道可以看作一张灰度图。
通道分离:
cv2.split()和数组切片都能提取单个通道,便于后续对特定通道进行单独处理(如调整亮度、增强对比度、替换通道等)。通道合并:
cv2.merge()用于将修改后的单通道重新组合成彩色图,是图像处理流水线中的常用操作。实际应用:常用于颜色空间转换、通道增强、水印叠加、通道交换(如将 R 通道与 B 通道互换)等场景。
代码如下:
a = cv2.imread("1.jpg") a1 = a[:,:,0] a2 = a[:,:,1] a3 = a[:,:,2] b, g, r = cv2.split(a)这时候分别输出这 a1、a2、a3 就行了。我们也存在对图片某处打上马赛克,也就是用一张图片的一部分对另一张图片的指定部分进行覆盖:
a[100:200, 200:300] = np.random.randint(0, 256, (100, 100, 3))a[100:200, 200:300]为被覆盖图片指定位置。
(100, 100, 3)前面两个数需要与 a 里面大小对应。
若用其他图片来替换马赛克呢:
a = cv2.imread(r'./1.jpg') b = cv2.imread(r'./3.jpg') b[100:200, 200:300] = a[200:300, 100:200]这下就用 a 中的部分图片替换 b 中图了。我们有时需要对图片进行缩放:
图片缩放 cv2.resize
用于调整图像的大小。它有以下几个参数:
- src:要调整大小的输入图像,可以是 numpy 数组、PIL 图像或其他类型。
- dsize:输出图像的大小,可以是一个元组,例如(宽,高),或者使用整数标量来缩放原始图像。如果 dsize 为 None,则根据 fx 和 fy 缩放原始图像。
我们有两种方法:
# 方法一:直接指定尺寸 a_new = cv2.resize(a, (200, 200)) # 宽、高 方法二:使用缩放系数 a_new = cv2.resize(a, dsize:None, fx=0.5, fy=0.5)fx:沿 x 轴的缩放系数。
fy:沿 y 轴的缩放系数。
可用第一句代码实现,当然可以直接使用第二种。第二种可缩放比例,也可以不写前置参数dsize:。