リモートセンシング画像に基づく道路の完全性と接続性の評価指標

序文

この特別な機能である道路のトポロジー構造情報を考慮して、このブログ投稿では、道路の結果の完全性と接続性を計算するために、道路の完全性と道路の接続性の2つの指標を紹介します。

道路の完全性

Lpredは予測された道路の長さであり、Ltruthは実際のラベルの道路の長さです。ここで、道路の予測結果と実際のラベルは両方とも単一ピクセルのラスターデータです。Lpredは、統計を通じてLtruthによって予測された路面の長さです。
ここに画像の説明を挿入
次の図は、道路の完全性を計算する方法を示しています。黄色は予測された道路、青は実際の道路、細い青い線は間伐後のLtruthです。3番目の図では、重ね合わせた後、予測結果に当たる緑色は、成功した予測の長さを表しています。 Lpred、赤は欠けている長さです。
ここに画像の説明を挿入

import numpy as np
import skimage
from skimage import morphology
import cv2

def thin_image(mask_dir, mask_file):
    im = cv2.imread(mask_dir + mask_file, 0)
    im = im > 128
    selem = skimage.morphology.disk(2)
    im = skimage.morphology.binary_dilation(im, selem)
    im = skimage.morphology.thin(im)
    return im.astype(np.uint8) * 255


mask_dir = 'E:/shao_xing/out/result_boost12345/'
gt_dir = 'E:/shao_xing/test/lab/'
region = 'd'

mylogs = open('E:/shao_xing/out/tiny_evalog/new_metric/' + region + '_boost12345.log','w')
ratio_list=[]
for i in range(-4, 4):
    for j in range(-4, 4):
        gt_file = region + '_' + str(i) + '_' + str(j) + '_osm.png'
        mask_file = gt_file[:-7] + 'merge.png'

        mask = cv2.imread(mask_dir + mask_file, 0)
        thin_gt = thin_image(gt_dir, gt_file)
        num_mask = np.sum(thin_gt[mask > 128]) / 255
        num_gt = np.sum(thin_gt) / 255
        ratio = num_mask / (num_gt+0.00001)
        if num_gt != 0:
            ratio_list.append(ratio)
        print('test image ', str(i), '_', str(j), 'ratio:', round(ratio, 2), file=mylogs)
        print('test image ', str(i), '_', str(j), 'ratio:', round(ratio, 2))

print('********************************', file=mylogs)
print('Average Ratio:', round((sum(ratio_list) / len(ratio_list)), 2), file=mylogs)
print('********************************')
print('Average Ratio:', round((sum(ratio_list) / len(ratio_list)), 2))
mylogs.close()

道路の接続性

次の式は、道路接続の計算方法を表しています。Nconnectedは、予測結果の連続する道路セグメントの数を表し、Ntotalは、真の値の道路セグメントの数を表します。統計的手法は、ベクトルデータの真の値を同じ長さのセグメントに分割し、これらのセグメントが完全に予測されているかどうかをカウントすることです。完全に予測されている場合は接続済みとして記録され、完全に予測されていない場合はそれらが接続されていると記録されます。未接続として記録されます。
ここに画像の説明を挿入
次の図は、道路接続の統計的プロセスを示しています。黄色は予測された道路であり、青と赤の細い線はベクトル形式の実際の道路ラベルであり、多くのフラグメントで構成されています。赤い部分は壊れた部分、つまり接続されていません。青い部分は接続されています。
ここに画像の説明を挿入

import sys
sys.path.append("./discoverlib")
from discoverlib import geom, graph
import numpy as np
import cv2
import skimage
from skimage import morphology


"""
evaluate connectivity based on ground truth graph
We split the total graph into segments with length of around 20 pixels
Then, statistic the number of fully connected segments in segmentation masks.
The connectivity ratio is the percentage of fully connected segments. 
"""

log_name = 'mask' # evaluation log file
mask_dir = '~/data/out/mask/' # segmentation masks for evaluating

total_gt_number = 0
total_connected_number = 0
total_not_connected_number = 0
total_pred_number = 0

total_connected_length = 0
total_gt_length = 0
total_pred_length = 0
mylog = open('~/data/out/eval_log/' + log_name + '_connect.log', 'w')

region_name_list = [["amsterdam",-4,-4,4,4], ["chicago",-4,-4,4,4], ["denver",-4,-4,4,4]]
for region_info in region_name_list:
    print("test region: "+region_info[0])
    graph_name = '~/data/graph_gt/'+ region_info[0] + ".graph" # ground truth graph

    gt_graph = graph.read_graph(graph_name)
    edge_nodes=[]
    for i,edge in enumerate(gt_graph.edges):
        if i % 2 ==0:
            edge_nodes.append([edge.src.point.x,edge.src.point.y,edge.dst.point.x,edge.dst.point.y])
    base_gt_mask=np.zeros((1024, 1024))
    edge_nodes=np.array(edge_nodes)

    for i in range(region_info[1], region_info[3]):
        for j in range(region_info[2], region_info[4]):
            mask_file = region_info[0] + '_' + str(i) + '_' + str(j) + '_fusion.png'
            # print(mask_dir + mask_file)
            mask = cv2.imread(mask_dir + mask_file, 0)/255

            patch_gt_number=0
            patch_connected_number=0
            patch_not_connected_number=0

            patch_connected_length = 0
            patch_gt_length = 0

            offset=[-i*1024, -j*1024, -i*1024, -j*1024]
            patch_nodes=edge_nodes+offset
            for seg_edge in patch_nodes:
                if (seg_edge>=[0,0,0,0]).all() and (seg_edge<[1024,1024,1024,1024]).all():
                    base_gt_mask = np.zeros((1024, 1024))
                    patch_gt_number+=1 # number of segments on the ground-truth graph
                    base_gt_mask=cv2.line(base_gt_mask,(seg_edge[0],seg_edge[1]),(seg_edge[2],seg_edge[3]),color=1, thickness=1)
                    pred_seg_length=np.sum(mask[base_gt_mask>0])
                    gt_length=np.sum(base_gt_mask>0)
                    patch_gt_length += gt_length
                    if pred_seg_length < gt_length:
                        patch_not_connected_number+=1
                    else:
                        patch_connected_number+=1
                        patch_connected_length += gt_length
                else:
                    pass

            im = (mask*255) > 128
            selem = skimage.morphology.disk(2)
            im = skimage.morphology.binary_dilation(im, selem)
            im = skimage.morphology.thin(im)
            thin_mask = im.astype(np.uint8) * 255

            patch_pred_length = np.sum(thin_mask > 0)

            patch_pred_number = patch_pred_length / 20.0 # number of segments on the prediction graph

            ratio = 2*patch_connected_length/(patch_gt_length+patch_pred_length+0.00001)

            print('test image {}_{} connected:not:total {}/{}/{}, ratio: {}'.format(i,j,patch_connected_number,
                                                                                        patch_not_connected_number,
                                                                                        patch_gt_number,
                                                                                        round(ratio, 4)))
            print('test image {}_{} connected:not:total {}/{}/{}, ratio: {}'.format(i, j, patch_connected_number,
                                                                                    patch_not_connected_number,
                                                                                    patch_gt_number,
                                                                                    round(ratio, 4)), file=mylog)
            total_gt_number += patch_gt_number
            total_connected_number += patch_connected_number
            total_not_connected_number += patch_not_connected_number
            total_pred_number += patch_pred_number

            total_connected_length += patch_connected_length
            total_gt_length += patch_gt_length
            total_pred_length += patch_pred_length

# total_ratio = 2*total_connected_number/(total_gt_number+total_pred_number)
total_ratio = 2*total_connected_length/(total_gt_length+total_pred_length)

print('********************************')
print("total connected:not:total {}/{}/{}, ratio: {}".format(total_connected_number,
                                                             total_not_connected_number,
                                                             total_gt_number,
                                                             round(total_ratio, 4)))
print("total_gt_length:{}".format(total_gt_length))
print("average gt length:{}".format(total_gt_length/total_gt_number))
print('********************************', file=mylog)
print("total connected:not:total {}/{}/{}, ratio: {}".format(total_connected_number,
                                                             total_not_connected_number,
                                                             total_gt_number,
                                                             round(total_ratio, 4)),
      file=mylog)
print("total_gt_length:{}".format(total_gt_length),file=mylog)
print("average gt length:{}".format(total_gt_length/total_gt_number),file=mylog)

mylog.close()

参照

https://github.com/astro-ck/Road-Extraction

おすすめ

転載: blog.csdn.net/weixin_42990464/article/details/114290480