Spaces:
Configuration error
Configuration error
|
Download README.md from ZainabEman/OCR-Based-Spare-Part-Localization: direct link, hf CLI and curl.
- Browser
- Download file 5.73 kB
-
https://huggingface.co/spaces/ZainabEman/OCR-Based-Spare-Part-Localization/resolve/main/README.md
- Command line
-
hf download hf://spaces/ZainabEman/OCR-Based-Spare-Part-Localization/README.md
-
curl -L -o README.md https://huggingface.co/spaces/ZainabEman/OCR-Based-Spare-Part-Localization/resolve/main/README.md
5.73 kB
| title: Machine Part Finder | |
| emoji: π | |
| colorFrom: red | |
| colorTo: gray | |
| sdk: streamlit | |
| sdk_version: 1.63.0 | |
| python_version: '3.11' | |
| app_file: app.py | |
| app_port: 7860 | |
| pinned: false | |
| # Machine Part Finder β BQ188 spare-parts catalogue | |
| Type a spare-part number, get the catalogue diagram with **the actual machine | |
| component outlined in red** β not just the printed number. | |
| ``` | |
| 30642 -> page 34, section 07 "Motor-drive", Schnecke,kpl. / worm,cpl. | |
| red box drawn around the worm gear itself | |
| ``` | |
| The source document is `1.pdf`, a 55-page catalogue for the BQ188 warp tying | |
| machine. Its exploded-view diagrams label parts with the part number itself, | |
| joined to the component by a thin leader line. Finding the *text* `30642` is | |
| easy; finding the *worm gear* it points at is the actual problem this solves. | |
| ## How it works | |
| Two stages. All the expensive work happens once, offline. | |
| ``` | |
| OFFLINE (once, ~10 min) RUNTIME (per search, instant) | |
| 1.pdf part number | |
| | parse catalogue tables (real text) | SQLite lookup | |
| | extract diagrams at native resolution | load cached PNG | |
| | OCR the diagrams (RapidOCR) | draw red box in memory | |
| | snap callouts to the known part set | display | |
| | trace leader lines -> component boxes | |
| v | |
| data/catalog.db + data/pages/*.png | |
| ``` | |
| The search path never runs OCR, computer vision or PDF parsing β it reads the | |
| database and draws rectangles. No network, no LLM, no cloud service is involved | |
| at any point, before or after the build. | |
| | Piece | What it does | | |
| |---|---| | |
| | `spareparts/pdf_loader.py` | Finds the 30 catalogue pages, extracts each diagram | | |
| | `spareparts/table_parser.py` | Reads the parts tables (real vector text, never OCR) | | |
| | `spareparts/ocr.py` | OCRs the 30 diagrams, cached to JSON | | |
| | `spareparts/matcher.py` | Snaps OCR output to the 705 known part numbers | | |
| | `spareparts/localizer.py` | Traces leader lines to the component (the hard part) | | |
| | `spareparts/index_db.py` | SQLite schema and queries | | |
| | `spareparts/lookup.py`, `overlay.py` | Runtime query and red-box rendering | | |
| | `app.py` | Streamlit UI | | |
| `PSD.md` is the project's specification and records what was found in the PDF. | |
| ## Install | |
| Python 3.11. | |
| ```bash | |
| pip install -r requirements.txt | |
| ``` | |
| Everything runs on CPU and offline. The OCR models ship inside the | |
| `rapidocr-onnxruntime` wheel; nothing is downloaded at run time. | |
| ## Build the index | |
| Needed once, before first use, and only again if `1.pdf` changes. | |
| ```bash | |
| python -m spareparts.build_index | |
| ``` | |
| Takes about ten minutes and writes `data/catalog.db` plus `data/pages/*.png`. | |
| It is safe to re-run: the database is rebuilt from scratch rather than appended | |
| to. OCR results are cached in `data/ocr_cache/`, so re-running after a change to | |
| the localizer only costs a couple of minutes: | |
| ```bash | |
| python -m spareparts.build_index --stage annotate # skip re-indexing | |
| python -m spareparts.build_index --stage annotate --debug-images # + overlays | |
| ``` | |
| Expected output: 30 catalogue pages, 705 distinct parts, 861 table occurrences, | |
| 987 located callouts. | |
| ## Run the app | |
| ```bash | |
| streamlit run app.py | |
| ``` | |
| Then open <http://localhost:8501>, type a part number and press Enter. | |
| ### Example searches | |
| | Search | What you get | | |
| |---|---| | |
| | `30642` | One page. Red box on the worm gear, page 34, section 07. | | |
| | `74506` | One page, but the part is drawn four times β all four boxed and numbered #1β#4. | | |
| | `73290` | Ten pages. An occurrence selector appears; pick which to view. | | |
| | `99999` | "Part number not found in the catalogue." | | |
| Input is forgiving: ` part no. 30642 ` finds the same part. It is not fuzzy, | |
| though β the digits you type either name a real part or they do not. | |
| ## Tests | |
| ```bash | |
| python -m pytest tests -q | |
| ``` | |
| Accuracy of the offline stages can be re-measured at any time: | |
| ```bash | |
| python tools/ocr_report.py # OCR recall, per page | |
| python tools/evaluate.py # localization vs. the hand-checked ground truth | |
| ``` | |
| ## Limitation worth knowing | |
| Localization is deterministic OCR and classical computer vision β binarize, | |
| find connected components, trace the leader line from the callout to what it | |
| touches. There is no model and nothing is learned from data, so every result | |
| can be explained by the geometry that produced it. | |
| That approach has one real limit: **where two parts are drawn physically | |
| touching, they are a single connected shape and cannot be separated.** On the | |
| hand-checked set of 87 callouts the tool puts the box on the correct component | |
| **90.8%** of the time; the misses are almost all parts merged into a larger | |
| housing or arm. | |
| Rather than hide this, the app labels every result with how it was obtained: | |
| * **Located** β the leader line was traced cleanly to the component. | |
| * **Assembly** β the callout is boxed in the catalogue, so it names a whole group. | |
| * **Approximate** β the component could not be isolated; the highlight is a | |
| conservative area around the leader line's end. Shown with a low confidence. | |
| * **Not located** β a callout was found but no component could be resolved. | |
| Page 51 is the clearest example: it is a single assembled view where everything | |
| touches, so every callout there falls back to "Approximate". The box still lands | |
| on the right area, and the app says so instead of implying precision it does not | |
| have. | |
| Two other honest caveats: | |
| * The catalogue does not draw every part it lists. When a part is listed on a | |
| page but not drawn there, the page is shown without a highlight and the app | |
| explains why. | |
| * Occasionally a part is drawn on a page whose own table omits it. Those | |
| callouts are still matched against the full catalogue, and flagged. |