Esempio n. 1
0
def test_select_annotations(config, image):
    windows = preprocess.compute_windows(image, config["patch_size"],
                                         config["patch_overlap"])
    image_annotations = pd.read_csv("tests/data/OSBS_029.csv")
    selected_annotations = preprocess.select_annotations(image_annotations,
                                                         windows,
                                                         index=7)

    # Returns a 5 column matrix
    assert selected_annotations.shape[0] == 17

    # image name should be name of image plus the index .tif
    assert selected_annotations.image_path.unique()[0] == "OSBS_029_7.png"
Esempio n. 2
0
def test_select_annotations_tile(config, image):
    config["patch_size"] = 50
    windows = preprocess.compute_windows(image, config["patch_size"],
                                         config["patch_overlap"])
    image_annotations = pd.read_csv("tests/data/OSBS_029.csv")
    selected_annotations = preprocess.select_annotations(image_annotations,
                                                         windows,
                                                         index=10)

    # The largest box cannot be off the edge of the window
    assert selected_annotations.xmin.min() >= 0
    assert selected_annotations.ymin.min() >= 0
    assert selected_annotations.xmax.max() <= config["patch_size"]
    assert selected_annotations.ymax.max() <= config["patch_size"]
Esempio n. 3
0
def test_compute_windows(config, image):
    windows = preprocess.compute_windows(image, config["patch_size"],
                                         config["patch_overlap"])
    assert len(windows) == 9
Esempio n. 4
0
    def predict_tile(self,
                     raster_path=None,
                     numpy_image=None,
                     patch_size=400,
                     patch_overlap=0.05,
                     iou_threshold=0.15,
                     return_plot=False,
                     show=False):
        """For images too large to input into the model, predict_tile cuts the
        image into overlapping windows, predicts trees on each window and
        reassambles into a single array.

        Args:
            raster_path: Path to image on disk
            numpy_image (array): Numpy image array in BGR channel order
                following openCV convention
            patch_size: patch size default400,
            patch_overlap: patch overlap default 0.15,
            iou_threshold: Minimum iou overlap among predictions between
                windows to be suppressed. Defaults to 0.5.
                Lower values suppress more boxes at edges.
            return_plot: Should the image be returned with the predictions drawn?
            show (bool): Plot the predicted image with bounding boxes.
                Ignored if return_plot=False

        Returns:
            boxes (array): if return_plot, an image.
                Otherwise a numpy array of predicted bounding boxes, scores and labels
        """

        if numpy_image is not None:
            pass
        else:
            # Load raster as image
            raster = Image.open(raster_path)
            numpy_image = np.array(raster)

        # Compute sliding window index
        windows = preprocess.compute_windows(numpy_image, patch_size, patch_overlap)

        # Save images to tmpdir
        predicted_boxes = []

        for index, window in enumerate(tqdm(windows)):
            # Crop window and predict
            crop = numpy_image[windows[index].indices()]

            # Crop is RGB channel order, change to BGR
            crop = crop[..., ::-1]
            boxes = self.predict_image(numpy_image=crop,
                                       return_plot=False,
                                       score_threshold=self.config["score_threshold"])

            # transform coordinates to original system
            xmin, ymin, xmax, ymax = windows[index].getRect()
            boxes.xmin = boxes.xmin + xmin
            boxes.xmax = boxes.xmax + xmin
            boxes.ymin = boxes.ymin + ymin
            boxes.ymax = boxes.ymax + ymin

            predicted_boxes.append(boxes)

        predicted_boxes = pd.concat(predicted_boxes)

        # Non-max supression for overlapping boxes among window
        if patch_overlap == 0:
            mosaic_df = predicted_boxes
        else:
            with tf.Session() as sess:
                print(
                    "{} predictions in overlapping windows, applying non-max supression".
                    format(predicted_boxes.shape[0]))
                new_boxes, new_scores, new_labels = predict.non_max_suppression(
                    sess,
                    predicted_boxes[["xmin", "ymin", "xmax", "ymax"]].values,
                    predicted_boxes.score.values,
                    predicted_boxes.label.values,
                    max_output_size=predicted_boxes.shape[0],
                    iou_threshold=iou_threshold)

                # Recreate box dataframe
                image_detections = np.concatenate([
                    new_boxes,
                    np.expand_dims(new_scores, axis=1),
                    np.expand_dims(new_labels, axis=1)
                ],
                                                  axis=1)

                mosaic_df = pd.DataFrame(
                    image_detections,
                    columns=["xmin", "ymin", "xmax", "ymax", "score", "label"])
                
                if mosaic_df.shape[0] == 0:
                    print("No predictions made, returning None")
                    return None
                    
                mosaic_df.label = mosaic_df.label.str.decode("utf-8")
                print("{} predictions kept after non-max suppression".format(
                    mosaic_df.shape[0]))

        if return_plot:
            # Draw predictions
            for box in mosaic_df[["xmin", "ymin", "xmax", "ymax"]].values:
                draw_box(numpy_image, box, [0, 0, 255])

            if show:
                plt.imshow(numpy_image[:, :, ::-1])
                plt.show()

            # Mantain consistancy with predict_image
            return numpy_image
        else:
            return mosaic_df
Esempio n. 5
0
def predict_tile(model,
                 device,
                 raster_path=None,
                 image=None,
                 patch_size=400,
                 patch_overlap=0.05,
                 iou_threshold=0.15,
                 return_plot=False,
                 mosaic=True,
                 use_soft_nms=False,
                 sigma=0.5,
                 thresh=0.001,
                 color=None,
                 thickness=1):
    """For images too large to input into the model, predict_tile cuts the
    image into overlapping windows, predicts trees on each window and
    reassambles into a single array.

    Args:
        model: pytorch model
        device: pytorch device of 'cuda' or 'cpu' for gpu prediction. Set internally.
        numeric_to_label_dict: dictionary in which keys are numeric integers and values are character labels
        raster_path: Path to image on disk
        image (array): Numpy image array in BGR channel order
            following openCV convention
        patch_size: patch size default400,
        patch_overlap: patch overlap default 0.15,
        iou_threshold: Minimum iou overlap among predictions between
            windows to be suppressed. Defaults to 0.14.
            Lower values suppress more boxes at edges.
        return_plot: Should the image be returned with the predictions drawn?
        mosaic: If true, return a single annotations dataframe. If false, return a list of windows and predictions
        use_soft_nms: whether to perform Gaussian Soft NMS or not, if false, default perform NMS.
        sigma: variance of Gaussian function used in Gaussian Soft NMS
        thresh: the score thresh used to filter bboxes after soft-nms performed

    Returns:
        boxes (array): if return_plot, an image.
        windows (list): if mosaic = False, a two item tuple for each window of patch_size with predictions
        Otherwise a numpy array of predicted bounding boxes, scores and labels
    """

    if image is not None:
        pass
    else:
        # load raster as image
        image = rio.open(raster_path).read()
        image = np.moveaxis(image, 0, 2)

    # Compute sliding window index
    windows = preprocess.compute_windows(image, patch_size, patch_overlap)
    predicted_boxes = []
    crops = []

    for index, window in enumerate(tqdm(windows)):
        # crop window and predict
        crop = image[windows[index].indices()]
        crop = crop.astype('float32')

        # crop is RGB channel order, change to BGR?
        boxes = predict_image(model=model,
                              image=crop,
                              return_plot=False,
                              device=device)
        if boxes is not None:
            if mosaic:
                # transform the coordinates to original system
                xmin, ymin, xmax, ymax = windows[index].getRect()
                boxes.xmin = boxes.xmin + xmin
                boxes.xmax = boxes.xmax + xmin
                boxes.ymin = boxes.ymin + ymin
                boxes.ymax = boxes.ymax + ymin
            else:
                crops.append(crop)
            predicted_boxes.append(boxes)

    if len(predicted_boxes) == 0:
        print("No predictions made, returning None")
        return None
    if mosaic:
        predicted_boxes = pd.concat(predicted_boxes)
        # Non-max supression for overlapping boxes among window
        if patch_overlap == 0:
            mosaic_df = predicted_boxes
        else:
            print(
                f"{predicted_boxes.shape[0]} predictions in overlapping windows, applying non-max supression"
            )
            # move prediciton to tensor
            boxes = torch.tensor(
                predicted_boxes[["xmin", "ymin", "xmax", "ymax"]].values,
                dtype=torch.float32)
            scores = torch.tensor(predicted_boxes.score.values,
                                  dtype=torch.float32)
            labels = predicted_boxes.label.values

            if not use_soft_nms:
                # Performs non-maximum suppression (NMS) on the boxes according to
                # their intersection-over-union (IoU).
                bbox_left_idx = nms(boxes=boxes,
                                    scores=scores,
                                    iou_threshold=iou_threshold)
            else:
                # Performs soft non-maximum suppression (soft-NMS) on the boxes.
                bbox_left_idx = soft_nms(boxes=boxes,
                                         scores=scores,
                                         sigma=sigma,
                                         thresh=thresh)

            bbox_left_idx = bbox_left_idx.numpy()
            new_boxes, new_labels, new_scores = boxes[bbox_left_idx].type(
                torch.int), labels[bbox_left_idx], scores[bbox_left_idx]

            # Recreate box dataframe
            image_detections = np.concatenate([
                new_boxes,
                np.expand_dims(new_labels, axis=1),
                np.expand_dims(new_scores, axis=1)
            ],
                                              axis=1)

            mosaic_df = pd.DataFrame(
                image_detections,
                columns=["xmin", "ymin", "xmax", "ymax", "label", "score"])

            print(
                f"{mosaic_df.shape[0]} predictions kept after non-max suppression"
            )

        if return_plot:
            # Draw predictions on BGR
            image = image[:, :, ::-1]
            image = visualize.plot_predictions(image,
                                               mosaic_df,
                                               color=color,
                                               thickness=thickness)
            # Mantain consistancy with predict_image
            return image
        else:
            return mosaic_df
    else:
        return list(zip(predicted_boxes, crops))
Esempio n. 6
0
import numpy as np
from deepforest import preprocess
from preProcess import pre_process_image_in_folder
test_model = deepforest.deepforest()
test_model.use_release()

#predict image
pre_process_image_in_folder("./data", "./processed")

images = os.listdir('./processed')
for image in images:
    image_path = os.path.join("./processed", image)
    raster = cv2.imread(image_path)
    numpy_image = np.array(raster)
    windows = preprocess.compute_windows(numpy_image,
                                         patch_size=400,
                                         patch_overlap=0.1)
    for window in windows:
        crop = numpy_image[window.indices()]

        img = test_model.predict_image(numpy_image=crop,
                                       return_plot=True,
                                       score_threshold=0.05)

        #Show image, matplotlib expects RGB channel order, but keras-retinanet predicts in BGR
        plt.imshow(img[..., ::-1])
        plt.show()

#raster = cv2.imread("./processed/IITK1.JPG")
#numpy_image = np.array(raster)
#windows = preprocess.compute_windows(numpy_image, patch_size=400,patch_overlap=0.1)