OpenCV计算机视觉实战 - 图像特征(Harris+Sift)检测 和 全景图像拼接

#################################################################
纸上得来终觉浅,绝知此事要躬行
B站视频
新课件:https://pan.baidu.com/s/1frWHqCVGR2VTn5QBtW4lPA 提取码:xh02
老课件:https://pan.baidu.com/s/1Wi31FxSPBqWiuJX9quX-jA 提取码:bbfg
################################################################

一、Harris 角点检测

角点检测算法基本思想:使用一个固定窗口在图像上进行任意方向上的滑动,比较滑动前与滑动后两种情况,窗口中的像素灰度变化程度,如果存在任意方向上的滑动,都有着较大灰度变化,那么我们可以认为该窗口中存在角点。

Harris 算法的原理 与 公式解析

在一副图像中可能存在以下三类点:平面点,边界点 和 角点
在这里插入图片描述
用下面这张图两条线做个夹角,表示三种点的位置。当它们移动的时候,灰度值会发生变化
平面点:x 和 y 方向变化不大
边界点:x 或 y 方向变化大
角点:x 和 y 方向的变化都大
在这里插入图片描述
做减法:是为了获得平移前后的差异
平方:是为了获得这样一个变化的趋势,负数就无意义了,因为-5 比 2的变化幅度大;而且对这趋势做了个增强
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

度量角点响应

在这里插入图片描述
总结一下Harris算法流程

  • 获取点数据后,计算Ix 和 Iy
  • 整合矩阵,求特征值
  • 比较特征值大小
  • 非极大值抑制NMS,过滤掉不是那么角的

详细解析 https://blog.csdn.net/linqianbi/article/details/78930239

OpenCV中的Harris操作

  • cv2.cornerHarris(img, blockSize, k)
    img: 数据类型为 float32 的入图像
    blockSize: 角点检测中指定区域的大小,前面提到的w(u,v),可能是个高斯函数
    ksize: 就像Sobel求导中使用的窗口大小
    k: 取值参数为 [0,04,0.06]. 默认0.04
    返回dst:输出图像
import cv2 
import numpy as np

img = cv2.imread(‘test_1.jpg’)
print (‘img.shape:’,img.shape)
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
# gray = np.float32(gray)
dst = cv2.cornerHarris(gray, 2, 3, 0.04)
print (‘dst.shape:’,dst.shape)

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9

dst.max是最大值,一定是角点
只要dst中满足0.01倍的最大值,就判定为角点,要求较高的也可以调大点

# 设置为其他倍数
img[dst>0.01*dst.max()]=[0,0,255]
cv2.imshow('dst',img) 
cv2.waitKey(0) 
cv2.destroyAllWindows()

 
 
  • 1
  • 2
  • 3
  • 4
  • 5

二、Sift 角点检测

1.图像尺度空间

在一定的范围内,无论物体是大还是小,人眼都可以分辨出来,然而计算机要有相同的能力却很难,所以要让机器能够对物体在不同尺度下有一个统一的认知,就需要考虑图像在不同的尺度下都存在的特点,对图像进行不同尺度的改变。

尺度空间的获取通常使用高斯模糊来实现
在这里插入图片描述

  • 高斯函数对图像做滤波操作,得到高斯模糊后的结果
    在这里插入图片描述
    不同σ的高斯函数决定了对图像的平滑程度,越大的σ值对应的图像越模糊。

2.多分辨率金字塔

  1. 金字塔有多个层级
  2. 同一层级中,有不同的高斯滤波
    在这里插入图片描述

3.高斯差分金字塔(DOG)

在这里插入图片描述
在这里插入图片描述
两个高斯模糊后的特征相减,得到DOG
然后怎么找极值点?每个点都要跟周围的点比较。继续往下看

4.DoG空间极值检测

为了寻找尺度空间的极值点,每个像素点要和其图像域(同一尺度空间-8个点)和尺度域(相邻的尺度空间-上下各9个 共18个)的所有相邻点(共26)进行比较,当其大于(或者小于)所有相邻点时,该点就是极值点。如下图所示,中间的检测点要和其所在图像的3×3邻域8个像素点,以及其相邻的上下两层的3×3领域18个像素点,共26个像素点进行比较。
在这里插入图片描述
最上/下层无法比较,故4层特征图中只有2层才能检测极值点。
但这步检测的离散极值点 不一定是 最终的极值点,故需要精确定位

5.关键点的精确定位

这些候选关键点是DOG空间的局部极值点,而且这些极值点均为离散的点,精确定位极值点的一种方法是,对尺度空间DoG函数进行曲线拟合,计算其极值点,从而实现关键点的精确定位。
在这里插入图片描述
在这里插入图片描述

6.消除边界响应

在这里插入图片描述
类似于Harris角点中的角点相应R值,Tr(H)2 / Det(H),大于10的是边界,要进行过滤操作

7.特征点的主方向

在这里插入图片描述
每个特征点可以得到三个信息(x,y,σ,θ),即位置、尺度(m(x,y))和方向。具有多个方向的关键点可以被复制成多份,然后将方向值分别赋给复制后的特征点,一个特征点就产生了多个坐标、尺度相等,但是方向不同的特征点。

然后咋用这些点?看下面

8.生成特征描述

在完成关键点的梯度计算后,使用直方图统计邻域内像素的梯度和方向。
为了简单起见,只统计8个方向(0-45, 45-90, 90-135,135-180, 180-235, 235-270, 270-315, 315-360)
在这里插入图片描述
为了保证特征矢量的旋转不变性,要以特征点为中心,在附近邻域内将坐标轴旋转θ角度,即将坐标轴旋转为特征点的主方向。
在这里插入图片描述
旋转之后的主方向为中心取8x8的窗口,求每个像素的梯度幅值和方向,箭头方向代表梯度方向,长度代表梯度幅值,然后利用高斯窗口对其进行加权运算,最后在每个4x4的小块上绘制8个方向的梯度直方图,计算每个梯度方向的累加值,即可形成一个种子点,即每个特征的由4个种子点组成,每个种子点有8个方向的向量信息。
在这里插入图片描述
论文中建议对每个关键点使用4x4共16个种子点来描述,这样一个关键点就会产生128维的SIFT特征向量。
在这里插入图片描述

OpenCV中的Sift操作

OpenCV大于3.4版本 就对sift进行专利保护了,所以想免费使用的,看看sift效果的,降低一下版本吧

卸载 pip uninstall opencv-python 
安装 pip install opencv-contrib-python==3.4.1.15 
里面有很多包 pip install opencv-contrib-python==3.4.1.15

 
 
  • 1
  • 2
  • 3
import cv2
import numpy as np

img = cv2.imread(‘test_1.jpg’)
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
print(cv2.version) # 3.4.1.15

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

得到特征点 kp, 直接用drawKeypoints绘制关键点

sift = cv2.xfeatures2d.SIFT_create()
kp = sift.detect(gray, None)

img = cv2.drawKeypoints(gray, kp, img)

cv2.imshow(‘drawKeypoints’, img)
cv2.waitKey(0)
cv2.destroyAllWindows()

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8

计算特征 sift.compute
还是关键点kp 和 关键点相应的特征des (每个关键点都转化为128维向量)

kp, des = sift.compute(gray, kp)
print (np.array(kp).shape)	# (6827,) 原来是list, 用np转化一下, 就可以看shape了
# des.shape					# (6827, 128)
# des[0]
'''
array([  0.,   0.,   0.,   0.,   0.,   0.,   0.,   0.,  21.,   8.,   0.,
         0.,   0.,   0.,   0.,   0., 157.,  31.,   3.,   1.,   0.,   0.,
         2.,  63.,  75.,   7.,  20.,  35.,  31.,  74.,  23.,  66.,   0.,
         0.,   1.,   3.,   4.,   1.,   0.,   0.,  76.,  15.,  13.,  27.,
         8.,   1.,   0.,   2., 157., 112.,  50.,  31.,   2.,   0.,   0.,
         9.,  49.,  42., 157., 157.,  12.,   4.,   1.,   5.,   1.,  13.,
         7.,  12.,  41.,   5.,   0.,   0., 104.,   8.,   5.,  19.,  53.,
         5.,   1.,  21., 157.,  55.,  35.,  90.,  22.,   0.,   0.,  18.,
         3.,   6.,  68., 157.,  52.,   0.,   0.,   0.,   7.,  34.,  10.,
        10.,  11.,   0.,   2.,   6.,  44.,   9.,   4.,   7.,  19.,   5.,
        14.,  26.,  37.,  28.,  32.,  92.,  16.,   2.,   3.,   4.,   0.,
         0.,   6.,  92.,  23.,   0.,   0.,   0.], dtype=float32)
'''

 
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18

三、特征匹配

  • cv2.drawMatches(imageA, kpsA, imageB, kpsB, matches[:10], None, flags=2) # 对两个图像关键点进行连线操作
    参数说明:imageA和imageB表示图片,kpsA和kpsB表示关键点, matches表示进过cv2.BFMatcher获得的匹配的索引值,也有距离, flags表示有几个图像

书籍的SIFT特征点连接:
第一步:使用sift.detectAndComputer找出关键点和sift特征向量
第二步:构建BFMatcher()蛮力匹配器,bf.match匹配sift特征向量,使用的是欧式距离
第三步:根据匹配结果matches.distance对matches按照距离进行排序
第四步:进行画图操作,使用cv2.drawMatches进行画图操作

  • bf.match(des1, des2) 1 对 1 匹配
  • bf.knnMatch(des1, des2, k=2) k对最佳匹配,此处是1个点最多可以跟2个点匹配
import cv2 
import numpy as np

img1 = cv2.imread(‘box.png’, 0)
img2 = cv2.imread(‘box_in_scene.png’, 0)
def cv_show(name,img):
cv2.imshow(name, img)
cv2.waitKey(0)
cv2.destroyAllWindows()
cv_show(‘img1’,img1)
cv_show(‘img2’,img2)

# 第一步:构造sift,求解出特征点和sift特征向量
sift = cv2.xfeatures2d.SIFT_create()
kp1, des1 = sift.detectAndCompute(img1, None)
kp2, des2 = sift.detectAndCompute(img2, None)

# 第二步:构造BFMatcher()蛮力匹配,匹配sift特征向量距离最近对应组分
# crossCheck 表示两个特征点要互相匹,
# 例如A中的第i个特征点与B中的第j个特征点最近的,并且B中的第j个特征点到A中的第i个特征点也是
# NORM_L2: 归一化数组的(欧几里德距离),如果其他特征计算方法需要考虑不同的匹配计算方式
bf = cv2.BFMatcher(crossCheck=True)

# 获得匹配的结果【1 对 1 匹配】
matches = bf.match(des1, des2)

#第三步:对匹配的结果按照距离进行排序操作
matches = sorted(matches, key=lambda x: x.distance)

# 第四步:使用cv2.drawMacthes进行画图操作
# 只画前10个点
img3 = cv2.drawMatches(img1, kp1, img2, kp2, matches[:10], None,flags=2)
cv_show(‘img3’,img3)

# 【k对最佳匹配】
bf = cv2.BFMatcher()
matches = bf.knnMatch(des1, des2, k=2)
good = []
for m, n in matches:
if m.distance < 0.75 * n.distance:
good.append([m])

# good所有点都显示,就会有很多连线了
img4 = cv2.drawMatchesKnn(img1,kp1,img2,kp2,good,None,flags=2)
cv_show(‘img4’,img4)

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46

在这里插入图片描述
在这里插入图片描述

四、图像拼接

from Stitcher import Stitcher
import cv2

# 读取拼接图片
imageA = cv2.imread(“left_01.png”)
imageB = cv2.imread(“right_01.png”)

# 把图片拼接成全景图
stitcher = Stitcher()
(result, vis) = stitcher.stitch([imageA, imageB], showMatches=True)

# 显示所有图片
cv2.imshow(“Image A”, imageA)
cv2.imshow(“Image B”, imageB)
cv2.imshow(“Keypoint Matches”, vis)
cv2.imshow(“Result”, result)
cv2.waitKey(0)
cv2.destroyAllWindows()

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
Stitcher的 stitch函数 检测流程 简述:

  1. img A 和 img B做sift检测
  2. 匹配特征点(具体看matchKeypoints流程)
  3. 提取匹配结果,其中H是单应性矩阵
  4. 对A进行H的视角变换
  5. 将图片B传入result图片最左端
  6. 检测是否需要显示图片匹配

matchKeypoints流程

  1. 建立暴力匹配器
  2. k对匹配
  3. 当筛选后的匹配对大于4时,计算视角变换矩阵
    其中findHomography: 计算多个二维点对之间的最优单映射变换矩阵 H(3行x3列),使用最小均方误差或者RANSAC(原理匹配效果)方法

Stitcher.py 完整代码如下:

import numpy as np
import cv2

class Stitcher:

<span class="token comment"># 拼接函数</span>
<span class="token keyword">def</span> <span class="token function">stitch</span><span class="token punctuation">(</span>self<span class="token punctuation">,</span> images<span class="token punctuation">,</span> ratio<span class="token operator">=</span><span class="token number">0.75</span><span class="token punctuation">,</span> reprojThresh<span class="token operator">=</span><span class="token number">4.0</span><span class="token punctuation">,</span>showMatches<span class="token operator">=</span><span class="token boolean">False</span><span class="token punctuation">)</span><span class="token punctuation">:</span>
    <span class="token comment">#获取输入图片</span>
    <span class="token punctuation">(</span>imageB<span class="token punctuation">,</span> imageA<span class="token punctuation">)</span> <span class="token operator">=</span> images
    <span class="token comment"># 1.检测A、B图片的SIFT关键特征点,并计算特征描述子</span>
    <span class="token punctuation">(</span>kpsA<span class="token punctuation">,</span> featuresA<span class="token punctuation">)</span> <span class="token operator">=</span> self<span class="token punctuation">.</span>detectAndDescribe<span class="token punctuation">(</span>imageA<span class="token punctuation">)</span>
    <span class="token punctuation">(</span>kpsB<span class="token punctuation">,</span> featuresB<span class="token punctuation">)</span> <span class="token operator">=</span> self<span class="token punctuation">.</span>detectAndDescribe<span class="token punctuation">(</span>imageB<span class="token punctuation">)</span>

    <span class="token comment"># 2.匹配两张图片的所有特征点,返回匹配结果</span>
    M <span class="token operator">=</span> self<span class="token punctuation">.</span>matchKeypoints<span class="token punctuation">(</span>kpsA<span class="token punctuation">,</span> kpsB<span class="token punctuation">,</span> featuresA<span class="token punctuation">,</span> featuresB<span class="token punctuation">,</span> ratio<span class="token punctuation">,</span> reprojThresh<span class="token punctuation">)</span>

    <span class="token comment"># 如果返回结果为空,没有匹配成功的特征点,退出算法</span>
    <span class="token keyword">if</span> M <span class="token keyword">is</span> <span class="token boolean">None</span><span class="token punctuation">:</span>
        <span class="token keyword">return</span> <span class="token boolean">None</span>

    <span class="token comment"># 3. 否则,提取匹配结果</span>
    <span class="token comment"># H是3x3视角变换矩阵      </span>
    <span class="token punctuation">(</span>matches<span class="token punctuation">,</span> H<span class="token punctuation">,</span> status<span class="token punctuation">)</span> <span class="token operator">=</span> M
    <span class="token comment"># 4.将图片A进行视角变换,result是变换后图片</span>
    result <span class="token operator">=</span> cv2<span class="token punctuation">.</span>warpPerspective<span class="token punctuation">(</span>imageA<span class="token punctuation">,</span> H<span class="token punctuation">,</span> <span class="token punctuation">(</span>imageA<span class="token punctuation">.</span>shape<span class="token punctuation">[</span><span class="token number">1</span><span class="token punctuation">]</span> <span class="token operator">+</span> imageB<span class="token punctuation">.</span>shape<span class="token punctuation">[</span><span class="token number">1</span><span class="token punctuation">]</span><span class="token punctuation">,</span> imageA<span class="token punctuation">.</span>shape<span class="token punctuation">[</span><span class="token number">0</span><span class="token punctuation">]</span><span class="token punctuation">)</span><span class="token punctuation">)</span>
    self<span class="token punctuation">.</span>cv_show<span class="token punctuation">(</span><span class="token string">'result'</span><span class="token punctuation">,</span> result<span class="token punctuation">)</span>
    <span class="token comment"># 5.将图片B传入result图片最左端</span>
    result<span class="token punctuation">[</span><span class="token number">0</span><span class="token punctuation">:</span>imageB<span class="token punctuation">.</span>shape<span class="token punctuation">[</span><span class="token number">0</span><span class="token punctuation">]</span><span class="token punctuation">,</span> <span class="token number">0</span><span class="token punctuation">:</span>imageB<span class="token punctuation">.</span>shape<span class="token punctuation">[</span><span class="token number">1</span><span class="token punctuation">]</span><span class="token punctuation">]</span> <span class="token operator">=</span> imageB
    self<span class="token punctuation">.</span>cv_show<span class="token punctuation">(</span><span class="token string">'result'</span><span class="token punctuation">,</span> result<span class="token punctuation">)</span>
    <span class="token comment"># 6.检测是否需要显示图片匹配</span>
    <span class="token keyword">if</span> showMatches<span class="token punctuation">:</span>
        <span class="token comment"># 生成匹配图片</span>
        vis <span class="token operator">=</span> self<span class="token punctuation">.</span>drawMatches<span class="token punctuation">(</span>imageA<span class="token punctuation">,</span> imageB<span class="token punctuation">,</span> kpsA<span class="token punctuation">,</span> kpsB<span class="token punctuation">,</span> matches<span class="token punctuation">,</span> status<span class="token punctuation">)</span>
        <span class="token comment"># 返回结果</span>
        <span class="token keyword">return</span> <span class="token punctuation">(</span>result<span class="token punctuation">,</span> vis<span class="token punctuation">)</span>

    <span class="token comment"># 返回匹配结果</span>
    <span class="token keyword">return</span> result
<span class="token keyword">def</span> <span class="token function">cv_show</span><span class="token punctuation">(</span>self<span class="token punctuation">,</span>name<span class="token punctuation">,</span>img<span class="token punctuation">)</span><span class="token punctuation">:</span>
    cv2<span class="token punctuation">.</span>imshow<span class="token punctuation">(</span>name<span class="token punctuation">,</span> img<span class="token punctuation">)</span>
    cv2<span class="token punctuation">.</span>waitKey<span class="token punctuation">(</span><span class="token number">0</span><span class="token punctuation">)</span>
    cv2<span class="token punctuation">.</span>destroyAllWindows<span class="token punctuation">(</span><span class="token punctuation">)</span>

<span class="token keyword">def</span> <span class="token function">detectAndDescribe</span><span class="token punctuation">(</span>self<span class="token punctuation">,</span> image<span class="token punctuation">)</span><span class="token punctuation">:</span>
    <span class="token comment"># 将彩色图片转换成灰度图</span>
    gray <span class="token operator">=</span> cv2<span class="token punctuation">.</span>cvtColor<span class="token punctuation">(</span>image<span class="token punctuation">,</span> cv2<span class="token punctuation">.</span>COLOR_BGR2GRAY<span class="token punctuation">)</span>

    <span class="token comment"># 建立SIFT生成器</span>
    descriptor <span class="token operator">=</span> cv2<span class="token punctuation">.</span>xfeatures2d<span class="token punctuation">.</span>SIFT_create<span class="token punctuation">(</span><span class="token punctuation">)</span>
    <span class="token comment"># 检测SIFT特征点,并计算描述子</span>
    <span class="token punctuation">(</span>kps<span class="token punctuation">,</span> features<span class="token punctuation">)</span> <span class="token operator">=</span> descriptor<span class="token punctuation">.</span>detectAndCompute<span class="token punctuation">(</span>image<span class="token punctuation">,</span> <span class="token boolean">None</span><span class="token punctuation">)</span>

    <span class="token comment"># 将结果转换成NumPy数组</span>
    kps <span class="token operator">=</span> np<span class="token punctuation">.</span>float32<span class="token punctuation">(</span><span class="token punctuation">[</span>kp<span class="token punctuation">.</span>pt <span class="token keyword">for</span> kp <span class="token keyword">in</span> kps<span class="token punctuation">]</span><span class="token punctuation">)</span>

    <span class="token comment"># 返回特征点集,及对应的描述特征</span>
    <span class="token keyword">return</span> <span class="token punctuation">(</span>kps<span class="token punctuation">,</span> features<span class="token punctuation">)</span>

<span class="token keyword">def</span> <span class="token function">matchKeypoints</span><span class="token punctuation">(</span>self<span class="token punctuation">,</span> kpsA<span class="token punctuation">,</span> kpsB<span class="token punctuation">,</span> featuresA<span class="token punctuation">,</span> featuresB<span class="token punctuation">,</span> ratio<span class="token punctuation">,</span> reprojThresh<span class="token punctuation">)</span><span class="token punctuation">:</span>
    <span class="token comment"># 1.建立暴力匹配器</span>
    matcher <span class="token operator">=</span> cv2<span class="token punctuation">.</span>BFMatcher<span class="token punctuation">(</span><span class="token punctuation">)</span>

    <span class="token comment"># 2.使用KNN检测来自A、B图的SIFT特征匹配对,K=2</span>
    rawMatches <span class="token operator">=</span> matcher<span class="token punctuation">.</span>knnMatch<span class="token punctuation">(</span>featuresA<span class="token punctuation">,</span> featuresB<span class="token punctuation">,</span> <span class="token number">2</span><span class="token punctuation">)</span>

    matches <span class="token operator">=</span> <span class="token punctuation">[</span><span class="token punctuation">]</span>
    <span class="token keyword">for</span> m <span class="token keyword">in</span> rawMatches<span class="token punctuation">:</span>
        <span class="token comment"># 当最近距离跟次近距离的比值小于ratio值时,保留此匹配对</span>
        <span class="token keyword">if</span> <span class="token builtin">len</span><span class="token punctuation">(</span>m<span class="token punctuation">)</span> <span class="token operator">==</span> <span class="token number">2</span> <span class="token operator">and</span> m<span class="token punctuation">[</span><span class="token number">0</span><span class="token punctuation">]</span><span class="token punctuation">.</span>distance <span class="token operator">&lt;</span> m<span class="token punctuation">[</span><span class="token number">1</span><span class="token punctuation">]</span><span class="token punctuation">.</span>distance <span class="token operator">*</span> ratio<span class="token punctuation">:</span>
        <span class="token comment"># 存储两个点在featuresA, featuresB中的索引值</span>
            matches<span class="token punctuation">.</span>append<span class="token punctuation">(</span><span class="token punctuation">(</span>m<span class="token punctuation">[</span><span class="token number">0</span><span class="token punctuation">]</span><span class="token punctuation">.</span>trainIdx<span class="token punctuation">,</span> m<span class="token punctuation">[</span><span class="token number">0</span><span class="token punctuation">]</span><span class="token punctuation">.</span>queryIdx<span class="token punctuation">)</span><span class="token punctuation">)</span>

    <span class="token comment"># 3.当筛选后的匹配对大于4时,计算视角变换矩阵</span>
    <span class="token keyword">if</span> <span class="token builtin">len</span><span class="token punctuation">(</span>matches<span class="token punctuation">)</span> <span class="token operator">&gt;</span> <span class="token number">4</span><span class="token punctuation">:</span>    <span class="token comment"># 至少4对,8个方程的单应性矩阵</span>
        <span class="token comment"># 获取匹配对的点坐标</span>
        ptsA <span class="token operator">=</span> np<span class="token punctuation">.</span>float32<span class="token punctuation">(</span><span class="token punctuation">[</span>kpsA<span class="token punctuation">[</span>i<span class="token punctuation">]</span> <span class="token keyword">for</span> <span class="token punctuation">(</span>_<span class="token punctuation">,</span> i<span class="token punctuation">)</span> <span class="token keyword">in</span> matches<span class="token punctuation">]</span><span class="token punctuation">)</span>
        ptsB <span class="token operator">=</span> np<span class="token punctuation">.</span>float32<span class="token punctuation">(</span><span class="token punctuation">[</span>kpsB<span class="token punctuation">[</span>i<span class="token punctuation">]</span> <span class="token keyword">for</span> <span class="token punctuation">(</span>i<span class="token punctuation">,</span> _<span class="token punctuation">)</span> <span class="token keyword">in</span> matches<span class="token punctuation">]</span><span class="token punctuation">)</span>

        <span class="token comment"># 计算视角变换矩阵</span>
        <span class="token punctuation">(</span>H<span class="token punctuation">,</span> status<span class="token punctuation">)</span> <span class="token operator">=</span> cv2<span class="token punctuation">.</span>findHomography<span class="token punctuation">(</span>ptsA<span class="token punctuation">,</span> ptsB<span class="token punctuation">,</span> cv2<span class="token punctuation">.</span>RANSAC<span class="token punctuation">,</span> reprojThresh<span class="token punctuation">)</span>

        <span class="token comment"># 返回结果</span>
        <span class="token keyword">return</span> <span class="token punctuation">(</span>matches<span class="token punctuation">,</span> H<span class="token punctuation">,</span> status<span class="token punctuation">)</span>

    <span class="token comment"># 4.如果匹配对小于4时,返回None</span>
    <span class="token keyword">return</span> <span class="token boolean">None</span>

<span class="token keyword">def</span> <span class="token function">drawMatches</span><span class="token punctuation">(</span>self<span class="token punctuation">,</span> imageA<span class="token punctuation">,</span> imageB<span class="token punctuation">,</span> kpsA<span class="token punctuation">,</span> kpsB<span class="token punctuation">,</span> matches<span class="token punctuation">,</span> status<span class="token punctuation">)</span><span class="token punctuation">:</span>
    <span class="token comment"># 初始化可视化图片,将A、B图左右连接到一起</span>
    <span class="token punctuation">(</span>hA<span class="token punctuation">,</span> wA<span class="token punctuation">)</span> <span class="token operator">=</span> imageA<span class="token punctuation">.</span>shape<span class="token punctuation">[</span><span class="token punctuation">:</span><span class="token number">2</span><span class="token punctuation">]</span>
    <span class="token punctuation">(</span>hB<span class="token punctuation">,</span> wB<span class="token punctuation">)</span> <span class="token operator">=</span> imageB<span class="token punctuation">.</span>shape<span class="token punctuation">[</span><span class="token punctuation">:</span><span class="token number">2</span><span class="token punctuation">]</span>
    vis <span class="token operator">=</span> np<span class="token punctuation">.</span>zeros<span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token builtin">max</span><span class="token punctuation">(</span>hA<span class="token punctuation">,</span> hB<span class="token punctuation">)</span><span class="token punctuation">,</span> wA <span class="token operator">+</span> wB<span class="token punctuation">,</span> <span class="token number">3</span><span class="token punctuation">)</span><span class="token punctuation">,</span> dtype<span class="token operator">=</span><span class="token string">"uint8"</span><span class="token punctuation">)</span>
    vis<span class="token punctuation">[</span><span class="token number">0</span><span class="token punctuation">:</span>hA<span class="token punctuation">,</span> <span class="token number">0</span><span class="token punctuation">:</span>wA<span class="token punctuation">]</span> <span class="token operator">=</span> imageA
    vis<span class="token punctuation">[</span><span class="token number">0</span><span class="token punctuation">:</span>hB<span class="token punctuation">,</span> wA<span class="token punctuation">:</span><span class="token punctuation">]</span> <span class="token operator">=</span> imageB

    <span class="token comment"># 联合遍历,画出匹配对</span>
    <span class="token keyword">for</span> <span class="token punctuation">(</span><span class="token punctuation">(</span>trainIdx<span class="token punctuation">,</span> queryIdx<span class="token punctuation">)</span><span class="token punctuation">,</span> s<span class="token punctuation">)</span> <span class="token keyword">in</span> <span class="token builtin">zip</span><span class="token punctuation">(</span>matches<span class="token punctuation">,</span> status<span class="token punctuation">)</span><span class="token punctuation">:</span>
        <span class="token comment"># 当点对匹配成功时,画到可视化图上</span>
        <span class="token keyword">if</span> s <span class="token operator">==</span> <span class="token number">1</span><span class="token punctuation">:</span>
            <span class="token comment"># 画出匹配对</span>
            ptA <span class="token operator">=</span> <span class="token punctuation">(</span><span class="token builtin">int</span><span class="token punctuation">(</span>kpsA<span class="token punctuation">[</span>queryIdx<span class="token punctuation">]</span><span class="token punctuation">[</span><span class="token number">0</span><span class="token punctuation">]</span><span class="token punctuation">)</span><span class="token punctuation">,</span> <span class="token builtin">int</span><span class="token punctuation">(</span>kpsA<span class="token punctuation">[</span>queryIdx<span class="token punctuation">]</span><span class="token punctuation">[</span><span class="token number">1</span><span class="token punctuation">]</span><span class="token punctuation">)</span><span class="token punctuation">)</span>
            ptB <span class="token operator">=</span> <span class="token punctuation">(</span><span class="token builtin">int</span><span class="token punctuation">(</span>kpsB<span class="token punctuation">[</span>trainIdx<span class="token punctuation">]</span><span class="token punctuation">[</span><span class="token number">0</span><span class="token punctuation">]</span><span class="token punctuation">)</span> <span class="token operator">+</span> wA<span class="token punctuation">,</span> <span class="token builtin">int</span><span class="token punctuation">(</span>kpsB<span class="token punctuation">[</span>trainIdx<span class="token punctuation">]</span><span class="token punctuation">[</span><span class="token number">1</span><span class="token punctuation">]</span><span class="token punctuation">)</span><span class="token punctuation">)</span>
            cv2<span class="token punctuation">.</span>line<span class="token punctuation">(</span>vis<span class="token punctuation">,</span> ptA<span class="token punctuation">,</span> ptB<span class="token punctuation">,</span> <span class="token punctuation">(</span><span class="token number">0</span><span class="token punctuation">,</span> <span class="token number">255</span><span class="token punctuation">,</span> <span class="token number">0</span><span class="token punctuation">)</span><span class="token punctuation">,</span> <span class="token number">1</span><span class="token punctuation">)</span>

    <span class="token comment"># 返回可视化结果</span>
    <span class="token keyword">return</span> vis
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83
  • 84
  • 85
  • 86
  • 87
  • 88
  • 89
  • 90
  • 91
  • 92
  • 93
  • 94
  • 95
  • 96
  • 97
  • 98
  • 99
  • 100
  • 101
  • 102
  • 103
  • 104
  • 105
  • 106
  • 0
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值