Spaces:
Runtime error
Runtime error
| """ | |
| utils/predictor.py | |
| Handles image preprocessing and running predictions through each model. | |
| Returns: (label, confidence_score, input_tensor) | |
| The input_tensor is passed back so Grad-CAM can use it. | |
| """ | |
| import torch | |
| import torchvision.transforms as transforms | |
| from PIL import Image | |
| import numpy as np | |
| # ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ | |
| # IMAGE PREPROCESSING | |
| # ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ | |
| # Standard ImageNet normalization values β used because most | |
| # deep learning models are pretrained on ImageNet. | |
| IMAGENET_MEAN = [0.485, 0.456, 0.406] | |
| IMAGENET_STD = [0.229, 0.224, 0.225] | |
| def preprocess_image(image: Image.Image) -> torch.Tensor: | |
| """ | |
| Convert a PIL image into a normalized tensor ready for model input. | |
| Steps: | |
| 1. Resize to 224x224 (standard input size for ResNet) | |
| 2. Convert to PyTorch tensor (values 0β1) | |
| 3. Normalize using ImageNet mean and std | |
| Args: | |
| image: A PIL Image (RGB). | |
| Returns: | |
| A tensor of shape [1, 3, 224, 224] β batch of 1 image. | |
| """ | |
| transform = transforms.Compose([ | |
| transforms.Resize((224, 224)), | |
| transforms.ToTensor(), | |
| transforms.Normalize(mean=IMAGENET_MEAN, std=IMAGENET_STD) | |
| ]) | |
| # Add a batch dimension: [3, 224, 224] β [1, 3, 224, 224] | |
| tensor = transform(image).unsqueeze(0) | |
| return tensor | |
| # ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ | |
| # LABEL DEFINITIONS | |
| # ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ | |
| TREE_LABELS = ["Non-Tree", "Tree"] | |
| SPECIES_LABELS = ["Mango", "White Gum"] | |
| STAGE_LABELS = ["Seedling", "Sapling", "Mature", "Overmature"] | |
| # ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ | |
| # INFERENCE HELPER | |
| # ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ | |
| def run_inference(model: torch.nn.Module, tensor: torch.Tensor) -> tuple: | |
| """ | |
| Run a forward pass through a model and return prediction results. | |
| Args: | |
| model: A loaded PyTorch model in eval mode. | |
| tensor: Input tensor of shape [1, 3, 224, 224]. | |
| Returns: | |
| (predicted_index, confidence_score) | |
| """ | |
| device = next(model.parameters()).device | |
| tensor = tensor.to(device) | |
| with torch.no_grad(): # No gradient tracking needed for inference | |
| outputs = model(tensor) # Raw logits: [1, num_classes] | |
| probs = torch.softmax(outputs, dim=1) # Convert to probabilities | |
| confidence, predicted_idx = torch.max(probs, dim=1) | |
| return predicted_idx.item(), confidence.item() | |
| # ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ | |
| # PHASE 1: TREE vs NON-TREE | |
| # ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ | |
| def predict_tree(image: Image.Image, model: torch.nn.Module) -> tuple: | |
| """ | |
| Predict whether the image contains a tree or not. | |
| Args: | |
| image: PIL Image. | |
| model: Loaded tree vs non-tree model. | |
| Returns: | |
| (label: str, confidence: float, tensor: torch.Tensor) | |
| e.g. ("Tree", 0.97, tensor) | |
| """ | |
| tensor = preprocess_image(image) | |
| idx, confidence = run_inference(model, tensor) | |
| label = TREE_LABELS[idx] | |
| return label, confidence, tensor | |
| # ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ | |
| # PHASE 2: SPECIES DETECTION | |
| # ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ | |
| def predict_species(image: Image.Image, model: torch.nn.Module) -> tuple: | |
| """ | |
| Predict the tree species: Mango or White Gum. | |
| Args: | |
| image: PIL Image. | |
| model: Loaded species detection model. | |
| Returns: | |
| (label: str, confidence: float, tensor: torch.Tensor) | |
| e.g. ("Mango", 0.89, tensor) | |
| """ | |
| tensor = preprocess_image(image) | |
| idx, confidence = run_inference(model, tensor) | |
| label = SPECIES_LABELS[idx] | |
| return label, confidence, tensor | |
| # ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ | |
| # PHASE 3: STAGE CLASSIFICATION | |
| # ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ | |
| def predict_stage(image: Image.Image, model: torch.nn.Module, species: str) -> tuple: | |
| """ | |
| Predict the growth stage of the tree. | |
| Routes to the appropriate model based on detected species. | |
| Args: | |
| image: PIL Image. | |
| model: The stage model for the detected species (mango or gum). | |
| species: Species name (used for logging/display only here). | |
| Returns: | |
| (label: str, confidence: float, tensor: torch.Tensor) | |
| e.g. ("Mature", 0.92, tensor) | |
| """ | |
| tensor = preprocess_image(image) | |
| idx, confidence = run_inference(model, tensor) | |
| label = STAGE_LABELS[idx] | |
| return label, confidence, tensor | |