OpenCV 作为计算机视觉领域的核心库,提供了丰富的高级图像处理功能。本文将从实战角度出发,系统讲解图像金字塔、直方图分析、直方图均衡化、角点检测与 SIFT 特征提取等核心进阶操作,帮助你掌握计算机视觉的关键技术。
一、图像金字塔:多尺度图像处理
图像金字塔是一种以多分辨率来解释图像的结构,通过对图像进行上采样 / 下采样,构建不同尺度的图像层级,广泛应用于图像缩放、特征检测等场景。
1.1 核心概念
- 向下采样(缩小图像) :使用
cv2.pyrDown()函数,先对图像进行高斯模糊,再删除偶数行和列,图像尺寸变为原来的 1/2。 - 向上采样(放大图像) :使用
cv2.pyrUp()函数,先将图像尺寸放大两倍(补 0),再进行高斯模糊,放大后图像会丢失细节。 - 拉普拉斯金字塔:通过原图像与下采样后上采样的图像差值构建,用于图像复原与融合。
1.2 实战代码
python
import cv2
import numpy as np
# 读取灰度图像
img = cv2.imread('face.png', cv2.IMREAD_GRAYSCALE)
if img is None:
print("请检查图像路径是否正确!")
else:
# 向下采样(G1、G2)
img_down1 = cv2.pyrDown(img) # 第一次下采样
img_down2 = cv2.pyrDown(img_down1) # 第二次下采样
# 向上采样
img_up1 = cv2.pyrUp(img) # 原图像上采样
img_down1_up = cv2.pyrUp(img_down1) # 下采样G1后上采样
# 构建拉普拉斯金字塔
L0 = img - img_down1_up # 拉普拉斯金字塔第0层
img_down2_up = cv2.pyrUp(img_down2)
L1 = img_down1 - img_down2_up # 拉普拉斯金字塔第1层
# 图像复原
restore_img = img_down1_up + L0
# 显示结果
cv2.imshow('Original', img)
cv2.imshow('Down1', img_down1)
cv2.imshow('L0', L0)
cv2.imshow('Restore', restore_img)
cv2.waitKey(0)
cv2.destroyAllWindows()
1.3 关键说明
- 下采样是不可逆的:下采样后再上采样,图像会模糊,无法完全复原。
- 拉普拉斯金字塔存储了图像的细节信息,结合高斯金字塔可实现图像精准复原。
二、直方图分析:像素分布的可视化
直方图是图像像素灰度分布的统计图表,横坐标为灰度值(0-255),纵坐标为对应灰度值的像素数量,是图像增强、阈值分割的基础。
2.1 核心函数与参数
cv2.calcHist(images, channels, mask, histSize, ranges)
images:输入图像(需用中括号包裹,如[img])。channels:通道索引(灰度图为[0],彩色图 BGR 对应[0]/[1]/[2])。mask:掩模图像(统计局部区域直方图时使用,全局则为None)。histSize:直方图的区间数(BINS,如[256]表示分 256 个区间)。ranges:像素值范围,通常为[0, 256]。
2.2 实战代码
python
import cv2
import matplotlib.pyplot as plt
import numpy as np
# 1. 灰度图直方图
img_gray = cv2.imread('phone.png', cv2.IMREAD_GRAYSCALE)
if img_gray is None:
print("请检查图像路径是否正确!")
else:
# matplotlib 直接绘制
plt.hist(img_gray.ravel(), bins=256, range=[0, 256])
plt.title('灰度图直方图')
plt.show()
# OpenCV 计算后绘制(16个区间)
hist_16 = cv2.calcHist([img_gray], [0], None, [16], [0, 256])
plt.plot(hist_16)
plt.title('16区间灰度直方图')
plt.show()
# 2. 彩色图通道直方图
img_color = cv2.imread('phone.png')
colors = ('b', 'g', 'r')
for i, col in enumerate(colors):
hist = cv2.calcHist([img_color], [i], None, [256], [0, 256])
plt.plot(hist, color=col)
plt.title('彩色图BGR通道直方图')
plt.show()
# 3. 掩模局部直方图
mask = np.zeros(img_gray.shape[:2], np.uint8)
mask[50:350, 100:470] = 255 # 定义感兴趣区域(ROI)
img_masked = cv2.bitwise_and(img_gray, img_gray, mask=mask)
hist_mask = cv2.calcHist([img_gray], [0], mask, [256], [0, 256])
# 显示掩模效果与局部直方图
cv2.imshow('Mask', mask)
cv2.imshow('Masked Image', img_masked)
plt.plot(hist_mask)
plt.title('掩模区域直方图')
plt.show()
cv2.waitKey(0)
cv2.destroyAllWindows()
三、直方图均衡化:提升图像对比度
直方图均衡化通过重新分配像素灰度值,使直方图分布更均匀,从而提升图像对比度,是图像增强的经典方法。
3.1 两种均衡化方式
- 全局均衡化 :
cv2.equalizeHist(),适用于整体对比度低的图像,但可能过度增强噪声。 - 自适应均衡化 :
cv2.createCLAHE(),分块局部均衡化,保留细节,避免过度增强。
3.2 实战代码
python
import cv2
import matplotlib.pyplot as plt
import numpy as np
# 读取灰度图像
img = cv2.imread('woman.png', cv2.IMREAD_GRAYSCALE)
if img is None:
print("请检查图像路径是否正确!")
else:
# 1. 全局直方图均衡化
img_eq = cv2.equalizeHist(img)
# 2. 自适应直方图均衡化
clahe = cv2.createCLAHE(clipLimit=1.0, tileGridSize=(16, 16))
img_clahe = clahe.apply(img)
# 绘制直方图对比
plt.subplot(311)
plt.hist(img.ravel(), 256, [0, 256])
plt.title('原始图像直方图')
plt.subplot(312)
plt.hist(img_eq.ravel(), 256, [0, 256])
plt.title('全局均衡化直方图')
plt.subplot(313)
plt.hist(img_clahe.ravel(), 256, [0, 256])
plt.title('自适应均衡化直方图')
plt.show()
# 显示图像对比
res = np.hstack((img, img_eq, img_clahe))
cv2.imshow('对比:原始 | 全局均衡化 | 自适应均衡化', res)
cv2.waitKey(0)
cv2.destroyAllWindows()
3.3 效果说明
- 全局均衡化会整体拉伸灰度范围,但可能丢失局部细节。
- 自适应均衡化通过
clipLimit(对比度阈值)和tileGridSize(分块大小)控制局部增强效果,更适合保留细节的场景。
四、特征检测:角点与 SIFT 特征
特征检测是计算机视觉的核心,用于图像匹配、目标识别等场景,本文重点讲解 Harris 角点检测和 SIFT 特征提取。
4.1 Harris 角点检测
角点是图像中灰度变化剧烈的区域,Harris 算法通过计算像素邻域的灰度变化矩阵,判断是否为角点。
python
import cv2
import numpy as np
# 读取图像并转灰度
img = cv2.imread('huanghelou.png')
if img is None:
print("请检查图像路径是否正确!")
else:
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
gray = np.float32(gray) # Harris算法要求输入为float32
# Harris角点检测
dst = cv2.cornerHarris(gray, blockSize=4, ksize=3, k=0.04)
# 膨胀角点响应图(方便可视化)
dst = cv2.dilate(dst, None)
# 标记角点(红色)
img[dst > 0.01 * dst.max()] = [0, 0, 255]
cv2.imshow('Harris角点检测', img)
cv2.waitKey(0)
cv2.destroyAllWindows()
4.2 SIFT 特征提取
SIFT(尺度不变特征变换)是具有尺度、旋转不变性的特征提取算法,可在不同尺度下检测关键点并生成描述符。
python
import cv2
import numpy as np
# 读取图像并转灰度
img = cv2.imread('man.png')
if img is None:
print("请检查图像路径是否正确!")
else:
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
# 创建SIFT对象
sift = cv2.SIFT_create()
# 检测关键点
kp = sift.detect(gray, None)
# 计算关键点描述符(用于特征匹配)
kp, des = sift.compute(gray, kp)
# 绘制关键点(带尺度和方向的富信息绘制)
img_sift = cv2.drawKeypoints(img, kp, None, flags=cv2.DRAW_MATCHES_FLAGS_DRAW_RICH_KEYPOINTS)
# 输出关键点数量和描述符形状
print(f"关键点数量:{len(kp)}")
print(f"描述符形状:{des.shape}") # (关键点数量, 128)
cv2.imshow('SIFT特征检测', img_sift)
cv2.waitKey(0)
cv2.destroyAllWindows()
4.3 关键说明
- Harris 角点检测的
blockSize为邻域大小,ksize为 Sobel 求导窗口,k为经验参数(0.04-0.06)。 - SIFT 关键点包含坐标、尺度、方向等信息,描述符为 128 维向量,可用于跨尺度、旋转的图像匹配。