赞
踩
如果粉色窗口向四周移动,窗口内的像素没有变化则认定为平坦区域,如果窗口向上移动无明显变化,而左右移动有变化则认定为边缘,如果窗口向任意方向移动均有明显变化则为角点,如下图
dst不是输入参数,是输出参数,输出检测出来的角点
Shi-Tomasi是Harris角点检测
Harris角点检测算的稳定性和k有关,而k是个经验值,不是设定最佳值。而Shi-Tomasi好处(区别)在于不需要再对k值进行设定
第一个参数maxCorners是要检测的角点数量,无限制就是把能检测到的角点全部输出。qualityLevel是角点质量,实际上就是Harris检测时的代码img[dst>0.01*dst.max()],将很小的角点去掉,使用ShiTimasi方法就不用这一步了,直接在参数内填数值即可。第三个参数minDistance指两个交点间最小的距离,如果小于所设定的最小距离,则角点会舍弃只保留一个。第四个参数mask就是掩码,要检测哪个区域就创建一个mask,只保留要检测的区域,其他区域变为黑色。第五个参数blockSize与Harris相同。第六个参数useHarrisDetector,如果是true则使用Harris角点检测方法,如果是False则使用Shi-Tomasi检测方法,默认为false。第七个参数k是在第六个参数为true时启用的默认为0.04
- import numpy as np
- import cv2
- img = cv2.imread('2.jpg')
- gray = cv2.cvtColor(img,cv2.COLOR_BGR2GRAY)
- qualityLevel = 0.01#相当于之前的img[dst>0.01*dst.max()]
- #Shi-Tomasi角点检测。获取的角点存在corners中,输出的corners是一个三维数组且有小数点
- corners = cv2.goodFeaturesToTrack(gray,1000,qualityLevel,5)
- #将corners数组中的浮点型数据转换为整型
- corners = np.int64(corners)
- #Shi-Tomasi绘制角点
- for i in corners:
- x,y = i.ravel()#corners中的数组为多维数组,这里转换成一维数组
- cv2.circle(img,(x,y),3,255,-1)#-1画实心圆
- cv2.imshow('img',img)
- cv2.waitKey(0)
未进行整型转换的corners是一个三维数组且有小数点
进行整型转换后的corners
corners[1]输出内容为一个二维数组
进行corners[1].ravel()操作后,corners[1]变为一维数组
具体原理可以查看文章:SIFT算法原理-CSDN博客
Harris角点具有旋转不变性,但缩放后,原来的角点可能就无法检测,如下图
使用步骤:
- import numpy as np
- import cv2
- img = cv2.imread('2.jpg')
- gray = cv2.cvtColor(img,cv2.COLOR_BGR2GRAY)
- #创建SIFT对象
- sift = cv2.xfeatures2d.SIFT_create()
- #进行检测
- kp = sift.detect(gray, None)#第二个参数可以设置一个掩码,对某区域进行检测,设为None表示对整 #张图进行检测
- #绘制关键点
- cv2.drawKeypoints(gray, kp, img)#在img图像上绘制
- #计算描述子
- kp, des = sift.compute(gray, kp)#返回两个结果,第一个结果kp还是关键点,第二个参数是每个关键
- #点对应的特征向量,des.shape输出结果为(关键点数量,128)即每个关键点特征向量为128维
- cv2.imshow('SIFT', img)
- cv2.waitKey(0)
- cv2.destroyAllWindows()
- import numpy as np
- import cv2
- img = cv2.imread('2.jpg')
- gray = cv2.cvtColor(img,cv2.COLOR_BGR2GRAY)
- #创建SIFT对象
- sift = cv2.xfeatures2d.SIFT_create()
- #进行检测
- kp, des = sift.detectAndCompute(gray, None)
- #绘制关键点
- cv2.drawKeypoints(gray, kp, img)#在img图像上绘制
- cv2.imshow('SIFT', img)
- cv2.waitKey(0)
- cv2.destroyAllWindows()
SIFT最大的问题就是速度慢,而SURF速度更快,并且保留了SIFT的优点。
- import numpy as np
- import cv2
- img = cv2.imread('2.jpg')
- gray = cv2.cvtColor(img,cv2.COLOR_BGR2GRAY)
- #创建SURF对象
- surf = cv2.xfeatures2d.SURF_create()
- #进行检测并计算描述子
- kp, des = surf.detectAndCompute(gray, None)#第二个参数可以设置一个掩码,对某区域进行检测,设为None表示对整张图进行检测
- #绘制关键点
- cv2.drawKeypoints(gray, kp, img)#在img图像上绘制
- cv2.imshow('SURF', img)
- cv2.waitKey(0)
- cv2.destroyAllWindows()
ORB可以做到实时监测,也就是它的计算速度很快。ORB是FAST和BRIEF两种技术的结合,他的计算速度均高于两者,但准确度却不如两者。而且ORB是没有版权的,放在Opencv主库
FAST可以做到特征点的实时监测。BRIEF是对已检测到的特征点进行描述,它加快了特征描述建立的速度,同时也极大降低了特征匹配的时间
使用步骤:
- import numpy as np
- import cv2
- img = cv2.imread('2.jpg')
- gray = cv2.cvtColor(img,cv2.COLOR_BGR2GRAY)
- #创建ORB对象
- orb = cv2.ORB_create()
- #进行检测并计算描述子
- kp, des = orb.detectAndCompute(gray, None)#第二个参数可以设置一个掩码,对某区域进行检测,设为None表示对整张图进行检测
- #绘制关键点
- cv2.drawKeypoints(gray, kp, img)#在img图像上绘制
- cv2.imshow('SURF', img)
- cv2.waitKey(0)
- cv2.destroyAllWindows()
通过枚举方式进行特征匹配
原理:特征匹配要有两张图,首先计算第一张图的关键点和描述子。然后使用第一张图的每个特征的描述子与第二组中的所有特征描述子进行匹配。计算两者之间的差距,然后将匹配度最接近的一个匹配返回
特征匹配步骤:
- import numpy as np
- import cv2
- img1 = cv2.imread('1.jpg')
- img2 = cv2.imread('2.jpg')
- g1 = cv2.cvtColor(img,cv2.COLOR_BGR2GRAY)
- g2 = cv2.cvtColor(img2,cv2.COLOR_BGR2GRAY)
- #创建SIFT对象
- sift = cv2.xfeatures2d.SIFT_create()
- #进行检测,并计算描述子
- kp1, des1 = sift.detectAndCompute(g1,None)
- kp2, des2 = sift.detectAndCompute(g2,None)
- bf = cv2.BFMatcher(cv2.NORM_L1)
- match = bf.match(des1,des2)
- img3 = cv2.drawMatches(img1,kp1,img2,kp2,match,None)
- cv2.imshow('SIFT', img3)
- cv2.waitKey(0)
- cv2.destroyAllWindows()
在进行批量特征匹配时,FLANN速度更快。但是由于它使用的是邻近近似值,所以精度较差
使用步骤:
- import numpy as np
- import cv2
- img1 = cv2.imread('img1.jpg')
- img2 = cv2.imread('img2.jpg')
- g1 = cv2.cvtColor(img1, cv2.COLOR_BGR2GRAY)
- g2 = cv2.cvtColor(img2, cv2.COLOR_BGR2GRAY)
- sift = cv2.xfeatures2d.SIFT_create()
- kp1, des1 = sift.detectAndCompute(g1, None)
- kp2, des2 = sift.detectAndCompute(g2, None)
- #创建匹配器
- index_params = dict(algorithm = 1, trees = 5)
- search_params = dict(checks=50)
- flann = cv2.FlannBasedMatcher(index_params, search_params)
- matches = flann.knnMatch(des1, des2, k=2)
- #对所有匹配点进行过滤优化
- good = []
- for i,(m,n) in enumerate(matches):
- if m.distance < 0.7*n.distance:
- good.append(m)
- ret = cv2.drawMatchesKnn(img1, kp1, img2, kp2, [good], None)
- cv2.imshow('ret', ret)
- cv2.waitKey(0)
- cv2.destroyAllWindows()
图像查找用到了 特征匹配+单应性矩阵。特征匹配得到结果后可以把它当作输入来计算单应性矩阵,拿到单应性矩阵再经过透视变换就可以获取到最终的图像了。当我们需要通过一张图去找另一张图时,通过以上步骤就可以找到
单应性矩阵:通过单应性矩阵可以让图像由一个视角转换到另一个视角
在上述FLANN文件下,只需要利用获取的匹配点matches计算单应性矩阵,然后利用单应性矩阵通过透视变换最后找到想找的图像
- import numpy as np
- import cv2
- img1 = cv2.imread('img1.jpg')
- img2 = cv2.imread('img2.jpg')
- g1 = cv2.cvtColor(img1, cv2.COLOR_BGR2GRAY)
- g2 = cv2.cvtColor(img2, cv2.COLOR_BGR2GRAY)
- sift = cv2.xfeatures2d.SIFT_create()
- kp1, des1 = sift.detectAndCompute(g1, None)
- kp2, des2 = sift.detectAndCompute(g2, None)
- #创建匹配器
- index_params = dict(algorithm = 1, trees = 5)
- search_params = dict(checks=50)
- flann = cv2.FlannBasedMatcher(index_params, search_params)
- matches = flann.knnMatch(des1, des2, k=2)
- #对所有匹配点进行过滤优化
- good = []
- for i,(m,n) in enumerate(matches):
- if m.distance < 0.7*n.distance:
- good.append(m)
- #计算单应性矩阵H时,输入特征点必须大于等于4
- if len(good) >= 4:
- srcPts = np.float32([kp1[m.queryIdx].pt for m in good]).reshape(-1,1,2)
- dstPts = np.float32([kp2[m.trainIdx].pt for m in good]).reshape(-1,1,2)
- #找到单应性矩阵,cv2.RANSAC是对匹配点的过滤,过滤到错误匹配的点。
- #该函数有两个返回值,第一个返回值H是需要的单应性矩阵,第二个参数是掩码,我们不需要所以用_代替即可
- H, _ =cv2.findHomography(srcPts, dstPts, cv2.RANSAC, 5.0)
- #透视变换
- #pts是原图的四个角点
- h, w = img1.shape[:2]
- pts = np.float32([[0,0], [0, h-1], [w-1, h-1], [w-1, 0]]).reshape(-1,1,2)
- dst = cv2.perspectiveTransform(pts, H)
- #将找到的图像框起来
- cv2.polylines(img2, [np.int32(dst)], True, (255,0,0))
- else:
- print('there are no matches')
- exit()
- ret = cv2.drawMatchesKnn(img1, kp1, img2, kp2, [good], None)
- cv2.imshow('ret', ret)
- cv2.waitKey(0)
- cv2.destroyAllWindows()
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。