BRIEF描述子原理、 python源码实现及基于opencv实现

写在前面:

伴着《似夜流月》,已到七月下旬。黄宁然,看你看过的算法系列,就要完结了。

参考文献镇楼:

[1] 扫地机器人
[2]徐征辉,基于BRIEF描述子的特征点匹配系统
[3]zhaocj,Opencv2.4.9源码分析——BRIEF
注:csdn发文助手提示“外链过多”,故文献链接网址请见评论区。

问题来源:

笔者的执念。

1、原理简介

在求出图像的关键点后,需要对关键点做出描述,以便进行后续的图像匹配。SIFT描述子具备抗噪声、光照不变、尺度旋转不变的特性,SURF亦是对SIFT的改进。但SIFT、SURF选择的特征点描述符结构较为复杂,描述符的维数多且采用浮点格式,嵌入式平台下处理能力、存储能力均受限[1]。基于二进制位串的BRIEF、ORB描述子可以较好解决上述问题。
BRIEF(Bianry Robust Independent Elementary Features)由Calonder M 等人于2010年提出。BRIEF 算法以检测到的特征点为中心,通过选取符合高斯分布的点对进行像素强度的对比,将对比的结果记录为二进制字符串,这个二进制字符串就称为该特征点的 BRIEF 描述子。两个二进制 BRIEF 描述子之间可以通过计算它们的汉明距离(Hamming Distance)来判断描述子是否匹配,这样简化了描述子匹配过程,也加快了描述子匹配的速度[2]。
BRIEF描述子的主要步骤为:
(1)对原始图像进行平滑处理
(2)选取以目标点为中心的S*S正方形区域作为采样窗口
(3)在采样窗口内,选择 n d n_d nd组点对,对每一组点对,进行下式的运算:
在这里插入图片描述
I是平滑处理后的图像,X、Y分别是以目标点为中心的S*S区域内的坐标位置。
(4)将每组点对得到的τ串起来(形成二进制数据流),得到BRIEF描述子:
在这里插入图片描述
具体的,参考opencv源码brief.cpp文件以及文献3,首先以特征点为中心,选取S*S中的区域,opencv源码中S取48(代码中为PATCH_SIZE);然后在该区域内,选择 n d n_d nd个像素点对,按照式(1)进行比对。从opencv源码中可看出,式(1)中的I,取的是KERNEL_SIZE为9的方形区域内所有像素之和。

2、python源码实现

参阅opencv源码brief.cpp文件,自行编写brief算子

#coding=utf8
import numpy as np
from PIL import Image
import matplotlib.pyplot as plt
import matplotlib.cm as cm
import math
import cv2
import os,sys
import scipy.ndimage
import time
import scipy
import re
from pygame import Rect

PATCH_SIZE = 48  #对每一个关键点,在48*48矩形区域内,形成比较点对
KERNEL_SIZE = 9 #对每一个比较点,求该点9*9区域内的像素和

从opencv原始代码中,找到generated_16.i(或generated_32.i)文件,并修改其后缀变成.txt文件。该文件中定义了比较点对的位置。通过读取该文件,筛选出比较点对,供后续使用。

def get_pt_lines(rawstr):#从原始txt文档中,获取比较点对
	lines = rawstr.split(";")
	pt_bytes = []
	for l in lines: #对于所有行中的每一行
		pt_byte=get_pt_line(l)#提取每一行的点对
		if len(pt_byte)!=0:
			pt_bytes.append(pt_byte)#保存点对
	return pt_bytes

def get_pt_line(line):#从原始文件的每一行中,提取出比较点对,每一行8个点对,对应一个字节
	line = line.replace(" ","")#删除空格
	blocks = line.split("+")#按‘+’进行分割
	pts=[]
	for b in blocks:
		str1 = re.findall("\(SMOOTHED\((.+?)\)<SMOOTHED",b)#匹配关键字副
		str2 = re.findall("<SMOOTHED\((.+?)\)\)", b) #匹配关键字副
		if str1!=[] and str2!=[]:
			str1 = str1[0].split(',')
			str2 = str2[0].split(',')
			num1 = np.array(str1).astype(int)#得到左边数字
			num2 = np.array(str2).astype(int)#得到右边数字
			pts.append((num1,num2)) #保存点对
	return pts #返回点对数组,8个点对

在上文描述中,算子整个过程涉及到两个矩形框,PATCH_SIZE和KERNEL_SIZE,对于原始的关键点,需要对位置越界的关键点进行剔除。

def  runByImageBorder(kps,img_src,border_size):#剔除越界的关键点
	r = Rect(border_size,border_size,img_src.shape[1]-border_size,img_src.shape[0]-border_size)
	newkp=[]
	for kp in kps:
		x,y  = kp.pt
		if x >= r[0] and y >= r[1] and x < r[2] and y < r[3]:
			newkp.append(kp)
	return newkp

公式(1)中I的是求取中心位置附近KERNEL_SIZE大小区域的像素之和,为便于实现,使用积分图像作为函数输入参数,代码实现为:

def get_sum_from_integral(x,y,img_sum):
	# 以x,y为中心,选择矩形框,求该矩形区域内所有像素点之和
	# 矩形框左上和右下的坐标为([-HALF_KERNEL,-HALF_KERNEL],[HALF_KERNEL+1,HALF_KERNEL+])(相对于中心点的偏移坐标)
	# 因输入图像已经是积分图像,所以原图该区域的像素点之和,等同于,在积分图像上对该矩形四个顶点处像素的加减运算
	x, y= int(x),int(y)
	HALF_KERNEL = (int)(KERNEL_SIZE / 2)
	return img_sum[y-HALF_KERNEL,x-HALF_KERNEL] + img_sum[y+HALF_KERNEL+1,x+HALF_KERNEL+1] \
			-img_sum[y-HALF_KERNEL,x+HALF_KERNEL+1] - img_sum[y+HALF_KERNEL+1,x-HALF_KERNEL]

公式(2)中,对所有比较点对进行逐个判断并保存为二进制串,代码实现为:

def generated_des(kpx,kpy,sum_img,pt_arr):#为每一个关键点生成描述符
	byte_arr = []
	for pt_byte in pt_arr: #对于所有点对(例如,32×8个点对)中的每一字节对点(1×8个点对)
		byte_val = 0
		for bit in pt_byte:#对于每个字节点对(8个点对)中的每一点对
			byte_val = byte_val<<1
			left_offset,right_offset = bit#得到待比较的左、右点
			left_cx,left_cy = kpx+0.5+left_offset[1],kpy+0.5+left_offset[0]#得到左边中心点
			right_cx, right_cy = kpx+0.5 + right_offset[1], kpy +0.5+ right_offset[0]#得到右边中心点
			#根据左、右中心点,获取相应区域的像素和 ,并进行大小比较
			bit = get_sum_from_integral(left_cx,left_cy,sum_img) <  get_sum_from_integral(right_cx,right_cy,sum_img)
			bit = bit.astype(int)
			byte_val = byte_val+bit#将bit保存至byte中
		byte_arr.append(byte_val)#保存该byte至byte数组中
	return np.array(byte_arr)#返回byte数组,例如32个bytes

完整的brief算子实现为:

def my_brief_des(img_src,kps_src,bytes=32):
	#先读取文件,获得比较点对
	if bytes==16:
		filename = 'generated_16.txt'
	else:
		filename = 'generated_32.txt'
	with open(filename) as f:
		rawtxt = f.read()
	pt_arr = get_pt_lines(rawtxt)
	# 生成积分图像,便于后续的加速运算
	sum_img = cv2.integral(img_src, sdepth=cv2.CV_32S)
	# 对关键点进行筛选,剔除边界之外的点
	kps = runByImageBorder(kps_src, img_src, PATCH_SIZE / 2 + KERNEL_SIZE / 2)
	# 为所有关键点生成描述符
	des = []
	for kp in kps:
		byte_arr = generated_des(kp.pt[0],kp.pt[1], sum_img,pt_arr)#计算每一个关键点的描述符
		des.append(byte_arr)
	return kps, np.array(des)

主程序调用:

if __name__ == '__main__':

	img_src = cv2.imread('susan_input1.png',cv2.IMREAD_GRAYSCALE)
	#使用fast算子,寻找出图像的关键点
	fast = cv2.FastFeatureDetector_create(threshold=10,type=cv2.FastFeatureDetector_TYPE_9_16)
	fast.setNonmaxSuppression(True)
	fast_kps = fast.detect(img_src)
	#使用自行编写的brief函数生成描述符
	my_kps,my_des = my_brief_des(img_src, fast_kps, bytes=32)

3、基于opencv实现

Opencv自带BRIEF算子,可以直接对关键点生成描述子。这里使用的opencv版本为3.4.11。
调用方式为:

brief = cv2.xfeatures2d.BriefDescriptorExtractor_create(bytes=16)
kps,des = brief.compute(img_src, kps)

主程序调用,并与自行编写的brief算子进行比较:

if __name__ == '__main__':

	img_src = cv2.imread('susan_input1.png',cv2.IMREAD_GRAYSCALE)
	#使用fast算子,寻找出图像的关键点
	fast = cv2.FastFeatureDetector_create(threshold=10,type=cv2.FastFeatureDetector_TYPE_9_16)
	fast.setNonmaxSuppression(True)
	fast_kps = fast.detect(img_src)
	#使用自行编写的brief函数生成描述符
	my_kps,my_des = my_brief_des(img_src, fast_kps, bytes=32)
	#调用opencv库的brief算子生成描述符
	brief = cv2.xfeatures2d.BriefDescriptorExtractor_create(bytes=32)
	kps,des = brief.compute(img_src,fast_kps)
	#检验误差范围
	err = 1.0*my_des - des
	print(np.max(abs(err)))

对于给定的图,自行编写的brief算子和opencv库中的brief算子,计算结果一致。

4、python源码下载

Python程序源码下载地址
https://download.csdn.net/download/xiaohuolong1827/86221146

  • 0
    点赞
  • 17
    收藏
    觉得还不错? 一键收藏
  • 3
    评论
### 回答1: ORB是一种特征点检测和描述符生成算法,它在计算机视觉和图像处理中广泛使用。Python是一种高级编程语言,非常适合进行科学计算和算法实现。 ORB Python源码实现可以使用OpenCV库中的函数库,该库提供了ORB函数的实现。首先需要导入OpenCV库,然后使用ORB_create()函数创建一个ORB对象。可以设置ORB算法的参数,例如关键点数量、金字塔层数、尺度因和边缘阈值等。 下一步是使用ORB算法检测图像中的关键点和生成描述符。使用detect()和compute()函数分别实现这些操作。detect()函数找到关键点,并将其存储在一个特定的数据结构中;compute()函数利用检测到的关键点计算特征描述符。ORB算法生成32位的描述符向量,在OpenCV中使用BytesIO格式进行存储。 最后,使用match()函数实现ORB算法的图像匹配。这个函数将两个图像的ORB特征描述符进行比较,并返回一个能量值。通过比较两个图像的ORB特征描述符,可以找到相似或匹配的图像。 综上所述,ORB Python源码实现可以通过调用OpenCV库中ORB函数实现。这个算法可以用于图像识别、目标跟踪、三维重建等应用领域。对于初学者来说,建议先了解ORB算法的原理,再通过代码实现加深理解。 ### 回答2: ORB(Oriented FAST and Rotated BRIEF)是一种受欢迎的特征描述符,广泛应用于计算机视觉领域中的目标识别、跟踪、建图和图像检索等任务。在Python中,我们可以使用OpenCV库中的ORB函数来提取图像中的ORB特征。 ORB算法的实现通常包含以下步骤: 1. 第一步是对图像进行高斯滤波和尺度空间构建,以便在不同尺度下寻找图像的关键点。 2. 第二步是通过FAST(Features from Accelerated Segment Test)检测器来寻找图像中的角点,FAST检测器可以快速确定一组像素是否为关键点,并剔除非关键点。 3. 接下来进行BRIEF(Binary Robust Independent Elementary Features)描述符的计算,BRIEF描述符是一种基于二进制的局部特征描述符。BRIEF算法通过提取两个像素点之间的差异来描述特征,由于这些差异只有1和0两种情况,因此可以用二进制数表示。 4. 最后,通过对描述符进行方向矫正和尺度统一,得到旋转不变的ORB特征。 PythonOpenCV库提供了ORB()函数来实现ORB算法,实现代码如下: ```python import cv2 # 读取图像 img = cv2.imread('test.jpg') # 执行ORB特征提取 orb = cv2.ORB_create() keypoints, descriptors = orb.detectAndCompute(img, None) # 绘制关键点 img_kp = cv2.drawKeypoints(img, keypoints, None) cv2.imshow('ORB keypoints', img_kp) cv2.waitKey(0) cv2.destroyAllWindows() ``` 在上述代码中,我们首先读取了一张图像,然后使用ORB_create()函数创建了ORB对象。接着使用detectAndCompute()函数来提取图像中的关键点和描述符,最后使用drawKeypoints()函数绘制关键点,并显示结果图像。 总之,Python中使用OpenCV库提供的ORB函数实现ORB特征描述符的提取非常简单,可以帮助我们快速完成图像处理任务。 ### 回答3: ORB是计算机视觉中一种经典的特征提取算法,它采用了旋转不变性和尺度不变性的思想,对于光照变化和旋转缩放等变化具有较好的适应性。在Python中,我们可以通过OpenCV提供的ORB函数来实现ORB特征提取。 具体地,我们可以通过以下步骤来实现ORB特征提取: 1. 导入OpenCV库,并读取待处理的图像。 2. 构建ORB对象,设置相关参数。其中,ORB对象的参数包括特征点数、金字塔层数、尺度因等。可以根据具体应用场景进行自行设置。 3. 调用ORB对象的detect()和compute()方法,分别对图像进行关键点检测和特征描述。其中,detect()方法用于寻找图像中的关键点,而compute()方法用于计算关键点的ORB特征描述。 4. 将ORB特征描述保存至文件或内存中,用于后续的特征匹配和目标识别等任务。 需要注意的是,在实际应用中,ORB特征提取往往需要与其它特征提取和匹配算法结合使用,以提高检测和识别的准确性和鲁棒性。此外,由于ORB算法本身的局限性,我们还需要针对具体应用场景进行参数调整和优化。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值