AdvanceEast源码理解

文章思路

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

源码理解

一. 标签点形式

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

'''github

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

​ 若是最后计算的第二个点的Y比第一个点大,那就让最后一个点作为第一个点,其余点依次右移)app

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

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

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

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

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

'''3d

  • 下面给出一些例子

图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

最后说明

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

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

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