Image Color Classifier — README Classify an image as rust, zinc, or normal using simple, fast color-space heuristics (OpenCV + NumPy). You get three ways to use it: a FastAPI server (/classify/ endpoint) a Gradio web UI for quick testing CLI tools to generate color reports and classify offline Features Heuristic color analysis in CIELab: rustish_ratio → fraction of pixels with elevated a* (reddish/brownish) zincish_ratio → fraction of pixels with elevated b* (yellowish) Dominant colors via K-Means (palette + relative shares) Three thresholds you can tune: rust_thr, zinc_thr, and lab_delta Repository Layout . ├─ api.py # FastAPI app exposing /classify/ ├─ app.py # Gradio demo UI ├─ classify.py # (named 'app.py' in your message) classify from *_color_report.json ├─ color.py # Report generator (stats + palette + heuristics) ├─ main.py # CLI variant (stats + palette + heuristics + classification) ├─ requirements.txt # Python deps (fix the typos—see below) └─ color_out/ # (created at runtime) reports and palette images ⚠️ Fix your requirements.txt: Replace: "fastapi[all]" opencv-python-headless numpy gardio With: fastapi[all] uvicorn opencv-python-headless numpy gradio Quickstart 1) Environment python -m venv .venv # Windows .venv\Scripts\activate # macOS/Linux source .venv/bin/activate pip install -r requirements.txt 2) Run the FastAPI server uvicorn api:app --host 127.0.0.1 --port 8000 Endpoint: POST /classify/ Body: multipart form with file field file (image) Query params (optional): k (int, default 3) — number of dominant colors rust_thr (float, default 0.01) zinc_thr (float, default 0.02) lab_delta (float, default 6.0) cURL example: curl -X POST "http://127.0.0.1:8000/classify/?k=3&rust_thr=0.01&zinc_thr=0.02&lab_delta=6.0" \ -F "file=@/path/to/sample.jpg" Response (JSON): { "filename": "sample.jpg", "classification": "rust", "rustish_ratio": 0.0342, "zincish_ratio": 0.0051, "top_colors_rgb": [[183, 98, 72], [220, 210, 205], [120, 85, 70]], "top_colors_share": [0.62, 0.25, 0.13] } OpenAPI docs at: http://127.0.0.1:8000/docs 3) Run the Gradio demo python gradio_app.py Upload an image, tweak sliders, and see the JSON output instantly. Parameters mirrored: k, rust_thr, zinc_thr, lab_delta. 4) CLI workflows You have two report generators and one “classify from JSON” helper. Pick either color.py or main.py to generate a report. A) Generate a detailed report with color.py Creates: Stats in RGB/HSV/Lab Dominant color palette image Heuristic ratios python color.py --img /path/to/img.jpg --k 3 --resize_max 1200 --outdir color_out \ --rust_thr 0.01 --zinc_thr 0.02 --lab_delta 6.0 Outputs: color_out/_palette.png color_out/_color_report.json (includes classification) B) Alternative generator main.py Similar to color.py, also prints a short console summary. python main.py --img /path/to/img.jpg --k 3 --resize_max 1200 --outdir color_out Outputs: color_out/_palette.png color_out/_color_report.json C) Classify an existing report with classify.py (Your message labeled this file as app.py—the code shows it’s a JSON classifier.) python classify.py --report color_out/_color_report.json \ --rust_thr 0.01 --zinc_thr 0.02 Console output: { "file": "img.jpg", "rustish_ratio": 0.0342, "zincish_ratio": 0.0051, "classification": "rust" } How it works (short) Convert image to CIELab: L*, a*, b* (OpenCV uses a scaled 8-bit Lab). Compute medians of a* and b*, add lab_delta (e.g., 6.0) to form thresholds. Rustish = fraction of pixels with a* > median(a*) + lab_delta. Zincish = fraction with b* > median(b*) + lab_delta. Decision rule: If zincish_ratio > zinc_thr → zinc Else if rustish_ratio > rust_thr → rust Else → normal These are simple heuristics for quick screening, not robust material detection. Tuning tips Increase lab_delta to be stricter (fewer pixels count as rustish/zincish). Decrease thresholds rust_thr / zinc_thr to make classification more sensitive. For large images, set --resize_max to speed up K-Means and stats. Notes & gotchas Color spaces: OpenCV reads images as BGR; conversions are handled internally. Lighting & WB: Results vary with illumination and white balance. Try to keep input lighting consistent. Performance: k=3 works well for speed. Increase for richer palettes at a compute cost. Headless environments: Using opencv-python-headless avoids GUI dependencies. Example programmatic use (Python) import cv2 as cv from api import rust_zinc_indicators, classify_from_ratios, dominant_colors_kmeans bgr = cv.imread("sample.jpg", cv.IMREAD_COLOR) inds = rust_zinc_indicators(bgr, delta=6.0) label = classify_from_ratios(inds["rustish_ratio"], inds["zincish_ratio"], rust_thr=0.01, zinc_thr=0.02) palette = dominant_colors_kmeans(bgr, k=3) print(label, inds, palette[:1]) Troubleshooting Invalid image file. Could not decode image. The upload wasn’t a valid image. Try a supported format (JPG/PNG). ModuleNotFoundError / import errors: Re-check your virtualenv and pip install -r requirements.txt. Uvicorn not found: Add uvicorn to requirements.txt and pip install -r requirements.txt. License Add your preferred license (e.g., MIT) as LICENSE.