• 基于OpenCv的图像特征匹配


    目录

    图像特征检测SIFT算法介绍:

    DOG尺度空间构造(Difference of Gaussian)

    关键点搜索与定位

    SIFT的优点:

    特征匹配

    python代码实现

    效果展示:


    图像特征检测SIFT算法介绍:

    DOG尺度空间构造(Difference of Gaussian

    首先是对原特征图下采样可以得到金字塔形状的多分辨率空间,作为特征金字塔,该特征金字塔可以方便提取出不同尺度的特征(也可以叫多尺度空间)。

    多尺度空间:利用高斯核对图像进行卷积操作,不同的高斯核参数 σ \sigma σ对应不同的形状,相当于多尺度空间。利用高斯核对图像做卷积操作就是高斯模糊,卷积和形状越矮越扁,模糊程度就越大。关键特征在不断模糊的过程中相对其他位置应该是更容易保留下来的,因此在后面对特征图做差时可以形成极值点。

    分别对每层特征金字塔中的特征图,用不同的高斯核进行卷积操作,就得到了高斯特征金字塔,再对相邻的两层作差,进一步得到DOG金字塔。

    关键点搜索与定位

    关键特征在不同的高斯模糊下更容易保留,在DOG特征图中表现为极值点。

    SIFT的优点:

    1、具有较好的稳定性和不变性,能够适应旋转、尺度缩放、亮度的变化,能在一定程度上不受视角变化、仿射变换、噪声的干扰。
    2、区分性好,能够在海量特征数据库中进行快速准确的区分信息进行匹配
    3、多量性,就算只有单个物体,也能产生大量特征向量
    4、高速性,能够快速的进行特征向量匹配
    5、可扩展性,能够与其它形式的特征向量进行联合

    特征匹配

     暴力(Brute-Force)匹配:一种描述符匹配算法,该方法会比较两个描述符,并产生匹配结果列表,第一个描述符的所有特征都拿来和第二个进行比较。

    python代码实现

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

    效果展示:

     拼接后:

     

     

  • 相关阅读:
    技师学院物联网实训室建建设方案
    详解Python中的切片(一看就懂版)
    JAVA计算机毕业设计程序设计类课程的课堂教学效果评价系统Mybatis+系统+数据库+调试部署
    虚幻引擎:C++网络属性同步
    HTTP 抓包工具——Fiddler项目实战
    OSG学习之三:坐标变换
    在 Kubernetes 上运行 Elasticsearch
    【Linux operation 46】Centos 7.9中安装使用nmap
    C 语言指针与函数
    随缘记录一些MySQL问题
  • 原文地址:https://blog.csdn.net/L888666Q/article/details/127103574