大神的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
針對上面兩幅圖,第一張的long_edge=0,2
,第二張的long_edge=1,3
注意:這裏頭尾都是針對最長邊上的操做
注意:頭和尾是按照標籤點的順序進行的,排在前面爲頭,排在後面爲尾
這部分比較簡單,建議由須要的讀者直接讀取一個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和LNMS都比較簡單,大概看一下就行了
這裏主要是說明一下幾個參數:
pixel_threshold = 0.9 #內部點閾值(目標點機率) side_vertex_pixel_threshold = 0.9 #內部頭尾點的閾值 ##頭尾點取值範圍,head->[0,trunc_threshold] tail->[1-trunc_threshold,1],變大以後檢測能力變強 trunc_threshold = 0.1
其實這個項目的思路很簡單,看一下就明白,可是具體實現仍是有點棘手,難點在於標籤的製做
邊界點負責迴歸邊界,這個邊界如何肯定?如何肯定頭和尾?
具體代碼的註釋寫在裏面了,還有不少小細節看筆者註釋便可
下載地址