• AdvanceEast源码理解


    文章思路

    大神的github和个人网站已经对此进行了说明,这里不再赘述。。。

    源码理解

    一. 标签点形式

    • 给四个点排列顺序制定规则

    '''

    按顺序排列四个点,逆时针旋转,且第一个点为左上角点(刚开始选择最左边的点,

    ​ 如果最后计算的第二个点的Y比第一个点大,那就让最后一个点做为第一个点,其他点依次右移)

    • 1.以最小的X坐标为起点(起名为A)

    • 2.其他三个点和第一个点(A)连线形成夹角,取中间的点为第三个点(起名C)

    • 3.以AC为连线,在AC上方为D,下方为B

    • 4.最后比较AC和BD的斜率,AC>BD ===> 顺序调整为DABC AC<BD ===> 维持ABCD

    • 5.感觉第四步没啥意义,只要是顺序就好了,没必要那么苛刻。。。。

    '''

    • 下面给出一些例子

    图1.1

    图1.2

    • 注意长边的位置

    针对上面两幅图,第一张的long_edge=0,2,第二张的long_edge=1,3

    二. 标签切边

    • 以最短边的0.3进行缩放当做内部点

    图1.3

    • 以最短边的0.6作为头尾点

    注意:这里头尾都是针对最长边上的操作

    注意:头和尾是按照标签点的顺序进行的,排在前面为头,排在后面为尾

    图1.4

    图1.5

    三. loss计算

    这部分比较简单,建议由需要的读者直接读取一个data进行debug即可:

    #input : 1*w*h*3
    #label : 1*160*160*7(batch,w,h,type)
    def quad_loss(y_true, y_pred):
        # loss for inside_score
        logits = y_pred[:, :, :, :1]
        labels = y_true[:, :, :, :1]
        # balance positive and negative samples in an image
        beta = 1 - tf.reduce_mean(labels)
        # first apply sigmoid activation
        predicts = tf.nn.sigmoid(logits)
        # log +epsilon for stable cal
        inside_score_loss = tf.reduce_mean(
            -1 * (beta * labels * tf.log(predicts + cfg.epsilon) +
                  (1 - beta) * (1 - labels) * tf.log(1 - predicts + cfg.epsilon)))
        inside_score_loss *= cfg.lambda_inside_score_loss
    
        # loss for side_vertex_code
        vertex_logits = y_pred[:, :, :, 1:3]
        vertex_labels = y_true[:, :, :, 1:3]
        vertex_beta = 1 - (tf.reduce_mean(y_true[:, :, :, 1:2])
                           / (tf.reduce_mean(labels) + cfg.epsilon))
        vertex_predicts = tf.nn.sigmoid(vertex_logits)
        pos = -1 * vertex_beta * vertex_labels * tf.log(vertex_predicts +
                                                        cfg.epsilon)
        neg = -1 * (1 - vertex_beta) * (1 - vertex_labels) * tf.log(
            1 - vertex_predicts + cfg.epsilon)
        positive_weights = tf.cast(tf.equal(y_true[:, :, :, 0], 1), tf.float32)
        side_vertex_code_loss = 
            tf.reduce_sum(tf.reduce_sum(pos + neg, axis=-1) * positive_weights) / (
                    tf.reduce_sum(positive_weights) + cfg.epsilon)
        side_vertex_code_loss *= cfg.lambda_side_vertex_code_loss
    
        # loss for side_vertex_coord delta
        g_hat = y_pred[:, :, :, 3:]
        g_true = y_true[:, :, :, 3:]
        vertex_weights = tf.cast(tf.equal(y_true[:, :, :, 1], 1), tf.float32)
        pixel_wise_smooth_l1norm = smooth_l1_loss(g_hat, g_true, vertex_weights)
        side_vertex_coord_loss = tf.reduce_sum(pixel_wise_smooth_l1norm) / (
                tf.reduce_sum(vertex_weights) + cfg.epsilon)
        side_vertex_coord_loss *= cfg.lambda_side_vertex_coord_loss
        return inside_score_loss + side_vertex_code_loss + side_vertex_coord_loss
    
    
    def smooth_l1_loss(prediction_tensor, target_tensor, weights):
        n_q = tf.reshape(quad_norm(target_tensor), tf.shape(weights))
        diff = prediction_tensor - target_tensor
        abs_diff = tf.abs(diff)
        abs_diff_lt_1 = tf.less(abs_diff, 1)
        pixel_wise_smooth_l1norm = (tf.reduce_sum(
            tf.where(abs_diff_lt_1, 0.5 * tf.square(abs_diff), abs_diff - 0.5),
            axis=-1) / n_q) * weights
        return pixel_wise_smooth_l1norm
    
    
    def quad_norm(g_true):
        shape = tf.shape(g_true)
        delta_xy_matrix = tf.reshape(g_true, [-1, 2, 2])
        diff = delta_xy_matrix[:, 0:1, :] - delta_xy_matrix[:, 1:2, :]
        square = tf.square(diff)
        distance = tf.sqrt(tf.reduce_sum(square, axis=-1))
        distance *= 4.0
        distance += cfg.epsilon
        return tf.reshape(distance, shape[:-1])
    
    if __name__ == '__main__':
        x, y = data_generator.gen(1)
        loss_t = quad_loss(y,y)
    

    四. NMS

    这部分没仔细看,传统的NMS和LNMS都比较简单,大概看一下就好了

    这里主要是说明一下几个参数:

    pixel_threshold = 0.9 #内部点阈值(目标点概率)
    side_vertex_pixel_threshold = 0.9 #内部头尾点的阈值
    ##头尾点取值范围,head->[0,trunc_threshold] tail->[1-trunc_threshold,1],变大之后检测能力变强
    trunc_threshold = 0.1 
    

    最后说明

    其实这个项目的思路很简单,看一下就明白,但是具体实现还是有点棘手,难点在于标签的制作

    边界点负责回归边界,这个边界如何确定?如何确定头和尾?

    具体代码的注释写在里面了,还有很多小细节看笔者注释即可
    下载地址

  • 相关阅读:
    Idea快捷键
    Java学习之路--书籍推荐
    泵式等待基元
    uni-app,wex5,APPcan,ApiCloud几款国内webapp开发框架的选型对比
    前端框架2019 云开发
    select2 javascript控件 如何设置指定的值
    Github 索引
    linux
    WPF 中的 Uri 地址的不同写法
    WPF GridSplitter 使用技巧
  • 原文地址:https://www.cnblogs.com/wjy-lulu/p/11370527.html
Copyright © 2020-2023  润新知