Exemplo n.º 1
0
 def add_detections(self, filename, boxes):
     fileid = os.path.basename(filename)
     fileid = ''.join(fileid.split('.')[:-1])
     img = cv2.imread(filename)
     img_size = Size(img.shape[1], img.shape[0])
     for conf, box in boxes:
         xmin, xmax, ymin, ymax = prop2abs(box.center, box.size, img_size)
         if xmin < 0:
             xmin = 0
         if xmin >= img_size.w:
             xmin = img_size.w - 1
         if xmax < 0:
             xmax = 0
         if xmax >= img_size.w:
             xmax = img_size.w - 1
         if ymin < 0:
             ymin = 0
         if ymin >= img_size.h:
             ymin = img_size.h - 1
         if ymax < 0:
             ymax = 0
         if ymax >= img_size.h:
             ymax = img_size.h - 1
         det = Detection(fileid, conf, float(xmin + 1), float(ymin + 1),
                         float(xmax + 1), float(ymax + 1))
         self.boxes[box.label].append(det)
Exemplo n.º 2
0
def transform_box(box, orig_size, new_size, h_off, w_off):
    #---------------------------------------------------------------------------
    # Compute the new coordinates of the box
    #---------------------------------------------------------------------------
    xmin, xmax, ymin, ymax = prop2abs(box.center, box.size, orig_size)
    xmin += w_off
    xmax += w_off
    ymin += h_off
    ymax += h_off

    #---------------------------------------------------------------------------
    # Check if the center falls within the image
    #---------------------------------------------------------------------------
    width = xmax - xmin
    height = ymax - ymin
    new_cx = xmin + int(width / 2)
    new_cy = ymin + int(height / 2)
    if new_cx < 0 or new_cx >= new_size.w:
        return None
    if new_cy < 0 or new_cy >= new_size.h:
        return None

    center, size = abs2prop(xmin, xmax, ymin, ymax, new_size)

    return Box(box.label, box.labelid, center, size)
Exemplo n.º 3
0
def anchors2array(anchors, img_size):
    """
    Computes a numpy array out of absolute anchor params (img_size is needed
    as a reference)
    """
    arr = np.zeros((len(anchors), 4))
    for i in range(len(anchors)):
        anchor = anchors[i]
        xmin, xmax, ymin, ymax = prop2abs(anchor.center, anchor.size, img_size)
        arr[i] = np.array([xmin, xmax, ymin, ymax])
    return arr
Exemplo n.º 4
0
    def __call__(self, data, label, gt):
        #-----------------------------------------------------------------------
        # Check whether to sample or not
        #-----------------------------------------------------------------------
        if not self.sample:
            return data, label, gt

        #-----------------------------------------------------------------------
        # Retry sampling a couple of times
        #-----------------------------------------------------------------------
        source_boxes = anchors2array(gt.boxes, gt.imgsize)
        box = None
        box_arr = None
        for _ in range(self.max_trials):
            #-------------------------------------------------------------------
            # Sample a bounding box
            #-------------------------------------------------------------------
            scale = random.uniform(self.min_scale, self.max_scale)
            aspect_ratio = random.uniform(self.min_aspect_ratio,
                                          self.max_aspect_ratio)

            # make sure width and height will not be larger than 1
            aspect_ratio = max(aspect_ratio, scale**2)
            aspect_ratio = min(aspect_ratio, 1 / (scale**2))

            width = scale * sqrt(aspect_ratio)
            height = scale / sqrt(aspect_ratio)
            cx = 0.5 * width + random.uniform(0, 1 - width)
            cy = 0.5 * height + random.uniform(0, 1 - height)
            center = Point(cx, cy)
            size = Size(width, height)

            #-------------------------------------------------------------------
            # Check if the box satisfies the jaccard overlap constraint
            #-------------------------------------------------------------------
            box_arr = np.array(prop2abs(center, size, gt.imgsize))
            overlap = compute_overlap(box_arr, source_boxes, 0)
            if overlap.best and overlap.best.score >= self.min_jaccard_overlap:
                box = Box(None, None, center, size)
                break

        if box is None:
            return None

        #-----------------------------------------------------------------------
        # Crop the box and adjust the ground truth
        #-----------------------------------------------------------------------
        new_size = Size(box_arr[1] - box_arr[0], box_arr[3] - box_arr[2])
        w_off = -box_arr[0]
        h_off = -box_arr[2]
        data = data[box_arr[2]:box_arr[3], box_arr[0]:box_arr[1]]
        gt = transform_gt(gt, new_size, h_off, w_off)

        return data, label, gt
Exemplo n.º 5
0
    def add_detections(self, gt_boxes, boxes):
        """
        Add new detections to the calculator.
        :param gt_sample: ground truth sample
        :param boxes:     a list of (float, Box) tuples representing
                          detections and their confidences, the detections
                          must have a correctly set label
        """

        sample_id = len(self.gt_boxes)
        self.gt_boxes.append(gt_boxes)

        for conf, box in boxes:
            arr = np.array(prop2abs(box.center, box.size, IMG_SIZE))
            self.det_params[box.label].append(arr)
            self.det_confidence[box.label].append(conf)
            self.det_sample_ids[box.label].append(sample_id)
Exemplo n.º 6
0
    def compute_aps(self):
        """
        Compute the average precision per class
        """

        # Split the ground truth samples by class and sample
        counts = defaultdict(lambda: 0)
        gt_map = defaultdict(dict)

        for sample_id, boxes in enumerate(self.gt_boxes):
            boxes_by_class = defaultdict(list)
            for box in boxes:
                counts[box.label] += 1
                boxes_by_class[box.label].append(box)

            for k, v in boxes_by_class.items():
                arr = np.zeros((len(v), 4))
                match = np.zeros((len(v)), dtype=np.bool)
                for i, box in enumerate(v):
                    arr[i] = np.array(prop2abs(box.center, box.size, IMG_SIZE))
                gt_map[k][sample_id] = (arr, match)

        # Compare predictions to ground truth
        aps = {}
        for k in gt_map:
            # Create numpy arrays of detection parameters and sort them
            # in descending order
            params = np.array(self.det_params[k], dtype=np.float32)
            confs = np.array(self.det_confidence[k], dtype=np.float32)
            sample_ids = np.array(self.det_sample_ids[k], dtype=np.int)
            idxs_max = np.argsort(-confs)
            params = params[idxs_max]
            confs = confs[idxs_max]
            sample_ids = sample_ids[idxs_max]

            # Loop over the detections and count true and false positives
            tps = np.zeros((params.shape[0]))  # true positives
            fps = np.zeros((params.shape[0]))  # false positives
            for i in range(params.shape[0]):
                sample_id = sample_ids[i]
                box = params[i]

                # The image this detection comes from contains no objects of
                # of this class
                if not sample_id in gt_map[k]:
                    fps[i] = 1
                    continue

                # Compute the jaccard overlap and see if it's over the threshold
                # Note:
                #   gt:
                #       The 2D array containing all the boxes in sample with sample_id
                #       that belong to the class k
                #   matched:
                #       The boolean array of the same shape as gt.shape[0]
                gt = gt_map[k][sample_id][0]
                matched = gt_map[k][sample_id][1]

                iou = jaccard_overlap(box, gt)
                max_idx = np.argmax(iou)

                if iou[max_idx] < self.minoverlap:
                    fps[i] = 1
                    continue

                # Check if the max overlap ground truth box is already matched
                # Note:
                #   If multiple detections of the same object are found, they will be
                #   considered as false positives.
                if matched[max_idx]:
                    fps[i] = 1
                    continue

                tps[i] = 1
                matched[max_idx] = True

            # Compute the precision, recall
            fps = np.cumsum(fps)
            tps = np.cumsum(tps)
            # Note:
            #   This is the running precision of the predictions sorted according
            #   to confidence
            #   However, recall calculations are performed with respect to the total
            #   number of ground truth boxes. Hence, the recall value monotonically
            #   increases while the precision value can fluctuate
            #   To smooth out the precision curve, at each recall level, we consider
            #   the maximum precision level occuring at or after that recall level.
            #   This makes the precision vs recall curve monotonically decreasing.
            recall = tps / counts[k]
            prec = tps / (tps + fps)
            ap = 0
            for r_tilde in np.arange(0, 1.1, 0.1):
                prec_rec = prec[recall >= r_tilde]
                if len(prec_rec) > 0:
                    ap += np.amax(prec_rec)

            ap /= 11.
            aps[k] = ap

        return aps
Exemplo n.º 7
0
def non_maximum_suppression(boxes, overlap_threshold):
    #---------------------------------------------------------------------------
    # Convert to absolute coordinates and to a more convenient format
    #---------------------------------------------------------------------------
    xmin = []
    xmax = []
    ymin = []
    ymax = []
    conf = []
    img_size = Size(1000, 1000)

    for box in boxes:
        params = prop2abs(box[1].center, box[1].size, img_size)
        xmin.append(params[0])
        xmax.append(params[1])
        ymin.append(params[2])
        ymax.append(params[3])
        conf.append(box[0])

    xmin = np.array(xmin)
    xmax = np.array(xmax)
    ymin = np.array(ymin)
    ymax = np.array(ymax)
    conf = np.array(conf)

    #---------------------------------------------------------------------------
    # Compute the area of each box and sort the indices by confidence level
    # (lowest confidence first first).
    #---------------------------------------------------------------------------
    area = (xmax - xmin + 1) * (ymax - ymin + 1)
    idxs = np.argsort(conf)
    pick = []

    #---------------------------------------------------------------------------
    # Loop until we still have indices to process
    #---------------------------------------------------------------------------
    while len(idxs) > 0:
        #-----------------------------------------------------------------------
        # Grab the last index (ie. the most confident detection), remove it from
        # the list of indices to process, and put it on the list of picks
        #-----------------------------------------------------------------------
        last = idxs.shape[0] - 1
        i = idxs[last]
        idxs = np.delete(idxs, last)
        pick.append(i)
        suppress = []

        #-----------------------------------------------------------------------
        # Figure out the intersection with the remaining windows
        #-----------------------------------------------------------------------
        xxmin = np.maximum(xmin[i], xmin[idxs])
        xxmax = np.minimum(xmax[i], xmax[idxs])
        yymin = np.maximum(ymin[i], ymin[idxs])
        yymax = np.minimum(ymax[i], ymax[idxs])

        w = np.maximum(0, xxmax - xxmin + 1)
        h = np.maximum(0, yymax - yymin + 1)
        intersection = w * h

        #-----------------------------------------------------------------------
        # Compute IOU and suppress indices with IOU higher than a threshold
        #-----------------------------------------------------------------------
        union = area[i] + area[idxs] - intersection
        iou = intersection / union
        overlap = iou > overlap_threshold
        suppress = np.nonzero(overlap)[0]
        idxs = np.delete(idxs, suppress)

    #---------------------------------------------------------------------------
    # Return the selected boxes
    #---------------------------------------------------------------------------
    selected = []
    for i in pick:
        selected.append(boxes[i])

    return selected
Exemplo n.º 8
0
def box2array(box, img_size):
    xmin, xmax, ymin, ymax = prop2abs(box.center, box.size, img_size)
    return np.array([xmin, xmax, ymin, ymax])
Exemplo n.º 9
0
    def __call__(self, data, label, gt):
        #-----------------------------------------------------------------------
        # Check whether to sample or not
        #-----------------------------------------------------------------------
        if not self.sample:
            return data, label, gt

        #-----------------------------------------------------------------------
        # Retry sampling a couple of times
        #-----------------------------------------------------------------------
        source_boxes = anchors2array(
            gt.boxes, gt.imgsize)  # get abs value(xmin,xmax,ymin,ymax)
        box = None
        box_arr = None
        for _ in range(self.max_trials):
            #-------------------------------------------------------------------
            # Sample a bounding box
            #-------------------------------------------------------------------
            # min_scale=0.3, max_scale=1.0,
            # min_aspect_ratio=0.5, max_aspect_ratio=2.0,
            scale = random.uniform(self.min_scale, self.max_scale)
            aspect_ratio = random.uniform(self.min_aspect_ratio,
                                          self.max_aspect_ratio)

            # make sure width and height will not be larger than 1
            aspect_ratio = max(aspect_ratio, scale**2)
            aspect_ratio = min(aspect_ratio, 1 / (scale**2))

            width = scale * sqrt(aspect_ratio)
            height = scale / sqrt(aspect_ratio)
            cx = 0.5 * width + random.uniform(0, 1 - width)
            cy = 0.5 * height + random.uniform(0, 1 - height)
            center = Point(cx, cy)
            size = Size(width, height)

            #-------------------------------------------------------------------
            # Check if the box satisfies the jaccard overlap constraint
            #-------------------------------------------------------------------
            box_arr = np.array(prop2abs(center, size, gt.imgsize))
            overlap = compute_overlap(box_arr, source_boxes, 0)
            if overlap.best and overlap.best.score >= self.min_jaccard_overlap:
                box = Box(None, None, center, size)
                break

        if box is None:
            return None

        #-----------------------------------------------------------------------
        # Crop the box and adjust the ground truth
        #-----------------------------------------------------------------------
        new_size = Size(box_arr[1] - box_arr[0], box_arr[3] - box_arr[2])
        w_off = -box_arr[0]
        h_off = -box_arr[2]

        data = data.crop(
            (box_arr[0], box_arr[2], box_arr[1], box_arr[3])
        )  # gt와 gt근처의 가상의 anchor를 잡은뒤, iou 0.1, 0.3, 0.5, 0.7, 0.9 이상이면 그 가상의 anchor부분을 crop하고 gt 좌표도 같이 변경
        # 즉 일부로 gt와 iou 연관있는 그림부분을 crop함
        gt = transform_gt(gt, new_size, h_off, w_off)

        return data, label, gt  # change gt and image_size
Exemplo n.º 10
0
    def compute_aps(self):
        """
        Compute the average precision per class as well as mAP.
        """

        #-----------------------------------------------------------------------
        # Split the ground truth samples by class and sample
        #-----------------------------------------------------------------------
        counts = defaultdict(lambda: 0)
        gt_map = defaultdict(dict)

        for sample_id, boxes in enumerate(self.gt_boxes):
            boxes_by_class = defaultdict(list)
            for box in boxes:
                counts[box.label] += 1
                boxes_by_class[box.label].append(box)

            for k, v in boxes_by_class.items():
                arr = np.zeros((len(v), 4))
                match = np.zeros((len(v)), dtype=np.bool)
                for i, box in enumerate(v):
                    arr[i] = np.array(prop2abs(box.center, box.size, IMG_SIZE))
                gt_map[k][sample_id] = (arr, match)

        #-----------------------------------------------------------------------
        # Compare predictions to ground truth
        #-----------------------------------------------------------------------
        aps = {}
        for k in gt_map:
            #-------------------------------------------------------------------
            # Create numpy arrays of detection parameters and sort them
            # in descending order
            #-------------------------------------------------------------------
            params = np.array(self.det_params[k], dtype=np.float32)
            confs = np.array(self.det_confidence[k], dtype=np.float32)
            sample_ids = np.array(self.det_sample_ids[k], dtype=np.int)
            idxs_max = np.argsort(-confs)
            params = params[idxs_max]
            confs = confs[idxs_max]
            sample_ids = sample_ids[idxs_max]

            #-------------------------------------------------------------------
            # Loop over the detections and count true and false positives
            #-------------------------------------------------------------------
            tps = np.zeros((params.shape[0]))  # true positives
            fps = np.zeros((params.shape[0]))  # false positives
            for i in range(params.shape[0]):
                sample_id = sample_ids[i]
                box = params[i]

                #---------------------------------------------------------------
                # The image this detection comes from contains no objects of
                # of this class
                #---------------------------------------------------------------
                if not sample_id in gt_map[k]:
                    fps[i] = 1
                    continue

                #---------------------------------------------------------------
                # Compute the jaccard overlap and see if it's over the threshold
                #---------------------------------------------------------------
                gt = gt_map[k][sample_id][0]
                matched = gt_map[k][sample_id][1]

                iou = jaccard_overlap(box, gt)
                max_idx = np.argmax(iou)

                if iou[max_idx] < self.minoverlap:
                    fps[i] = 1
                    continue

                #---------------------------------------------------------------
                # Check if the max overlap ground truth box is already matched
                #---------------------------------------------------------------
                if matched[max_idx]:
                    fps[i] = 1
                    continue

                tps[i] = 1
                matched[max_idx] = True

            #-------------------------------------------------------------------
            # Compute the precision, recall
            #-------------------------------------------------------------------
            fps = np.cumsum(fps)
            tps = np.cumsum(tps)
            recall = tps / counts[k]
            prec = tps / (tps + fps)
            ap = 0
            for r_tilde in np.arange(0, 1.01, 0.01):
                prec_rec = prec[recall >= r_tilde]
                if len(prec_rec) > 0:
                    ap += np.amax(prec_rec)

            ap /= 101.
            aps[k] = ap

        return aps