一、Harris角点检测
1. 核心概念
-
角点定义:图像中在两个垂直方向都有明显变化的像素点
-
基本思想:通过分析图像局部窗口在各个方向移动时的灰度变化来判断是否为角点
-
响应值:每个像素点计算出一个角点响应值,值越大表示越可能是角点
2. dst数组详解
python
dst = cv2.cornerHarris(gray, blockSize, ksize, k)
-
dst形状:与输入图像相同大小(height × width)
-
dst数据类型:float32
-
dst值含义:每个位置的值表示该像素点是角点的"可能性"或"响应强度"
-
正值:可能是角点(值越大可能性越高)
-
负值:平坦区域或边缘
-
接近0:平坦区域
-
3. 关键函数
python
# 核心函数
cv2.cornerHarris(src, blockSize, ksize, k)
参数含义:
-
src:输入灰度图像
-
blockSize:邻域大小(考虑像素点的窗口大小)
-
ksize:Sobel算子的孔径大小(用于计算梯度)
-
k:Harris检测器的经验参数(通常0.04-0.06)
4. 阈值处理原理
python
# 标记角点的标准方法
img[dst > 0.01 * dst.max()] = [0, 0, 255]
-
dst.max():获取整个响应图中的最大值
-
0.01 * dst.max():设定阈值(最大值的1%)
-
逻辑:只保留响应值大于阈值的像素点作为角点
二、SIFT特征提取
1. SIFT算法四个步骤
-
尺度空间极值检测:在不同尺度空间寻找稳定特征点
-
关键点精确定位:去除低对比度和边缘响应点
-
方向分配:为每个关键点分配主方向
-
描述符生成:生成128维特征向量
2. SIFT关键函数说明
创建SIFT对象
python
sift = cv2.SIFT_create()
创建SIFT检测器实例,可以设置参数控制特征点数量、对比度阈值等。
detect()函数
python
kp = sift.detect(image, mask=None)
-
功能:只检测关键点的位置信息
-
返回值:关键点列表(每个关键点包含位置、尺度、方向等信息)
-
kp属性:
-
pt:坐标位置 (x, y) -
size:关键点直径 -
angle:方向(角度) -
response:响应强度 -
octave:金字塔层数
-
compute()函数
python
kp, des = sift.compute(image, kp)
-
功能:为已检测的关键点计算描述符
-
输入:图像 + 已检测的关键点
-
输出:
-
kp:更新后的关键点(添加了方向信息) -
des:描述符数组(n×128)
-
detectAndCompute()函数
python
kp, des = sift.detectAndCompute(image, mask=None)
-
功能:一步完成检测和计算(更高效)
-
返回值:关键点列表 + 描述符数组
3. 描述符(des)详解
python
# des的结构
print(des.shape) # 输出:(n, 128)
-
n:关键点数量
-
128:每个关键点的特征向量维度
-
数据特性:
-
对尺度、旋转、光照变化具有不变性
-
对视角变化、仿射变换具有一定鲁棒性
-
4. 关键点(kp)与描述符(des)的关系
| 组件 | 内容 | 用途 |
|---|---|---|
| 关键点(kp) | 位置、尺度、方向、响应值 | 定位特征位置 |
| 描述符(des) | 128维特征向量 | 描述特征内容 |
类比理解:
-
关键点 ≈ 指纹的纹线交叉点(位置信息)
-
描述符 ≈ 指纹的细节特征(内容信息)
-
匹配:比较两张图片的描述符,找到相似的特征对
5.角点检测和特征提取对比
Harris角点检测流程:
输入图像 → 灰度化 → Harris检测 → 响应图 → 阈值处理 → 标记角点
SIFT特征提取流程:
输入图像 → 灰度化 → SIFT检测 → 关键点位置 → 计算描述符 → 特征向量
(detect()) (compute())
6. 应用场景差异
Harris角点适合:
-
简单的角点检测需求
-
实时性要求高的应用
-
只需要位置信息,不需要特征描述
SIFT适合:
-
图像匹配和识别
-
需要特征描述的应用
-
对尺度、旋转变化有要求的场景
7. 核心区别总结
| 方面 | Harris | SIFT |
|---|---|---|
| 输出 | 角点响应值(单值) | 关键点+128维描述符 |
| 不变性 | 旋转、光照 | 尺度、旋转、光照 |
| 信息量 | 位置信息 | 位置+特征描述 |
| 复杂度 | 简单快速 | 复杂但功能强大 |
关键记住:
-
Harris给出的是"每个像素可能是角点的概率"
-
SIFT给出的是"特征点的精确位置和详细描述"
-
选择哪种方法取决于你的具体需求:
-
只需要找到角点 → Harris
-
需要匹配和识别 → SIFT
-
8.实际运用
Harris角点检测
python
import cv2
import numpy as np
# 角点检测部分
img = cv2.imread('005.jpg')
img=cv2.resize(img,dsize=None,fx=0.5,fy=0.5)
cv2.imshow('005',img)
cv2.waitKey(0)
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
dst = cv2.cornerHarris(gray, 4, 3, 0.04)
# 标记检测到的角点
img[dst > 0.01 * dst.max()] = [0, 0 , 255]
# 这里通过对角点响应进行阈值处理,标记出检测到的角点。
# 0.05 * dst.max() 是一个阈值,大于这个值的像素点会被标记为红色。
cv2.imshow('img', img)
cv2.waitKey(0)
cv2.destroyAllWindows()

SIFT特征提取
python
import cv2
import numpy as np
people = cv2.imread('peopleone.jpg')
people=cv2.resize(people,dsize=None,fx=0.5,fy=0.5)
cv2.imshow('people',people)
cv2.waitKey(0)
people_gray = cv2.cvtColor(people, cv2.COLOR_BGR2GRAY)
sift = cv2.SIFT_create() # sift对象
kp = sift.detect(people)
# 查找关键点
people_sift = cv2.drawKeypoints(people, kp, None, flags=cv2.DRAW_MATCHES_FLAGS_DRAW_RICH_KEYPOINTS)
cv2.imshow('people_sift', people_sift)
cv2.waitKey(0)
# 使用sift.compute()计算关键点描述符,方便后期的特征匹配
kp, des = sift.compute(people, kp)
print(np.array(kp).shape, des.shape)
cv2.destroyAllWindows()


三、图片抠图小案例
任务:
按照要求利用轮廓检测和按位与操作实现抠图功能。
有一张名为fan.jpg的图片,现要求使用 Python 结合 OpenCV 库编写代码实现以下功能:
(1)读取名为fan.jpg的图片,将尺寸设置为宽640,高480,然后逆时针旋转90度;
(2)使用Canny边缘检测提取(1)处理后的边缘;
(3)在提取边缘的基础上,查找轮廓并选取扇子的外轮廓,生成相应的掩模;
(4)通过掩模与原图进行按位与操作将对应部分提取出来,并保存为"shanzi.png"文件。
代码
python
import cv2
import numpy as np
def cv_show(name,img):
cv2.imshow(name,img)
cv2.waitKey(0)
image=cv2.imread('fan.jpg')
image=cv2.resize(image,(640,480))
cv_show('yuan',image)
rotated_image = np.rot90(image, k=1)
rotated_gray=cv2.cvtColor(rotated_image,cv2.COLOR_BGR2GRAY)
cv_show('rotated',rotated_image)
canny=cv2.Canny(rotated_gray,15,45)
cv_show('canny',canny)
cnts=cv2.findContours(canny,cv2.RETR_EXTERNAL,cv2.CHAIN_APPROX_SIMPLE)[-2]
cnts=sorted(cnts,key=cv2.contourArea,reverse=True)[:3]
if len(cnts) > 0:
# 选取最大的轮廓(扇子通常是面积最大的)
largest_contour = cnts[0]
area = cv2.contourArea(largest_contour)
print(f"最大轮廓面积: {area}")
# 创建掩膜
mask = np.zeros(rotated_gray.shape, dtype="uint8")
cv2.drawContours(mask, [largest_contour], -1, 255, -1) # -1表示填充
cv_show('mask', mask)
# 应用掩膜
masked_image = cv2.bitwise_and(rotated_image, rotated_image, mask=mask)
cv_show('masked_image', masked_image)
cv2.imwrite('shanzi.png',masked_image)
cv2.destroyAllWindows()
运行结果

