OpenCV---0011(图像特征)

本文介绍了角点检测的基本概念,如灰度梯度和边界变化,重点剖析了Harris角点检测原理,并展示了如何通过OpenCV实现关键点绘制、Harris角点计算以及ORB特征点检测。此外,还涵盖了特征点匹配与描述子的重要性,如SIFT和ORB的区别,以及匹配优化技术如RANSAC的应用。
摘要由CSDN通过智能技术生成

图像特征

角点检测

所谓角点是 当沿着x和y进行移动 灰度值极大变化
和边界不同 边界是沿着x或者y变化

角点是图像中某些属性较为突出的像素
例如 像素最大或最小 线段端点
孤立的边缘点 
常见的角点 有
灰度梯度最大值对应的点
两直线 或者曲线的交点
...

关键点绘制:
    关键点指的是角点或者特征点
    outImg = cv.drawKeypoints(img,keypoint,outimg)
    keypoints 里面存放的是keypoint类型的对象

    keypoint类:
        特征的被放在特殊的类中   
        里面有特征点的坐标 角度


    在绘制关键点的时候 有时需要进行数据类型的转换
    cv.Keypoint(x,y,_size)
    _size为关键点邻域

Harris角点
    Harris角点是最经典的角点之一
    从像素值变化的角度来对角点进行定义
    要检测Harris角点:
    先创建一个以某像素为中心的矩形滑动窗口
    通过线性叠加 滑动窗口覆盖图像的像素值得到一个
    滑动窗口内的所有像素值的衡量系数
    当窗口内像素值整体变大 衡量系数变大
    当窗口内像素值整体变小 衡量系数变小
    当窗口以某像素为中心 向任意方向移动 衡量系数都下降 则为角点

    Harris角点可以计算出一个R
    R较大 表示为角点、
    R<0 表示在直线
    |R| 较小 表示在平面

    dst = cv.cornerHarris()
    img
    blockSize  邻域大小通常为2
    ksize 索贝尔算子大小 
    k  [0.02--0.04] 计算R的权重系数
    该函数计算图像中每个图像的R 并且通过矩阵返回
    通过对R的比较可以确定是否为角点

    R有正由负 需要归一化 到指定区域再通过阈值来判断
    阈值往往根据经验的出
点击查看代码
import cv2 as cv
    import numpy as np
    
    if __name__ == '__main__':
        img = cv.imread('img_7.png')
        gray = cv.cvtColor(img, cv.COLOR_BGR2GRAY)
        #得到R
        har_m = cv.cornerHarris(gray, 2, 3, 0.04, borderType=cv.BORDER_DEFAULT)
        #归一化
        har_m = cv.normalize(har_m, None, alpha=0, beta=255, norm_type=cv.NORM_MINMAX)
        print(har_m)
        #换个类型
        har_m = har_m.astype('uint8')
        # print(np.argwhere(har_m > 100))
        kps = []
        # print(np.argwhere(har_m > 0))
        # 拿到大于阈值的点转换为keypoint类型
        for i in np.argwhere(har_m > 125):
            # print(i)
            kps.append(cv.KeyPoint(i[1], i[0], 1))
    
        # 画出来
        res = cv.drawKeypoints(img, kps, None)
        cv.imshow('R', har_m)
        cv.imshow('res', res)
        cv.waitKey(0)
        cv.destroyAllWindows()

image

特征点检测算法

特征点 与角点 在宏观定义上相同 但特征点具有能唯一描述像素特征的描述子 例如 左侧像素大于右侧像素...
特征点通常由 关键点 和 描述子组成 例如SIFT特征点 ORB特征点 都需要先计算关键点坐标 然后计算描述子

让计算机可以在远近,清晰模糊都可以认出
尺度空间:
    高斯滤波 清糊
    多分辨率图像金字塔 远近

因为特征点种类繁多 但几乎每一类特征点都涉及了 关键点 和 描述子的计算
所以Opencv提供了一个抽象基类 Feature2D 包含了 detect() compute() detectAndCompute()

描述子:
    用来描述关键点的一串数字 通过描述子
    可以区分两个关键点 
    cv.Feature2D.compute(img,keypoint)
    img 关键点的图像
    keypoint 关键点 通过关键点得到描述子


    keypoints,des = detectAndCompute(img)
    直接得到关键点和描述子 不用分步计算

SIFT特征点有专利了 不能用 所以直接接受ORB特征点
SIFI特征点是最著名的特征点 好多特征点都是SIFT特征点的衍生物
它在光照 噪声 缩放 旋转的稳定性  

取得SIFI特征点 需要构建一个多尺度的高斯金字塔
每层具有同样的大小 但是每层又有多个不同的高斯模糊图像
这样模拟了实际生活中的近大远小 进清远模糊
    
对于同一层的相邻图像进行相减 构成高斯差分金字塔
关键点是其内部的极值组成

对于关键点进行筛选后 剩余的就是SIFT的特征点
特征点的方向根据像素的梯度确定 

为了实现旋转不变性 计算描述子时 将图像坐标轴旋转到与特征点方向一致

SURF 因为SIFT太慢了 所以 SURF通过方框滤波的方法 代替了差分..等来实现更快的特征点检测

ORB由FAST角点和BRIEF描述子组成 更加快速 是SURF的10倍 是SIFT的100倍

ORB特征点:(特征点的计算方式不同 都继承了抽象基类)
    
    ret = cv.ORB_create()
    points = ORB.detect(img,None) 返还的是列表
    outimg = cv.drawKeypoints(img,points,outimg)

特征点匹配

顾名思义 利用特征点来进行匹配 在两个图片中 寻找同一个物体的的
相同特征点 每个特征点都是特殊的 所以是寻找相似的特征点
特征点匹配可以快速的确定一个物体在新的图像中的位置

同样的提供了特征点匹配的抽象基类 DescriptorMatcher 里面由不同的匹配方式
而不同的匹配方法 都继承了这个类
1. 一对一对于的描述子匹配
    matchs = cv.DescriptorMatcher.match(qpoints,tpoints)
    qpoint 查询描述子集合
    tpoint 训练描述子集合

    matchs 符合的结果

2. 一对多匹配指定数目 一个描述子对应了多个可能与之匹配的描述子 为了后续的处理
    matchs = cv.DescriptorMatcher.match(qpoints,tpoints,k)

3. 指定条件  通过距离阈值来匹配 距离是两个描述子的欧氏距离 汉明距离等
    matchs = cv.DescriptorMatcher.match(qpoints,tpoints,maxDistance)
    matchs 需要float32类型的描述子
    

所以的matchs存的是[DMatch类]    


汉明距离是以理查德•卫斯里•汉明的名字命名的。在信息论中,两个等长字符串之间的汉明距离是两个字符串对应位置的不同字符的个数。换句话说,它就是将一个字符串变换成另外一个字符串所需要替换的字符个数。例如:
1011101 与 1001001 之间的汉明距离是 2。
2143896 与 2233796 之间的汉明距离是 3。
"toned" 与 "roses" 之间的汉明距离是 3。

DMatch类
    匹配结果是DMatch类
    有在训练集和匹配集的特征点的索引 和 汉明距离


显示匹配结果
    outimg = cv.drawMatches(img1,keypoint1,img2,keypoint2,)

暴力匹配为每个描述子一定寻找一个最佳描述子 即使只在一张图片内存在 也会强行进行匹配

FLANN 匹配 可以实现特征点的快速匹配


即使使用了描述子的距离 及汉明距离来作为第一次筛选 但是还是会有部分的误匹配
为了提高匹配的精度 我们使用RANSAC 算法

匹配点优化

retval,mask = cv.findHomogarphy(spoints,dstpoints,method)
retval: 返还的是单应矩阵
mask: 则是返还的一个掩码 通过判断是否为1 来确定是否匹配
spoints: 原图像特征点的坐标  [-1, 1,2] -1行数    1,2 一行二列的矩阵 (x,y)
dstpoints: 目标图像特征点的坐标
method : cv.RANSAC

image

步骤总结:
点击查看代码
import cv2 as cv
        import numpy as np
        
        if __name__ == '__main__':
            # 拿到特征点
            img1 = cv.imread('AI.png')
            img2 = cv.imread('img_4.png')
            gray1 = cv.cvtColor(img1, cv.COLOR_BGR2GRAY)
            gray2 = cv.cvtColor(img2, cv.COLOR_BGR2GRAY)
        
            orb = cv.ORB_create()
                    
            # points1 = orb.detect(gray1, None)  # 返还的是一个列表
            # points2 = orb.detect(gray2, None)
            # points1_des = orb.compute(gray1, points1)
            # points2_des = orb.compute(gray2, points2)
            #拿到特征点和描述子 
            p1, pdes1 = orb.detectAndCompute(gray1, None, None)
            p2, pdes2 = orb.detectAndCompute(gray2, None, None)


            # print(pdes1)
        
            #创建一个用于特征点匹配的对象 内部有匹配方法
            flann_match = cv.FlannBasedMatcher()
        
            # 转换类型 描述子需要float32位类型
            pdes1 = pdes1.astype('float32')
            pdes2 = pdes2.astype('float32')
        
            # 得到匹配结果 匹配结果位DMatch 类的对象
            # 内部有 匹配的特征点在 图一和图二中的特征点索引
            matchs = flann_match.match(pdes1, pdes2)

            # 拿到匹配的特征点的在图1和图2的位置 并转换位ndarray的数据类型 
            src_kps = np.float32([p1[i.queryIdx].pt for i in matchs]).reshape(-1, 1, 2)
            dst_kps = np.float32([p2[i.trainIdx].pt for i in matchs]).reshape(-1, 1, 2)
        
            # 拿到掩码 该函数根据位置坐标进行筛选 并且返回一个掩码结果 来对匹配的进行筛选
            M, mask = cv.findHomography(src_kps, dst_kps, cv.RANSAC)
            print(M, mask)
        

            good_pt = []
            for i in range(len(mask)):
                # 掩码不为1的
                if mask[i] == 1:
                    good_pt.append(matchs[i])
        
            # 画出来筛选后的点
            res = cv.drawMatches(gray1, p1, gray2, p2,  good_pt, None)
        
            cv.imshow('res', res)
            # print(matchs)
            cv.waitKey(0)
            cv.destroyAllWindows()
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值