diff --git a/.gitignore b/.gitignore index fdbf014b5..d69f78681 100644 Binary files a/.gitignore and b/.gitignore differ diff --git a/docs/user_guide/16_prediction.md b/docs/user_guide/16_prediction.md index fc15038bf..ce514bea0 100644 --- a/docs/user_guide/16_prediction.md +++ b/docs/user_guide/16_prediction.md @@ -1,12 +1,12 @@ # Prediction -There are atleast four ways to make predictions with DeepForest. +There are at least four ways to make predictions with DeepForest. 1. Predict an image using [model.predict_image](https://deepforest.readthedocs.io/en/latest/source/deepforest.html#deepforest.main.deepforest.predict_image). The entire image is passed to the model. -2. Predict a large number, which we call a 'tile', using [model.predict_tile](https://deepforest.readthedocs.io/en/latest/source/deepforest.html#deepforest.main.deepforest.predict_tile). The tile is cut into smaller windows and each window is predicted. +2. Predict a large image (a "tile"), using [model.predict_tile](https://deepforest.readthedocs.io/en/latest/source/deepforest.html#deepforest.main.deepforest.predict_tile). The tile is cut into smaller windows and each window is predicted. -3. Predict a directory of images using a csv file using [model.predict_file](https://deepforest.readthedocs.io/en/latest/source/deepforest.html#deepforest.main.deepforest.predict_file). Each unique image listed in a csv file is predicted. +3. Predict a directory of images using a CSV file with [model.predict_file](https://deepforest.readthedocs.io/en/latest/source/deepforest.html#deepforest.main.deepforest.predict_file). Each unique image listed in a CSV file is predicted. 4. Predict a batch of images using [model.predict_batch](https://deepforest.readthedocs.io/en/latest/source/deepforest.html#deepforest.main.deepforest.predict_batch). This is useful when you have an existing dataloader from outside DeepForest that yields data in batches. @@ -45,11 +45,11 @@ deepforest predict ./path/to/your/image.tif -o results.csv patch_size=250 patch_ We use [Hydra](https://hydra.cc/docs/intro/) for configuration management, and the format for specifying predictions is a space-separated list of `=`s, like the example above. -To see the default configuration and to check what options you can set, you can run `deepforest --show-config` flag (no other options are required). +To see the default configuration and to check what options you can set, you can run `deepforest --show-config` command (no other options are required). ## Predict an image using model.predict_image -This is most commonly used for small images or pre-cropped windows of large tiles. Passing a large tile to predict_image will lead to poor performance, use predict_tile. +This is most commonly used for small images or pre-cropped windows of large tiles. Passing a large tile to predict_image will lead to poor performance; use predict_tile. ```python from deepforest import get_data @@ -67,37 +67,83 @@ img = model.predict_image(path=sample_image_path) plot_results(img) ``` -## Predict a tile using model.predict_tile +# Predicting Large Images with `predict_tile` -Large tiles covering wide geographic extents cannot fit into memory during prediction and would yield poor results due to the density of bounding boxes. Often provided as geospatial .tif files, remote sensing data is best suited for the `predict_tile` function, which splits the tile into overlapping windows, performs prediction on each of the windows, and then reassembles the resulting annotations. +`predict_tile` is designed for making predictions on large raster images +(e.g., high-resolution `.tif` remote-sensing data) that may not fit into memory. -Let's show an example with a small image. For larger images, patch_size should be increased. +Instead of loading the full image at once, the method: +1. Splits the image into overlapping tiles +2. Runs prediction on each tile independently +3. Merges tile-level predictions into a single pandas DataFrame -```python +This tiled approach reduces memory usage while ensuring objects near tile +boundaries are not missed. -from deepforest import main -from deepforest import get_data -from deepforest.visualize import plot_results -import matplotlib.pyplot as plt +--- -# Initialize the model class -model = main.deepforest() +## Return Type -# Load a pretrained tree detection model from Hugging Face -model.load_model(model_name="weecology/deepforest-tree", revision="main") +Both `predict_tile` and `predict_file` return a pandas DataFrame. +`predict_batch` returns a list of pandas DataFrames, one per batch. + +Each row in the DataFrame corresponds to one detected object and typically +includes bounding box coordinates, confidence scores, and class labels. + +These methods do **not** return raster files or images. + +--- + +## Key Parameters + +- **`path`** + Path to the input raster image. + +- **`patch_size`** + Size (in pixels) of each tile. Larger values provide more spatial context + but increase memory usage. Typical values range from 300 to 800 pixels. + +- **`patch_overlap`** + Fractional overlap between adjacent tiles (default: 0.25). Overlap helps + ensure objects at tile edges are detected correctly. + +- **`dataloader_strategy`** + Strategy used to load tiles during prediction: + - `"single"`: Loads and predicts one tile at a time. + - `"batch"`: Processes multiple tiles together on the GPU. + - `"window"`: Reads only the requested window from disk. + +--- + +## Example Usage + +```python +from deepforest import main, get_data + +model = main.deepforest() +model.load_model( + model_name="weecology/deepforest-tree", + revision="main" +) -# Predict on large geospatial tiles using overlapping windows path = get_data("OSBS_029.tif") -predicted_raster = model.predict_tile(path, patch_size=300, patch_overlap=0.25) -plot_results(predicted_raster) + +predictions = model.predict_tile( + path=path, + patch_size=300, + patch_overlap=0.25, + dataloader_strategy="window" +) + +print(predictions.head()) ``` -### dataloader-strategy +### `dataloader_strategy` An optional argument to predict_tile allows the user to control how to scale prediction of tiles and how the windows are created within tiles. ```python -prediction_single = m.predict_tile(path=path, patch_size=300, dataloader_strategy="single") +prediction_single = model.predict_tile(path=path, patch_size=300, dataloader_strategy="single") ``` The `dataloader_strategy` parameter has three options: @@ -117,15 +163,17 @@ The image shows that the speed of the predict_tile function is related to the st The _predict_tile_ function is sensitive to _patch_size_, especially when using the prebuilt model on new data. We encourage users to experiment with various patch sizes. For 0.1m data, 400-800px per window is appropriate, but it will depend on the density of tree plots. For coarser resolution tiles, >800px patch sizes have been effective. -## Predict a directory of using a csv file using model.predict_file +## Predict a directory of images using a CSV file with model.predict_file -For a list of images with annotations in a csv file, the `predict_file` function will return a dataframe with the predicted bounding boxes for each image as a single dataframe. This is useful for making predictions on a large number of images that have ground truth annotations. +For a list of images specified in a CSV file, the `predict_file` function will return a dataframe with the predicted bounding boxes for each image as a single dataframe. This is useful for making predictions on a large number of images that have ground truth annotations. ```python - +import os +import pandas as pd +from deepforest import get_data csv_file = get_data("OSBS_029.csv") original_file = pd.read_csv(csv_file) -df = m.predict_file(csv_file, root_dir=os.path.dirname(csv_file)) +df = model.predict_file(csv_file, root_dir=os.path.dirname(csv_file)) ``` ``` @@ -147,6 +195,7 @@ from deepforest.datasets.training import BoxDataset from torch.utils.data import DataLoader import numpy as np from PIL import Image +from deepforest import get_data path = get_data("OSBS_029.tif") tile = np.array(Image.open(path)) @@ -156,6 +205,6 @@ dl = DataLoader(ds, batch_size=3) # Perform prediction predictions = [] for batch in dl: - prediction = m.predict_batch(batch) + prediction = model.predict_batch(batch) predictions.append(prediction) ```