其他分享
首页 > 其他分享> > 小总结-特征点检测的两种方法-FC回归和heat map

小总结-特征点检测的两种方法-FC回归和heat map

作者:互联网

最近研究了一下特征点检测最后一步的的两种主流方法,整理了分享出来。其实说的是经过一系列网络运算之后,最后一步如何由网络的feature map直接预测出特征点坐标位置。

---------Agenda-------

----------------------------

 

-------------------------------------------------------------------开始吧------------------------------------------------------------------

主流的做关键点检测有两大流派

 

 

 

 基本的heat map是怎么实现的

FC的方法比较好理解,下面着重介绍下最基本的heatmap的方法怎么去做的

def get_preds_fromhm(hm, center=None, scale=None):

    """Obtain (x,y) coordinates given a set of N heatmaps. If the center

    and the scale is provided the function will return the points also in

    the original coordinate frame.

 

    Arguments:

        hm {torch.tensor} -- the predicted heatmaps, of shape [B, N, W, H]

 

    Keyword Arguments:

        center {torch.tensor} -- the center of the bounding box (default: {None})

        scale {float} -- face scale (default: {None})

    """

    B, C, H, W = hm.shape

    hm_reshape = hm.reshape(B, C, H * W)

    idx = np.argmax(hm_reshape, axis=-1) # 首先通过argmax得到每个channel最大的相应的位置

    scores = np.take_along_axis(hm_reshape, np.expand_dims(idx, axis=-1), axis=-1).squeeze(-1)

    preds, preds_orig = _get_preds_fromhm(hm, idx, center, scale)

 

    return preds, preds_orig, scores

@jit(nopython=True)

def _get_preds_fromhm(hm, idx, center=None, scale=None):

    """Obtain (x,y) coordinates given a set of N heatmaps and the

    coresponding locations of the maximums. If the center

    and the scale is provided the function will return the points also in

    the original coordinate frame.

    Arguments:

        hm {torch.tensor} -- the predicted heatmaps, of shape [B, N, W, H]

 

    Keyword Arguments:

        center {torch.tensor} -- the center of the bounding box (default: {None})

        scale {float} -- face scale (default: {None})

    """

    B, C, H, W = hm.shape

    idx += 1

    preds = idx.repeat(2).reshape(B, C, 2).astype(np.float32)

    preds[:, :, 0] = (preds[:, :, 0] - 1) % W + 1

    preds[:, :, 1] = np.floor((preds[:, :, 1] - 1) / H) + 1 #然后得到每个热力图最热的部位的x和y的坐标,分别存在preds[:,:,0]和preds[:,:,1]中

 

    for i in range(B):

        for j in range(C):

            hm_ = hm[i, j, :]

            pX, pY = int(preds[i, j, 0]) - 1, int(preds[i, j, 1]) - 1

            if pX > 0 and pX < 63 and pY > 0 and pY < 63:

                diff = np.array(

                    [hm_[pY, pX + 1] - hm_[pY, pX - 1],

                     hm_[pY + 1, pX] - hm_[pY - 1, pX]])

                preds[i, j] += np.sign(diff) * 0.25 #  去计算热力图上最热部位的左右两边的热力值,如果右边的大,那么热力图的最热点(preds)的值就往右边移1/4个pixel,反之亦然。同样适用于上下两个像素的值,通过这种方式去得到一个接近亚像素的坐标值

 

    preds -= 0.5 #取中心的坐标

 

    preds_orig = np.zeros_like(preds)

    if center is not None and scale is not None:

        for i in range(B):

            for j in range(C):

                preds_orig[i, j] = transform_np(

                    preds[i, j], center, scale, H, True)

 

    return preds, preds_orig

就比较简单了,咱们多讨论一下

这种方法显然不是特别合理,首先说如果就用argmax肯定是不行的,因为可能边上的点其实跟你几乎一模一样就小一点点,那这样像素的精度只能达到1个pixel,其实很多关键点检测是缩小了去做的,那么达到的关键点坐标放大回去就会有几个像素的偏差,很多任务中会造成抖动,显然是不可接受的。这就是很多文章中会提及的heatmap的方法存在一个理论误差下值。

那么左边这段代码的方法方法可以稍微考虑下左右像素,实现亚像素精度。但是如果左右两个像素值其实比中心小很多,然后你还去区分左边多一点还是右边多一点,然后硬往那边挪1/4个像素,其实也是不合理的。

 

 

Hm[py-1,px]

 

Hm[py,px-1]

Hm[py,px]

Hm[py,px-1]

 

Hm[py+1,px]

 

在训练标签的准备中,需要由数据标签坐标值去准备高斯热图

在训练的时候,所有的像素点都对Loss有贡献,但是在实际Inference的时候,只有5个像素点能决定最终的坐标,输出和坐标之间不能完全对应

像右边这种图,在算Loss的时候,中间的是5x5x4 = 100, 而右边的是(9-5)^2=16,似乎是右边的更好,但是在取了argmax之后,其实是中间的结果更好,就是上面所说的训练的时候计算的loss不能完全对应到输出坐标。

 

 

 

 

 

 

 

FC vs heat map

 

“”实战中发现fc更倾向于预测一个合理得模板,heatmap方法相对关注局部一点得特征,相对来说,heatmap方法更容易出现点位错乱的情况,而fc更多的是单个点精度不足导致偏差

 

regression模型很容易训练,甚至即是很少的数据也能够训练。当然与此带来的就是极度的容易过拟合和泛化问题(如果说数据能够觉得那当我没说)。key points之间的能够保持某种潜在的“秩序”(比如face alignment中双眼+鼻子+两嘴角构成的5个点,这5个点总是会保持方位上的秩序)。这种秩序性更体现在,如果输入是一张完全不相关的图像,regression依然可以给出一个形状上非常合理的结果(反观heatmap所给的key points则会完全乱了套)”

 

From <https://zhuanlan.zhihu.com/p/374842773>

 

Numerical Coordinate Regression with Convolutional Neural Networks这篇文章中有详细比较

 

FC的方法直接得到一个坐标点是不靠谱的,因为坐标点这个东西太隐晦了,比如说在目标检测的时候,为什么不直接FC输出4个值呢?因为这样效果不会好,所以要有什么maskRcnn还有yolo还有SSD的方法。用FC在小数据集上很容易出现过拟合。

高斯热图的方法就对CNN友好很多

就人脸关键点检测这个任务来说,FC的方法又有其优越性,毕竟人脸其实是一个相对人体更加刚性的结构,FC的方方能八九不离十的猜出一个好不错的特征点。而且人脸的很多特征点其实并不是角点,比如眼睛上部的那个点,还有脸颊上的点,在标注的时候都有猜的成分在。高斯热图想要在这里有一个高响应比较困难。

 

但是高斯热图的方法计算量比较大,毕竟最后几层需要输出与输入等分辨率的而且channel数很多的热图。

 

 

 

 

 heat map v2.0

那么有一种改进后的方法就来了,叫做DSNT differentiable spatial to numerical transform (DSNT) layer,他在heat map方法上进行了改进。paper link Numerical Coordinate Regression with Convolutional Neural Networks

怎么做的呢?其实就是把所有的取值做了softmax, 然后得到下图第一张,然后生成一下每个点x的坐标,每个点y的坐标,即下面图的中间和右边部分。

然后去计算x的期望和y的期望,用这个期望作为预测出的x和y。就是下面两个式子算的。这样可得亚像素的精度,而且是任意精度,不是上面基本的heat map方法的0.25像素大小的精度。非常合理。

 

 

 

 

说完合理的部分,下面说一说可能会有的问题,那就是如果光用跟这个去约束,可能得到的heat map会很奇怪,比如我们在GT的坐标的左右对称有两个高响应点也可以得到很小的loss,其实这个是会有问题的,就像下面几种方法得到的坐标位置都不差,但是还是在目标点处的一个高响应是最理想的,实验证明,如果对heat map的形状进行约束,这样可以指导网络得到更好的效果。所以loss上还会加一些约束,得到一个尽可能接近高斯相应的heat map。

 

 

 

 

具体怎么做的呢?

就是用KL散度去计算得到的heat map响应和高斯图之间的相似度即可。加一个Loss。

 

----------------------------------------------------------END-----------------------------------------------------------------------------------------------------

Related paper

Numerical Coordinate Regression with Convolutional Neural Networks https://arxiv.org/pdf/1801.07372.pdf

Learning Feature Pyramids for Human Pose Estimation https://arxiv.org/pdf/1708.01101.pdf

Human pose estimation via Convolutional Part Heatmap Regression https://arxiv.org/pdf/1609.01743.pdf

How far are we from solving the 2D & 3D Face Alignment problem? (and a dataset of 230,000 3D facial landmarks) https://arxiv.org/pdf/1703.07332.pdf

 

标签:map,scale,center,preds,heat,FC,hm
来源: https://www.cnblogs.com/sunny-li/p/16102263.html