""" app.py ------ Streamlit front-end for the Crop vs No-Crop SegFormer-B2 demo. """ import logging import streamlit as st import utils from predictor import ( INPUT_SIZE, MODEL_NAME, CropSegmenter, InferenceError, ModelLoadError, ) logging.basicConfig(level=logging.INFO) st.set_page_config( page_title="Crop vs No-Crop Segmentation (Crop Contains only Wheat and Tomato)", page_icon="🌾", layout="wide", ) @st.cache_resource(show_spinner="Loading segmentation model (first run only)…") def get_segmenter() -> CropSegmenter: return CropSegmenter() def render_sidebar() -> None: st.sidebar.header("ℹ️ Model Information") st.sidebar.markdown( f""" - **Architecture:** NVIDIA SegFormer-B2 - **Backbone:** `{MODEL_NAME}` - **Task:** Binary semantic segmentation - **Weights:** `best.pt` """ ) st.sidebar.header("🎨 Class Definitions") st.sidebar.markdown( """ | Class | Meaning | Mask color | |:-----:|---------|------------| | 0 | Background / No Crop | Dark gray | | 1 | Crop | Bright yellow | """ ) def main() -> None: render_sidebar() st.title("🌾 Crop vs No-Crop Segmentation") st.markdown( "Upload a field image and the fine-tuned **SegFormer-B2** model " "segments it into **Crop** and **Background (No Crop)** regions." ) try: segmenter = get_segmenter() except ModelLoadError as exc: st.error(f"🚫 Could not load the model: {exc}") st.stop() except Exception as exc: # noqa: BLE001 st.error(f"🚫 Unexpected error while loading the model: {exc}") st.stop() uploaded = st.file_uploader( "Upload an image", type=["jpg", "jpeg", "png"], accept_multiple_files=False ) if uploaded is None: st.info("👆 Upload a JPG / JPEG / PNG image to get started.") return try: image = utils.load_image(uploaded) except utils.ImageLoadError as exc: st.error(f"🚫 {exc}") return st.subheader("Uploaded image") st.image(image, caption="Input", use_container_width=True) if not st.button("🚀 Run Segmentation", type="primary"): return try: with st.spinner("Running segmentation… a few seconds on CPU."): mask = segmenter.predict( image, input_size=INPUT_SIZE, swap_classes=False, normalization="imagenet", ) color_mask = utils.create_color_mask(mask) overlay = utils.create_overlay(image, mask) combined = utils.combine_panels(image, color_mask, overlay) except InferenceError as exc: st.error(f"🚫 {exc}") return except Exception as exc: # noqa: BLE001 st.error(f"🚫 Unexpected error during inference: {exc}") return st.subheader("Results") col1, col2, col3 = st.columns(3) with col1: st.image(image, caption="Original", use_container_width=True) with col2: st.image(color_mask, caption="Predicted Mask", use_container_width=True) with col3: st.image(overlay, caption="Crop Overlay", use_container_width=True) crop_ratio = float((mask == 1).mean()) * 100.0 st.metric("Estimated crop coverage", f"{crop_ratio:.1f}%") summary = segmenter.last_logit_summary if summary: with st.expander("📈 More Details"): st.write( f"Mean logit gap (crop − background): " f"{summary['mean_gap_crop_minus_bg']:.3f} " f"(positive favors crop, negative favors background)" ) st.write( f"Logit range: {summary['logit_min']:.2f} … {summary['logit_max']:.2f}" ) png_bytes = utils.image_to_png_bytes(combined) st.download_button( label="⬇️ Download Result", data=png_bytes, file_name="prediction_result.png", mime="image/png", ) if __name__ == "__main__": main()