Example #1
0
def test_random_transform(annotations):
    test_model = deepforest.deepforest()
    test_model.config["random_transform"] = True
    classes_file = utilities.create_classes(annotations)
    arg_list = utilities.format_args(annotations, classes_file,
                                     test_model.config)
    assert "--random-transform" in arg_list
Example #2
0
def config():
    print("Configuring tfrecord tests")
    config = {}
    config["patch_size"] = 200
    config["patch_overlap"] = 0.05
    config["annotations_xml"] = get_data("OSBS_029.xml")
    config["rgb_dir"] = "data"
    config["annotations_file"] = "tests/data/OSBS_029.csv"
    config["path_to_raster"] =get_data("OSBS_029.tif")
    config["image-min-side"] = 800
    config["backbone"] = "resnet50"
    
    #Create a clean config test data
    annotations = utilities.xml_to_annotations(xml_path=config["annotations_xml"])
    annotations.to_csv("tests/data/tfrecords_OSBS_029.csv",index=False)
    
    annotations_file = preprocess.split_raster(path_to_raster=config["path_to_raster"],
                                                        annotations_file="tests/data/tfrecords_OSBS_029.csv",
                                                        base_dir= "tests/data/",
                                                        patch_size=config["patch_size"],
                                                        patch_overlap=config["patch_overlap"])
    
    annotations_file.to_csv("tests/data/testfile_tfrecords.csv", index=False,header=False)
    class_file = utilities.create_classes("tests/data/testfile_tfrecords.csv")    
    
    return config
Example #3
0
    def evaluate_generator(self,
                           annotations,
                           comet_experiment=None,
                           iou_threshold=0.5,
                           max_detections=200):
        """ Evaluate prediction model using a csv fit_generator

        Args:
            annotations (str): Path to csv label file, labels are in the format -> path/to/image.png,x1,y1,x2,y2,class_name
            iou_threshold(float): IoU Threshold to count for a positive detection (defaults to 0.5)
            max_detections (int): Maximum number of bounding box predictions
            comet_experiment(object): A comet experiment class objects to track

        Return:
            mAP: Mean average precision of the evaluated data
        """
        #Format args for CSV generator
        classes_file = utilities.create_classes(annotations)
        arg_list = utilities.format_args(annotations, classes_file, self.config)
        args = parse_args(arg_list)

        #create generator
        validation_generator = CSVGenerator(
            args.annotations,
            args.classes,
            image_min_side=args.image_min_side,
            image_max_side=args.image_max_side,
            config=args.config,
            shuffle_groups=False,
        )

        average_precisions = evaluate(validation_generator,
                                      self.prediction_model,
                                      iou_threshold=iou_threshold,
                                      score_threshold=args.score_threshold,
                                      max_detections=max_detections,
                                      save_path=args.save_path,
                                      comet_experiment=comet_experiment)

        # print evaluation
        total_instances = []
        precisions = []
        for label, (average_precision, num_annotations) in average_precisions.items():
            print('{:.0f} instances of class'.format(num_annotations),
                  validation_generator.label_to_name(label),
                  'with average precision: {:.4f}'.format(average_precision))
            total_instances.append(num_annotations)
            precisions.append(average_precision)

        if sum(total_instances) == 0:
            print('No test instances found.')
            return

        print('mAP using the weighted average of precisions among classes: {:.4f}'.format(
            sum([a * b for a, b in zip(total_instances, precisions)]) /
            sum(total_instances)))

        mAP = sum(precisions) / sum(x > 0 for x in total_instances)
        print('mAP: {:.4f}'.format(mAP))
        return mAP
def from_retinanet(annotations_csv):
    model = deepforest.deepforest()
    model.use_release()
    """use the keras retinanet source to create detections"""
    ### Keras retinanet
    # Format args for CSV generator
    classes_file = utilities.create_classes(annotations_csv)
    arg_list = utilities.format_args(annotations_csv, classes_file,
                                     model.config)
    args = parse_args(arg_list)

    # create generator
    validation_generator = csv_generator.CSVGenerator(
        args.annotations,
        args.classes,
        image_min_side=args.image_min_side,
        image_max_side=args.image_max_side,
        config=args.config,
        shuffle_groups=False,
    )

    all_detections = _get_detections(validation_generator,
                                     model.prediction_model,
                                     score_threshold=args.score_threshold,
                                     max_detections=100)
    all_annotations = _get_annotations(validation_generator)

    return all_detections, all_annotations, validation_generator
Example #5
0
def test_format_args_steps(annotations, config):
    classes_file = utilities.create_classes(annotations)    
    arg_list = utilities.format_args(annotations,classes_file, config, images_per_epoch=2)
    assert isinstance(arg_list, list)
    
    #A bit ugly, but since its a list, what is the argument after --steps to assert
    steps_position = np.where(["--steps" in x for x in arg_list])[0][0] + 1
    assert arg_list[steps_position] == '2'
Example #6
0
def test_retrain_release(annotations, release_model):
    release_model.config["epochs"] = 1
    release_model.config["save-snapshot"] = False
    release_model.config["steps"] = 1

    assert release_model.config["weights"] == release_model.weights

    #test that it gets passed to retinanet
    classes_file = utilities.create_classes(annotations)
    arg_list = utilities.format_args(annotations,
                                     classes_file,
                                     release_model.config,
                                     images_per_epoch=1)
    strs = ["--weights" == x for x in arg_list]
    index = np.where(strs)[0][0] + 1
    assert arg_list[index] == release_model.weights
Example #7
0
    def train(self,
              annotations,
              input_type="fit_generator",
              list_of_tfrecords=None,
              comet_experiment=None,
              images_per_epoch=None):
        """Train a deep learning tree detection model using keras-retinanet.
        This is the main entry point for training a new model based on either
        existing weights or scratch.

        Args:
            annotations (str): Path to csv label file,
                labels are in the format -> path/to/image.png,x1,y1,x2,y2,class_name
            input_type: "fit_generator" or "tfrecord"
            list_of_tfrecords: Ignored if input_type != "tfrecord",
                list of tf records to process
            comet_experiment: A comet ml object to log images. Optional.
            images_per_epoch: number of images to override default config
                of images in annotations file / batch size. Useful for debug

        Returns:
            model (object): A trained keras model
            prediction model: with bbox nms
                trained model: without nms
        """
        # Test if there is a new classes file in case # of classes has changed.
        self.classes_file = utilities.create_classes(annotations)
        self.read_classes()
        arg_list = utilities.format_args(annotations, self.classes_file, self.config,
                                         images_per_epoch)

        print("Training retinanet with the following args {}".format(arg_list))

        # Train model
        self.model, self.prediction_model, self.training_model = retinanet_train(
            forest_object=self,
            args=arg_list,
            input_type=input_type,
            list_of_tfrecords=list_of_tfrecords,
            comet_experiment=comet_experiment)
Example #8
0
    def predict_generator(self,
                          annotations,
                          comet_experiment=None,
                          iou_threshold=0.5,
                          max_detections=200,
                          return_plot=False,
                          color=None):
        """Predict bounding boxes for a model using a csv fit_generator

        Args:
            annotations (str): Path to csv label file, labels are in the
                format -> path/to/image.png,x1,y1,x2,y2,class_name
            comet_experiment(object): A comet experiment class objects to track
            color: rgb color for the box annotations if return_plot is True e.g. (255,140,0) is orange.
            return_plot: Whether to return prediction boxes (False) or Images (True). If True, files will be written to current working directory if model.config["save_path"] is not defined.

        Return:
            boxes_output: If return_plot=False, a pandas dataframe of bounding boxes
                for each image in the annotations file
                None: If return_plot is True, images are written to save_dir as a side effect.
        """
        # Format args for CSV generator
        classes_file = utilities.create_classes(annotations)
        arg_list = utilities.format_args(annotations, classes_file, self.config)
        args = parse_args(arg_list)

        # create generator
        generator = CSVGenerator(
            args.annotations,
            args.classes,
            image_min_side=args.image_min_side,
            image_max_side=args.image_max_side,
            config=args.config,
            shuffle_groups=False,
        )

        if self.prediction_model:
            boxes_output = []

            # For each image, gather predictions
            for i in range(generator.size()):
                # pass image as path
                plot_name = generator.image_names[i]
                image_path = os.path.join(generator.base_dir, plot_name)
                result = self.predict_image(image_path,
                                            return_plot=return_plot,
                                            score_threshold=args.score_threshold,
                                            color=color)

                if return_plot:
                    if not self.config["save_path"]:
                        print("model.config['save_path'] is None,"
                              "saving images to current working directory")
                        save_path = "."
                    else:
                        save_path = self.config["save_path"]
                    # Save image
                    fname = os.path.join(save_path, plot_name)
                    cv2.imwrite(fname, result)
                    continue
                else:
                    # Turn boxes to pandas frame and save output
                    box_df = pd.DataFrame(result)
                    # use only plot name, not extension
                    box_df["plot_name"] = os.path.splitext(plot_name)[0]
                    boxes_output.append(box_df)
        else:
            raise ValueError(
                "No prediction model loaded. Either load a retinanet from file, "
                "download the latest release or train a new model")

        if return_plot:
            return None
        else:
            # if boxes, name columns and return box data
            boxes_output = pd.concat(boxes_output)
            boxes_output.columns = [
                "xmin", "ymin", "xmax", "ymax", "score", "label", "plot_name"
            ]
            boxes_output = boxes_output.reindex(
                columns=["plot_name", "xmin", "ymin", "xmax", "ymax", "score", "label"])
            return boxes_output
Example #9
0
    def predict_generator(self,
                          annotations,
                          comet_experiment=None,
                          iou_threshold=0.5,
                          max_detections=200):
        """Predict bounding boxes for a model using a csv fit_generator
        
        Args:
            annotations (str): Path to csv label file, labels are in the format -> path/to/image.jpg,x1,y1,x2,y2,class_name
            iou_threshold(float): IoU Threshold to count for a positive detection (defaults to 0.5)
            max_detections (int): Maximum number of bounding box predictions
            comet_experiment(object): A comet experiment class objects to track
        
        Return:
            boxes_output: a pandas dataframe of bounding boxes for each image in the annotations file
        """
        #Format args for CSV generator
        classes_file = utilities.create_classes(annotations)
        arg_list = utilities.format_args(annotations, classes_file,
                                         self.config)
        args = parse_args(arg_list)

        #create generator
        generator = CSVGenerator(
            args.annotations,
            args.classes,
            image_min_side=args.image_min_side,
            image_max_side=args.image_max_side,
            config=args.config,
            shuffle_groups=False,
        )

        if self.prediction_model:
            boxes_output = []
            #For each image, gather predictions
            for i in range(generator.size()):
                #pass image as path
                plot_name = generator.image_names[i]
                image_path = os.path.join(generator.base_dir, plot_name)
                boxes = self.predict_image(
                    image_path,
                    return_plot=False,
                    score_threshold=args.score_threshold)

                #Turn to pandas frame and save output
                box_df = pd.DataFrame(boxes)
                #use only plot name, not extension
                box_df["plot_name"] = os.path.splitext(plot_name)[0]
                boxes_output.append(box_df)
        else:
            raise ValueError(
                "No prediction model loaded. Either load a retinanet from file, download the latest release or train a new model"
            )

        #name columns and return box data
        boxes_output = pd.concat(boxes_output)
        boxes_output.columns = [
            "xmin", "ymin", "xmax", "ymax", "score", "label", "plot_name"
        ]
        boxes_output = boxes_output.reindex(columns=[
            "plot_name", "xmin", "ymin", "xmax", "ymax", "score", "label"
        ])

        return boxes_output
Example #10
0
def test_format_args(annotations, config):
    classes_file = utilities.create_classes(annotations)
    arg_list = utilities.format_args(annotations, classes_file, config)
    assert isinstance(arg_list, list)
Example #11
0
def test_create_classes(annotations):
    classes_file = utilities.create_classes(annotations_file=annotations)
    assert os.path.exists(classes_file)
Example #12
0
#Prepare data

#Load annotations file
annotations = pd.read_csv(
    BASE_PATH + "pretraining/crops/pretraining.csv",
    names=["image_path", "xmin", "ymin", "xmax", "ymax", "label"])

#Select a set of n image
annotations = annotations[annotations.image_path ==
                          "2019_DELA_5_423000_3601000_image_0.jpg"].copy()

#Generate tfrecords
annotations_file = BASE_PATH + "pretraining/crops/test.csv"
annotations.to_csv(annotations_file, header=False, index=False)

class_file = utilities.create_classes(annotations_file)

tfrecords_path = tfrecords.create_tfrecords(annotations_file,
                                            class_file,
                                            size=1)
print("Created {} tfrecords: {}".format(len(tfrecords_path), tfrecords_path))
inputs, targets = tfrecords.create_tensors(tfrecords_path)

#### Fit generator ##
comet_experiment = Experiment(api_key="ypQZhYfs3nSyKzOfz13iuJpj2",
                              project_name="deepforest",
                              workspace="bw4sz")

comet_experiment.log_parameter("Type", "testing")
comet_experiment.log_parameter("input_type", "fit_generator")
Example #13
0
def generate_hand_annotations(DEBUG, BASE_PATH, FILEPATH, SIZE, config, dask_client):
    
    #Generate tfrecords
    dirname = "hand_annotations/"

    annotations_file = BASE_PATH + dirname + "crops/hand_annotations.csv"

    class_file = utilities.create_classes(annotations_file)

    if DEBUG:
        tfrecords.create_tfrecords(annotations_file=annotations_file,
                                   class_file=class_file,
                                   image_min_side=config["image-min-side"],
                                   backbone_model=config["backbone"],
                                   size=SIZE,
                                   savedir=FILEPATH + dirname + "tfrecords/")
    else:

        #Collect annotation files for each tile
        annotations_file= BASE_PATH + dirname + "crops/hand_annotations.csv"
        df = pd.read_csv(annotations_file, names=["image_path","xmin","ymin","xmax","ymax","label"])

        #enforce dtype, as there might be errors
        df.xmin = df.xmin.astype(pd.Int64Dtype())
        df.ymin = df.ymin.astype(pd.Int64Dtype())
        df.xmax = df.xmax.astype(pd.Int64Dtype())
        df.ymax = df.ymax.astype(pd.Int64Dtype())

        #Randomize rows
        df = df.sample(frac=1)

        #split pandas frame into chunks
        images = df.image_path.unique()
        indices = np.arange(len(images))
        size = 500

        chunk_list = [ ]

        #Split dataframe into chunks of images and write to file
        for i in range(ceil(len(indices) / size)):
            image_indices = indices[i * size:(i * size) + size]
            selected_images = images[image_indices]
            split_frame = df[df.image_path.isin(selected_images)]
            filename = BASE_PATH + dirname + "crops/hand_annotations{}.csv".format(i)
            split_frame.to_csv(filename, header=False,index=False)
            chunk_list.append(filename)

        print(" Created {} files to create tfrecords".format(len(chunk_list)))

        #Apply create tfrecords to each
        futures = dask_client.map(
            tfrecords.create_tfrecords,
            chunk_list,
            class_file=class_file,
            image_min_side=config["image-min-side"],
            backbone_model=config["backbone"],
            size=SIZE,
            savedir=FILEPATH + dirname + "tfrecords/")

        wait(futures)
        for future in futures:
            try:
                local_annotations = future.result()
            except Exception as e:
                print("future {} failed with {}".format(future, e))