1.Harris角点检测
cv2.cornerHarris(imge,blockSize,ksize,k)角点检测 a*b-k(a+b)**2来判断(a,b是特征值)
大于0边角,等于0平坦,小于0边界 image为float32 , blockSize角点检测的区域大小
ksize是sobel求导使用的窗口大小 k取值范围是[0.04,0.06]
dst = cv2.cornerHarris(image,2,3,0.04 )
cv2.imshow('dst',dst),cv2.waitKey(0)
im_color[dst>0.01*dst.max()] = [0,0,255]
cv2.imshow('image', im_color),cv2.waitKey(0),cv2.destroyAllWindows()
2.Sift尺度不变
#尺度不变 可在图像中检测出关键点,是一种局部特征描述子。
#1.建立高斯金字塔(1.不同方差2.降采样原图)====>构建高斯差分金字塔
#2.关键点位置的确定 利用差分找极值
#3.确定关键点主原图方向(找到关键点[极值点])
#4.构建关键点描述符
构造sift,求解出特征点和sift特征向量
sift = cv2.xfeatures2d.SIFT_create()
kpsA, dpA = sift.detectAndCompute(imgA, None)
kpsB, dpB = sift.detectAndCompute(imgB, None)
# 第三步:构造BFMatcher()蛮力匹配(Brute-Force),匹配sift特征向量距离最近对应组分
bf = cv2.BFMatcher()
# ===================================1对1的匹配
# A图像的一关键点和B图像的一关键点,互相都是对方最匹配的点。
# 获得匹配的结果,结果是一对,A图像的第 i 个kp 和 B图像的第 j 个kp一堆,匹配程度是多少,
# 匹配程度(两个128维度特征向量的近似度)用欧式距离表示,距离越小,表示越相近
matches = bf.match(dpA, dpB)
# 按照匹配程度,对匹配的 对儿 排个序,
matches = sorted(matches, key=lambda x: x.distance)
# 使用cv2.drawMacthes进行画图操作,这里我们只画出前30个最相近的。
ret = cv2.drawMatches(imgA, kpsA, imgB, kpsB, matches[:30], None, flags=2)
# ===================================K对最佳的匹配
# A图像中的某个关键点,可以在B图像中找到K的最匹配的点都保留下来。
# 假如我们取前2最匹配,
# 第一个图像有个点A,和第二个图像的有个点B最匹配,和C是次级最匹配。
# 匹配程度(两个128维度特征向量的近似度)用欧式距离表示,距离越小,表示越相近,dis(A,B)=m, dis(A,B)=n
# 我们再做个比较,如果 m < 0.75 * n 就可以取m,否则不取m,因为区分度不高,这个很模糊,不好说的。
matches = bf.knnMatch(dpA, dpB, k=2)
# 完了后需要做个过滤
good_pts = []
for res in matches:
m, n = res
if m.distance < 0.75 * n.distance:
good_pts.append([m])
# 第四步:使用cv2.drawMacthes进行画图操作,这里我们只画出前30个最相近的。
ret = cv2.drawMatchesKnn(imgA, kpsA, imgB, kpsB, good_pts, None, flags=2)
3透视变换
计算各个图像的关键点信息和特征描述信息
sift = cv2.xfeatures2d.SIFT_create()
kpA, dpA = sift.detectAndCompute(img, None)
kpB, dpB = sift.detectAndCompute(img, None)
进行特征匹配并且获得变换矩阵
bf = cv2.BFMatcher()
src_matches = bf.knnMatch(dpA, dpB, k=2)#返回二个最近的邻点
# 完了后需要做个过滤
good_pts = []
for res in src_matches:
if len(res) == 2:
m, n = res # 单个点可以取出多个匹配结果。
# bf.knnMatch返回的参数是:
# distance: 匹配度,欧氏距离度量的
# trainIdx: 图像A的关键点下标编号,也就是第几个关键点,数组下标
# queryIdx: 图像B的关键点下标编号,也就是第几个关键点,数组下标
if m.distance < 0.75 * n.distance:
# 每个元素保存的是图像A的关键点, 和图像B的关键点
good_pts.append((m.trainIdx, m.queryIdx))
if len(good_pts) > 4:#起码大于4个点才
pts_src = np.float32([kptA[j] for (_, j) in good_pts]) # 获得对应的真实的关键点的位置数值
print(pts_src.shape)
pts_dst = np.float32([kptB[i] for (i, _) in good_pts]) # 获得对应的真实的关键点的位置数值
print(pts_dst.shape)
# 这个函数是将 RANSAC 算法融合在内了,拟合方式选择的是cv2.RANSAC,允许的误差阈值是4
# 计算多个二维点对之间的最优单映射变换矩阵 H(3行x3列) ,使用最小均方误差或者RANSAC方法
homography, status = cv2.findHomography(pts_src, pts_dst, cv2.RANSAC, ransacReprojThreshold=4.0)
对图像进行变换homography是透视变换的矩阵
im_out = cv2.warpPerspective(imgA_SRC, homography, (w_A + w_B, h_A))
图像拼接
im_out[0: h_B, 0: w_B, :] = imgB_SRC