PD_FA的计算


一、在BasicIRSTD中的计算

  • 这个函数不会用于训练中,只会在测试中进行使用
  • 并且这种只初始化时reset一次,其余时候全程累加
class PD_FA():
    def __init__(self,):
        super(PD_FA, self).__init__()
        self.image_area_total = []
        self.image_area_match = []
        self.dismatch_pixel = 0
        self.all_pixel = 0
        self.PD = 0
        self.target= 0
    def update(self, preds, labels, size):
        predits  = np.array((preds).cpu()).astype('int64')
        labelss = np.array((labels).cpu()).astype('int64') 

        image = measure.label(predits, connectivity=2)
        coord_image = measure.regionprops(image)
        label = measure.label(labelss , connectivity=2)
        coord_label = measure.regionprops(label)

        # label中目标的个数
        self.target    += len(coord_label)
        # 没有用到
        self.image_area_total = []
        # 用于计算image中匹配label的目标的个数,即计算image中检测出来的目标的个数
        self.distance_match   = []
        # 没有用到
        self.dismatch         = []

        # 没有用到
        for K in range(len(coord_image)):
            area_image = np.array(coord_image[K].area)
            self.image_area_total.append(area_image)

        true_img = np.zeros(predits.shape)
        for i in range(len(coord_label)):
            centroid_label = np.array(list(coord_label[i].centroid))
            for m in range(len(coord_image)):
                centroid_image = np.array(list(coord_image[m].centroid))
                distance = np.linalg.norm(centroid_image - centroid_label)
                # 没有用到
                area_image = np.array(coord_image[m].area)
                if distance < 3:
                    self.distance_match.append(distance)
                    true_img[coord_image[m].coords[:,0], coord_image[m].coords[:,1]] = 1
                    del coord_image[m]
                    break

        # image检测错误的像素个数,(计算方法存在争议,因为true_img中的坐标来自于image,而不是label(本来就应当来自于label的);此外,是否匹配是由质心决定的,没有像素级对比因而不准确)
        self.dismatch_pixel += (predits - true_img).sum()
        # label整体像素个数 (=image整体像素个数)
        self.all_pixel +=size[0]*size[1]
        # image中匹配label的目标的个数,即image中检测出来的目标的个数
        self.PD +=len(self.distance_match)

    # 此处的计算会导致偏高,但不影响整体的评估
    def get(self):
        # 这里也不是纯目标级的虚警
        # image检测错误的像素个数 / [label整体像素个数 (实际应当为label中负样本即非目标的像素个数)]
        Final_FA =  self.dismatch_pixel / self.all_pixel
        # 这里是纯目标级的预测精度
        # image中匹配label的目标的个数 / label中目标的个数
        Final_PD =  self.PD /self.target
        # Final_FA其实不用.cpu().detach()
        return Final_PD, float(Final_FA.cpu().detach().numpy())

    def reset(self):
        self.FA  = np.zeros([self.bins+1])
        self.PD  = np.zeros([self.bins+1])

二、在SCTransNet中的计算

  • 这个函数不会用于训练中,只会在测试中进行使用
  • 并且这种只初始化时reset一次,其余时候全程累加
class PD_FA():
    def __init__(self, ):
        super(PD_FA, self).__init__()
        self.image_area_total = []
        self.image_area_match = []
        self.dismatch_pixel = 0
        self.all_pixel = 0
        self.PD = 0
        self.target = 0

    def update(self, preds, labels, size):
        predits = np.array((preds).cpu()).astype('int64')
        labelss = np.array((labels).cpu()).astype('int64')

        image = measure.label(predits, connectivity=2)
        coord_image = measure.regionprops(image)
        label = measure.label(labelss, connectivity=2)
        coord_label = measure.regionprops(label)

        self.target += len(coord_label)  # 目标总数  直接就搞GT的连通域个数
        self.image_area_total = []  # 图像中预测的区域列表
        self.image_area_match = []
        self.distance_match = []
        self.dismatch = []

        for K in range(len(coord_image)):
            area_image = np.array(coord_image[K].area)
            self.image_area_total.append(area_image)

        for i in range(len(coord_label)):  # image 与 label 之间 根据中心点 进行连通域的确定
            centroid_label = np.array(list(coord_label[i].centroid))
            for m in range(len(coord_image)):
                centroid_image = np.array(list(coord_image[m].centroid))
                distance = np.linalg.norm(centroid_image - centroid_label)
                area_image = np.array(coord_image[m].area)
                if distance < 3:
                    self.distance_match.append(distance)
                    self.image_area_match.append(area_image)

                    del coord_image[m]  # 匹配上一个之后就 清除一个
                    break

        # image中不与label匹配的各个块的面积
        self.dismatch = [x for x in self.image_area_total if x not in self.image_area_match]  # 在image里面 但是不在label里面

        # image中不与label匹配的各个块的面积,找到后加起来。(计算方法也存在争议,因为是否匹配是由质心决定的,没有像素级对比因而不准确)
        self.dismatch_pixel += np.sum(self.dismatch)  # Fa 虚警个数 像素的虚警
        # print(self.dismatch_pixel)
        self.all_pixel += size[0] * size[1]
        self.PD += len(self.distance_match)  # 如果中心点之间距离在3一下 就算Pd  所以Pd 是匹配上了的目标的个数

    def get(self):
        Final_FA = self.dismatch_pixel / self.all_pixel
        Final_PD = self.PD / self.target
        return Final_PD, float(Final_FA.cpu().detach().numpy())

    def reset(self):
        self.FA = np.zeros([self.bins + 1])
        self.PD = np.zeros([self.bins + 1])

三、在SeRankDet中的计算

  • 这个函数不会用于训练中,只会在测试中进行使用
  • 并且这种只初始化时reset一次,其余时候全程累加
class PD_FA():
    def __init__(self, nclass, bins, cfg):
        super(PD_FA, self).__init__()
        self.nclass = nclass
        self.bins = bins
        self.image_area_total = []
        self.image_area_match = []
        self.FA = np.zeros(self.bins + 1)
        self.PD = np.zeros(self.bins + 1)
        self.target = np.zeros(self.bins + 1)
        self.cfg = cfg

    def update(self, preds, labels):

        # 先进行外围的threshold
        for iBin in range(self.bins + 1):
            score_thresh = iBin * (255 / self.bins)
            batch = preds.size()[0]
            # 再进行内围的batch,也就是一张image和一张label进行比较
            for b in range(batch):
                predits = np.array((preds[b, :, :, :] > score_thresh).cpu()).astype('int64')
                predits = np.reshape(predits, (self.cfg.data['crop_size'], self.cfg.data['crop_size']))
                labelss = np.array((labels[b, :, :, :]).cpu()).astype('int64')  # P
                labelss = np.reshape(labelss, (self.cfg.data['crop_size'], self.cfg.data['crop_size']))

                image = measure.label(predits, connectivity=2)
                coord_image = measure.regionprops(image)
                label = measure.label(labelss, connectivity=2)
                coord_label = measure.regionprops(label)

                # 持续累加的变量1
                self.target[iBin] += len(coord_label)
                # 叠加的每一对图片内部的指标,到下一张图片之前,要清空。
                self.image_area_total = []
                self.image_area_match = []
                self.distance_match = []
                # 后面直接赋值,所以其实不用进行清空
                self.dismatch = []

                for K in range(len(coord_image)):
                    area_image = np.array(coord_image[K].area)
                    self.image_area_total.append(area_image)

                for i in range(len(coord_label)):
                    centroid_label = np.array(list(coord_label[i].centroid))
                    for m in range(len(coord_image)):
                        centroid_image = np.array(list(coord_image[m].centroid))
                        distance = np.linalg.norm(centroid_image - centroid_label)
                        area_image = np.array(coord_image[m].area)
                        if distance < 3:
                            self.distance_match.append(distance)
                            self.image_area_match.append(area_image)

                            del coord_image[m]
                            break

                self.dismatch = [x for x in self.image_area_total if x not in self.image_area_match]
                # 持续累加的变量2
                self.FA[iBin] += np.sum(self.dismatch)
                # 持续累加的变量3
                self.PD[iBin] += len(self.distance_match)

    # 所有图片都输入之后,才执行self.PD_FA.get,这个时候,才输入img_num
    def get(self, img_num):

        Final_FA = self.FA / ((self.cfg.data['crop_size'] * self.cfg.data['crop_size']) * img_num)
        Final_PD = self.PD / self.target

        return Final_FA, Final_PD

    def reset(self):
        # 持续累加变量1
        self.FA = np.zeros([self.bins + 1])
        # 持续累加变量2
        self.PD = np.zeros([self.bins + 1])
        # 持续累加变量3
        # 后面自己添加的
        self.target = np.zeros(self.bins + 1)

Author: Ruimin Huang
Reprint policy: All articles in this blog are used except for special statements CC BY 4.0 reprint polocy. If reproduced, please indicate source Ruimin Huang !
  TOC