基于python+opencv的SIFT算法分析

基于python+opencv的SIFT算法分析
当对图像进行平移、旋转、缩放等操作后,其特性保持不变,此算法即SIFT算法。图像在平移、旋转比例和光照条件发生变化时的匹配,对视角变换和仿射变换,SIFT算法具有较稳定的特征匹配性能。SIFT 算法实现具体过程如下:
(1)特征点检测
a.建立尺度空间
尺度空间理论于1983年被提出,后被推广到二维图像。二维图像尺度空间,可由图像与高斯核进行卷积得到:
公式 (4- 1)
式中:I(x,y)代表二维图像,G(x,y,σ)是高斯核,L(x,y,σ)表示尺度空间。σ大小与图像的平滑程度有关,σ值越大则尺度越粗糙。
b.DOG空间关键点检测
Lowe教授提出,可以用差分高斯DoG极值作为判断,对归一化LoG算子进行近似,可以得到DoG算子。
公式 (4- 2)
其中,K为相邻两个尺度因子的比值.
先把高斯图像金字塔分成若干阶,每阶又分成3~5层,相邻层之间的σ相差一个k。为了得到保持图像的连续性,下一阶图像的底层是通过第一阶图像得到的,最后一阶图像的尺度因子为2σ进行2降采样。为了搜索尺度空间的极值点,如下图所示,中间的蓝色像素要比同层的8个像素,以及上下层的18个像素,只有当其值最大或最小,才将该点作为极值点并存储起来供后续计算使用。
c.关键点的位置与尺度的确定
由关键点周围的每个像素梯度计算其位置及尺度,拟合计算采用三维二次函数。尺度空间函数D(x,y,σ)在极值点(x0,y0,σ)处的Taylor展开式如下:
公式 (4- 3)

对上式求导,当等于零时,比较准确的位置如下:
公式 (4- 4)

可得极值点的方程:
公式 (4- 5)

当 ,表示其不易受噪声影响,可保留,反之要去除。
边缘响应的去除,需要通过一个2×2的Hessian矩阵来计算主曲率。
公式 (4- 6)

其中,主曲率用D表示,特征值用H表示,特征值用α、β表示,则:
公式 (4- 7)

 Det(H)代表矩阵H的行列式,Tr(H)代表矩阵H对角线元素之和。令𝛼=𝑟𝛽,可以得到下式
                     公式 (4- 8)

 (r+1) 2r的比值与r成正比,在去除边缘影响时,需要按照下式进行检测。
                                              公式 (4- 9)

当上式成立时保留,反之去除。
d.计算关键点的方向
利用关键点邻域像素其梯度方向特性,为每个关键点指定方向参数,采用下式计算关键点的梯度和方向。
公式 (4- 10)
式中,L为检测的关键点所在的尺度。
(2)生成特征向量
首先,将坐标轴旋转为关键点的方向,取8×8的窗口,如图4-3所示,(a)的中心点为关键点,对其进行加权运算。每4×4的小块上,计算8个方向的梯度方向直方图,形成一个种子点,如图4-3(b)所示。一个关键点由4个种子点组成,每个种子点有8个方向信息。每个关键点使用16个种子点来描述,一个关键点就形成128维的SIFT特征向量。
(3)特征匹配
如何确定其适用性是SIFT匹配算法的最后一个关键步骤。这里选择关键点特征向量的欧氏距离作为相似性的判断。判断步骤如下。首先在第一幅图像中提取一个特征点,再提取另一幅图像的特征点,并记录两个欧氏距离最近的点。其次,比较最后一步的欧几里得距离。如果分割第二最小距离的最小距离的值小于阈值,则这两个点匹配成功,反之不接受。
(4)算法特点
SIFT算子对图像的亮度变化、尺度缩放、旋转、噪声有很好的鲁棒性,算法较稳定。但是,存在匹配精度差、匹配准确率低、实时性差等问题,仍需和其它算法相结合。
(5)适用场景
目标的旋转、缩放、平移;图像仿射/投影变换;光照影响;目标遮挡;杂物场景;噪声。
代码段如下:

#coding=utf-8
import cv2
import time

sift = cv2.xfeatures2d.SIFT_create(nfeatures=1000)
img1 = cv2.imread("E:/left3.2.bmp")
img2 = cv2.imread("E:/right3.2.bmp")
img3=img2
#img3=cv2.flip(img2,-1)
#求中心点,对图像进行旋转
#(h,w)=img2.shape[:2]
#center=(w//2,h//2)
#M=cv2.getRotationMatrix2D(center,30,1.0)
#img3=cv2.warpAffine(img2,M,(w,h))
#灰度化
img1_gray = cv2.cvtColor(img1, cv2.COLOR_RGB2GRAY)
img3_gray = cv2.cvtColor(img3, cv2.COLOR_RGB2GRAY)
kp1, des1 = sift.detectAndCompute(img1_gray, None)
kp2, des2 = sift.detectAndCompute(img3_gray, None)
#绘制特征点图
img1t=cv2.drawKeypoints(img1_gray,kp1,img1)
img3t=cv2.drawKeypoints(img3_gray,kp2,img3)
#进行KNN特征匹配,K设置为2
start=time.time()
bf = cv2.BFMatcher()
matches = bf.knnMatch(des1, des2, k=2)
good=[]
print(len(matches))
matchesMask = [[0, 0] for i in range(len(matches))]
for i, (m1, m2) in enumerate(matches):
    if m1.distance < 0.7* m2.distance:  # 两个特征向量之间的欧氏距离,越小表明匹配度越高。
        good.append(m1)
        matchesMask[i]=[1,0]
        pt1 = kp1[m1.queryIdx].pt  # queryIdx  是匹配之后所对应关键点的序号,第一个载入图片的匹配关键点序号
        pt2 = kp2[m1.trainIdx].pt  # trainIdx  是匹配之后所对应关键点的序号,第二个载入图片的匹配关键点序号
        #print(kpts1)
        print(i, pt1, pt2)   #打印匹配点个数,并标出两图中的坐标位置
        #画特征点及其周围的圆圈
        cv2.circle(img1, (int(pt1[0]), int(pt1[1])), 5, (0, 255, 0), -1)
        num = "{}".format(i)
        cv2.putText(img1, num, (int(pt1[0]), int(pt1[1])),
                    cv2.FONT_HERSHEY_SIMPLEX, 0.5, (255, 255, 255), 1)
        cv2.circle(img3, (int(pt2[0]), int(pt2[1])), 5, (0, 255, 0), -1)
        cv2.putText(img3, num, (int(pt2[0]), int(pt2[1])),
                    cv2.FONT_HERSHEY_SIMPLEX, 0.5, (255, 255, 255), 1)
end=time.time()
print("good match num:{} good match points:".format(len(good)))
print("number of feature points:", len(kp1), len(kp2))
#匹配连线
draw_params = dict(matchColor=(255, 0, 0),
                   singlePointColor=(0, 0, 255),
                   matchesMask=matchesMask,
                   flags=0)

res = cv2.drawMatchesKnn(img1, kp1, img3, kp2, matches, None,**draw_params)


print("运行时间:%.2f秒"%(end-start))
cv2.imshow("img1_gray",img1_gray)
cv2.imshow("img3_gray",img3_gray)
cv2.imshow("Result", res)
cv2.imshow("img1", img1)
cv2.imshow("img3", img3)
cv2.imwrite("SIFTimg1_gray.jpg",img1_gray)
cv2.imwrite("SIFTimg3_gray.jpg",img3_gray)
cv2.imwrite("SIFTimg1.jpg",img1)
cv2.imwrite("SIFTimg3.jpg",img3)
cv2.imwrite("SIFTimg1t.jpg",img1t)
cv2.imwrite("SIFTimg3t.jpg",img3t)
cv2.imwrite("SIFTResult.jpg",res)
#cv2.waitKey(0)
#cv2.destroyAllWindows()

可以分别对所要匹配图像进行原图匹配、进行尺度变换后匹配、旋转后匹配、以及对图像进行遮挡后进行匹配;进而来对匹配结果进行分析是否符合SIFT算法的特点。
尺度变换时输出结果:
远近角度匹配输出结果
左右图各取特征点1000,匹配对数195,匹配时间为0.36s
逆时针旋转30度输出结果:
在这里插入图片描述
左图特征点835右图特征点714,匹配对数499,匹配时间0.54s
遮挡情况下的输出匹配结果:
对图片加入马赛克遮挡
左图特征点835,右图特征点807,匹配对数631,匹配时间0.27s

  • 5
    点赞
  • 13
    收藏
    觉得还不错? 一键收藏
  • 6
    评论
评论 6
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值