OpenCV 图像处理基础操作

FreeGuideOnline 最新 2026-07-08

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:转 HSV
  • cv2.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_CUBICcv2.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()