1.Project Overview by Tushar Agrawal Project Name: FRI (Field Readiness Index) API Purpose: Compute the FRI Value for the snow covered field areas from the Satellite imagery (Sentinel-1 VV/VH bands) and store it in the Database. Core Workflow: Input: GeoTIFF image (VV & VH bands) Processing: Mean extraction + formula Output: FRI value + status Storage: PostgreSQL database 2. Tech Stack Component Technology Backend FastAPI Language Python Database PostgreSQL ORM SQLAlchemy Raster Processing rasterio, numpy Cache / Queue Redis (optional / async tasks) 3. Project Structure fri_service/ │ ├── app/ │ ├── main.py │ ├── database.py │ ├── config.py │ ├── models/ │ ├── utils/ │ ├── models/ │ ├── routers/ │ ├── services/ │ ├── .env ├── run.py └── check_cache.py └── clear_cache.py └── requirements.txt 4. Environment Configuration .env file: DB_NAME= DB_USER= DB_PASSWORD= DB_HOST= DB_PORT= DATABASE_URL=postgresql://postgres:pass%40123@192.168.2.54:5433/geolytics REDIS_URL=redis://localhost:6379 SENTINEL_API_URL=https://api.sentinel-hub.com SENTINEL_CLIENT_ID=0bb30c5e-6dc1-4e4e-b806-ca323d2d58c2 SENTINEL_CLIENT_SECRET=CecyLrDvtvYptSI70VIplrAuT47pvqG9 5. Database Schema Table: fri_results CREATE TABLE fri_results ( id SERIAL PRIMARY KEY, parcel_id TEXT, date DATE, fri_value DOUBLE PRECISION, status TEXT, reason TEXT, geometry GEOMETRY, Field TEXT ); Field Explanation: Field Description parcel_id Unique land parcel identifier date Processing date fri_value Calculated FRI value status Ready / Not Ready / Approaching reason Failure reason (e.g. High Moisture) geometry Parcel polygon field FieldID 6. Core Logic (FRI Calculation) Step 1: Read TIFF with MemoryFile(tif_bytes) as memfile: with memfile.open() as src: vv = src.read(1) vh = src.read(2) Step 2: Remove NoData vv[vv <= -50] = np.nan vh[vh <= -50] = np.nan Step 3: Mean Calculation vv_mean = np.nanmean(vv) vh_mean = np.nanmean(vh) Step 4: FRI Formula FRI = 0.5 × VH_norm_inverse + 0.3 × VV_stability + 0.2 × SoilDryness Where: VH_norm_inverse = 1 − normalize(VH) VV_stability = 1 − stddev(VV_last_3_acquisitions) SoilDryness = 1 − normalize(VH/VV) Step 5: Status Logic Example: if fri > threshold: status = "Ready" else: status = "Not Ready" reason = "High Moisture" 7. API Endpoints 1. Upload & Process TIFF POST /calculate-fri give the .shp file 2. upload predefined geometry POST /calculate-fri-run-geojson Example: run this { "type": "FeatureCollection", "features": [ { "type": "Feature", "id": "tbl_projects_fields.1", "geometry": { "type": "MultiPolygon", "coordinates": [ [ [ [51.438087, 51.011816], [51.439739, 51.017174], [51.441968, 51.017167], [51.446784, 51.016395], [51.452172, 51.015407], [51.451064, 51.012853], [51.44975, 51.010073], [51.449446, 51.009731], [51.441603, 51.011216], [51.438087, 51.011816] ] ] ] }, "geometry_name": "geom", "properties": { "project_id": "PRJ-0001", "fieldname": "kaza", "cordstr": "51.438087 51.011816, 51.439739 51.017174, 51.441968 51.017167, 51.446784 51.016395, 51.452172 51.015407, 51.451064 51.012853, 51.449750 51.010073, 51.449446 51.009731, 51.441603 51.011216, 51.438087 51.011816", "companyid": "CMP-0001", "fieldarea": "56.41 hectares", "remark": "kaza fields", "status": "Active", "isactive": true, "createdby": "CMP-0001", "createdon": "2026-02-24T05:13:02.326Z", "updatedby": "CMP-0001", "updatedon": "2026-02-24T05:13:02.327Z", "type": "Polygon", "field": "FLD-1" } } ], "totalFeatures": 1, "numberMatched": 1, "numberReturned": 1, "timeStamp": "2026-03-25T09:41:36.407Z", "crs": { "type": "name", "properties": { "name": "urn:ogc:def:crs:EPSG::4326" } }, "date": "2026-03-31" } Request: File: .tif Response: { "parcel_id": " ", "fri_value": 0.2765, "status": "Not Ready", "reason": "High Moisture" } 8. Redis Usage (Optional) Purpose: Background processing (async tasks) Caching results if you run without redis then images will read in RAM (memory) after processing it will discard. Flow: API request → Redis queue Worker process Result in DB 9. Key Design Decisions MemoryFile use for → for avoid disk I/O NaN handling → ignore invalid pixel Hash / parcel_id → unique identification Redis → scalability + async processing 10. Edge Cases Case Handling Empty TIFF Error return All NaN values skip / fail VH = 0 divide-by-zero handle Invalid bands validation 11. Common Issues & Fixes Issue: Slow Processing Solution: Reduce raster size Use async (Redis + worker) Optimize numpy ops Issue: DB Connection Error Check .env Check PostgreSQL running Issue: Redis not working Ensure Redis server running Check URL command for run redis Path\Redis-x64-5.0.14.1 (venv) Path\Redis-x64-5.0.14.1> .\redis-server.exe 12. Deployment Steps: Install dependencies Setup .env Start PostgreSQL Start Redis (optional) Run FastAPI with python run.py