【youcans 的 OpenCV 例程 300篇】249. 特征检测之视网膜算法(FREAK)


1. FREAK 算法简介

快速视网膜算法(FREAK)算法是 Alexandre Alahi 在 ICCV 2012 的论文 FREAK: Fast Retina Keypoint 中提出的,其灵感来自人类视觉系统,通过比较视网膜采样模式的图像强度来计算二进制串的级联。。

快速视网膜关键点描述(FREAK,Fast Retina Keypoint)模拟人类视网膜的拓扑结构设计关键点的采样模式,构造二进制编码串珠外关键点的特征描述符,具有速度快、内存占用小和鲁棒性强的优点。

视觉系统基于不同尺度的高斯差分从图像中提取细节,视网膜的拓扑结构非常重要。如图16-11所示,神经细胞分为中央凹Foveal、中央凹Fovea、中心凹旁Parafoveal和中央凹周围Perifoveal的四个区域,空间分布具有中间密集、四周稀疏的特点。

【OpenCV 例程 300篇】249. 特征描述之视网膜算法(FREAK)-LMLPHP


BRISK算法的采样模式是均匀采样模式(在同一圆上等间隔的进行采样),FREAK算法采取了更为接近于人眼视网膜接收图像信息的采样模型。

人眼视网膜细胞的分布,中间密集,四周稀疏。FREAK算法的采样区域由大小不同并有重叠的同心圆构成,中心点是特征点,其它圆心是采样点。采样区域由以关键点为圆心的7 个同心圆组成。每个同心圆上各有 6个均匀分布的采样点,相邻同心圆的采样点的旋转角度交错分布,相隔30度。采样区域中共有 1+7x6=43个采样点。采样点离特征点的距离越远,采样点圆的半径越大,也表示该圆内的高斯函数半径越大。

采样像素的滤波内核半径都是各自所在同心圆半径的一半,而圆心处的特征点的滤波内核半径为1/24,一般来说,采用高斯滤波的方法效果更好。此时,滤波内核的半径就是高斯函数的标准差,均值滤波应该有着更快的特点,可以应用积分图像的方法,此时的滤波内核大小就是均值滤波的面积。


【OpenCV 例程 300篇】249. 特征描述之视网膜算法(FREAK)-LMLPHP


FREAK算法使用二进制串对特征点进行描述。

F = ∑ 0 ≤ a < N 2 a T ( P a ) T ( P a ) = { 1 , I ( P a r 1 ) − I ( P a r 2 ) > 0 0 , o t h e r w i s e F=\sum_{0 \le a\lt N}{2^a T(P_a)} \\ T(P_a) = \begin{cases} 1 &,I(P_a^{r1})-I(P_a^{r2})>0\\ 0 &,otherwise\\ \end{cases} F=0a<N2aT(Pa)T(Pa)={10,I(Par1)I(Par2)>0,otherwise
F 表示二进制描述子,Pa 表示一个采样点对,N 是二进制编码长度。 I ( P a r 1 ) I(P_a^{r1}) I(Par1) 表示采样点对Pa中前一个采样点的像素值, I ( P a r 2 ) I(P_a^{r2}) I(Par2) 表示后一个采样点的像素值。

FREAK 还将得到的 N bit的二进制描述子进行筛选降维,以获得更好和更具有辨识度的描述子。

1、建立矩阵D,D的每一行是一个FREAK二进制描述符,即每一行有N个元素。对每个特征点提取了43个采样点,可以产生 N=43*(43-1)/2=903 个采样点对,因此矩阵 D 有 903 行列。

2、对矩阵D的每一列计算其均值,由于D中元素都是0/1分布的,均值在0.5附近说明该列具有高的方差;

3、每一列都有一个均值,以均值最接近0.5的排在第一位,均值离0.5越远的排在越靠后,对列进行排序;

4、选取矩阵的前 k 列作为二进制描述符,例如 k=512。也可以是256、128、64、32等。

把得到的512个采样点对分成4组,每128个为一组,如图所示:


![在这里插入图片描述](https://img-blog.csdnimg.cn/50732fedf25d4fed976d9cfce9935d69.png#pic_center)

这四组的连线中第一组主要在外侧,之后的每组连线逐渐向内收缩,最后一组的连线主要在内侧。这与人眼视觉系统很
相似。人眼视觉系统首先通过perifoveal区域对感兴趣的物体的位置进行估计,然后通过感光细胞更加密集的fovea区域进行验证,最终确定物体的位置。

人眼的fovea区域由于有比较密集的感光细胞,可以捕捉高分辨率的图像,在识别和匹配过程中起关键作用。perifoveal区域的感光细胞则较为稀疏,只能捕捉到模糊的图像,因此首先用他们来进行物体位置的估计。这是人眼识别和匹配的原理,模仿这种流程对特征点进行匹配。

FREAK描述符的前段方差大表征粗略信息,后段方差小表征精细的高频数据。视觉系统的运行机制是先通过Perifoveal区域进行初步估计,再通过Fovea区域获取高分辨的图像。参考这种机制,FREAK实行描述符的级联匹配,先对前段的第一级进行匹配,如果匹配通过再继续下一级的匹配,这种方法显著提高了特征描述符的匹配速度。

FREAK 描述符的圆形对称采样结构使其具有旋转不变性,采样的位置半径随着尺度的变化使其具有尺度不变性,对每个采样点进行高斯模糊,也具有一定的抗噪性能,像素点的强度对比生成二进制描述子使其具有光照不变性。因此由上述产生的二进制描述子可以用来进行特征匹配。在匹配之前,再补充一下特征点的方向信息。

FREAK 比 SIFT、SURF、BRISK 算法的计算速度更快,内存负载更低,鲁棒性强,是现有算法的替代品,尤其适用于嵌入式应用。


2. OpenCV 的 FREAK 类

OpenCV提供了cv::xfeatures2d::FREAK类实现FREAK特征描述符。FREAK类继承cv::Feature2D父类,通过create静态方法创建。在Python语言中,通过接口函数FREAK.create实例化FREAK类,创建FREAK对象。

FREAK描述符是针对关键点的描述符,不涉及特征检测方法,需要配合SURF、FAST、STAR等特征检测算法,使用检测到的关键点keypoints作为输入,构造关键点描述符。

函数原型

参数说明
 orientationNormalized:方向标准化设置选项,默认值为true。
 scaleNormalized:尺度标准化设置选项,默认值为true。
 patternScale:描述符模式的缩放系数,默认值为22.0。
 nOctaves:倍频程的组数,即尺度空间金字塔的层数,默认值为4。
 selectedPairs:用户指定点对的索引。
 image:输入图像,数据类型CV_8U。
 keypoints:检测到的关键点,元组。
 descriptors:关键点的描述符,形为(n,64)的Numpy 数组。

注意问题

⑴ 函数cv.FREAK_create()实例化FREAK类,定义一个FREAK类对象。默认设置尺度和方向标准化,具有尺度不变性和旋转不变性。
⑵ 描述符descriptors是FREAK特征描述符的数组,形状为(n,64),n是关键点的数量,描述符长度为64,对应于512位二进制编码。


3. 例程:特征描述之FREAK关键点描述

本例程使用STAR方法进行特征点检测,构造BRIEF关键点描述符。

# 【1611】特征描述之FREAK 描述符
import cv2 as cv
import numpy as np
from matplotlib import pyplot as plt

if __name__ == '__main__':
    # 读取图像
    img = cv.imread("../images/Fig1701.png", flags=1)  # 基准图像
    height, width = img.shape[:2]  # (500, 500)
    print("shape of image: ({},{})".format(height, width))

    # BRISK 检测关键点
    brisk = cv.BRISK_create()  # 创建 BRISK 检测器
    kp = brisk.detect(img)  # 关键点检测,kp 为元组
    print("Num of keypoints: ", len(kp))  # 271

    # BRIEF 特征描述
    brief = cv.xfeatures2d.BriefDescriptorExtractor_create()  # 实例化 BRIEF 类
    kpBrief, desBrief = brief.compute(img, kp)  # 计算 BRIEF 描述符
    print("BRIEF descriptors: ", desBrief.shape)  # (270, 32)

    # FREAK 特征描述
    freak = cv.xfeatures2d.FREAK_create()  # 实例化 FREAK 类
    kpFreak, desFreak = freak.compute(img, kp)  # 生成描述符
    print("FREAK descriptors: ", desFreak.shape)  # (196, 64)

    imgS = cv.convertScaleAbs(img, alpha=0.5, beta=128)
    imgKp1 = cv.drawKeypoints(imgS, kpBrief, None, flags=cv.DRAW_MATCHES_FLAGS_DRAW_RICH_KEYPOINTS)
    imgKp2 = cv.drawKeypoints(imgS, kpFreak, None, flags=cv.DRAW_MATCHES_FLAGS_DRAW_RICH_KEYPOINTS)
    plt.figure(figsize=(9, 3.5))
    plt.subplot(131), plt.title("1. Original")
    plt.axis('off'), plt.imshow(cv.cvtColor(img, cv.COLOR_BGR2RGB))
    plt.subplot(132), plt.title("2. BRIEF keypoints scaled")
    plt.axis('off'), plt.imshow(cv.cvtColor(imgKp1, cv.COLOR_BGR2RGB))
    plt.subplot(133), plt.title("3. FREAK keypoints scaled")
    plt.axis('off'), plt.imshow(cv.cvtColor(imgKp2, cv.COLOR_BGR2RGB))
    plt.tight_layout()
    plt.show()


【OpenCV 例程 300篇】249. 特征描述之视网膜算法(FREAK)-LMLPHP

程序说明:

  • ⑴ 运行结果如图16-12所示。子图1是原始图像,使用BRISK算法检测到271个关键点。
  • ⑵ BRIEF描述符的形状为(270,32),子图2中的圆圈表示每个关键点的尺度与方向。
  • ⑶ FREAK描述符的形状为(196,64),64表示描述符由512位二进制编码组成。子图3中的圆圈表示每个关键点的尺度与方向。


参考文献:
A Alahi,R Ortiz,P Vandergheynst, FREAK: Fast Retina Keypoint, 2012, Published in: 2012 IEEE Conference on Computer Vision and Pattern Recognition (CVPR 2012)

【OpenCV 例程 300篇】249. 特征描述之视网膜算法(FREAK)-LMLPHP

【本节完】

12-05 16:53