在前文中,我们提到了索贝尔滤波(Sobel Filter)卷积核对中心点周边方向信息的提炼,可以被用来获取方向梯度直方图的梯度矢量计算中。那么什么是方向梯度直方图呢?
方向梯度直方图最早的 概念原型(Prototype) 来自于 罗伯特·麦康纳尔(Robert K. McConnell) 在 1986 年申请的有关模式识别专利中,对 视野(FoV [Field of View]) 方向性输入产生输出结果差异的判断过程。并于 1994 年 三菱电子研究实验室(Mitsubishi Electric Research Laboratories) 在手势识别应用的区域检测过程中,首次总结为当前称谓 [16] 。最终经过 2005 年 CVPR 顶会参会论文验证,重新确认了 HOG 在动态检测上的高适配度,才开始被人熟知 [17] 。
方向梯度直方图(HOG [Histogram of Oriented Gradient]) 是对用于提炼并描述区域范围内像素漂移情况方法论的概念抽象。是对过程的抽象,而非对结果的抽象。由于本身最终运算能够表示为处理单元形式,因而属于 特征描述算子(Feature Descriptor) 的一种。整体思想则是在单元间隔均匀的卷积核内,使用重叠的局部梯度提炼算法并 录表统计归一化(Normalization),以取得中心点变化方向矢量。方法常结合 阈值限定(Thresholding) 筛选结果,提高运动预测的准确度。
显然,方向梯度直方图并不只适用于索贝尔, 只要能够提供中心点周边梯度变化的大小和方向的算子,都可以被应用于 HOG 的求解中。一个方向梯度直方图是否优秀,最大的影响点就在于梯度提炼的是否精准。
HOG 的标准处理流
HOG 有一套相对固定的标准过程的。基本可以按照如下顺序进行:
数据优化,通过滤波算法(如高斯滤波),减少干扰信息并增强灰度(光亮度)对比;
梯度计算,通过梯度滤波器(如索贝尔滤波)提取图像每个像素的梯度矢量;
分组抽象,指定梯度矢量采样卷积核范围,即分组(Cell)
矢量合并,将分组内所有像素的梯度矢量,以方向投票统计合并权重,获取 HOG
块归一化,指定块大小(由分组为单位),整合 HOG 统计结果并归一化快内分组权重
五个步骤,共同构成了方向梯度直方图方法论本身。 且四五两步概念不同,但密不可分。
数据优化
数据优化的目的是为了增强光亮度变化差异,并减少干扰噪声,从而更好的保存并放大像素梯度变化情况。我们记原信号为 S(x) ,记经过滤波降噪和修饰后的灰度(光亮度)数据为 Sg(x) 。从 S(x) 到 Sg(x) 的处理过程就不再赘述(见滤波,类比处理)。记经过优化函数 Og(x) 处理,以 Sg(x) 获取的优化结果为 So(x) 。那么,相对简单的处理方式,就是直接对 Sg(x) 进行 伽马矫正(Gamma Correction)来得到 So(x) 。取伽马因子为 γ ,矫正系数(Adjust Factor)为 A (一般情况 A=1.0 为常量),有:
Og(x)=Gamma(S)=A⋅S(x)γ 伽马矫正(Gamma Correction) 本是用于应对,早期 阴极射线管(CRT [Cathode Ray Tube])显示器 的电子偏转特征,引入的采样源数据非线性转换算法。传统的 CRT 显示器在显示时就会完成对偏转数据的自然逆向过程,而在 液晶显示器(LCD [Liquid Crystal Display]) 上,则需要 主动的实现这一反向运算,否则会面临数据亮度过爆的问题。
由于采样时采用 γ<1 应用于数据修正, 所以 γ<1 时的 γ 值被称为 编码伽马值(Encoding Gamma)。相应的,γ>1 时的 γ 值被称为 解码伽马值(Decoding Gamma)。而采样到还原的过程中,对伽马矫正的不同运用被分别称为 伽马编码(Gamma Encode) 和 伽马解码(Gamma Decode)。
图 3-4 原数据经过伽马编解码(伽马矫正)的还原过程示意图 伽马矫正本身的作用正是针对原图色彩通道数据,进行非线性的映射。衍生为对图片整体光亮度的调节,因此在灰度值上的体现最为明显。我们利用这种特性,来增强图片的对比信息,放大像素梯度变化。
这一步,通常取用 γ∈[0.45, 1.25] 区间内的值,或 γ=0.5 的原论文推荐值来进行修正。得到用于后续处理的灰度数据源 So(x) 。
梯度计算
在经过优化得到高对比度的 灰度(光亮度)图 后,就可以利用一些方向梯度卷积核算法,来计算每一个像素点光亮度变换的梯度矢量了。
此时应用边缘检测索贝尔滤波,目的同 HOG 的默认设定中,采用横纵方向均取 单一中线 的简化 普雷维特算子(Prewitt Operator),以求取梯度 方向(Orientate) 和 强度(Magnitude) 的作用一致。显然,并不只有索贝尔算法或普雷维特算法,适用于方向梯度直方图中梯度矢量的计算。只要能够提供中心点周边梯度变化的大小和方向的算子,都可以被应用于 HOG 的此步的求解计算中。
我们记方向为 Θ ,强度为 A ,横向 x 轴方向的滤波核函数 Gx ,纵向 y 轴方向的滤波核函数 Gy 。强度系数 K 为同态值 $$K= K_x = K_y$$$ 。此处不含推导展示结论。
记 边缘检测普雷维特滤波核函数 为 Pp(xc) ,有:
Gx=Gy=A=Θ=Kx⋅[+1,0,−1] ⋅So(xc)3×1Ky⋅[+1,0,−1]T⋅So(xc)1×3∣Pp(xc)∣=K⋅Gx2+Gy2∠Pp(xc) =atan2(Gy, Gx) 记 边缘检测索贝尔滤波核函数 为 Sp(xc) ,有:
Gx=Gy=A=Θ=Kx⋅+1,+2,+1,0,0,0, −1 −2 −1⋅So(xc)3×3Ky⋅+1, 0,−1, +2,0, −2, +10 −1⋅So(xc)3×3∣Sp(xc)∣=K⋅Gx2+Gy2∠Sp(xc) =atan2(Gy, Gx) 更明确的,当我们采用不同算法进行梯度计算时,梯度提炼的结果,将会在较大程度上影响最终得到的方向梯度直方图。是需要更准确、更快捷,还是需要高抗性、低波动,应以实际工程角度考量。根据具体需要来采用不同的边缘检测算法。
而梯度方向和强度的计算则可统一为共识:
A=Θ=K⋅Gx2+Gy2∠ [tan−1(GxGy)] 称为 通用卷积核梯度矢量公式(Formula of Kernel Gradient Vector)。
经过此步计算后,灰度数据源 So(x) 的输入就被转换为原信号为 S(x) 的所有像素点,梯度方向数据集 Θ(x) 和 梯度强度数据集 A(x) 。不过此时的数据量相对较大,不便于计算处理,还需 简化信息量。
分组抽象 & 矢量合并
分组抽象的目的是为了提炼每个像素点的数据,汇总分组内逐个像素特征到分组整体的单元特征。 由于原有梯度方向的平面完整性,以 Θ 范围即便只限定为整数角,也包含 [0∘, 360∘) 共 360 个取值。 这样造成的数据膨胀,不利于有限算力的处理。 因此,以尽可能不损失方向包含实际意义为前提, 将角度按照权重分割 来表示原梯度包含信息,是个不错的办法。
假设我们将 [0∘, 360∘) 按照 ∠Θ=[Θ0 , ... , Θθ−1] 的边界角度,拆分为 θ 个指定方向。记存在像素点 xc 的梯度 G(xc)=(Ac, Θc) 的方向落于角度区间 [Θa, Θb) 内,有:
Ac=WaΘc=WaWa=Θb−ΘaΘc−Θa⋅Aa+Wb⋅Ab⋅Θa+Wb⋅ΘbWb=Θb−ΘaΘb−Θc 其中 Wa+Wb=1 ,按照权重 Wa 、 Wb 即可拆分 G(xc) 数据到 Θa 、 Θb 角度分量混合表示。记两个角度方向的分量分别为 Ga 、 Gb ,则:
Ga=Gb=G(xc)(Wa⋅Ac, Wa⋅Θc)(Wb⋅Ac, Wa⋅Θc)=Ga+Gb 显然,以 ∠Θ=[Θ0 , ... , Θθ−1] 指定方向的矢量合形式表示, G(xc) 除了 Θa 、 Θb 角度外,其余角度分量为 0 , 有:
G(xc)=∠Θ(0, ... ,Wa,Wb, ... ,0) 由于不需要考虑反向的数据还原,核内采样按照 ∠Θ=[Θ0 , ... , Θθ−1] 的边界角度的方向矢量合形式求和,即可完成分组内的特征整合。记得到分组的 θ 维特征向量 Cell ,则:
Cell=∑∠G(xc) 那么现在的问题就是如何分组,或者分为几组了。
当采样核为 n×n 时,我们取边界整数点出发过核心 (21n, 21n) 的连线,加上对角线一起作为分组分割线。 由任意两条相邻分割线间的夹角,构成以核心为原点的角度分组。 所以, ∠Θ=[Θ0 , ... , Θθ−1] 代表的正是分割线角度。因此,当不区分夹角及其对角方向时,中心角能够分为 θ=n+1 组,称为 无符号梯度(Unsigned Gradient) 分组。当考虑夹角与对角方向互反时,中心角能够分为 θ=2(n+1) 组,称为 有符号梯度(Signed Gradient) 分组。
采样核一般为 n×n=8×8 大小,此时无符号梯度以方向标记,可分为 9 组即:
∠Θ=[0∘, 20∘, 40∘, 60∘, 80∘, 100∘, 120∘, 140∘, 160∘] 而有符号梯度则可分为 18 组:
∠Θ=[∠Θlt∠Θrb]=[0∘,180∘,20∘,200∘,40∘,220∘,60∘,240∘,80∘,260∘,100∘,280∘,120∘,300∘,140∘,320∘,160∘340∘] 以无符号梯度的 9 组分组为例,统计只需累计入组即可:
图 3-5 核大小 8x8 的无符号梯度(Unsigned Gradient)分组示意图 随后依次统计分组的采样核内数据。上图数据统计结果如下(概略图):
图 3-6 无符号梯度分组的单组采样核内统计结果示意直方图 统计完毕时,特征向量 Cell 随即生成完毕。我们以 Wθ 表示分组的特征向量,在方向 θ 上的强度大小(即此方向矢量的秩),则对于无符号梯度(Unsigned Gradient)分组:
Cell=∑∠G(xc)=Θ(W0∘, ... ,W160∘)∈R9×1 同样,对有符号梯度(Signed Gradient)分组:
Cell=∑∠G(xc)=Θ(W0∘, ... ,W160∘, ... ,W340∘)∈R18×1 至此,完成分组提炼。
这种对数据梯度的蒸馏手段非常重要,因为它不只可以运用于物体识别等情况的中间步骤,也可以被运用于粗糙的运动特征检测。
而从分组的数据得来的分组特征,还需要归一化才能被有效使用。
块归一化
由于分组内梯度矢量的分解叠加有可能会使某个方向上的梯度强度 远超其他方向,因而造成该方向上的灰度(光亮度)变化会极大的影响结果。 这样的影响当然是有利的,但无法相对统一的权重,也会给处理带来大量的不确定性。 如图例:
取绿色框中以 n×n=8×8 采样核,经过前几步以无符号梯度(Unsigned Gradient)方式处理,会得到的四个分组:
图 3-8 图例(数据源)绿色框中四个分组特征向量直方图表示 如果能够将这种变化趋势原封不动的保存下来,并缩小尺度到统一标准,就可以实现即保证特征不被不必要的削减,也有足够一致的度量衡。 因此,归一化就是解决办法。
归一化(Normalization) 是将目标数据集,按照总体权重等比放缩到指定区间范围的一种数学工具。通常我们选取当前采样分组包含的数据,即为归一化的目标数据集。组与组间独立归一化。但 块归一化(Block Normalization) 和一般情况下不完全一样,是以 块(Block) 为样本源而非 组(Cell) 样本源本身,来进行归一化处理的。
什么是块(Block)呢?
块(Block)是对于由一系列分组(Cell)按照一定规则(例如四叉树、标准单元等)组合构成的分组并集单元的称谓。 是组的集合。对块的分法有各种形式,但在方向梯度直方图中,使用的是一种直接切入的固定设置。记块大小为 N×N ,块的最小单位为组,则取 N×N=2×2 的固定大小组采样,构成 HOG 的分块。即图例中的绿色方块:
同分组一样,分块的目的也是为了更好的将特征数据进行汇总。只不过分块时的基础单元,从分组时的像素梯度矢量,变为了分组特征向量。记分块为 Block ,分块特征向量为 Block 。仍以 ∣target∣1 表示归一化操作,有:
Block=∣[Cell1, Cell2, Cell3, Cell4]∣1∈R(N×N)⋅θ×1 可见,在 2×2 大小的固定分块下,分块特征向量 的维度即为分组特征向量方向的 4 倍,即 (N×N)⋅θ 。如果我们采用 L-2 归一化(即 L2范数)处理,记归一化因子为 L2 ,则:
L2Block=∣Cell1∣2+ ∣Cell2∣2+ ∣Cell3∣2+ ∣Cell4∣2=∑(∣∠G1∣2+ ∣∠G2∣2+ ∣∠G3∣2+ ∣∠G4∣2)=L21[Cell1, Cell2, Cell3, Cell4]∈R(N×N)⋅θ×1 那么,对图例中的分组进行块归一化到 [0, 1] 区间,所得如下:
图 3-10 图例(数据源)绿色框对应块的块归一化特征向量结果 之后,按照块大小为步长,对全图分块计算即可得到输入图片的方向梯度直方图运算结果。达成对图片整体和分块区域的运动检测目的。
那么,在具体实践中是怎么做的呢?
同前文中对滤波的处理方法类似,对于此类存在核操作流的方法论,为了充分利用 GPU 并行计算能力,通用思路仍然是抽象为可执行的渲染程序片来交由 GPU 加速。
以索贝尔梯度计算 HOG 的 GLSL 渲染程序片
现在,我们可以依据理论来做 GPU 的动态管线程序片封装。
首先,我们需要定义 顶点程序片(Vertex Shader)。通过该程序片指定 GPU 的绘制区域,以及纹理与物体的点位映射。由于我们是对整个视窗界面进行处理,所以可以采用对传入的顶点数据进行坐标变换的方式,来求得顶点映射的纹理坐标,减少少量数据通信:
程序化 HOG 的关键处理部分,依旧在 像素程序片(Pixel Shader/Fragment Shader) 上。相比之前对于滤波算法的实现,这里 显然复杂得多 :
样例采用 单一流水线过程,我们将几个关键流程节点封装为方法,实现了 HOG 的处理。相对于顶点程序片,像素程序片不太容易理解,还需分步拆开解读。
HOG 片元着色器(Fragment Shader)的细节拆解
首先需要在处理前,进行一部分方法和常量准备。这些 前置工作包含两个部分。
第一部分由纯常量构成。用于辅助实现 方向梯度直方图(HOG)算法 中,各个步骤所使用到的关键恒定参数,有:
第二部分则包含常量和辅助方法。用于辅助 HOG 最终结果的图像化显示,有:
灰度(光亮度)值采用 BT.601 的狭隘区间(Narrow Range) 标准快速计算,运用中也可以替换为均值(部分场景)或根据情况更换其他标准( 如 RGB数据 非采样得原始数据的标准原色格式而来,则因根据转换前的传输格式来选择配套的规格,见上一章)。
注意以 HOG_[xx] 为格式的常量。这些常量被用于计算,上屏显示的无符号梯度(Unsigned Gradient)对应方向上的权重柱形轴。 柱形轴过分块中心,轴的长度和颜色的深浅(即能量密度)代表归一化后的权重大小。而方法计算所得 density 则为当前像素点对应块内位置的能量密度值。显然,密度值只有在轴方向上才存在有效值。另一方面,较小的能量密度也不具有代表性,需要通过 阈值限定进行过滤,此处采用 max(HOG_MIN_MAGNITUDE, hog_magnitude_limit) 进行设置。
准备完成后,就该正式流程的处理了。这里的封装思路,是以 生成的最小结果单元为分割依据 进行的。所以,将 HOG 步骤方法封为一下三个:
sobel_edge_detection 针对 像素点(Pixel)梯度矢量 的 索贝尔边界检测
cell_feature_extraction 针对 分组(Cell)特征提取 为结果的 矢量统计合并
block_feature_extraction 针对 分块(Block)特征提取 为结果的 块归一化
考虑到思路连贯性,样例中的实现将所有步骤放在一张纹理过程中处理,且没有对核计算做优化。这会导致每个像素都存在一次 HOG 计算金字塔,而按理来说 一个块内并不需要重复计算。样例中相当于将块内运算重复了 16×16 次,极大的增加了消耗。
因此,在实际应用中,需要对上文的实现进行改造。 把文中程序片内的各个步骤的方法,分配到不同阶的程序片中,并优化纹理过程。 之后才能被更为高效的予以运用。介于骨干并无不同,此处就不再展开赘述。
经过处理后的最终结果,以能量密度的形式附加到当前像素点的色彩值上,实现最终的图形化展示:
现在,整个 HOG 的简易程序片就完成了。
到此为止,方向梯度直方图技术可以初步应用于音视频当中了。 虽然在上文样例的渲染程序片实现过程中,但从普遍意义上来讲,HOG 仍然属于相对高消耗的算法, HOG 提供的方法论更多被应用在 编解码规格制定的时域冗余处理 上。其本身具有一定的 硬件门槛。
HOG 最终产物的用处
假设输入帧长宽为 W×H=256×256 。按照前文采用块大小 2×2 ,分组大小 8×8 进行处理,则得到方向梯度直方图最终输出结果为包含 16×16=256 个块特征向量的数据集合。每一个块特征向量由 (2×2)⋅9=36 维(参数)构成。为了方便描述,我们将输出数据集称为 HOG 数据帧。
HOG 数据帧(HOG Frame)更多被作为经过特征提取后的预处理输入数据,传入目标物体检测等人工智能计算机视觉方向的算法模型。 通过模型获取的物体识别结果后,再利用训练好的目标跟踪模型,或传统目标跟踪算法(诸如:核卷积滤波(KCF [Kernelized Correlation Filter])[18] 、MOSSE 算法等)等,来获取视频流中运动物体在时序上的关联性。
那么,用于判断目标检测结果是否准确的方法,也就是目标检测模型的 损失函数(Loss Function) 是什么呢?