def test_single_class_with_empty(tmpdir): """Add fake empty annotations to test parsing """ csv_file1 = get_data("example.csv") csv_file2 = get_data("OSBS_029.csv") df1 = pd.read_csv(csv_file1) df2 = pd.read_csv(csv_file2) df = pd.concat([df1, df2]) df.loc[df.image_path == "OSBS_029.tif", "xmin"] = 0 df.loc[df.image_path == "OSBS_029.tif", "ymin"] = 0 df.loc[df.image_path == "OSBS_029.tif", "xmax"] = 0 df.loc[df.image_path == "OSBS_029.tif", "ymax"] = 0 df.to_csv("{}_test_empty.csv".format(tmpdir)) root_dir = os.path.dirname(get_data("OSBS_029.png")) ds = dataset.TreeDataset(csv_file="{}_test_empty.csv".format(tmpdir), root_dir=root_dir, label_dict={"Tree": 0}) assert len(ds) == 2 #First image has annotations assert not torch.sum(ds[0][2]["boxes"]) == 0 #Second image has no annotations assert torch.sum(ds[1][2]["boxes"]) == 0
def multi_annotations(): annotations = utilities.xml_to_annotations(get_data("SOAP_061.xml")) annotations.image_path = annotations.image_path.str.replace(".tif", ".png") annotations_file = get_data("testfile_multi.csv") annotations.to_csv(annotations_file, index=False, header=False) return annotations_file
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
def annotations(): annotations = utilities.xml_to_annotations(get_data("OSBS_029.xml")) # Point at the png version for tfrecords annotations.image_path = annotations.image_path.str.replace(".tif", ".png") annotations_file = get_data("testfile_deepforest.csv") annotations.to_csv(annotations_file, index=False, header=False) return annotations_file
def two_class_m(): m = main.deepforest(num_classes=2,label_dict={"Alive":0,"Dead":1}) m.config["train"]["csv_file"] = get_data("testfile_multi.csv") m.config["train"]["root_dir"] = os.path.dirname(get_data("testfile_multi.csv")) m.config["train"]["fast_dev_run"] = True m.config["batch_size"] = 2 m.config["validation"]["csv_file"] = get_data("testfile_multi.csv") m.config["validation"]["root_dir"] = os.path.dirname(get_data("testfile_multi.csv")) m.create_trainer() return m
def m(download_release): m = main.deepforest() m.config["train"]["csv_file"] = get_data("example.csv") m.config["train"]["root_dir"] = os.path.dirname(get_data("example.csv")) m.config["train"]["fast_dev_run"] = False m.config["batch_size"] = 2 m.config["validation"]["csv_file"] = get_data("example.csv") m.config["validation"]["root_dir"] = os.path.dirname(get_data("example.csv")) m.use_release() return m
def m(): m = main.deepforest() m.config["train"]["csv_file"] = get_data("example.csv") m.config["train"]["root_dir"] = os.path.dirname(get_data("example.csv")) m.config["train"]["fast_dev_run"] = True m.config["batch_size"] = 2 m.config["validation"]["csv_file"] = get_data("example.csv") m.config["validation"]["root_dir"] = os.path.dirname( get_data("example.csv")) m.create_trainer() return m
def config(): config = utilities.read_config(get_data("deepforest_config.yml")) config["patch_size"] = 200 config["patch_overlap"] = 0.25 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") # Create a clean config test data annotations = utilities.xml_to_annotations(xml_path=config["annotations_xml"]) annotations.to_csv("tests/data/OSBS_029.csv", index=False) return config
def test_predict_image(download_release): # Load model test_model = deepforest.deepforest(weights=get_data("NEON.h5")) assert isinstance(test_model.model, keras.models.Model) # Predict test image and return boxes boxes = test_model.predict_image(image_path=get_data("OSBS_029.tif"), show=False, return_plot=False, score_threshold=0.1) # Returns a 6 column numpy array, xmin, ymin, xmax, ymax, score, label assert boxes.shape[1] == 6 assert boxes.score.min() > 0.1
def test_evaluate_multi(m): csv_file = get_data("testfile_multi.csv") m = main.deepforest(num_classes=2, label_dict={"Alive": 0, "Dead": 1}) ground_truth = pd.read_csv(csv_file) results = evaluate.evaluate(predictions=ground_truth, ground_df=ground_truth, show_plot=True, root_dir=os.path.dirname(csv_file), savedir=None) assert results["results"].shape[0] == ground_truth.shape[0] assert results["class_recall"].shape == (2, 4) assert all(results['class_recall'].recall == pd.Series([1, 1])) #def test_evaluate_benchmark(m): #csv_file = "/Users/benweinstein/Documents/NeonTreeEvaluation/evaluation/RGB/benchmark_annotations.csv" #predictions = m.predict_file(csv_file=csv_file, root_dir=os.path.dirname(csv_file)) #ground_truth = pd.read_csv(csv_file) #results = evaluate.evaluate(predictions=predictions, ground_df=ground_truth, show_plot=False, root_dir=os.path.dirname(csv_file), savedir=None) #assert results["results"].shape[0] == ground_truth.shape[0] #assert results["class_recall"].shape == (2,4)
def test_compute_IoU(download_release): m = main.deepforest() m.use_release(check_release=False) csv_file = get_data("OSBS_029.csv") predictions = m.predict_file(csv_file=csv_file, root_dir=os.path.dirname(csv_file)) ground_truth = pd.read_csv(csv_file) predictions['geometry'] = predictions.apply( lambda x: shapely.geometry.box(x.xmin, x.ymin, x.xmax, x.ymax), axis=1) predictions = gpd.GeoDataFrame(predictions, geometry='geometry') ground_truth['geometry'] = ground_truth.apply( lambda x: shapely.geometry.box(x.xmin, x.ymin, x.xmax, x.ymax), axis=1) ground_truth = gpd.GeoDataFrame(ground_truth, geometry='geometry') ground_truth.label = 0 predictions.label = 0 visualize.plot_prediction_dataframe(df=predictions, ground_truth=ground_truth, root_dir=os.path.dirname(csv_file)) result = IoU.compute_IoU(ground_truth, predictions) assert result.shape[0] == ground_truth.shape[0] assert sum(result.IoU) > 10
def test_predict_tile(m): #test raster prediction raster_path = get_data(path= 'OSBS_029.tif') prediction = m.predict_tile(raster_path = raster_path, patch_size = 300, patch_overlap = 0.5, return_plot = False) assert isinstance(prediction, pd.DataFrame) assert set(prediction.columns) == {"xmin","ymin","xmax","ymax","label","score"} assert not prediction.empty #test soft-nms method soft_nms_pred = m.predict_tile(raster_path = raster_path, patch_size = 300, patch_overlap = 0.5, return_plot = False, use_soft_nms =True) assert isinstance(soft_nms_pred, pd.DataFrame) assert set(soft_nms_pred.columns) == {"xmin","ymin","xmax","ymax","label","score"} assert not soft_nms_pred.empty #test predict numpy image image = io.imread(raster_path) prediction = m.predict_tile(image = image, patch_size = 300, patch_overlap = 0.5, return_plot = False) assert not prediction.empty # Test no non-max suppression prediction = m.predict_tile(raster_path = raster_path, patch_size=300, patch_overlap=0, return_plot=False) assert not prediction.empty
def test_predict_image_fromarray(m): image = get_data(path="2019_YELL_2_528000_4978000_image_crop2.png") image = io.imread(image) prediction = m.predict_image(image = image) assert isinstance(prediction, pd.DataFrame) assert set(prediction.columns) == {"xmin","ymin","xmax","ymax","label","score"}
def __init__(self, num_classes=1, label_dict={"Tree": 0}): """ Args: num_classes (int): number of classes in the model Returns: self: a deepforest pytorch ligthning module """ super().__init__() # Read config file - if a config file exists in local dir use it, # if not use installed. if os.path.exists("deepforest_config.yml"): config_path = "deepforest_config.yml" else: try: config_path = get_data("deepforest_config.yml") except Exception as e: raise ValueError( "No deepforest_config.yml found either in local " "directory or in installed package location. {}".format(e)) print("Reading config file: {}".format(config_path)) self.config = utilities.read_config(config_path) # release version id to flag if release is being used self.__release_version__ = None self.num_classes = num_classes self.create_model() #Label encoder and decoder self.label_dict = label_dict self.numeric_to_label_dict = {v: k for k, v in label_dict.items()}
def test_predict_file(m, tmpdir): csv_file = get_data("example.csv") df = m.predict_file(csv_file, root_dir = os.path.dirname(csv_file), savedir=tmpdir) assert set(df.columns) == {"xmin","ymin","xmax","ymax","label","score","image_path","numeric"} printed_plots = glob.glob("{}/*.png".format(tmpdir)) assert len(printed_plots) == 1
def test_evaluate_multiple_images(m, tmpdir): orignal_csv_file = get_data("OSBS_029.csv") original_root_dir = os.path.dirname(orignal_csv_file) df = pd.read_csv(orignal_csv_file) df2 = df.copy() df2["image_path"] = "OSBS_029_1.tif" df3 = df.copy() df3["image_path"] = "OSBS_029_2.tif" multiple_images = multiple_images = pd.concat([df, df2, df3]) multiple_images = multiple_images.reset_index(drop=True) csv_file = "{}/example.csv".format(tmpdir) root_dir = os.path.dirname(csv_file) multiple_images.to_csv(csv_file) #Create multiple files shutil.copyfile("{}/OSBS_029.tif".format(original_root_dir), "{}/OSBS_029.tif".format(root_dir)) shutil.copyfile("{}/OSBS_029.tif".format(original_root_dir), "{}/OSBS_029_1.tif".format(root_dir)) shutil.copyfile("{}/OSBS_029.tif".format(original_root_dir), "{}/OSBS_029_2.tif".format(root_dir)) root_dir = os.path.dirname(csv_file) results = m.evaluate(csv_file, root_dir, iou_threshold=0.4, savedir=tmpdir) assert results["results"].shape[0] == multiple_images.shape[0] assert all( [x in results["results"] for x in ["xmin", "xmax", "ymin", "ymax"]])
def test_predict_tile(release_model): raster_path = get_data("OSBS_029.tif") image = release_model.predict_tile(raster_path, patch_size=300, patch_overlap=0.5, return_plot=True) # Test no non-max suppression boxes = release_model.predict_tile(raster_path, patch_size=100, patch_overlap=0, return_plot=False) assert not boxes.empty # Test numpy_image read numpy_array = cv2.imread(raster_path) boxes = release_model.predict_tile(numpy_image=numpy_array, patch_size=100, patch_overlap=0, return_plot=False) assert not boxes.empty numpy_array = cv2.imread(raster_path) #Check image creation image = release_model.predict_tile(numpy_image=numpy_array, patch_size=100, patch_overlap=0, return_plot=True) assert image.shape == numpy_array.shape
def test_xml_to_annotations(): annotations = utilities.xml_to_annotations(xml_path = get_data("OSBS_029.xml")) print(annotations.shape) assert annotations.shape == (61 ,6) #bounding box extents should be int assert annotations["xmin"].dtype == "int"
def test_predict_dataloader(): csv_file = get_data("example.csv") root_dir = os.path.dirname(csv_file) ds = dataset.TreeDataset(csv_file=csv_file, root_dir=root_dir, train=False) image = next(iter(ds)) #Assert image is channels first format assert image.shape[0] == 3
def test_predict_image_fromfile(m): path = get_data(path="2019_YELL_2_528000_4978000_image_crop2.png") prediction = m.predict_image(path=path) assert isinstance(prediction, pd.DataFrame) assert set(prediction.columns) == { "xmin", "ymin", "xmax", "ymax", "label", "score" }
def test_get_data(): assert os.path.exists(deepforest.get_data("testfile_deepforest.csv")) assert os.path.exists(deepforest.get_data("testfile_multi.csv")) assert os.path.exists(deepforest.get_data("example.csv")) assert os.path.exists( deepforest.get_data("2019_YELL_2_541000_4977000_image_crop.png")) assert os.path.exists(deepforest.get_data("OSBS_029.png")) assert os.path.exists(deepforest.get_data("OSBS_029.tif")) assert os.path.exists(deepforest.get_data("SOAP_061.png")) assert os.path.exists(deepforest.get_data("classes.csv"))
def test_split_raster(config, tmpdir): """Split raster into crops with overlaps to maintain all annotations""" raster = get_data("2019_YELL_2_528000_4978000_image_crop2.png") annotations = utilities.xml_to_annotations( get_data("2019_YELL_2_528000_4978000_image_crop2.xml")) annotations.to_csv("{}/example.csv".format(tmpdir), index=False) #annotations.label = 0 #visualize.plot_prediction_dataframe(df=annotations, root_dir=os.path.dirname(get_data(".")), show=True) annotations_file = preprocess.split_raster( path_to_raster=raster, annotations_file="{}/example.csv".format(tmpdir), base_dir=tmpdir, patch_size=500, patch_overlap=0) # Returns a 6 column pandas array assert annotations_file.shape[1] == 6
def test_evaluate_image(m): csv_file = get_data("OSBS_029.csv") predictions = m.predict_file(csv_file=csv_file, root_dir=os.path.dirname(csv_file)) ground_truth = pd.read_csv(csv_file) predictions.label = 0 result = evaluate.evaluate_image(predictions=predictions, ground_df=ground_truth, root_dir=os.path.dirname(csv_file)) assert result.shape[0] == ground_truth.shape[0] assert sum(result.IoU) > 10
def test_evaluate(m): csv_file = get_data("OSBS_029.csv") root_dir = os.path.dirname(csv_file) results = m.evaluate(csv_file, root_dir, iou_threshold=0.4, show_plot=True) #Does this make reasonable predictions, we know the model works. assert np.round(results["box_precision"], 2) > 0.5 assert np.round(results["box_recall"], 2) > 0.5
def m(download_release): m = main.deepforest() m.config["train"]["csv_file"] = get_data("example.csv") m.config["train"]["root_dir"] = os.path.dirname(get_data("example.csv")) m.config["train"]["fast_dev_run"] = True m.config["batch_size"] = 2 m.config["validation"]["csv_file"] = get_data("example.csv") m.config["validation"]["root_dir"] = os.path.dirname( get_data("example.csv")) m.config["workers"] = 0 m.config["validation"]["val_accuracy_interval"] = 1 m.config["train"]["epochs"] = 2 m.create_trainer() m.use_release(check_release=False) return m
def big_file(): tmpdir = tempfile.gettempdir() csv_file = get_data("OSBS_029.csv") image_path = get_data("OSBS_029.png") df = pd.read_csv(csv_file) big_frame = [] for x in range(3): img = Image.open("{}/{}".format(os.path.dirname(csv_file), df.image_path.unique()[0])) cv2.imwrite("{}/{}.png".format(tmpdir, x), np.array(img)) new_df = df.copy() new_df.image_path = "{}.png".format(x) big_frame.append(new_df) big_frame = pd.concat(big_frame) big_frame.to_csv("{}/annotations.csv".format(tmpdir)) return "{}/annotations.csv".format(tmpdir)
def run(): csv_file = get_data("OSBS_029.csv") root_dir = os.path.dirname(csv_file) ds = dataset.TreeDataset(csv_file=csv_file, root_dir=root_dir, transforms=dataset.get_transform(augment=True)) for x in range(1000): next(iter(ds))
def test_annotations_to_shapefile(download_release): img = get_data("OSBS_029.tif") r = rio.open(img) transform = r.transform crs = r.crs m = main.deepforest() m.use_release(check_release=False) df = m.predict_image(path=img) gdf = utilities.annotations_to_shapefile(df, transform=transform, crs=crs) assert df.shape[0] == gdf.shape[0]
def test_over_score_thresh(m): """A user might want to change the config after model training and update the score thresh""" img = get_data("OSBS_029.png") original_score_thresh = m.model.score_thresh m.config["score_thresh"] = 0.8 #trigger update boxes = m.predict_image(path=img) assert m.model.score_thresh == 0.8 assert not m.model.score_thresh == original_score_thresh
def test_log_images_multiclass(m, tmpdir): m = main.deepforest(num_classes=2, label_dict={"Alive":0,"Dead":1}) m.config["train"]["csv_file"] = get_data("testfile_multi.csv") m.config["train"]["root_dir"] = os.path.dirname(get_data("testfile_multi.csv")) m.config["train"]["fast_dev_run"] = False m.config["batch_size"] = 2 m.config["validation"]["csv_file"] = get_data("testfile_multi.csv") m.config["validation"]["root_dir"] = os.path.dirname(get_data("testfile_multi.csv")) im_callback = callbacks.images_callback(csv_file=m.config["validation"]["csv_file"], root_dir=m.config["validation"]["root_dir"], savedir=tmpdir) m.create_trainer(callbacks=[im_callback]) m.max_steps = 2 m.trainer.fit(m) saved_images = glob.glob("{}/*.png".format(tmpdir)) assert len(saved_images) == 1