当前位置:   article > 正文

opencv图像处理—案例实战:全景图像拼接:特征匹配方法_cv2.bfmatcher

cv2.bfmatcher

目录

Brute-Force蛮力匹配

1对1的匹配

k对最佳匹配 

 随机抽样一致算法(Random sanple consensus,RANSAC)

单应性矩阵 

实战演练 :图像拼接方法

ImageStiching.py 

 Stitcher.py

具体效果

出现错误1 

出现错误2 


 

Brute-Force蛮力匹配

 得到的特征向量一个一个比,看哪两个特征向量离得最近,就应该是最相似的。

  1. kp1, des1 = sift.detectAndCompute()函数有两个返回值,第一个返回值是特征点的坐标,第二个返回值是特征向量。
  2. cv2.BFMatcher()的参数:第一个参数表示使用的测量距离,这里使用的是欧氏距离,为默认值,而且默认使用NORM_L2来归一化数组的欧氏距离。第二个参数是一个布尔值,默认为Faulse,本例中crossCheck为True,即两张图像中的特征点必须互相都是唯一选择,例如A中的第i个特征点与B中的第j个特征点最近的,并且B中的第j个特征点到A中的第i个特征点也是
  1. import cv2
  2. import numpy as np
  3. import matplotlib.pyplot as plt
  4. img1=cv2.imread('E:/OpenCV/image/1shu.png',0)#灰度图
  5. img2=cv2.imread('E:/OpenCV/image/2shu.png',0)#灰度图
  6. def cv_show(name,img):
  7. cv2.imshow('name',img)
  8. cv2.waitKey(0)
  9. cv2.destroyAllWindows()
  10. cv_show('img1',img1)
  11. cv_show('img2',img2)
  12. sift=cv2.xfeatures2d.SIFT_create()
  13. kp1,des1=sift.detectAndCompute(img1,None)#检测关键点并计算特征向量(des)
  14. kp2,des2=sift.detectAndCompute(img1,None)
  15. #crossCheck表示两个特征点要互相匹,例如A中的第i个特征点与B中的第j个特征点最近的,并且B中的第j个特征点到A中的第i个特征点也是
  16. #NORM_L2:归一化数组的(欧几里得距离),如果其他特征计算方法需要考虑不同的匹配计算方式。
  17. bf=cv2.BFMatcher(crossCheck=True)#BF:蛮力匹配的缩写

 

1对1的匹配

  1. distance:表示一对匹配的特征点的欧式距离,数值越小说明俩个特征点越相近。 
  2. cv2.drawMatches(img1, kp1, img2, kp2, matches_10[:10], None, flags=2)对图像的关键点进行连线操作。
  1. matches=bf.match(des1,des2)
  2. matches=sorted(matches,key=lambda x:x.distance)#排个序:最接近的、第二接近的、第三……
  3. img3=cv2.drawMatches(img1,kp1,img2,kp2,matches[:10],None,flags=2)#把关键点连在一起
  4. cv_show('img3',img3)

k对最佳匹配 

  1. bf=cv2.BFMatcher()#特征匹配算法
  2. matches=bf.knnMatch(des1,des2,k=2)#第一张图中的点对应第二张图中两个特征点
  3. good=[]
  4. for m,n in matches:
  5. if m.distance<0.75*n.distance:#过滤:这里m, n分别表示两个特征点,如果两个特征点distance比值小于0.75,则保留该特征匹配点。
  6. good.append([m])
  7. img3=cv2.drawMatchesKnn(img1,kp1,img2,kp2,good,None,flags=2)#对图像的关键点进行连线操作。
  8. cv_show('img3',img3)

如果需要更快速完成操作,可以尝试使用cv2.FlannBasedMatcher 

 随机抽样一致算法(Random sanple consensus,RANSAC

 选择初始样本点进行拟合,给定一个容忍范围,不断进行迭代

每一次拟合后,容差范围内都有对应的数据点数,找出数据点个数最多的情况,就是最终的拟合成果

单应性矩阵 

  •  对图像的投影变换
  • 最后一个值设为一,因为这样归一化好做
  • 8个值需要8个方程,需要四对点,(x,y)可以构成两个方程
  • 为防止取到错误点,需要用RANSAC先过滤

实战演练 :图像拼接方法

  1.  提取图像特征,需要关键点(sift)
  2. 对某一张图求H矩阵,得到对应结果
  3. 拼接在一起

pycharm运行代码 

ImageStiching.py 

  1. from Stitcher import Stitcher
  2. import cv2
  3. def resize(img):
  4. height, width = img.shape[:2]
  5. size = (int(width*0.4), int(height*0.4))
  6. img_resize = cv2.resize(img, size, interpolation=cv2.INTER_AREA)
  7. return img_resize
  8. # 读取拼接图片
  9. imageA = cv2.imread("bag_1.jpg")
  10. imageB = cv2.imread("bag_2.jpg")
  11. a = resize(imageA)
  12. b = resize(imageB)
  13. # 把图片拼接成全景图
  14. stitcher = Stitcher()
  15. (result, vis) = stitcher.stitch([a, b], showMatches=True)
  16. # 显示所有图片
  17. cv2.imshow("Image A", a)
  18. cv2.imshow("Image B", b)
  19. cv2.imshow("Keypoint Matches", vis)
  20. cv2.imshow("Result", result)
  21. cv2.waitKey(0)
  22. cv2.destroyAllWindows()

 Stitcher.py

  1. import numpy as np
  2. import cv2
  3. class Stitcher:
  4. # 拼接函数
  5. def stitch(self, images, ratio=0.75, reprojThresh=4.0, showMatches=False):
  6. # 获取输入图片
  7. (imageB, imageA) = images
  8. # 检测A、B图片的SIFT关键特征点,并计算特征描述子
  9. (kpsA, featuresA) = self.detectAndDescribe(imageA)
  10. (kpsB, featuresB) = self.detectAndDescribe(imageB)
  11. print("kpsA, featuresA", (kpsA, featuresA))
  12. # 匹配两张图片的所有特征点,返回匹配结果
  13. M = self.matchKeypoints(kpsA, kpsB, featuresA, featuresB, ratio, reprojThresh)
  14. print("M", M)
  15. # 如果返回结果为空,没有匹配成功的特征点,退出算法
  16. if M is None:
  17. return None
  18. # 否则,提取匹配结果
  19. # H是3x3视角变换矩阵
  20. (matches, H, status) = M
  21. # 将图片A进行视角变换,result是变换后图片
  22. result = cv2.warpPerspective(imageA, H, (imageA.shape[1] + imageB.shape[1], imageA.shape[0]))
  23. self.cv_show('result', result)
  24. # 将图片B传入result图片最左端
  25. result[0:imageB.shape[0], 0:imageB.shape[1]] = imageB
  26. self.cv_show('result', result)
  27. # 检测是否需要显示图片匹配
  28. if showMatches:
  29. # 生成匹配图片
  30. vis = self.drawMatches(imageA, imageB, kpsA, kpsB, matches, status)
  31. # 返回结果
  32. return (result, vis)
  33. # 返回匹配结果
  34. return result
  35. def cv_show(self, name, img):
  36. cv2.imshow(name, img)
  37. cv2.waitKey(0)
  38. cv2.destroyAllWindows()
  39. def detectAndDescribe(self, image):
  40. # 将彩色图片转换成灰度图
  41. gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
  42. # 建立SIFT生成器
  43. descriptor = cv2.xfeatures2d.SIFT_create()
  44. # 检测SIFT特征点,并计算描述子
  45. (kps, features) = descriptor.detectAndCompute(image, None)
  46. # 将结果转换成NumPy数组,即用数组来表示特征点的坐标。
  47. kps = np.float32([kp.pt for kp in kps])
  48. # 返回特征点集,及对应的描述特征
  49. return (kps, features)
  50. def matchKeypoints(self, kpsA, kpsB, featuresA, featuresB, ratio, reprojThresh):
  51. # 建立暴力匹配器
  52. matcher = cv2.BFMatcher()
  53. # 使用KNN检测来自A、B图的SIFT特征匹配对,K=2
  54. rawMatches = matcher.knnMatch(featuresA, featuresB, 2)
  55. matches = []
  56. for m in rawMatches:
  57. # 当最近距离跟次近距离的比值小于ratio值时,保留此匹配对
  58. if len(m) == 2 and m[0].distance < m[1].distance * ratio:
  59. # 存储两个点在featuresA, featuresB中的索引值
  60. matches.append((m[0].trainIdx, m[0].queryIdx))
  61. # 当筛选后的匹配对大于4时,计算视角变换矩阵
  62. if len(matches) > 4:
  63. # 获取匹配对的点坐标
  64. ptsA = np.float32([kpsA[i] for (_, i) in matches])
  65. ptsB = np.float32([kpsB[i] for (i, _) in matches])
  66. # 计算视角变换矩阵
  67. (H, status) = cv2.findHomography(ptsA, ptsB, cv2.RANSAC, reprojThresh)
  68. # 返回结果
  69. return (matches, H, status)
  70. # 如果匹配对小于4时,返回None
  71. return None
  72. def drawMatches(self, imageA, imageB, kpsA, kpsB, matches, status):
  73. # 初始化可视化图片,将A、B图左右连接到一起
  74. (hA, wA) = imageA.shape[:2]
  75. (hB, wB) = imageB.shape[:2]
  76. vis = np.zeros((max(hA, hB), wA + wB, 3), dtype="uint8")
  77. vis[0:hA, 0:wA] = imageA
  78. vis[0:hB, wA:] = imageB
  79. # 联合遍历,画出匹配对
  80. for ((trainIdx, queryIdx), s) in zip(matches, status):
  81. # 当点对匹配成功时,画到可视化图上
  82. if s == 1:
  83. # 画出匹配对
  84. ptA = (int(kpsA[queryIdx][0]), int(kpsA[queryIdx][1]))
  85. ptB = (int(kpsB[trainIdx][0]) + wA, int(kpsB[trainIdx][1]))
  86. cv2.line(vis, ptA, ptB, (0, 234, 0), 1)
  87. # 返回可视化结果
  88. return vis

具体解读步骤可看:全景图拼接 特征匹配 附代码_shuyeah的博客-CSDN博客_将地图点位与全景图匹配的代码 

具体效果

 

 

 

 

 

 

 

 

 

出现错误1 

自定义.py文件导入Module,报错ModuleNotFoundError: No module named

运行下面代码时候出现错误 

  1. from Stitcher import Stitcher
  2. import

错误如下

ModuleNotFoundError: No module named 

解决方法

通常情况下,当使用 import 语句导入模块后,Python 会按照以下顺序查找指定的模块文件:

  • 在当前目录,即当前执行的程序文件所在目录下查找;
  • 到 PYTHONPATH(环境变量)下的每个目录中查找;
  • 到 Python 默认的安装目录下查找。

解决“Python找不到指定模块”的方法有 3 种,分别是:

  1. 向 sys.path 中临时添加模块文件存储位置的完整路径;
  2. 将模块放在 sys.path 变量中已包含的模块加载路径中;
  3. 设置 path 系统环境变量。

具体方法:Python导入模块的3种方式(超级详细) 

 

出现错误2 

 

原因分析:NoneType可能是没有读取到图片,可以检查读取图片路径是否正确 

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/Monodyee/article/detail/81417
推荐阅读
相关标签
  

闽ICP备14008679号