【IMG Feature matching】openCV获取图像特征点的方法

本文探讨了电脑视觉中物件识别的关键技术,包括特征点选取、局部特征提取及特征匹配。通过不同算法如FAST、Harris、SIFT、SURF等,详细解析了关键点检测的原理与应用,为实现精准的图像识别与比对提供理论基础。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

 

        在电脑视觉中,我们经常需要侦测或判断两个物件相似程度?该物件是否出现在相片中?在那里地方?例如下图中的这个City Café…

        电脑是否能判断上图的咖啡与我手上的这杯是相同品牌?亦或,能否知道这杯就是City Café?

                对于我们人类来说,这应该是直觉又简单不过的事,但对于电脑可不是这样了,从物件中找出像素变化的规则与异同是它看待世界的方式。在下面的范例中,我们将透过机器学习方式,搭配Feature matching技术来授与电脑辨识及比对物体的能力。

Feature matching

要辨识某物体的条件就是先掌握其特征!由于我们要辨识的是某个物件而非整张相片,因此需要提取所谓称为「Local features」的特征,作法是先在影像中选取重要的特征点,接着以其为base取得周围的特征(即local features),这些来自不同相片的local features会透过稍后会说明的Feature matching功能来比对是否有相同的物件。

例如当我们孩提时第一次看到兔子,它那深具特色的长耳朵形象会立刻深植在我们脑海中,往后看到其它不同的兔子时,虽然是在不同的时空环境,但是那长耳朵的特征会立刻唤醒我们它可能是一只兔子的记忆。在这例子中,长耳朵对于我们来说就是辨识兔子的局部特征,那么电脑呢?它是如何透过特征点→局部特征→Feature matching的方式来看待这只兔子?

特征点的选取

要解释电脑如何看待特征之前,我们先看一下这些局部影像:

您能分辨这些局部影像出自于下面这张图片的那一部份吗?

相关图片

A、C图 →很难判别,平淡的局部影像,没有明显的特性可供识别,图片中很多地方都与其类似。

        B图 →容易一些,我们可从图片中物件的边缘找到线索,它应该位于兔子周围的区域,但兔子的边缘仍过于广泛,必须逐一比对后才能确定。

        E图 →较容易,我们可以确定是在兔子下半身与杂草交界处的某区域。

        F图 →最容易,马上就能明确的知道在眼睛的区域,因为它包含一个明确的区块。

        有没有发现其实上述的这些特性可用edges、corners、blobs等组合来描述!B图有edges,E图有corners,F图则具有blobs,因此,我们只要从感兴趣的物件中设定具有这些特性的区域为关键点keypoints,再针对各关键点计算并提取该区域的features,就能用来比对及辨识物体。事实上,基本的影像辨识,如上所述的特征点→局部特征→Feature matching步骤,所执行的动作依序是:Keypoint detection、Feature extraction以及Feature matching。

  1. Keypoint detection:
    在图片中取得感兴趣的关键点(可能为edges、corners或blobs)。
  1. Feature extraction:
    针对各关键点提取该区域的features(我们称为local features)。
  1. 关键点筛选并进行Feature matching。

我们可将上述的步骤归纳如下:

首先,在图片A与B分别找出Keypoints,再依据各个keypoints取出其local features(主要为梯度和角度所组成的Histogram),两张图片的local features进行feature matching,计算并match各个距离最小的keypoint 。

接下来分别针对A) Keypoint detection、B) Feature extraction以及C) Feature matching这三个步骤作说明,下方先介绍A) Keypoint detection,B)与C)步骤将会在下一篇文章中介绍。

  1. Keypoint detection关键点侦测

        Keypoint detection的演算法有很多,openCV便提供了十一种方法:

“FAST" – FastFeatureDetector

“STAR" – StarFeatureDetector

“SIFT" – SIFT (nonfree module)

“SURF" – SURF (nonfree module)

“ORB" – ORB

“BRISK" – BRISK

“MSER" – MSER

“GFTT" – GoodFeaturesToTrackDetector

“HARRIS" – GoodFeaturesToTrackDetector with Harris detector enabled

“Dense" – DenseFeatureDetector

“SimpleBlob" – SimpleBlobDetector

         还有以下二种Grid和Pyramid的方式,可合并以上各方法来使用:

“Grid" – GridAdaptedFeatureDetector

“Pyramid" – PyramidAdaptedFeatureDetector  

后方再append上述的各个feature detector name即可,

例如: “GridFAST", “PyramidSTAR" .

        Keypoints关键点除了用来比对或辨识物件之外,也经常用于拼接(stitch)图像以制作全景图。以下说明并实作各种关键点侦测。

原理:以FAST为例

不同的keypoint detector有其不同的演算方式,下面以FAST为例:

        FAST方法认为,一个以c为中心、半径为r的圆形,若它位于一个所谓的corner上,那么该圆的圆周上必有连续n个点,其强度值大于或小于中心点c加上一个指定的threshold门槛的强度值。如果是的话,该中心点c便被认为是keypoint。

各种Keypoint detector技术

FAST

  1. 原理简单
  2. 执行速度相当快
  3. 主要用于侦测corners,亦可侦测blob。
  4. 适用于要求速度的real-time analysis
  5. 适用于速度慢或较低阶的执行环境。
  6. 使用度极高,尤其在需要即时的realtime环境。

程式范例

detector = cv2.FeatureDetector_create(“FAST")

kps = detector.detect(gray)

print(“# of keypoints: {}".format(len(kps)))

C:\Users\CHE7C6~1.TSE\AppData\Local\Temp\x10sctmp10.png

抓取到1,458个特征点

Harris

  1. 速度相当快,但仍较FAST慢,不过侦测corner比起FAST准确一些。
  2. 广泛应用于侦测edges及corners

程式范例

detector = cv2.FeatureDetector_create(“HARRIS")

kps = detector.detect(gray)

print(“# of keypoints: {}".format(len(kps)))

C:\Users\CHE7C6~1.TSE\AppData\Local\Temp\x10sctmp11.png

抓取到350个特征点

GFTT

  1. GFTT为Harris keypoint detector的再修正。
  2. 针对edges/corner detect的准确率与速度有所提升,但实际上使用感觉差异不大。

程式范例

detector = cv2.FeatureDetector_create(“GFTT")

kps = detector.detect(gray)

print(“# of keypoints: {}".format(len(kps)))

C:\Users\CHE7C6~1.TSE\AppData\Local\Temp\x10sctmp12.png

抓取到922个特征点

DoG (SIFT)

  1. 原理较为复杂。
  2. 主要针对blob 侦测,不过亦可侦测corners。
  3. 可适应物件的scale(大小变化)及angle(旋转角度)等情况。
  4. 在DoG模型中,使用了不同尺寸影像并套用高斯模糊,比较不同模糊比例之间的变化,来决定是否为keypoint。
  5. 由于计算量大,DoG的执行速度较慢,不适用于realtime的环境。
  6. SIFT已广泛的应用于电脑视觉领域,并成为评定新keypoint detecter的效率指标。

程式范例

detector = cv2.FeatureDetector_create(“SIFT")

kps = detector.detect(gray)

print(“# of keypoints: {}".format(len(kps)))

C:\Users\CHE7C6~1.TSE\AppData\Local\Temp\x10sctmp13.png

抓取到553个特征点

Fast Hessian (SURF)

  1. 基于DoG(SIFT)模型而发展,改善其速度慢的缺点。
  2. 可使用于realtime的环境,但速度仍比不上FAST等keypoint detector。
  3. 与DoG相同,用于侦测corners以及明显材质纹路的textures。

程式范例

detector = cv2.FeatureDetector_create(“SURF")

kps = detector.detect(gray)

print(“# of keypoints: {}".format(len(kps)))

C:\Users\CHE7C6~1.TSE\AppData\Local\Temp\x10sctmp14.png

抓取到927个特征点

STAR

  1. 使用于侦测blog area。
  2. 与DoG相同,亦使用高斯模糊计算,但由于其演算方式相当复杂,目前并不常被使用。
  3. 侦测速度相当快,可应用于realtime分析,但效果并不如FAST。

程式范例

detector = cv2.FeatureDetector_create(“STAR")

kps = detector.detect(gray)

print(“# of keypoints: {}".format(len(kps)))

C:\Users\CHE7C6~1.TSE\AppData\Local\Temp\x10sctmp15.png

抓取到171个特征点

MSER

1. 使用于侦测blog area

2. 判断的依据(需满足此三点),则认定为blog area:

a. 相连的像素

b. 相似的像素强度

c. 与背景成对比

3. 对于小区域且对比明显的area侦测效果良好。

4. 不适用分析模糊的影像。

5. 不适合使用于要求速度的realtime环境。

6. 输入的影像符合其要求的三种条件,则侦测速度可加快。

程式范例

detector = cv2.FeatureDetector_create(“MSER")

kps = detector.detect(gray)

print(“# of keypoints: {}".format(len(kps)))

C:\Users\CHE7C6~1.TSE\AppData\Local\Temp\x10sctmp16.png

抓取到147个特征点

Dense

  1. Dense是最简单的keypoint detector。
  2. 它的原理是先设定一个K值,然后均匀的在整张图面上以每隔K pixels的距离布置一个keypoint,因此严格来说,Dense并没有detect的动作。
  3. 在某些情况下(如风景类图片),Dense的效果其实不会比FAST Harris  DoG等其它detector差。
  4. Dense算法虽然简单,但也是其缺点,因为过于简单而产生过多的keypoints,甚至于超过图片中实际的数量,过多的keypoints需要更多的记忆体储存及运算量。
  5. 单纯的Dense无法适用于不同尺寸的图像,因此需在Keypoints上加入不同半径大小的侦测点(Multiple radii)才能应用不同的尺寸大小(scale invariant)。
  6. 资源耗用大,因此Dense不适用于realtime及运行于小型装置。
  7. 适合用于机器学习的影像分类及基于内容的影像搜索。

Dense分为单一radii及多重radii两种方法,其中后者可适应尺寸变化的情况。

单一radii:

下方范例K值为9,使用单一radii(固定半径的侦测点),此方式无法应付尺寸大小变化的情况。

程式范例

detector = cv2.FeatureDetector_create(“Dense")

detector.setInt(“initXyStep", 9)

kps = detector.detect(gray)

C:\Users\CHE7C6~1.TSE\AppData\Local\Temp\x10sctmp17.png

抓取到3,350个特征点

多重Radii:

使用不同半径的keypoint(multi radii),以适应图像尺寸变化的情况。

下方范例K值为36,每个keypoint取三种半径3, 9, 15 pixels

程式范例

detector = cv2.FeatureDetector_create(“Dense")

detector.setInt(“initXyStep", 36)

rawKps = detector.detect(gray)

kps = []

for rawKp in rawKps:

        for r in (3, 9, 15):

                kp = cv2.KeyPoint(x= rawKp.pt [0], y= rawKp.pt [1], _size=r * 2)

                kps.append(kp)

C:\Users\CHE7C6~1.TSE\AppData\Local\Temp\x10sctmp18.png

抓取到663个特征点

BRISK

  1. FAST keypoint detectorh的强化,主要是针对尺寸缩放的部份(scale space invariance)。
  2. 会先以pyramid方式产生尺寸大小不同的影像,再针对每一层进行FAST运算及取值。
  3. 速度快,适用于realtime的环境。
  4. 适用于侦测Corners。

程式范例

detector = cv2.FeatureDetector_create(“BRISK")

kps = detector.detect(gray)

print(“# of keypoints: {}".format(len(kps)))

C:\Users\CHE7C6~1.TSE\AppData\Local\Temp\x10sctmp19.png

抓取到176个特征点

ORB

  1. 与BRISK相同,ORB亦是针对FAST的强化,但除了scale space invariance,亦加入了旋转不变性(rotation invariance).。
  2. ORB原理有三大步骤:
  1. Pyramid图像尺寸并进行各尺寸的FAST计算。
  2. 使用Harris keypoint detector的方法计算每个keypoint分数(是否近似corner?),并进行排序,最多仅取500个keypoints,其余则丢弃。
  3. 于此第三步中加入旋转不变性,使用「intensity centroid」计算每个keypoint的rotation。
  1. ORB与BRISK相同,继承了FAST运算快速的特性,可适用于realtime分析。

C:\Users\CHE7C6~1.TSE\AppData\Local\Temp\x10sctmp20.png

        抓取到500个特征点

不同特征点的合并使用

GridAdaptedFeatureDetector与FAST并用为例:

程式范例

detector = cv2.FeatureDetector_create(“GridFAST")

kps = detector.detect(gray)

print(“# of keypoints: {}".format(len(kps)))

C:\Users\CHE7C6~1.TSE\AppData\Local\Temp\x10sctmp21.png

抓取到570个特征点

PyramidAdaptedFeatureDetector与STAR并用为例

程式范例

detector = cv2.FeatureDetector_create(“PyramidSTAR")

kps = detector.detect(gray)

print(“# of keypoints: {}".format(len(kps)))

C:\Users\CHE7C6~1.TSE\AppData\Local\Temp\x10sctmp22.png

抓取到213个特征点

最后

        本文中我们介绍了这么多种(十种)的图像关键点侦测方法,到底要采用何种方法才是最好的呢?,其实并没有一定的标准,不同图像与专案环境有其适合的方法,必须视情况而定,我们也可以每种都尝试看看,再从中选择最佳的方式。

        现在我们透过Keypoint detection得到了keypoints,接下来,就可以开始透过Feature extraction以及Feature matching来进行影像片辨识比对了。

### 使用 Python OpenCV 和 PyQt5 实现特征点匹配 为了实现图像之间的特征点匹配,可以利用 OpenCV 提供的强大功能以及 PyQt5 的图形界面能力。以下是具体方法: #### 导入必要的库 首先导入所需的模块,包括用于处理图像的 `cv2` 库和构建 GUI 所需的各种 PyQt5 组件。 ```python import sys import cv2 from PyQt5.QtWidgets import QApplication, QMainWindow, QPushButton, QVBoxLayout, QWidget, QLabel, QFileDialog from PyQt5.QtGui import QPixmap, QImage ``` #### 创建主窗口类 定义一个继承自 `QMainWindow` 的类来设置应用程序的主要布局结构,并添加按钮以便加载待比较的两幅图像文件。 ```python class MainWindow(QMainWindow): def __init__(self): super().__init__() self.setWindowTitle('Feature Matching with SIFT') self.setGeometry(100, 100, 800, 600) central_widget = QWidget() layout = QVBoxLayout() btn_load_img1 = QPushButton('Load Image 1', self) btn_load_img1.clicked.connect(lambda: self.load_image(1)) layout.addWidget(btn_load_img1) btn_load_img2 = QPushButton('Load Image 2', self) btn_load_img2.clicked.connect(lambda: self.load_image(2)) layout.addWidget(btn_load_img2) match_btn = QPushButton('Match Features', self) match_btn.clicked.connect(self.match_features) layout.addWidget(match_btn) self.image_label_1 = QLabel(self) layout.addWidget(self.image_label_1) self.image_label_2 = QLabel(self) layout.addWidget(self.image_label_2) central_widget.setLayout(layout) self.setCentralWidget(central_widget) self.img_paths = {1: None, 2: None} self.images = {} ``` #### 加载并显示图像函数 编写两个辅助函数分别负责打开文件对话框让用户选择要分析的图片路径,并将选中的图片展示出来。 ```python def load_image(self, img_num): options = QFileDialog.Options() file_name, _ = QFileDialog.getOpenFileName( self, "Select an image", "", "Images (*.png *.jpg *.jpeg);;All Files (*)", options=options ) if not file_name: return pixmap = QPixmap(file_name).scaledToWidth(300) label = getattr(self, f'image_label_{img_num}') label.setPixmap(pixmap) self.img_paths[img_num] = file_name self.images[img_num] = cv2.imread(file_name, cv2.IMREAD_GRAYSCALE)[^1] ``` #### 特征点检测与描述符计算 当点击“Match Features”按钮时调用此函数,在两张输入图上应用SIFT算法提取关键点及其对应的局部不变量描述子向量。 ```python def detect_and_compute_descriptors(image_path): sift = cv2.SIFT_create() gray = cv2.cvtColor(cv2.imread(image_path), cv2.COLOR_BGR2GRAY) keypoints, descriptors = sift.detectAndCompute(gray, None) return keypoints, descriptors ``` #### 进行特征点匹配操作 最后一步就是基于上述得到的关键点位置信息来进行最近邻距离比率测试(NNDR),从而筛选出可靠的配对关系;之后绘制这些对应关系作为可视化结果的一部分返回给用户查看。 ```python def match_features(self): if all(path is not None for path in self.img_paths.values()): kp1, des1 = detect_and_compute_descriptors(self.img_paths[1]) kp2, des2 = detect_and_compute_descriptors(self.img_paths[2]) bf = cv2.BFMatcher() matches = bf.knnMatch(des1, des2, k=2) good_matches = [] for m,n in matches: if m.distance < 0.7*n.distance: good_matches.append([m]) matched_img = cv2.drawMatchesKnn( self.images[1], kp1, self.images[2], kp2, good_matches[:10], None, flags=cv2.DrawMatchesFlags_NOT_DRAW_SINGLE_POINTS ) h,w,_ = matched_img.shape qImg = QImage(matched_img.data, w, h, w*3, QImage.Format_RGB888).rgbSwapped() pixMap = QPixmap.fromImage(qImg) self.image_label_1.setPixmap(pixMap.scaledToHeight(int(h/2))) self.image_label_2.clear() ``` 以上即为完整的使用 Python 结合 OpenCV 及 PyQt5 来完成基本特征点匹配任务的应用程序框架。
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值