Spaces:
Sleeping
Sleeping
| 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/<name>_palette.png | |
| color_out/<name>_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/<name>_palette.png | |
| color_out/<name>_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/<name>_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. |