OpenCV 图像处理基础操作
bash pip install opencv-python
安装成功后,在代码中通过 `import cv2` 导入。如果还需要视频编码等完整功能,可以安装 `opencv-python-headless` 或 `opencv-contrib-python`,但基础操作使用标准版即可。
## 2. 图像的读取、显示与保存
### 2.1 读取图像
使用 `cv2.imread()` 读取图像,返回一个 NumPy 数组。参数包括文件路径和读取模式:
- `cv2.IMREAD_COLOR`(或 1):默认彩色模式,忽略透明度。
- `cv2.IMREAD_GRAYSCALE`(或 0):灰度模式。
- `cv2.IMREAD_UNCHANGED`(或 -1):包含 alpha 通道。
```python
import cv2
img = cv2.imread('example.jpg', cv2.IMREAD_COLOR)
2.2 显示图像
cv2.imshow('窗口名称', img) 显示图像,通常配合 cv2.waitKey() 暂停窗口:
cv2.imshow('My Image', img)
cv2.waitKey(0) # 0 表示无限等待,直到按下任意键
cv2.destroyAllWindows()
注意:OpenCV 的颜色顺序为 BGR,而非 RGB,直接显示可能出现颜色偏差。
2.3 保存图像
cv2.imwrite('output.jpg', img) 将图像保存到指定路径,文件格式由扩展名决定:
cv2.imwrite('saved.png', img)
保存成功返回 True。
3. 图像基本属性与像素操作
3.1 获取图像属性
图像作为 NumPy 数组,可以轻松获取形状、大小和数据类型:
height, width, channels = img.shape # 彩色图像
size = img.size # 总像素数
dtype = img.dtype # 数据类型(通常为 uint8)
灰度图 shape 仅返回 (rows, cols)。
3.2 访问和修改像素
通过行列索引直接读写像素值:
# 访问 (y=50, x=100) 处的 BGR 值
(b, g, r) = img[50, 100]
print(f"B: {b}, G: {g}, R: {r}")
# 将该像素设为白色
img[50, 100] = (255, 255, 255)
批量操作建议利用 NumPy 切片,效率更高。
3.3 感兴趣区域(ROI)
图像裁剪通过数组切片实现:
roi = img[100:300, 200:400] # 行列均为前闭后开区间
cv2.imshow('ROI', roi)
也可以将 ROI 赋值给另一区域,实现图像拼接:
img[0:200, 0:200] = roi
4. 颜色空间转换
4.1 常用转换
使用 cv2.cvtColor(src, code) 进行颜色空间转换,常用 code 如下:
cv2.COLOR_BGR2GRAY:转灰度cv2.COLOR_BGR2HSV:转 HSVcv2.COLOR_BGR2RGB:转 RGB(显示用)
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
hsv = cv2.cvtColor(img, cv2.COLOR_BGR2HSV)
转换 HSV 后可以方便地分离色调、饱和度和明度,用于颜色过滤。
4.2 通道分离与合并
使用 cv2.split() 和 cv2.merge():
b, g, r = cv2.split(img)
# 修改某通道后合并
merged = cv2.merge([b, g, r])
对于单通道操作,也可以直接使用索引:r_channel = img[:, :, 2],这样不会复制数据。
5. 图像几何变换
5.1 缩放
cv2.resize(src, dsize, fx, fy, interpolation) 调整尺寸:
dsize:目标大小 (宽, 高);若为 None,则按 fx/fy 缩放。interpolation:插值方法,推荐缩小用cv2.INTER_AREA,放大用cv2.INTER_CUBIC或cv2.INTER_LINEAR。
resized = cv2.resize(img, None, fx=0.5, fy=0.5, interpolation=cv2.INTER_AREA)
# 或者指定尺寸
resized = cv2.resize(img, (300, 200))
5.2 旋转
通过仿射变换实现旋转:
(height, width) = img.shape[:2]
center = (width // 2, height // 2)
angle = 45
scale = 1.0
M = cv2.getRotationMatrix2D(center, angle, scale)
rotated = cv2.warpAffine(img, M, (width, height))
getRotationMatrix2D 生成 2x3 仿射矩阵,warpAffine 应用变换。
5.3 平移与翻转
平移也可通过仿射矩阵实现:
M = np.float32([[1, 0, 50], [0, 1, 30]]) # 右移50,下移30
translated = cv2.warpAffine(img, M, (width, height))
翻转使用 cv2.flip(img, flipCode):
0垂直翻转,1水平翻转,-1同时垂直和水平翻转。
6. 图像阈值化
6.1 简单阈值
cv2.threshold(src, thresh, maxval, type) 将灰度图二值化:
cv2.THRESH_BINARY:大于阈值设 maxval,否则 0。cv2.THRESH_BINARY_INV:相反的二进制。cv2.THRESH_TRUNC:大于阈值设为阈值。cv2.THRESH_TOZERO:小于阈值设为 0。 返回值 ret(实际使用的阈值) 和 thresh_img。
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
_, binary = cv2.threshold(gray, 127, 255, cv2.THRESH_BINARY)
6.2 自适应阈值
对于光照不均的图像,使用自适应阈值:
adaptive = cv2.adaptiveThreshold(
gray, 255, cv2.ADAPTIVE_THRESH_MEAN_C, cv2.THRESH_BINARY, 11, 2
)
blockSize 为邻域大小,C 为减去的常数。
6.3 Otsu 二值化
Otsu 方法自动寻找最佳阈值,需结合 cv2.THRESH_OTSU 标志:
_, otsu = cv2.threshold(gray, 0, 255, cv2.THRESH_BINARY + cv2.THRESH_OTSU)
这种方式在双峰图像上效果极好。
7. 图像平滑与滤波
7.1 均值滤波
cv2.blur(src, ksize) 用邻域像素均值替换中心像素,核大小 (w, h) 越大平滑越强。
blurred = cv2.blur(img, (5, 5))
7.2 高斯滤波
cv2.GaussianBlur(src, ksize, sigmaX) 使用高斯核,能有效去除高斯噪声:
gaussian = cv2.GaussianBlur(img, (5, 5), 0)
若 sigmaX 设为 0,由核大小自动计算。
7.3 中值滤波
cv2.medianBlur(src, ksize) 对椒盐噪声特别有效,ksize 为大于 1 的奇数:
median = cv2.medianBlur(img, 5)
7.4 双边滤波
cv2.bilateralFilter(src, d, sigmaColor, sigmaSpace) 能保边去噪,速度较慢:
bilateral = cv2.bilateralFilter(img, 9, 75, 75)
8. 边缘检测
8.1 Canny 边缘检测
Canny 算法步骤:降噪 -> 梯度计算 -> 非极大值抑制 -> 双阈值筛选。
edges = cv2.Canny(img, threshold1=100, threshold2=200)
较低阈值 threshold1 用于弱边缘连接,较高阈值 threshold2 用于强边缘检测。灰度图输入效果更佳。
8.2 Sobel 算子
计算图像水平或垂直方向梯度:
sobelx = cv2.Sobel(img, cv2.CV_64F, 1, 0, ksize=3) # 水平梯度
sobely = cv2.Sobel(img, cv2.CV_64F, 0, 1, ksize=3) # 垂直梯度
# 合成梯度幅值
sobel_mag = cv2.magnitude(sobelx, sobely)
结果可能包含负值,需取绝对值并转换为 uint8 显示。
8.3 Laplacian 算子
二阶导数算子,对噪声敏感,通常先进行高斯平滑:
laplacian = cv2.Laplacian(img, cv2.CV_64F)
9. 形态学操作
9.1 结构元素
形态学操作需要定义结构元素(核),常用 cv2.getStructuringElement:
kernel = cv2.getStructuringElement(cv2.MORPH_RECT, (5, 5)) # 矩形核
9.2 膨胀与腐蚀
- 腐蚀:
cv2.erode(),缩小白色区域,消除小噪点。 - 膨胀:
cv2.dilate(),扩大白色区域,填充孔洞。
eroded = cv2.erode(binary_img, kernel, iterations=1)
dilated = cv2.dilate(binary_img, kernel, iterations=1)
9.3 开运算与闭运算
- 开运算(先腐蚀后膨胀):去除小物体,分离粘连。
- 闭运算(先膨胀后腐蚀):填充小孔,连接邻近物体。
opening = cv2.morphologyEx(binary_img, cv2.MORPH_OPEN, kernel)
closing = cv2.morphologyEx(binary_img, cv2.MORPH_CLOSE, kernel)
10. 实战示例:图像预处理流水线
以下代码整合了多个基础操作,展示从读取到边缘检测的典型流程:
import cv2
import numpy as np
# 1. 读取
img = cv2.imread('photo.jpg')
# 2. 缩放加速后续处理
img = cv2.resize(img, None, fx=0.4, fy=0.4)
# 3. 转灰度
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
# 4. 高斯去噪
blurred = cv2.GaussianBlur(gray, (5, 5), 0)
# 5. Canny 边缘检测
edges = cv2.Canny(blurred, 50, 150)
# 6. 形态学闭运算连接边缘
kernel = cv2.getStructuringElement(cv2.MORPH_RECT, (3, 3))
closed_edges = cv2.morphologyEx(edges, cv2.MORPH_CLOSE, kernel)
# 7. 显示结果
cv2.imshow('Original', img)
cv2.imshow('Edges', closed_edges)
cv2.waitKey(0)
cv2.destroyAllWindows()