此opencv系列博客只是为了记录本人对<<opencv3计算机视觉-pyhton语言实现>>的学习笔记,所有代码在我的github主页https://github.com/RenDong3/OpenCV_Notes.
欢迎star,不定时更新...
上一节中,我们介绍了Harris角点检测。角点在图像旋转的情况下也可以检测到,但是如果减小(或者增加)图像的大小,可能会丢失图像的某些部分,甚至导致检测到的角点发生改变。这样的损失现象需要一种与图像比例无关的角点检测方法来解决。尺度不变特征变换(Scale-Invariant Feature Transform,SIFT)可以解决这个问题。我们使用一个变换来进行特征变换,并且该变换会对不同的图像尺度输出相同的结果。
到底什么是SIFT算法?通俗一点说,SIFT算法利用DoG(差分高斯)来提取关键点(或者说成特征点),DoG的思想是用不同的尺度空间因子(高斯正态分布的标准差σσ)对图像进行平滑,然后比较平滑后图像的区别,差别大的像素就是特征明显的点,即可能是特征点。对得到的所有特征点,我们剔除一些不好的,SIFT算子会把剩下的每个特征点用一个128维的特征向量进行描述。
由上,易知,一幅图像经过SIFT算法后可以表示为一个128维的特征向量集。
SIFT具有一下特征:
- SIFT特征,对旋转、尺度缩放、亮度变化等保持不变性,对视角变换、仿射变化、噪声也保持一定程度的稳定性,是一种非常优秀的局部特征描述算法;
- 独特性好,信息量丰富,适用于海量特征库进行快速、准确的匹配;
- 多量性,即使是很少几个物体也可以产生大量的SIFT特征;
- 高速性,经优化的SIFT匹配算法甚至可以达到实时性的要求;
- 扩展性,可以很方便的与其他的特征向量进行联合。
一 使用DoG和SIFT进行特征提取和描述
我们先用OpenCV库函数演示一下DoG和SIFT特征提取的效果,然后再来讲述一下SIFT的原理。
我们先来介绍一下Different of Gaussians(DoG),DoG是对同一图象使用不同高斯滤波器作差所得到的结果。DoG操作的最终结果会得到感兴趣的区域(关键点),这将通过SIFT来进行特征描述。
我们来看看如何通过SIFT得到充满角点和特征的图像:
# -*- coding:utf-8 -*-
import os
import cv2
import numpy as np
'''
created on 08:05:10 2018-11-20
@author ren_dong
使用DoG和SIFT进行特征提取和描述
cv2.SIFT.detectAndCompute(image, mask[, descriptors[, useProvidedKeypoints]]) → keypoints, descriptors
cv2.drawKeypoints(image, keypoints[, outImage[, color[, flags]]]) → outImage
首先创建了一个SIFT对象,SIFT对象会使用DoG检测关键点,并且对每个关键点周围区域计算特征向量。
detectAndCompute()函数会返回关键点信息(每一个元素都是一个对象,有兴趣的可以看一下OpenCV源码)和关键点的描述符。
然后,我们在图像上绘制关键点,并显示出来。
'''
img = cv2.imread('chess.jpg')
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
#创建sift对象
sift = cv2.xfeatures2d.SIFT_create()
#进行检测和计算 返回特征点信息和描述符
keypoints , descriptor = sift.detectAndCompute(gray, None)
#keypoints:特征点集合list,向量内每一个元素是一个KeyPoint对象,包含了特征点的各种属性信息;
#绘制关键点
img = cv2.drawKeypoints(img, keypoints=keypoints, outImage=img, color= (51, 163, 236), flags= cv2.DRAW_MATCHES_FLAGS_DRAW_RICH_KEYPOINTS)
#sift得到的图像为128维的特征向量集
print len(keypoints)
print descriptor.shape
cv2.imshow('sift_keypoints',img)
cv2.waitKey()
cv2.destroyAllWindows()
我们首先创建了一个SIFT对象,SIFT对象会使用DoG检测关键点,并且对每个关键点周围区域计算特征向量。detectAndCompute()函数会返回关键点信息(每一个元素都是一个对象,有兴趣的可以看一下OpenCV源码)和关键点的描述符。然后,我们在图像上绘制关键点,并显示出来。
上面我们用到了一个函数,下面来介绍一下:
1cv2.drawKeypoints(image, keypoints[, outImage[, color[, flags]]]) → outImage |
参数描述:
image:原始图像,可以使三通道或单通道图像;
keypoints:特征点集合list,向量内每一个元素是一个KeyPoint对象,包含了特征点的各种属性信息;
outImage:特征点绘制的画布图像,可以是原图像;
color:颜色设置,绘制的特征点的颜色信息,默认绘制的是随机彩色;
flags:特征点的绘制模式,其实就是设置特征点的哪些信息需要绘制,哪些不需要绘制,有以下几种模式可选:
- cv2.DRAW_MATCHES_FLAGS_DEFAULT:创建输出图像矩阵,使用现存的输出图像绘制匹配对和特征点,对每一个关键点只绘制中间点;
- cv2.DRAW_MATCHES_FLAGS_DRAW_OVER_OUTIMG:不创建输出图像矩阵,而是在输出图像上绘制匹配对;
- cv2.DRAW_MATCHES_FLAGS_DRAW_RICH_KEYPOINTS:对每一个特征点绘制带大小和方向的关键点图形;
- cv2.DRAW_MATCHES_FLAGS_NOT_DRAW_SINGLE_POINTS:单点的特征点不被绘制;
我们传入了DRAW_MATCHES_FLAGS_DRAW_RICH_KEYPOINTS标志位,表明对图像每个关键点都绘制圆圈(大小)和方向。
总结下就是SIFT算法利用DOG进行特征点检测,然后对每个关键点周围的区域计算特征向量.解决了Harris角点检测的尺度变化影响问题.
这里并没有对SIFT算法的原理进行详细介绍,对此感兴趣的同学可以去大神的博客浏览观看,里面讲的非常详细,下面给上链接: