图像特征提取-下

Fast、ORB、LBP算子、HOG算子

Posted by 新宇 on March 13, 2020

一、Fast和ORB算法

1 Fast算法

1.1 原理

  • 前面已经介绍过几个特征检测器,它们的效果都很好,特别是SIFT和SURF算法,但是从实时处理的角度来看,效率还是太低了。
  • 为了解决这个问题,Edward Rosten和Tom Drummond在2006年提出了FAST算法,并在2010年对其进行了修正。
  • FAST (全称Features from accelerated segment test)是一种用于角点检测的算法,该算法的原理是取图像中检测点,以该点为圆心的周围邻域内像素点判断检测点是否为角点,通俗的讲就是若一个像素周围有一定数量的像素与该点像素值不同,则认为其为角点。

1.2 FAST算法的基本流程

1.3 机器学习的角点检测器

  • 选择一组训练图片(最好是跟最后应用相关的图片)
  • 使用 FAST 算法找出每幅图像的特征点,对图像中的每一个特征点,将其周围的 16 个像素存储构成一个向量P。
  • 每一个特征点的 16 像素点都属于下列三类中的一种
  • 根据这些像素点的分类,特征向量 P 也被分为 3 个子集:Pd ,Ps ,Pb,
  • 定义一个新的布尔变量Kp,如果 p 是角点就设置为 Ture,如果不是就设置为 False。
  • 利用特征值向量p,目标值是$K_p$,训练ID3 树(决策树分类器)。
  • 将构建好的决策树运用于其他图像的快速的检测。

1.4 非极大值抑制

1.5 代码

import numpy as np
import cv2 as cv
from matplotlib import pyplot as plt
# 1 读取图像

img = cv.imread('./image/tv.jpg')
# 2 Fast角点检测
# 2.1 创建一个Fast对象,传入阈值,注意:可以处理彩色空间图像 

fast = cv.FastFeatureDetector_create(threshold=30)
# 2.2 检测图像上的关键点

kp = fast.detect(img,None)
# 2.3 在图像上绘制关键点

img2 = cv.drawKeypoints(img, kp, None, color=(0,0,255))
# 2.4 输出默认参数

print( "Threshold: {}".format(fast.getThreshold()) )
print( "nonmaxSuppression:{}".format(fast.getNonmaxSuppression()) ) 
print( "neighborhood: {}".format(fast.getType()) )
print( "Total Keypoints with nonmaxSuppression: {}".format(len(kp)) )
# 2.5 关闭非极大值抑制 fast.setNonmaxSuppression(0) kp = fast.detect(img,None)

print( "Total Keypoints without nonmaxSuppression: {}".format(len(kp)) ) 
# 2.6 绘制为进行非极大值抑制的结果

img3 = cv.drawKeypoints(img, kp, None, color=(0,0,255))
# 3 绘制图像 

fig,axes=plt.subplots(nrows=1,ncols=2,figsize=(10,8),dpi=100) 
axes[0].imshow(img2[:,:,::-1]) 
axes[0].set_title("加入非极大值抑制") 
axes[1].imshow(img3[:,:,::-1]) 
axes[1].set_title("未加入非极大值抑制")
plt.show()

2. ORB算法

2.1 ORB算法流程

2.2 BRIEF算法

2.3 算法实现

import numpy as np
import cv2 as cv
from matplotlib import pyplot as plt 
# 1 图像读取

img = cv.imread('./image/tv.jpg')
# 2 ORB角点检测
# 2.1 实例化ORB对象

orb = cv.ORB_create(nfeatures=500)
# 2.2 检测关键点,并计算特征描述符

kp,des = orb.detectAndCompute(img,None)
print(des.shape)
# 3 将关键点绘制在图像上

img2 = cv.drawKeypoints(img, kp, None, color=(0,0,255), flags=0)
# 4. 绘制图像 
plt.figure(figsize=(10,8),dpi=100) 
plt.imshow(img2[:,:,::-1]) 
plt.xticks([]), plt.yticks([]) 
plt.show()

二、LBP和HOG特征算子

1. LBP算法

1.1 原理

  • LBP(Local Binary Pattern)指局部二值模式,是一种用来描述图像局部特征的算子,LBP特征具有灰度不变性和旋转不变性等显著优点。它是 由T. Ojala, M.Pietikäinen, 和 D. Harwood在1994年提出,由于LBP特征计算简单、效果较好,因此LBP特征在计算机视觉的许多领域都得到了广泛的应用。
  • LBP算子分类:
    • 原始LBP特征:
      • 在3 ∗ 3的窗口内,以窗口中心像素为阈值,将相邻的8个像素的灰度值与其进行比较,若周围像素值大于中心像素值,则该 像素点的位置被标记为1,否则为0。这样,3 ∗ 3邻域内的8个点经比较可产生8位二进制数,即LBP值。
    • 圆形LBP算子:
      • 计算不同半径邻域大小和不同像素点数的特征值
    • 旋转不变LBP算子:
      • 不断旋转圆形邻域得到一系列初始定义的 LBP值,取其最小值作为该邻域的 LBP 值
    • Uniform Pattern LBP特征:
      • 当某个LBP所对应的循环二进制数从0到1或从1到0最多有两次跳变时,该LBP所对应的二进制就称为一个等价模式类。。除等价模式类以外的模式都归为另一类,称为混合模式类。
    • 参考链接

1.2 代码实现

import cv2 as cv
from skimage.feature 
import local_binary_pattern import matplotlib.pyplot as plt
# 1.读取图像

img = cv.imread("face.jpeg")
face = cv.cvtColor(img,cv.COLOR_BGR2GRAY)
# 2.特征提取
# 2.0 需要的参数
# LBP算法中范围半径的取值

radius = 1
# 领域像素点数

n_points = 8 * radius
# 2.1 原始LBP特征

lbp = local_binary_pattern(face, 8, 1)
# 2.2 圆形LBP特征

clbp = local_binary_pattern(face,n_points,radius,method="ror")
# 2.3 旋转不变LBP特征

varlbp = local_binary_pattern(face,n_points,radius,method="var")
# 2.4 等价特征

uniformlbp = local_binary_pattern(face,n_points,radius,method="nri-uniform")
fig,axes=plt.subplots(nrows=2,ncols=2,figsize=(10,8)) 
axes[0,0].imshow(lbp,'gray') 
axes[0,0].set_title("原始的LBP特征") 
axes[0,0].set_xticks([])
axes[0,0].set_yticks([]) 
axes[0,1].imshow(clbp,'gray') 
axes[0,1].set_title("圆形LBP特征") 
axes[0,1].set_xticks([]) 
axes[0,1].set_yticks([]) 
axes[1,0].imshow(varlbp,'gray') 
axes[1,0].set_title("旋转不变LBP特征") 
axes[1,0].set_xticks([]) 
axes[1,0].set_yticks([]) 
axes[1,1].imshow(uniformlbp,"gray") 
axes[1,1].set_title("等价特征") 
axes[1,1].set_xticks([]) 
axes[1,1].set_yticks([])
plt.show()

2. HOG算法

2.1 原理

  • HOG(Histogram of Oriented Gridients的简写)特征检测算法,最早是由法国研究员Dalal等在CVPR-2005上提出来的,一种解决人体目标检测的图像描述子,是一种用于表征图像局部梯度方向和梯度强度分布特性的描述符。其主要思想是:在边缘具体位置未知的情况下,边 缘方向的分布也可以很好的表示行人目标的外形轮廓。
  • 流程:
    • 将输入图像灰度化,即将彩色图转换为灰度图
    • 颜色空间归一化:
      • 采用Gamma校正法对输入图像进行颜色空间的标准化(归一化),目的是调节图像的对比度,降低图像局部的阴影和光照变化所造成的影响,同时可以抑制噪音的干扰
    • 梯度计算:
      • 计算图像每个像素的梯度(包括大小和方向);主要是为了捕获轮廓信息,同时进一步弱化光照的干扰
    • 梯度方向直方图:
      • 将图像划分成小cells(例如6*6像素/cell), 统计每个cell的梯度直方图(不同梯度的个数),即可形成每个cell的描述符
    • 重叠直方图归一化:
      • 将每几个cell组成一个block(例如3*3个cell/block),一个block内所有cell的特征descriptor串联起来便得到该block的HOG特征描述符。
    • HOG特征:
      • 将图像image内的所有block的HOG特征描述符串联起来就可以得到该image的HOG特征描述符,就得到最终的可供分类使 用的特征向量了。
  • 参考链接
import cv2 as cv
import numpy as np
import matplotlib.pyplot as plt
# 1.读取图像

img = cv.imread('xingren.jpeg')
gray= cv.cvtColor(img,cv.COLOR_BGR2GRAY)
# 2.Hog特征提取
# 2.1 参数设置 

winSize = (64,128) 
blockSize = (16,16) 
blockStride = (8,8) 
cellSize = (8,8) 
nbins = 9
# 2.2 实例化hog对象

hog = cv.HOGDescriptor(winSize,blockSize,blockStride,cellSize,nbins)
# 2.3 计算Hog特征描述符

hogDes = hog.compute(img,winStride=(8,8))
# 2.4 输出描述符的大小 

print(hogDes.size)

三、视频操作

1. 视频读写

  • 读取视频:
    • 读取视频:cap = cv.VideoCapture()
    • 判断读取成功:cap.isOpened()
    • 读取每一帧图像:ret,frame = cap.read()
    • 获取属性:cap.get(proid)
    • 设置属性:cap.set(proid,value)
    • 资源释放:cap.release()
  • 保存视频
    • 保存视频: out = cv.VideoWrite()
    • 视频写入:out.write()
    • 资源释放:out.release()

1.1 从文件中读取视频并播放

import numpy as np
import cv2 as cv
# 1.获取视频对象

cap = cv.VideoCapture('DOG.wmv') 
# 2.判断是否读取成功 

while(cap.isOpened()):
	# 3.获取每一帧图像

	ret, frame = cap.read() 
	# 4. 获取成功显示图像

	if ret == True:
		cv.imshow('frame',frame)
	# 5.每一帧间隔为25ms

	if cv.waitKey(25) & 0xFF == ord('q'):
		break
# 6.释放视频对象 

cap.release() 
cv.destoryAllwindows()

1.2 保存视频

import cv2 as cv 
import numpy as np
# 1. 读取视频

cap = cv.VideoCapture("DOG.wmv")
# 2. 获取图像的属性(宽和高,),并将其转换为整数 

frame_width = int(cap.get(3))
frame_height = int(cap.get(4))
# 3. 创建保存视频的对象,设置编码格式,帧率,图像的宽高等

out = cv.VideoWriter('outpy.avi',cv.VideoWriter_fourcc('M','J','P','G'), 10, (frame_width,frame_height)) 
while(True):
	# 4.获取视频中的每一帧图像 

	ret, frame = cap.read() 
	if ret == True:
		# 5.将每一帧图像写入到输出文件中

		out.write(frame) 
	else:
		break
# 6.释放资源 

cap.release() 
out.release() 
cv.destroyAllWindows()

2. 视频追踪

2.1 meanshift

import numpy as np
import cv2 as cv
# 1.获取图像

cap = cv.VideoCapture('DOG.wmv')
# 2.获取第一帧图像,并指定目标位置 

ret,frame = cap.read()
# 2.1 目标位置(行,高,列,宽) 

r,h,c,w = 197,141,0,208 
track_window = (c,r,w,h)
# 2.2 指定目标的感兴趣区域 

roi = frame[r:r+h, c:c+w]
# 3. 计算直方图
# 3.1 转换色彩空间(HSV)

hsv_roi = cv.cvtColor(roi, cv.COLOR_BGR2HSV)
# 3.2 去除低亮度的值
# mask = cv.inRange(hsv_roi, np.array((0., 60.,32.)), np.array((180.,255.,255.))) 
# 3.3 计算直方图

roi_hist = cv.calcHist([hsv_roi],[0],None,[180],[0,180])
# 3.4 归一化 

cv.normalize(roi_hist,roi_hist,0,255,cv.NORM_MINMAX)
# 4. 目标追踪
# 4.1 设置窗口搜索终止条件:最大迭代次数,窗口中心漂移最小值

term_crit = ( cv.TERM_CRITERIA_EPS | cv.TERM_CRITERIA_COUNT, 10, 1 )
while(True):
	# 4.2 获取每一帧图像

	ret ,frame = cap.read() if ret == True:
	# 4.3 计算直方图的反向投影

	hsv = cv.cvtColor(frame, cv.COLOR_BGR2HSV)
	dst = cv.calcBackProject([hsv],[0],roi_hist,[0,180],1)
	# 4.4 进行meanshift追踪

	ret, track_window = cv.meanShift(dst, track_window, term_crit)
	# 4.5 将追踪的位置绘制在视频上,并进行显示

	x,y,w,h = track_window
	img2 = cv.rectangle(frame, (x,y), (x+w,y+h), 255,2) 
	cv.imshow('frame',img2)
	if cv.waitKey(60) & 0xFF == ord('q'): 
		break
	else: 
		break
# 5. 资源释放 

cap.release() 
cv.destroyAllWindows()

2.2 Camshift

CamShift算法全称是“Continuously Adaptive Mean-Shift”(连续自适应MeanShift算法),是对MeanShift算法的改进算法,可随着跟踪目标的 大小变化实时调整搜索窗口的大小,具有较好的跟踪效果。 Camshift算法首先应用meanshift,一旦meanshift收敛,它就会更新窗口的大小,还计算最佳拟合椭圆的方向,从而根据目标的位置和大小更新 搜索窗口。

# 进行camshift追踪

ret, track_window = cv.CamShift(dst, track_window, term_crit)
# 绘制追踪结果

pts = cv.boxPoints(ret)
pts = np.int0(pts)
img2 = cv.polylines(frame,[pts],True, 255,2)

2.3 总结

  • Meanshift和camshift算法都各有优势,自然也有劣势:
    • Meanshift算法: 简单,迭代次数少,但无法解决目标的遮挡问题并且不能适应运动目标的的形状和大小变化。
    • camshift算法: 可适应运动目标的大小形状的改变,具有较好的跟踪效果,但当背景色和目标颜色接近时,容易使目标的区域变大,最终有可能导致目标跟踪丢失。