feat: add halcon skill v2 plugin + fix marketplace source paths
- plugins/halcon: MVTec HALCON machine-vision skill v2 (local Windows HALCON + remote halcon-remote MCP). Bundles 2387-operator index, 20 official 24.11 manuals, HDevEngine runners, ROI teaching, D2W overlay recipes. - marketplace.json: register halcon; switch both entries to ./plugins/<name> source form (bare-name+pluginRoot was rejected by claude plugin validate v2.1.202); drop now-unused metadata.pluginRoot. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,8 @@
|
||||
{
|
||||
"name": "halcon",
|
||||
"description": "Drive MVTec HALCON machine vision — locally (Windows HALCON via WSL/uv/HDevEngine/hrun) or remotely over the halcon-remote MCP with no local install. Blob/edge/XLD, circle & shape fitting, 1D/2D/3D metrology, matching, calibration, bar/2D-code reading, OCR, D2W overlay. Bundles the 2387-operator index and 20 official 24.11 manuals.",
|
||||
"version": "2.0.0",
|
||||
"author": {
|
||||
"name": "goldyard"
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,173 @@
|
||||
---
|
||||
name: halcon
|
||||
description: >-
|
||||
Runs and orchestrates MVTec HALCON machine-vision tasks two ways: the local
|
||||
Windows-side HALCON 24.11 (driven from WSL via uv, HDevEngine, hrun, or the
|
||||
HDevelop GUI), or a remote HALCON compute service over MCP (server
|
||||
`halcon-remote`) that needs no local HALCON. Use whenever the work touches
|
||||
HALCON, HDevelop, .hdev/.hdvp scripts, HDevEngine, or a machine-vision goal it
|
||||
can solve: blob analysis, thresholding/segmentation, edge and contour (XLD)
|
||||
extraction, circle/line/shape fitting, 1D/2D/3D measuring and metrology, 2D/3D
|
||||
and surface-based matching, camera calibration, stereo/depth, bar code and 2D
|
||||
data code reading (QR, DataMatrix, PDF417), OCR/Deep OCR, classification,
|
||||
D2W overlay/bullseye alignment metrology, or looking up a HALCON operator — even
|
||||
when the user only states the vision goal (e.g. "measure these circles", "find
|
||||
the mark centers", "read this DataMatrix", "no HALCON on my machine") without
|
||||
naming HALCON.
|
||||
metadata:
|
||||
author: agent-studio
|
||||
skill_version: "2.0"
|
||||
halcon_version: "24.11.1.1 Windows (local) + 24.11.1 Linux (remote MCP)"
|
||||
environments: "local: WSL -> Windows HALCON + uv venv | remote: halcon-remote MCP -> headless Linux server"
|
||||
compatibility: >-
|
||||
Local path: this machine only (Windows HALCON + Windows uv.exe + project venv
|
||||
mvtec-halcon==24111.0.0 + monthly license). Remote path (halcon-remote MCP): any
|
||||
machine with network access + a bearer token; no local HALCON needed.
|
||||
---
|
||||
|
||||
# HALCON on this machine
|
||||
|
||||
MVTec HALCON is a machine-vision library (operators for imaging, measuring,
|
||||
matching, calibration, code reading, OCR, deep learning). This skill is about
|
||||
**driving the HALCON that is installed here** and orchestrating vision pipelines
|
||||
with it. It does **not** re-teach general vision theory — for operator details
|
||||
and worked examples, read the bundled manuals on demand (see
|
||||
`references/doc-map.md`).
|
||||
|
||||
## Two runtimes — pick one
|
||||
|
||||
**A. Local (Windows HALCON, this machine).** Everything below in this file
|
||||
(Environment, the three execution methods, ROI teaching, gotchas) is the **local**
|
||||
path. Use it when you are on this WSL/Windows box.
|
||||
|
||||
**B. Remote over MCP (`halcon-remote`) — no local HALCON.** A HALCON 24.11 compute
|
||||
service reachable over the public internet; the client needs only network + a
|
||||
bearer token (no HALCON install, no minio creds, no VPN/tailnet). **Prefer this
|
||||
when there is no local HALCON** (MacOS, plain Linux, a colleague's machine), or
|
||||
for turnkey D2W overlay / find-circles jobs and large batches (zip → process →
|
||||
CSV). Tools, image-in/result-out model, the zip batch pattern, D2W conventions,
|
||||
and examples: **read `references/remote-mcp.md`** before using the remote tools.
|
||||
Quick self-check: call `mcp__halcon-remote__halcon_get_env`.
|
||||
|
||||
## ⚠️ Environment (LOCAL path) — read this first (it overrides assumptions)
|
||||
|
||||
- **HALCON lives on the Windows side only.** Install:
|
||||
`C:\Users\NAURA\AppData\Local\Programs\MVTec\HALCON-24.11-Progress-Steady`,
|
||||
`bin\x64-win64` on the Windows PATH. **WSL has no Linux HALCON runtime** — you
|
||||
must dispatch every execution to Windows binaries or the Windows venv. Do not
|
||||
`pip install halcon` inside WSL and do not try to run it Linux-side.
|
||||
- **Python is managed by `uv`, never called directly.** `uv` is not on the WSL
|
||||
PATH; use the full path **`/mnt/c/Users/NAURA/.local/bin/uv.exe`**. From the
|
||||
project dir it auto-detects `.venv`:
|
||||
`uv.exe run python <script.py> [args]`. The venv has
|
||||
`mvtec-halcon==24111.0.0`. (See `references/invocation.md` for the exact,
|
||||
tested commands.)
|
||||
- **License** is a monthly evaluation `.dat` in `<install>\license\`, refreshed
|
||||
manually by the user. If operators fail with a license error, the current
|
||||
month's `.dat` is likely missing/expired — tell the user; don't work around it.
|
||||
|
||||
Smoke-test the environment before real work:
|
||||
`uv.exe run python .claude/skills/halcon/scripts/check_env.py` — prints the
|
||||
HALCON version and runs a trivial operator (exercises the license).
|
||||
|
||||
## Three ways to execute — pick by task
|
||||
|
||||
1. **HDevEngine from Python (preferred for automation).** Load an external
|
||||
procedure (`.hdvp`) or a program (`.hdev`), set inputs, execute, read outputs
|
||||
back as native Python values, and drive the loop in Python. Use the generic
|
||||
runners:
|
||||
- `scripts/run_procedure.py` — call one `.hdvp` with input/output params.
|
||||
- `scripts/run_program.py` — run a whole `.hdev` and read control vars.
|
||||
2. **`hrun.exe` (headless batch).** Runs a `.hdev` unattended; the script must
|
||||
write its own output files. Gotchas: `hrun` does **not** auto-open a graphics
|
||||
window (add `dev_open_window` if the script draws), and relative paths resolve
|
||||
from the working dir. See `references/invocation.md`.
|
||||
3. **HDevelop GUI (`hdevelop -run`, or `start_debug_server` + remote debug).**
|
||||
For interactive inspection/debugging. Not for unattended runs — there is no
|
||||
run-and-exit; the window stays open.
|
||||
|
||||
Full flags, encoding handling, and copy-paste commands: **`references/invocation.md`**.
|
||||
|
||||
## The human-in-the-loop seam: teach ROI once, reuse headless
|
||||
|
||||
Interactive operators (`draw_rectangle1`, `draw_circle`, `draw_region`) cannot
|
||||
run unattended. The clean pattern is:
|
||||
|
||||
1. **Teach once (human draws):** `scripts/teach_roi.py` opens a viewer on a
|
||||
representative image, the operator boxes the region, and `write_region`
|
||||
persists it to a `.hobj` file. For the common rectangle case it's an
|
||||
**interactive matplotlib picker** — left-drag = box, **right-drag = pan,
|
||||
scroll wheel = zoom** — which stays smooth on multi-megapixel images (it
|
||||
downsamples the display but keeps full-resolution box coordinates). `circle`
|
||||
and `region` fall back to HALCON's native `draw_*` window. Add `--box
|
||||
r1,c1,r2,c2` to write a rectangle headless (no GUI). Needs `matplotlib` +
|
||||
`numpy` in the venv (`uv.exe pip install matplotlib numpy`).
|
||||
The same thing is exposed as the MCP tool **`halcon_teach_roi`** (see
|
||||
`references/mcp-server.md`), which runs the picker in a subprocess and returns
|
||||
the saved bbox.
|
||||
2. **Reuse forever (headless):** downstream procedures `read_region` the `.hobj`
|
||||
and `reduce_domain` with it — no human needed.
|
||||
|
||||
Re-teach only when the fixture, camera, or dataset changes. **Draw the ROI
|
||||
tightly** around the target features: too large an ROI captures extra contours
|
||||
and downstream count checks (e.g. "expected 16 circles") fail.
|
||||
|
||||
A complete, tested example of this pattern is bundled in
|
||||
`references/examples/` and is worth reading before building a new pipeline:
|
||||
`teach_roi.py`, `find_circles.hdvp` (edge-fit **and** metrology-model circle
|
||||
finding in one procedure), and `run_compare.py` (HDevEngine driver over a folder
|
||||
of images).
|
||||
|
||||
## Top gotchas (this environment)
|
||||
|
||||
- **Never route Chinese/Unicode paths through `cmd.exe`.** Its GBK code page
|
||||
corrupts them into "syntax incorrect" errors. Call the `.exe` (or `uv.exe`)
|
||||
directly from WSL so argv is passed as UTF-16.
|
||||
- **Console output is GBK.** Pipe through `iconv -f GBK -t UTF-8` to restore
|
||||
Chinese text from HALCON/hrun stdout.
|
||||
- **`hdevelop.exe` is a GUI app — its stdout is NOT captured from WSL.** For
|
||||
conversion/export/batch, always write results to a **file**, never rely on
|
||||
stdout.
|
||||
- **Relative paths resolve from the current working directory.** `cd` into the
|
||||
script's dir before `hrun`, or pass absolute paths (HDevEngine: always
|
||||
absolute).
|
||||
- **`hrun` opens no graphics window.** A script using `dev_get_window` / `draw_*`
|
||||
must call `dev_open_window` first (HDevelop supplies one implicitly, hrun does
|
||||
not).
|
||||
- **`clip_region` defaults to `true` and clips regions to ~128×128.** Building a
|
||||
region from full-resolution coordinates (`gen_rectangle1(2000, 2400, …)`)
|
||||
silently yields an **empty** region, so a saved `.hobj` reads back with bbox
|
||||
`0,0,0,0`. Call `set_system('clip_region', 'false')` before generating/reading
|
||||
regions with large coordinates (clamp to image bounds yourself instead). The
|
||||
ROI scripts already do this.
|
||||
|
||||
## How to find the right operator / method
|
||||
|
||||
**Fastest: the operator index** under `references/operator-ref/` (HALCON 24.11,
|
||||
2387 operators). To find or confirm an operator, `grep -i <keyword>
|
||||
references/operator-ref/operators.txt` (e.g. `circle`, `measure`, `datacode`);
|
||||
browse the chapter tree in `categories.md`; then open any operator's online
|
||||
reference at `https://www.mvtec.com/doc/halcon/2411/en/<operator>.html`. This
|
||||
beats opening PDFs when you just need the right operator name/signature.
|
||||
|
||||
For depth, the 20 official manuals are bundled under `references/pdf/`. Do not
|
||||
read them wholesale — **`references/doc-map.md`** maps each guide to its topics
|
||||
and exact page ranges, so you open just the right pages with the Read tool
|
||||
(`pages:` parameter). For distilled, ready-to-adapt pipelines per task type
|
||||
(measuring, matching, code reading, calibration, …) read
|
||||
**`references/task-recipes.md`** first; it points into the PDFs for depth.
|
||||
|
||||
## Where to look — quick index
|
||||
|
||||
| Need | Read |
|
||||
|------|------|
|
||||
| **Use HALCON remotely (no local install)** — remote MCP tools, image I/O, zip batch, D2W overlay | **`references/remote-mcp.md`** |
|
||||
| Find/confirm a HALCON operator (name → doc URL), browse by category | `references/operator-ref/` (grep `operators.txt`, `categories.md`) |
|
||||
| Call local HALCON as MCP tools (enhance/match/find-circles/metrology/teach-roi/run scripts) | `references/mcp-server.md` |
|
||||
| Run/convert/export HALCON here; flags, encoding, license | `references/invocation.md` |
|
||||
| Which manual + pages cover topic X | `references/doc-map.md` |
|
||||
| A step-by-step pipeline for a task type | `references/task-recipes.md` |
|
||||
| Generic HDevEngine procedure runner | `scripts/run_procedure.py` |
|
||||
| Generic HDevEngine program runner | `scripts/run_program.py` |
|
||||
| Teach an ROI interactively | `scripts/teach_roi.py` |
|
||||
| Verify the environment works | `scripts/check_env.py` |
|
||||
@@ -0,0 +1,123 @@
|
||||
{
|
||||
"skill_name": "halcon",
|
||||
"notes": "Two eval sets. `trigger` checks the description fires on the right prompts and stays quiet on near-misses (run each >=3x, target should_trigger>0.5 / should_not_trigger<0.5). `quality` checks the loaded skill leads to correct machine-specific behavior; run with_skill vs without_skill and compare against assertions.",
|
||||
"trigger": [
|
||||
{ "prompt": "Run this HALCON procedure over a folder of images and give me the results", "should_trigger": true },
|
||||
{ "prompt": "I have a .hdev script, can you execute it and read back the Total variable?", "should_trigger": true },
|
||||
{ "prompt": "Measure the diameters of these circular marks in the image to sub-pixel accuracy", "should_trigger": true },
|
||||
{ "prompt": "Read the DataMatrix code stamped on this part", "should_trigger": true },
|
||||
{ "prompt": "Find where this template logo appears in each frame and report its angle", "should_trigger": true },
|
||||
{ "prompt": "Calibrate this camera so I can measure parts in millimeters", "should_trigger": true },
|
||||
{ "prompt": "Fit circles to the edges of these holes and compare two fitting methods", "should_trigger": true },
|
||||
{ "prompt": "How do I set up HDevEngine from Python on this machine?", "should_trigger": true },
|
||||
{ "prompt": "Align the point cloud of this bracket to its CAD model to get the 3D pose", "should_trigger": true },
|
||||
{ "prompt": "The image processing keeps saying license error, what's wrong?", "should_trigger": true },
|
||||
{ "prompt": "Let me draw a region on this image once and reuse it to restrict processing for a whole batch", "should_trigger": true },
|
||||
{ "prompt": "I'm on my Mac and there's no HALCON installed — can you measure the overlay deviation on this bullseye alignment image?", "should_trigger": true },
|
||||
{ "prompt": "Find the four ring-mark centers in every image in this folder and save them to a CSV", "should_trigger": true },
|
||||
{ "prompt": "Batch-process a few thousand die photos to detect circle marks and give me one CSV, over the remote service", "should_trigger": true },
|
||||
{ "prompt": "Parse this CSV of measurement results and plot a histogram", "should_trigger": false },
|
||||
{ "prompt": "Write a Python script to rename these image files by timestamp", "should_trigger": false },
|
||||
{ "prompt": "Explain how a Canny edge detector works in general terms", "should_trigger": false },
|
||||
{ "prompt": "Set up an OpenCV pipeline to detect circles with HoughCircles", "should_trigger": false },
|
||||
{ "prompt": "Convert this PNG to grayscale JPEG", "should_trigger": false },
|
||||
{ "prompt": "Help me train a PyTorch model for defect classification", "should_trigger": false }
|
||||
],
|
||||
"quality": [
|
||||
{
|
||||
"id": "run-a-procedure",
|
||||
"prompt": "Run the find_circles procedure in the project on the image C:/data/a.png with roi.hobj and give me the FitRow output.",
|
||||
"expected_behavior": [
|
||||
"Uses HDevEngine (run_procedure.py or equivalent), not an invented API",
|
||||
"Invokes python through uv.exe by full path, never bare `python`",
|
||||
"Passes absolute paths for the image and ROI",
|
||||
"Reads FitRow back as a native value from get_output_control_param_by_name"
|
||||
],
|
||||
"assertions": [
|
||||
"The command uses /mnt/c/Users/NAURA/.local/bin/uv.exe (or an alias to it), not `python`/`python3` directly",
|
||||
"Uses scripts/run_procedure.py or the documented HDevEngine set/execute/get sequence",
|
||||
"Does not attempt a Linux-side HALCON install or `pip install halcon` in WSL"
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "unattended-draw",
|
||||
"prompt": "I need to threshold inside a hand-drawn region for 500 images unattended. How should I structure this?",
|
||||
"expected_behavior": [
|
||||
"Recognizes draw_* cannot run unattended",
|
||||
"Proposes teach ROI once (teach_roi.py -> write_region -> .hobj) then read_region + reduce_domain headless",
|
||||
"Warns to draw the ROI tightly"
|
||||
],
|
||||
"assertions": [
|
||||
"Mentions the teach-once / reuse-headless ROI seam",
|
||||
"References write_region/read_region (.hobj) rather than drawing per image"
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "find-operator-docs",
|
||||
"prompt": "Which HALCON manual explains 2D metrology for fitting circles, and where?",
|
||||
"expected_behavior": [
|
||||
"Points to solution_guide_iii_b_2d_measuring.pdf with page ranges from doc-map.md",
|
||||
"Suggests reading only the relevant pages via the Read tool, not the whole PDF"
|
||||
],
|
||||
"assertions": [
|
||||
"Names solution_guide_iii_b_2d_measuring.pdf",
|
||||
"Gives specific pages/chapters rather than 'read the guide'"
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "teach-roi-interactive",
|
||||
"prompt": "I need to draw an ROI around a small Mark on a 24-megapixel image — I want to zoom and pan to place it precisely, then save it for reuse.",
|
||||
"expected_behavior": [
|
||||
"Uses scripts/teach_roi.py (rectangle) or the halcon_teach_roi MCP tool, which give pan (right-drag) / zoom (wheel) / box-select (left-drag)",
|
||||
"Persists the ROI as a .hobj via write_region for headless reuse",
|
||||
"Does not propose a plain draw_rectangle1-only window that cannot zoom/pan",
|
||||
"Handles full-resolution coordinates (aware clip_region must be false, or that the picker keeps full-res coords while downsampling only the display)"
|
||||
],
|
||||
"assertions": [
|
||||
"Proposes the interactive pan/zoom/box-select picker (teach_roi.py rectangle mode or halcon_teach_roi), not bare draw_rectangle1",
|
||||
"Saves to a .hobj (write_region) for reuse",
|
||||
"Mentions handling large/full-resolution coordinates (clip_region=false, or display-only downsampling)"
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "chinese-path",
|
||||
"prompt": "HALCON says 'File not found' / the Chinese file path shows garbled characters when I run it. Why?",
|
||||
"expected_behavior": [
|
||||
"Identifies the GBK/cmd.exe (or console) encoding issue",
|
||||
"Advises calling the .exe/uv.exe directly from WSL (UTF-16 argv) and iconv for GBK console output"
|
||||
],
|
||||
"assertions": [
|
||||
"Attributes garbling to GBK / cmd.exe / console code page, not to HALCON itself",
|
||||
"Recommends not routing Unicode paths through cmd.exe"
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "remote-no-local-halcon",
|
||||
"prompt": "I'm on a MacBook with no HALCON installed. Measure the Top/Bottom overlay deviation on this bullseye image ~/die.bmp and give me dX/dY in microns.",
|
||||
"expected_behavior": [
|
||||
"Uses the remote halcon-remote MCP (no local HALCON); reads references/remote-mcp.md",
|
||||
"Gets the image to the server via image_b64 (single small image) or halcon_create_upload -> PUT -> key, not a client-side file path",
|
||||
"Calls halcon_measure_overlay and reports overlay_dX_um/overlay_dY_um (um, Bottom - Top)"
|
||||
],
|
||||
"assertions": [
|
||||
"Uses mcp__halcon-remote__halcon_measure_overlay, not a local Windows HALCON invocation",
|
||||
"Supplies the image via image_b64 or halcon_create_upload presigned PUT (not `file:` which is server-side, nor a local path the server cannot see)",
|
||||
"Does not attempt a local HALCON install"
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "remote-batch-zip",
|
||||
"prompt": "I have ~2000 die images in a folder. Find the 4 ring-mark centers in each and give me one CSV, using the remote HALCON service.",
|
||||
"expected_behavior": [
|
||||
"Zips the folder into one file (store mode) and uploads once via halcon_create_upload -> single PUT",
|
||||
"Calls halcon_find_circles_zip(zip_key) and returns/downloads the csv_url",
|
||||
"Notes synchronous execution (~minutes for thousands) and a long client timeout"
|
||||
],
|
||||
"assertions": [
|
||||
"Uses the zip -> halcon_create_upload -> halcon_find_circles_zip pattern (one upload), not 2000 per-file uploads",
|
||||
"Retrieves the result CSV via the returned csv_url",
|
||||
"Does not call halcon_create_upload once per image"
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,134 @@
|
||||
# HALCON manual map — read the right pages on demand
|
||||
|
||||
The 20 official manuals are **bundled in this skill** at `references/pdf/`:
|
||||
|
||||
- Relative to the skill: `references/pdf/<file>.pdf`
|
||||
- Absolute (this machine): `/mnt/c/workspace/agent-studio/halcon-001/.claude/skills/halcon/references/pdf/<file>.pdf`
|
||||
- Windows: `C:\workspace\agent-studio\halcon-001\.claude\skills\halcon\references\pdf\<file>.pdf`
|
||||
|
||||
(The Read tool needs the absolute path.)
|
||||
|
||||
**Do not read a whole guide.** Use the Read tool's `pages:` parameter (max 20
|
||||
pages/request) with the page ranges below. Page numbers are the PDF's own page
|
||||
numbers (1-based); `reference_hdevelop.pdf` is 3218 pages — always target a
|
||||
range. For a task-first entry point, read `task-recipes.md` before diving into a
|
||||
PDF.
|
||||
|
||||
## Task → guide (start here)
|
||||
|
||||
| Your goal | Primary guide (file) | Pages |
|
||||
|-----------|----------------------|-------|
|
||||
| Orient / pick a method for any vision task | `solution_guide_i.pdf` | ch.1 p13–20 |
|
||||
| Learn HDevelop, the language, assistants | `hdevelop_users_guide.pdf` | see below |
|
||||
| Call HALCON from C++/.NET/Python/C, HDevEngine | `programmers_guide.pdf` | see below |
|
||||
| Acquire images from a camera/file | `solution_guide_ii_a_image_acquisition.pdf` | all (56p) |
|
||||
| Blob analysis (threshold → connection → features) | `solution_guide_i.pdf` | ch.4 p33–44 |
|
||||
| 1D measuring (edges along a line/arc; calipers) | `solution_guide_iii_a_1d_measuring.pdf` | all (64p) |
|
||||
| 2D measuring / metrology (fit circles, lines, geometry) | `solution_guide_iii_b_2d_measuring.pdf` | all (74p) |
|
||||
| Edge & contour (XLD) extraction, contour processing | `solution_guide_i.pdf` | ch.6–9 p55–88 |
|
||||
| 2D matching (find a template: shape/NCC/…) | `solution_guide_ii_b_matching.pdf` | all (106p) |
|
||||
| 3D matching / 3D position of known objects | `solution_guide_iii_c_3d_vision.pdf` | ch.4 p91–116 |
|
||||
| Surface-based (3D point-cloud) matching | `surface_based_matching.pdf` | all (30p) |
|
||||
| Camera calibration, world coords, single-camera metric | `solution_guide_iii_c_3d_vision.pdf` | ch.2–3 p13–90 |
|
||||
| Stereo / sheet-of-light / depth-from-focus / robot vision | `solution_guide_iii_c_3d_vision.pdf` | ch.5–8 p117–190 |
|
||||
| Bar codes | `solution_guide_i.pdf` | ch.16 p159–174 |
|
||||
| 2D data codes (DataMatrix, QR, PDF417), print quality | `solution_guide_ii_c_2d_data_codes.pdf` | all (58p) |
|
||||
| OCR (classic) / Deep OCR | `solution_guide_i.pdf` | ch.18 p183–208 / ch.19 p209–214 |
|
||||
| Classification (features, segmentation, OCR) | `solution_guide_ii_d_classification.pdf` | all (106p) |
|
||||
| Color / texture analysis | `solution_guide_i.pdf` | ch.14 p131–142 / ch.15 p143–158 |
|
||||
| Exact operator signature & parameters | `reference_hdevelop.pdf` | search by operator |
|
||||
| Install / license troubleshooting | `installation_guide.pdf` | ch.5,7 p25–40 |
|
||||
| Performance: parallelism, memory, GPU/compute devices | `parallel_programming.pdf`, `memory_management.pdf`, `solution_guide_i.pdf` ch.22 |
|
||||
|
||||
## Per-guide detail
|
||||
|
||||
### solution_guide_i.pdf (255p) — the master "how to solve X" guide
|
||||
The single most useful guide for method selection. Chapters (page = start):
|
||||
1 Guide to HALCON Methods p13 · 2 Image Acquisition p21 · 3 Region Of Interest
|
||||
p25 · 4 Blob Analysis p33 · 5 1D Measuring p45 · 6 Edge Extraction (pixel) p55 ·
|
||||
7 Edge Extraction (subpixel) p63 · 8 Structured Light p69 · 9 Contour Processing
|
||||
p79 · 10 2D Matching p89 · 11 3D Matching p101 · 12 Variation Model p111 · 13
|
||||
Classification p119 · 14 Color Processing p131 · 15 Texture Analysis p143 · 16
|
||||
Bar Code p159 · 17 Data Code p175 · 18 OCR p183 · 19 Deep OCR p209 · 20 Stereo
|
||||
Vision p215 · 21 Visualization p223 · 22 Compute Devices (GPU) p233 · 23 I/O
|
||||
Devices p247.
|
||||
|
||||
### hdevelop_users_guide.pdf (344p) — the IDE and the HDevelop language
|
||||
2 Getting Started p15 · 3 Acquiring Images p23 · 4 Programming With HDevelop p31
|
||||
· 5 Procedures (.hdvp, scope, JIT) p43 · 7 Assistants (Image Acquisition p180,
|
||||
**Calibration p184**, **Matching p202**, **Measure p219**, OCR p231) · 8 HDevelop
|
||||
Language (types p247, tuples p288, control flow p276, error handling p282,
|
||||
parallel p283) · 9 Remote Debugging p299 · 10 Code Export p303 · Appendix C
|
||||
**Command Line Usage** (HDevelop p323, Hrun p326).
|
||||
|
||||
### programmers_guide.pdf (209p) — calling HALCON from a language
|
||||
Part I General (which interface to use p13, parallel p15, tips p23) · II C++ p31 ·
|
||||
III .NET p59 · **IV Python p91** · V C p107 · **VI Using HDevEngine p137**. Read
|
||||
Part IV + VI for the Python/HDevEngine automation used by this skill.
|
||||
|
||||
### solution_guide_iii_b_2d_measuring.pdf (74p) — 2D metrology
|
||||
1 Introduction p7 · 2 **Basic Tools** p11 · 3 **Tool Selection** p27 · 4
|
||||
**Examples for Practical Guidance** p35 · 5 Miscellaneous p63. This is the guide
|
||||
for fitting circles/lines/rectangles and the metrology model (the approach used
|
||||
in `find_circles.hdvp`).
|
||||
|
||||
### solution_guide_iii_a_1d_measuring.pdf (64p) — calipers along a line/arc
|
||||
2 Basics of Measure Objects p9 · 3 Using the Measure Object p15 · 4 Fuzzy Measure
|
||||
Object p27 · A Slanted Edges p37. Use for edge position/width along a
|
||||
gen_measure_rectangle2 / _arc profile.
|
||||
|
||||
### solution_guide_ii_b_matching.pdf (106p) — 2D template matching
|
||||
1 Introduction p7 · 2 **General Topics** p17 · 3 **The Individual Approaches**
|
||||
p47 (shape-based, NCC/correlation, component, deformable, descriptor, …). Chapter
|
||||
3 is the menu of matching methods and how to choose.
|
||||
|
||||
### solution_guide_iii_c_3d_vision.pdf (238p) — everything 3D
|
||||
2 **Basics** (camera model, calibration) p13 · 3 **Metric Measurements in a Plane
|
||||
w/ Single Camera** p59 · 4 **3D Position of Known Objects** p91 · 5 Stereo p117 ·
|
||||
6 Sheet-of-Light (laser triangulation) p147 · 7 Depth from Focus p163 · 8 Robot
|
||||
Vision (hand-eye) p175 · 9 Calibrated Mosaicking p191 · 10 Uncalibrated
|
||||
Mosaicking p205 · 11 Rectification p219 · A HDevelop procedures used p231.
|
||||
|
||||
### solution_guide_ii_c_2d_data_codes.pdf (58p) — QR/DataMatrix/PDF417
|
||||
2 A First Example p9 · 3 Model Adaptation p11 · 4 Preprocessing Difficult Images
|
||||
p25 · 5 Problem Handling p29 · 6 Print Quality p45.
|
||||
|
||||
### solution_guide_ii_d_classification.pdf (106p) — classifiers
|
||||
3 Theoretical Background p15 · 4 Decisions to Make p27 · 5 General Features p31 ·
|
||||
6 Image Segmentation p57 · 7 OCR p75 · 8 General Tips p93. (Classic ML
|
||||
classifiers — MLP/SVM/GMM/k-NN; for deep learning see solution_guide_i ch.13/19.)
|
||||
|
||||
### surface_based_matching.pdf (30p) — 3D point-cloud matching
|
||||
1 Overview p7 · 2 **Workflow** p11 · 3 Data Requirements p15 · 4 Troubleshooting
|
||||
p17 · 5 Tips for Speed/Robustness/Accuracy p22 · 6 Background Removal p26.
|
||||
|
||||
### solution_guide_ii_a_image_acquisition.pdf (56p) — grabbing images
|
||||
Acquisition interface philosophy, connecting to a device, grab modes (single /
|
||||
continuous / async), and image/parameter appendices.
|
||||
|
||||
### reference_hdevelop.pdf (3218p) — the operator reference
|
||||
Every operator's signature, parameters, and semantics, grouped by chapter. **Do
|
||||
not browse.** To confirm a specific operator, search the TOC in
|
||||
`references/pdf/_toc.json` (bundled) or grep the extracted text, then Read only
|
||||
that operator's few pages.
|
||||
|
||||
### Smaller / situational guides
|
||||
- `quick_guide.pdf` (19p) — architecture + how to develop; good 5-minute orientation.
|
||||
- `installation_guide.pdf` (47p) — editions, install, **licenses (ch.5 p25)**, **troubleshooting (ch.7 p37)**, Docker, env vars.
|
||||
- `parallel_programming.pdf` (27p) — minimize response time / maximize throughput / responsiveness.
|
||||
- `memory_management.pdf` (17p) — image/global/temp caches, suspected leaks, FAQ.
|
||||
- `gray_value_interpolation.pdf` (16p) — nearest/bilinear/bicubic; affects rotate/zoom/affine accuracy.
|
||||
- `technical_updates.pdf` (10p) — Handles (18.05), **UTF-8 encoding (18.11)**.
|
||||
- `extension_package_programmers_manual.pdf` (147p) — writing custom C operators; **Appendix A HALCON Error Codes p105**.
|
||||
- `arm_based_platforms.pdf` (16p) — Arm/embedded (not this machine; reference only).
|
||||
|
||||
## Regenerating the TOC index
|
||||
|
||||
The full multi-level TOC is bundled at `references/pdf/_toc.json`. To rebuild
|
||||
(e.g. after adding/updating a manual):
|
||||
|
||||
```bash
|
||||
cd /mnt/c/workspace/agent-studio/halcon-001
|
||||
/mnt/c/Users/NAURA/.local/bin/uv.exe run --no-project --with pymupdf \
|
||||
python .claude/skills/halcon/scripts/extract_toc.py
|
||||
```
|
||||
@@ -0,0 +1,17 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<hdevelop file_version="1.2" halcon_version="24.11.1.0">
|
||||
<procedure name="main">
|
||||
<interface/>
|
||||
<body>
|
||||
<l>Values := [1, 2, 3, 4, 10]</l>
|
||||
<l>Total := sum(Values)</l>
|
||||
<l>gen_image_const (Img, 'byte', 20, 10)</l>
|
||||
<l>threshold (Img, Region, 0, 128)</l>
|
||||
<l>area_center (Region, Area, RowC, ColC)</l>
|
||||
<l>Message := 'driven by HDevEngine'</l>
|
||||
</body>
|
||||
<docu id="main">
|
||||
<parameters/>
|
||||
</docu>
|
||||
</procedure>
|
||||
</hdevelop>
|
||||
@@ -0,0 +1,10 @@
|
||||
"""Remote-control a .hdev program via HDevEngine: run it, read variables back."""
|
||||
from halcon.hdevengine import HDevProgram, HDevProgramCall
|
||||
|
||||
program = HDevProgram("demo_prog.hdev")
|
||||
call = HDevProgramCall(program)
|
||||
call.execute() # runs the exact same code HDevelop would run
|
||||
|
||||
# pull any control variable back out by name
|
||||
for name in ("Total", "Area", "RowC", "ColC", "Message"):
|
||||
print(f"{name} =", call.get_control_var_by_name(name))
|
||||
@@ -0,0 +1,58 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<hdevelop file_version="1.2" halcon_version="24.11.1.0">
|
||||
<procedure name="find_circles">
|
||||
<interface>
|
||||
<ic>
|
||||
<par name="ImageFile" base_type="ctrl" dimension="0"/>
|
||||
<par name="RoiFile" base_type="ctrl" dimension="0"/>
|
||||
</ic>
|
||||
<oc>
|
||||
<par name="FitRow" base_type="ctrl" dimension="0"/>
|
||||
<par name="FitCol" base_type="ctrl" dimension="0"/>
|
||||
<par name="MetroRow" base_type="ctrl" dimension="0"/>
|
||||
<par name="MetroCol" base_type="ctrl" dimension="0"/>
|
||||
</oc>
|
||||
</interface>
|
||||
<body>
|
||||
<l>read_image (Image1, ImageFile)</l>
|
||||
<l>read_region (Rectangle, RoiFile)</l>
|
||||
<l>get_image_size (Image1, Width, Height)</l>
|
||||
<l>reduce_domain (Image1, Rectangle, ImageReduced)</l>
|
||||
<l>edges_sub_pix (ImageReduced, Edges, 'canny', 3, 10, 40)</l>
|
||||
<l>select_contours_xld (Edges, SelectedContours1, 'contour_length', 50, 500, -0.5, 0.5)</l>
|
||||
<l>union_adjacent_contours_xld (SelectedContours1, UnionContours, 10, 1, 'attr_keep')</l>
|
||||
<l>select_contours_xld (UnionContours, SelectedContours, 'contour_length', 300, 400, -0.5, 0.5)</l>
|
||||
<l>sort_contours_xld (SelectedContours, SortedContours, 'character', 'true', 'column')</l>
|
||||
<l>fit_circle_contour_xld (SortedContours, 'algebraic', -1, 0, 0, 3, 2, FitRow, FitCol, Radius, StartPhi, EndPhi, PointOrder)</l>
|
||||
<l>if (|FitRow| != 16)</l>
|
||||
<l> throw ('fit circle count != 16, got ' + |FitRow|)</l>
|
||||
<l>endif</l>
|
||||
<l>CircleRadiusTolerance := 15</l>
|
||||
<l>create_metrology_model (MetrologyHandle)</l>
|
||||
<l>set_metrology_model_image_size (MetrologyHandle, Width, Height)</l>
|
||||
<l>add_metrology_object_circle_measure (MetrologyHandle, FitRow, FitCol, Radius, CircleRadiusTolerance, 5, 1, 30, [], [], MetrologyCircleIndices)</l>
|
||||
<l>set_metrology_object_param (MetrologyHandle, MetrologyCircleIndices, 'num_instances', 1)</l>
|
||||
<l>set_metrology_object_param (MetrologyHandle, MetrologyCircleIndices, 'measure_transition', 'positive')</l>
|
||||
<l>set_metrology_object_param (MetrologyHandle, MetrologyCircleIndices, 'min_score', 0.3)</l>
|
||||
<l>apply_metrology_model (Image1, MetrologyHandle)</l>
|
||||
<l>get_metrology_object_result (MetrologyHandle, MetrologyCircleIndices, 'all', 'result_type', 'all_param', CircleParameter)</l>
|
||||
<l>Sequence := [0:3:|CircleParameter| - 1]</l>
|
||||
<l>MetroRow := CircleParameter[Sequence]</l>
|
||||
<l>MetroCol := CircleParameter[Sequence + 1]</l>
|
||||
<l>if (|MetroRow| != 16)</l>
|
||||
<l> throw ('metrology circle count != 16, got ' + |MetroRow|)</l>
|
||||
<l>endif</l>
|
||||
<l>clear_metrology_model (MetrologyHandle)</l>
|
||||
</body>
|
||||
<docu id="find_circles">
|
||||
<parameters>
|
||||
<parameter id="ImageFile"/>
|
||||
<parameter id="RoiFile"/>
|
||||
<parameter id="FitRow"/>
|
||||
<parameter id="FitCol"/>
|
||||
<parameter id="MetroRow"/>
|
||||
<parameter id="MetroCol"/>
|
||||
</parameters>
|
||||
</docu>
|
||||
</procedure>
|
||||
</hdevelop>
|
||||
@@ -0,0 +1,79 @@
|
||||
"""HDevEngine 全自动驱动:读 roi.hobj,循环所有 png 跑 find_circles,
|
||||
对比 拟合法 vs 计量模型法 两种找圆结果,输出偏差统计,并写 CSV。"""
|
||||
import math
|
||||
import csv
|
||||
from halcon.hdevengine import HDevEngine, HDevProcedure, HDevProcedureCall, HDevEngineError
|
||||
import halcon as ha
|
||||
|
||||
PROJ = r"C:\workspace\agent-studio\halcon-001"
|
||||
IMG_DIR = r"C:\工作文档\2025.10.03_精度实验数据分析\两种找圆算法对比\初始状态-往复-右侧上视左标定片阵列Mark定位"
|
||||
ROI_FILE = PROJ + r"\roi.hobj"
|
||||
CSV_OUT = PROJ + r"\compare_result.csv"
|
||||
|
||||
def as_list(v):
|
||||
return list(v) if isinstance(v, (list, tuple)) else [v]
|
||||
|
||||
# 引擎 + procedure
|
||||
eng = HDevEngine()
|
||||
eng.set_procedure_path(PROJ)
|
||||
proc = HDevProcedure.load_external("find_circles")
|
||||
call = HDevProcedureCall(proc)
|
||||
|
||||
# 图片列表
|
||||
files = ha.list_files(IMG_DIR, "files")
|
||||
pngs = sorted(ha.tuple_regexp_select(files, r"\.png$"))
|
||||
print(f"待处理图片: {len(pngs)} 张")
|
||||
|
||||
all_dists = [] # 所有 图×圆 的中心欧氏距离
|
||||
per_image_mean = [] # 每张图的平均偏差
|
||||
skipped = 0
|
||||
rows_csv = [("image", "circle_idx", "fit_row", "fit_col", "metro_row", "metro_col", "dist_px")]
|
||||
|
||||
for path in pngs:
|
||||
call.reset()
|
||||
call.set_input_control_param_by_name("ImageFile", path)
|
||||
call.set_input_control_param_by_name("RoiFile", ROI_FILE)
|
||||
try:
|
||||
call.execute()
|
||||
except HDevEngineError as e:
|
||||
skipped += 1
|
||||
if skipped <= 3:
|
||||
print(f"[skip] {path.rsplit(chr(92),1)[-1]}: {e}")
|
||||
continue
|
||||
fr = as_list(call.get_output_control_param_by_name("FitRow"))
|
||||
fc = as_list(call.get_output_control_param_by_name("FitCol"))
|
||||
mr = as_list(call.get_output_control_param_by_name("MetroRow"))
|
||||
mc = as_list(call.get_output_control_param_by_name("MetroCol"))
|
||||
|
||||
name = path.rsplit("\\", 1)[-1]
|
||||
dists = []
|
||||
for i in range(16):
|
||||
d = math.hypot(fr[i] - mr[i], fc[i] - mc[i])
|
||||
dists.append(d)
|
||||
all_dists.append(d)
|
||||
rows_csv.append((name, i, f"{fr[i]:.4f}", f"{fc[i]:.4f}",
|
||||
f"{mr[i]:.4f}", f"{mc[i]:.4f}", f"{d:.4f}"))
|
||||
per_image_mean.append(sum(dists) / len(dists))
|
||||
|
||||
# 统计
|
||||
def stats(xs):
|
||||
n = len(xs)
|
||||
m = sum(xs) / n
|
||||
sd = math.sqrt(sum((x - m) ** 2 for x in xs) / n)
|
||||
return n, m, sd, min(xs), max(xs)
|
||||
|
||||
with open(CSV_OUT, "w", newline="", encoding="utf-8-sig") as f:
|
||||
csv.writer(f).writerows(rows_csv)
|
||||
|
||||
print("=" * 60)
|
||||
print(f"成功处理: {len(per_image_mean)} 张 跳过(圆数!=16): {skipped} 张")
|
||||
if all_dists:
|
||||
n, m, sd, lo, hi = stats(all_dists)
|
||||
print(f"两算法圆心偏差 (像素),样本 {n} 个圆:")
|
||||
print(f" 均值 = {m:.4f}")
|
||||
print(f" 标准差 = {sd:.4f}")
|
||||
print(f" 最小 = {lo:.4f}")
|
||||
print(f" 最大 = {hi:.4f}")
|
||||
_, mm, _, _, _ = stats(per_image_mean)
|
||||
print(f" 每图平均偏差的均值 = {mm:.4f}")
|
||||
print(f"明细已写: {CSV_OUT}")
|
||||
@@ -0,0 +1,30 @@
|
||||
"""ROI 示教工具:显示一张代表图,人工画一次矩形,存成 roi.hobj。运行一次即可。"""
|
||||
import halcon as ha
|
||||
|
||||
IMG_DIR = r"C:\工作文档\2025.10.03_精度实验数据分析\两种找圆算法对比\初始状态-往复-右侧上视左标定片阵列Mark定位"
|
||||
ROI_FILE = r"C:\workspace\agent-studio\halcon-001\roi.hobj"
|
||||
|
||||
# 取目录里第一张 png 作为代表图
|
||||
files = ha.list_files(IMG_DIR, "files")
|
||||
pngs = sorted(ha.tuple_regexp_select(files, r"\.png$"))
|
||||
if not pngs:
|
||||
raise SystemExit("目录里没有 png")
|
||||
img = ha.read_image(pngs[0])
|
||||
width, height = ha.get_image_size(img)
|
||||
width, height = width[0], height[0]
|
||||
|
||||
# 开窗口,映射到整幅图坐标(这样画出来的框就是图像坐标)
|
||||
win = ha.open_window(0, 0, 1024, 768, 0, "visible", "")
|
||||
ha.set_part(win, 0, 0, height - 1, width - 1)
|
||||
ha.disp_obj(img, win)
|
||||
ha.set_color(win, "green")
|
||||
|
||||
print("请在弹出的窗口里用鼠标左键拖出 ROI 矩形,松开即可 ...", flush=True)
|
||||
row1, col1, row2, col2 = ha.draw_rectangle1(win) # 阻塞,等人工画
|
||||
|
||||
rect = ha.gen_rectangle1(row1, col1, row2, col2)
|
||||
ha.write_region(rect, ROI_FILE)
|
||||
|
||||
print(f"ROI 已保存: {ROI_FILE}")
|
||||
print(f"矩形坐标 Row1={row1:.1f} Col1={col1:.1f} Row2={row2:.1f} Col2={col2:.1f}")
|
||||
ha.close_window(win)
|
||||
@@ -0,0 +1,179 @@
|
||||
# Invoking HALCON on this machine
|
||||
|
||||
Everything here is specific to this install. Read `SKILL.md` first for the
|
||||
one-paragraph environment summary; this file is the detailed, copy-paste
|
||||
reference.
|
||||
|
||||
## Fixed paths
|
||||
|
||||
| What | Path |
|
||||
|------|------|
|
||||
| HALCON install | `C:\Users\NAURA\AppData\Local\Programs\MVTec\HALCON-24.11-Progress-Steady` |
|
||||
| Windows binaries | `<install>\bin\x64-win64` (on Windows PATH: `hrun.exe`, `hdevelop.exe`, `hhostid.exe`) |
|
||||
| License dir | `<install>\license\` — monthly `license_eval_halcon_progress_YYYY_MM.dat` |
|
||||
| Project | `C:\workspace\agent-studio\halcon-001` (WSL: `/mnt/c/workspace/agent-studio/halcon-001`) |
|
||||
| venv | `C:\workspace\agent-studio\halcon-001\.venv` (`mvtec-halcon==24111.0.0`) |
|
||||
| venv python (direct) | `C:\workspace\agent-studio\halcon-001\.venv\Scripts\python.exe` |
|
||||
| **uv (use this)** | `/mnt/c/Users/NAURA/.local/bin/uv.exe` |
|
||||
|
||||
WSL has **no** Linux HALCON runtime. Every path above is Windows-side; drive it
|
||||
from WSL by calling the Windows `.exe` directly.
|
||||
|
||||
## Running Python (always via uv)
|
||||
|
||||
`uv` is not on the WSL PATH — call it by full path. Run from the **project
|
||||
directory** so `uv` auto-detects `.venv` (there is no `pyproject.toml`; uv picks
|
||||
up the local `.venv`):
|
||||
|
||||
```bash
|
||||
cd /mnt/c/workspace/agent-studio/halcon-001
|
||||
/mnt/c/Users/NAURA/.local/bin/uv.exe run python <script.py> [args...]
|
||||
```
|
||||
|
||||
Tested: `uv.exe run python -c "import halcon as ha; print(ha.get_system('version'))"`
|
||||
→ `['24.11']`. If you prefer a shorter command, alias it:
|
||||
`alias uv=/mnt/c/Users/NAURA/.local/bin/uv.exe` (session-local).
|
||||
|
||||
> Do **not** call `python`/`python3` directly (user rule). Use `uv run`. Direct
|
||||
> `.venv\Scripts\python.exe` also works but `uv` is preferred.
|
||||
|
||||
## Method 1 — HDevEngine from Python (preferred for automation)
|
||||
|
||||
HDevEngine runs the exact `.hdev`/`.hdvp` logic HDevelop would, from Python, so
|
||||
you can pass inputs in and read variables back. Interactive `draw_*` operators
|
||||
are **not** supported here — supply those inputs as parameters (see ROI seam).
|
||||
|
||||
### Imports (ground truth from the tested project)
|
||||
|
||||
```python
|
||||
from halcon.hdevengine import (
|
||||
HDevEngine, HDevProcedure, HDevProcedureCall,
|
||||
HDevProgram, HDevProgramCall, HDevEngineError,
|
||||
)
|
||||
import halcon as ha # plain operators: read_image, list_files, tuple_*, ...
|
||||
```
|
||||
|
||||
### External procedure (`.hdvp`)
|
||||
|
||||
```python
|
||||
eng = HDevEngine()
|
||||
eng.set_procedure_path(r"C:\workspace\agent-studio\halcon-001") # dir holding the .hdvp
|
||||
proc = HDevProcedure.load_external("find_circles") # base name, no extension
|
||||
call = HDevProcedureCall(proc)
|
||||
|
||||
call.reset() # before each iteration
|
||||
call.set_input_control_param_by_name("ImageFile", r"C:\data\a.png")
|
||||
call.set_input_control_param_by_name("RoiFile", r"C:\...\roi.hobj")
|
||||
call.execute()
|
||||
fit_row = call.get_output_control_param_by_name("FitRow") # -> native list/scalar
|
||||
```
|
||||
|
||||
Wrap `call.execute()` in `try/except HDevEngineError` to skip bad images (the
|
||||
tested `find_circles.hdvp` `throw`s when the circle count != 16; the Python
|
||||
driver catches it and continues). Helper: values come back as scalars or
|
||||
lists — normalize with `list(v) if isinstance(v,(list,tuple)) else [v]`.
|
||||
|
||||
Use the generic runner instead of hand-writing this:
|
||||
|
||||
```bash
|
||||
uv.exe run python .claude/skills/halcon/scripts/run_procedure.py \
|
||||
--proc-path C:/workspace/agent-studio/halcon-001 \
|
||||
--proc find_circles \
|
||||
--set ImageFile=C:/data/a.png --set RoiFile=C:/workspace/agent-studio/halcon-001/roi.hobj \
|
||||
--get FitRow --get FitCol --get MetroRow --get MetroCol
|
||||
# prints a JSON object of the requested outputs
|
||||
```
|
||||
|
||||
### Whole program (`.hdev`)
|
||||
|
||||
```python
|
||||
program = HDevProgram(r"C:\...\demo_prog.hdev")
|
||||
call = HDevProgramCall(program)
|
||||
call.execute()
|
||||
total = call.get_control_var_by_name("Total") # any control var by name
|
||||
```
|
||||
|
||||
Generic runner: `scripts/run_program.py --program <path.hdev> --get Total --get Area`.
|
||||
|
||||
## Method 2 — `hrun.exe` (headless batch)
|
||||
|
||||
Runs a `.hdev` to completion without the GUI. The script must persist its own
|
||||
results (write to file). Launch from WSL with the working dir set so relative
|
||||
paths resolve:
|
||||
|
||||
```bash
|
||||
cd /path/to/script/dir
|
||||
"/mnt/c/Users/NAURA/AppData/Local/Programs/MVTec/HALCON-24.11-Progress-Steady/bin/x64-win64/hrun.exe" \
|
||||
script.hdev | iconv -f GBK -t UTF-8
|
||||
```
|
||||
|
||||
Useful flags:
|
||||
|
||||
| Flag | Meaning |
|
||||
|------|---------|
|
||||
| `-c <var>` | after the run, check a variable; nonzero/true = success |
|
||||
| `-D name=value` | preset a global control variable |
|
||||
| `-d` | dump all control variable values after the run |
|
||||
| `-j` | run procedures JIT-compiled |
|
||||
|
||||
Gotchas: **no graphics window is opened** — if the script uses
|
||||
`dev_get_window`/`draw_*`, add `dev_open_window` first. Keep an
|
||||
hrun-runnable copy of interactive scripts (the project convention is a
|
||||
`*_hrun.hdev` variant with `dev_open_window` added and `stop()`/`draw_*`
|
||||
removed).
|
||||
|
||||
## Method 3 — HDevelop GUI (`hdevelop.exe`)
|
||||
|
||||
For interactive runs / inspection. There is **no run-and-exit**; the window stays
|
||||
open until closed. `hdevelop.exe` is a GUI app, so **its stdout is not captured
|
||||
from WSL** — for any batch/convert/export use file outputs.
|
||||
|
||||
- `hdevelop -run <prog.hdev>` — open GUI and auto-run.
|
||||
- `-override_stop <n>` — replace every `stop()` with `wait_seconds(n)` (use `0`).
|
||||
- `-override_wait <n>` — override all `wait_seconds()` durations.
|
||||
- `-external_proc_path "<dir1;dir2>"` — external procedure search path.
|
||||
|
||||
Remote debugging: a running application calls `start_debug_server` (HALCON) /
|
||||
enables the debug server, then HDevelop attaches to it. See
|
||||
`hdevelop_users_guide.pdf` ch. 9 (Remote Debugging, p299).
|
||||
|
||||
### Convert / export (batch, no interaction — write to a FILE)
|
||||
|
||||
- Convert: `hdevelop -convert <src> <dst>` — target type from `<dst>` extension
|
||||
(`.hdev/.dev/.hdvp/.dvp/.hdpl/.c/.cpp/.cs/.vb/.txt`). Add `-no_msg_box` to
|
||||
suppress GUI error dialogs in batch; `-external_procs_only_interfaces` for
|
||||
interface-only export.
|
||||
- Export project: `hdevelop -export_project` for a CMake C++/C# project.
|
||||
**`-namespace` is REQUIRED** — omitting it fails silently and writes nothing.
|
||||
Prefer absolute paths for input and output folder.
|
||||
|
||||
Command-line reference: `hdevelop_users_guide.pdf` Appendix C (p323 HDevelop,
|
||||
p326 Hrun).
|
||||
|
||||
## The ROI seam (teach once → reuse headless)
|
||||
|
||||
- **Teach:** `scripts/teach_roi.py` — shows a representative image, human drags a
|
||||
shape, `write_region` saves `roi.hobj`. Draw **tightly** (loose ROI → extra
|
||||
contours → count checks fail).
|
||||
- **Reuse:** in a procedure/program, `read_region(Roi, RoiFile)` then
|
||||
`reduce_domain(Image, Roi, ImageReduced)`. This is what unattended runs call
|
||||
instead of `draw_*`.
|
||||
|
||||
## Encoding & path gotchas (recap with fixes)
|
||||
|
||||
- Chinese/Unicode paths: call the `.exe`/`uv.exe` **directly** from WSL (UTF-16
|
||||
argv). Never wrap in `cmd.exe /c` (GBK → "syntax incorrect").
|
||||
- Restore Chinese console output: `... | iconv -f GBK -t UTF-8`.
|
||||
- HALCON internally uses UTF-8 for strings since 18.11 (see
|
||||
`technical_updates.pdf`); the GBK issue is the Windows *console/cmd* layer, not
|
||||
HALCON itself.
|
||||
- HDevEngine: always pass **absolute** paths — no cwd ambiguity.
|
||||
|
||||
## License
|
||||
|
||||
Monthly evaluation `.dat` in `<install>\license\`, updated manually by the user.
|
||||
Stale/expired `.dat` files may linger; HALCON auto-selects a valid one. If you
|
||||
hit a license error, the current month's file is probably missing — **surface
|
||||
this to the user**, don't attempt to bypass it. Host id for a new license:
|
||||
run `hhostid.exe` (also a quick "can the binaries execute?" check). License
|
||||
details: `installation_guide.pdf` ch. 5 (p25).
|
||||
@@ -0,0 +1,64 @@
|
||||
# halcon-mcp — the HALCON MCP server
|
||||
|
||||
A local MCP server that exposes common HALCON algorithms + script runners as
|
||||
tools, for driving HALCON experiments without hand-writing Python each time. It
|
||||
lives at the **project root** (outside this skill): `halcon-mcp/`. Source of truth
|
||||
is `halcon-mcp/README.md`; this file is the pointer from the skill.
|
||||
|
||||
## What it is
|
||||
|
||||
- Python + official `mcp` SDK (FastMCP), **stdio** transport.
|
||||
- Runs **in-process** in the shared HALCON venv (`import halcon`), so algorithm
|
||||
tools call operators directly and return structured JSON + the **equivalent
|
||||
HDevelop code** + an **overlay PNG**.
|
||||
- Errors return `{ok:false, error:...}` (no crash) so the model can self-correct.
|
||||
|
||||
## Tools (11)
|
||||
|
||||
Run/experiment: `halcon_check_env`, `halcon_run_script` (inline HDevelop snippet),
|
||||
`halcon_run_program` (.hdev), `halcon_run_procedure` (.hdvp), `halcon_run_hrun`
|
||||
(headless, GBK-decoded), `halcon_open_in_hdevelop` (GUI), `halcon_teach_roi`
|
||||
(interactive pan/zoom/box-select ROI → `.hobj`, or headless via `box`; runs
|
||||
`halcon-mcp/roi_picker.py` in a subprocess and returns the saved bbox).
|
||||
|
||||
Algorithms: `halcon_enhance_image`, `halcon_find_circles` (edge-fit + metrology,
|
||||
same chain as `examples/find_circles.hdvp`), `halcon_measure_metrology`
|
||||
(circle/line/rectangle2), `halcon_match_shape` (2D shape-based matching).
|
||||
|
||||
`halcon_teach_roi`'s output feeds `halcon_find_circles` / `halcon_match_shape` /
|
||||
`halcon_measure_metrology` as their `roi_file` / `template_roi`.
|
||||
|
||||
## Prerequisite (one-time)
|
||||
|
||||
Add `mcp` to the shared venv (mvtec-halcon is already there):
|
||||
|
||||
```bash
|
||||
/mnt/c/Users/NAURA/.local/bin/uv.exe pip install mcp
|
||||
```
|
||||
|
||||
## Register in Claude Code (this WSL)
|
||||
|
||||
A ready config is at the project root as `.mcp.json` (copied from
|
||||
`halcon-mcp/.mcp.json.example`). Or via CLI:
|
||||
|
||||
```bash
|
||||
claude mcp add halcon -- /mnt/c/Users/NAURA/.local/bin/uv.exe run \
|
||||
--directory C:/workspace/agent-studio/halcon-001 python halcon-mcp/server.py
|
||||
```
|
||||
|
||||
Then `/mcp` lists `halcon`. The server is a Windows process launched from WSL;
|
||||
it speaks JSON-RPC over stdio across the interop boundary (verified working).
|
||||
|
||||
## Test without a client
|
||||
|
||||
```bash
|
||||
/mnt/c/Users/NAURA/.local/bin/uv.exe run python halcon-mcp/examples/smoke_test.py
|
||||
```
|
||||
|
||||
## Relationship to this skill
|
||||
|
||||
The skill is the **knowledge** (how to run HALCON here, the manuals, recipes);
|
||||
the MCP server is the **executable surface** built from that knowledge. When a
|
||||
task needs repeatable, parameterized calls (enhance / find circles / metrology /
|
||||
matching / run a script), prefer the `halcon_*` MCP tools; for one-off custom
|
||||
pipelines, use the skill's `scripts/` runners or write an `.hdvp`.
|
||||
@@ -0,0 +1,41 @@
|
||||
# HALCON 24.11 算子参考索引 (Operator Reference Index)
|
||||
|
||||
面向 Halcon skills / Agent 检索用的离线索引,数据源为 MVTec 官方在线参考
|
||||
`https://www.mvtec.com/doc/halcon/2411/en/`(版本 24.11.2.0,公开无需登录)。
|
||||
|
||||
## 文件
|
||||
|
||||
| 文件 | 内容 |
|
||||
|---|---|
|
||||
| `operators.csv` | 全部算子 `operator,doc_url`(2387 行)。程序化检索首选。 |
|
||||
| `operators.txt` | 纯算子名列表,一行一个。`grep` 快查用。 |
|
||||
| `categories.md` | 算子分类目录树(29 个顶级章节 / 219 个 TOC 页),每个 TOC 页 URL 列出该类算子。 |
|
||||
|
||||
## 用法
|
||||
|
||||
**按名查文档**(拼出算子文档页):
|
||||
```
|
||||
https://www.mvtec.com/doc/halcon/2411/en/<operator>.html
|
||||
# 例: gen_measure_rectangle2 -> .../gen_measure_rectangle2.html
|
||||
```
|
||||
|
||||
**模糊找算子**:
|
||||
```bash
|
||||
grep -i circle operators.txt # 找圆相关算子
|
||||
grep -iE 'measure|metrology' operators.txt
|
||||
```
|
||||
|
||||
**按功能定位**(先查 categories.md 找到对应 TOC 页,再打开看该类下所有算子):
|
||||
- 圆心/边缘亚像素测量 → `toc_2dmetrology` / `toc_1dmeasuring` / `toc_xld_features`
|
||||
- 模板匹配(overlay 粗定位)→ `toc_matching_shapebased` / `toc_matching_correlationbased`
|
||||
- XLD 轮廓/圆拟合 → `toc_xld` 及子类
|
||||
- 标定 → `toc_calibration`
|
||||
|
||||
## 与本项目的对应
|
||||
|
||||
D2W overlay 复核链路常用:`gen_measure_rectangle2` / `measure_pos`(1D 边缘)、
|
||||
`edges_sub_pix` + `select_shape_xld` + `fit_circle_contour_xld`(XLD 圆拟合)、
|
||||
`find_shape_model`(套圈 Mark 粗定位)、`area_center` / `smallest_circle`(圆心统计)。
|
||||
|
||||
> 注:这是**索引**,不含算子正文。正文按需从上面的 URL 现取(或安装本地
|
||||
> HALCON 后从 `$HALCONROOT/doc/html/reference/` 离线读取)。
|
||||
@@ -0,0 +1,223 @@
|
||||
# HALCON 24.11 算子分类目录 (Operator Reference TOC)
|
||||
|
||||
顶级章节 29 个 · TOC 页 219 个 · 算子 2387 个
|
||||
|
||||
- **1dmeasuring** — https://www.mvtec.com/doc/halcon/2411/en/toc_1dmeasuring.html
|
||||
- **2dmetrology** — https://www.mvtec.com/doc/halcon/2411/en/toc_2dmetrology.html
|
||||
- **3dmatching** — https://www.mvtec.com/doc/halcon/2411/en/toc_3dmatching.html
|
||||
- 3dbox — https://www.mvtec.com/doc/halcon/2411/en/toc_3dmatching_3dbox.html
|
||||
- 3dgrippingpointdetection — https://www.mvtec.com/doc/halcon/2411/en/toc_3dmatching_3dgrippingpointdetection.html
|
||||
- deep3dmatching — https://www.mvtec.com/doc/halcon/2411/en/toc_3dmatching_deep3dmatching.html
|
||||
- deformablesurfacebased — https://www.mvtec.com/doc/halcon/2411/en/toc_3dmatching_deformablesurfacebased.html
|
||||
- shapebased — https://www.mvtec.com/doc/halcon/2411/en/toc_3dmatching_shapebased.html
|
||||
- surfacebased — https://www.mvtec.com/doc/halcon/2411/en/toc_3dmatching_surfacebased.html
|
||||
- **3dobjectmodel** — https://www.mvtec.com/doc/halcon/2411/en/toc_3dobjectmodel.html
|
||||
- creation — https://www.mvtec.com/doc/halcon/2411/en/toc_3dobjectmodel_creation.html
|
||||
- features — https://www.mvtec.com/doc/halcon/2411/en/toc_3dobjectmodel_features.html
|
||||
- segmentation — https://www.mvtec.com/doc/halcon/2411/en/toc_3dobjectmodel_segmentation.html
|
||||
- transformations — https://www.mvtec.com/doc/halcon/2411/en/toc_3dobjectmodel_transformations.html
|
||||
- **3dreconstruction** — https://www.mvtec.com/doc/halcon/2411/en/toc_3dreconstruction.html
|
||||
- binocularstereo — https://www.mvtec.com/doc/halcon/2411/en/toc_3dreconstruction_binocularstereo.html
|
||||
- depthfromfocus — https://www.mvtec.com/doc/halcon/2411/en/toc_3dreconstruction_depthfromfocus.html
|
||||
- multiviewstereo — https://www.mvtec.com/doc/halcon/2411/en/toc_3dreconstruction_multiviewstereo.html
|
||||
- photometricstereo — https://www.mvtec.com/doc/halcon/2411/en/toc_3dreconstruction_photometricstereo.html
|
||||
- sheetoflight — https://www.mvtec.com/doc/halcon/2411/en/toc_3dreconstruction_sheetoflight.html
|
||||
- structuredlight — https://www.mvtec.com/doc/halcon/2411/en/toc_3dreconstruction_structuredlight.html
|
||||
- **calibration** — https://www.mvtec.com/doc/halcon/2411/en/toc_calibration.html
|
||||
- binocular — https://www.mvtec.com/doc/halcon/2411/en/toc_calibration_binocular.html
|
||||
- calibrationobject — https://www.mvtec.com/doc/halcon/2411/en/toc_calibration_calibrationobject.html
|
||||
- cameraparameters — https://www.mvtec.com/doc/halcon/2411/en/toc_calibration_cameraparameters.html
|
||||
- handeye — https://www.mvtec.com/doc/halcon/2411/en/toc_calibration_handeye.html
|
||||
- inverseprojection — https://www.mvtec.com/doc/halcon/2411/en/toc_calibration_inverseprojection.html
|
||||
- monocular — https://www.mvtec.com/doc/halcon/2411/en/toc_calibration_monocular.html
|
||||
- multiview — https://www.mvtec.com/doc/halcon/2411/en/toc_calibration_multiview.html
|
||||
- projection — https://www.mvtec.com/doc/halcon/2411/en/toc_calibration_projection.html
|
||||
- rectification — https://www.mvtec.com/doc/halcon/2411/en/toc_calibration_rectification.html
|
||||
- selfcalibration — https://www.mvtec.com/doc/halcon/2411/en/toc_calibration_selfcalibration.html
|
||||
- **classification** — https://www.mvtec.com/doc/halcon/2411/en/toc_classification.html
|
||||
- gaussianmixturemodels — https://www.mvtec.com/doc/halcon/2411/en/toc_classification_gaussianmixturemodels.html
|
||||
- knearestneighbor — https://www.mvtec.com/doc/halcon/2411/en/toc_classification_knearestneighbor.html
|
||||
- lookuptable — https://www.mvtec.com/doc/halcon/2411/en/toc_classification_lookuptable.html
|
||||
- misc — https://www.mvtec.com/doc/halcon/2411/en/toc_classification_misc.html
|
||||
- neuralnets — https://www.mvtec.com/doc/halcon/2411/en/toc_classification_neuralnets.html
|
||||
- supportvectormachines — https://www.mvtec.com/doc/halcon/2411/en/toc_classification_supportvectormachines.html
|
||||
- **control** — https://www.mvtec.com/doc/halcon/2411/en/toc_control.html
|
||||
- **deeplearning** — https://www.mvtec.com/doc/halcon/2411/en/toc_deeplearning.html
|
||||
- anomalydetection — https://www.mvtec.com/doc/halcon/2411/en/toc_deeplearning_anomalydetection.html
|
||||
- classification — https://www.mvtec.com/doc/halcon/2411/en/toc_deeplearning_classification.html
|
||||
- framework — https://www.mvtec.com/doc/halcon/2411/en/toc_deeplearning_framework.html
|
||||
- model — https://www.mvtec.com/doc/halcon/2411/en/toc_deeplearning_model.html
|
||||
- multilabelclassification — https://www.mvtec.com/doc/halcon/2411/en/toc_deeplearning_multilabelclassification.html
|
||||
- objectdetection — https://www.mvtec.com/doc/halcon/2411/en/toc_deeplearning_objectdetection.html
|
||||
- semanticsegmentation — https://www.mvtec.com/doc/halcon/2411/en/toc_deeplearning_semanticsegmentation.html
|
||||
- **develop** — https://www.mvtec.com/doc/halcon/2411/en/toc_develop.html
|
||||
- **file** — https://www.mvtec.com/doc/halcon/2411/en/toc_file.html
|
||||
- access — https://www.mvtec.com/doc/halcon/2411/en/toc_file_access.html
|
||||
- images — https://www.mvtec.com/doc/halcon/2411/en/toc_file_images.html
|
||||
- misc — https://www.mvtec.com/doc/halcon/2411/en/toc_file_misc.html
|
||||
- object — https://www.mvtec.com/doc/halcon/2411/en/toc_file_object.html
|
||||
- region — https://www.mvtec.com/doc/halcon/2411/en/toc_file_region.html
|
||||
- tuple — https://www.mvtec.com/doc/halcon/2411/en/toc_file_tuple.html
|
||||
- xld — https://www.mvtec.com/doc/halcon/2411/en/toc_file_xld.html
|
||||
- **filters** — https://www.mvtec.com/doc/halcon/2411/en/toc_filters.html
|
||||
- arithmetic — https://www.mvtec.com/doc/halcon/2411/en/toc_filters_arithmetic.html
|
||||
- bit — https://www.mvtec.com/doc/halcon/2411/en/toc_filters_bit.html
|
||||
- color — https://www.mvtec.com/doc/halcon/2411/en/toc_filters_color.html
|
||||
- edges — https://www.mvtec.com/doc/halcon/2411/en/toc_filters_edges.html
|
||||
- enhancement — https://www.mvtec.com/doc/halcon/2411/en/toc_filters_enhancement.html
|
||||
- fft — https://www.mvtec.com/doc/halcon/2411/en/toc_filters_fft.html
|
||||
- geometrictransformations — https://www.mvtec.com/doc/halcon/2411/en/toc_filters_geometrictransformations.html
|
||||
- inpainting — https://www.mvtec.com/doc/halcon/2411/en/toc_filters_inpainting.html
|
||||
- lines — https://www.mvtec.com/doc/halcon/2411/en/toc_filters_lines.html
|
||||
- match — https://www.mvtec.com/doc/halcon/2411/en/toc_filters_match.html
|
||||
- misc — https://www.mvtec.com/doc/halcon/2411/en/toc_filters_misc.html
|
||||
- noise — https://www.mvtec.com/doc/halcon/2411/en/toc_filters_noise.html
|
||||
- opticalflow — https://www.mvtec.com/doc/halcon/2411/en/toc_filters_opticalflow.html
|
||||
- points — https://www.mvtec.com/doc/halcon/2411/en/toc_filters_points.html
|
||||
- sceneflow — https://www.mvtec.com/doc/halcon/2411/en/toc_filters_sceneflow.html
|
||||
- smoothing — https://www.mvtec.com/doc/halcon/2411/en/toc_filters_smoothing.html
|
||||
- texture — https://www.mvtec.com/doc/halcon/2411/en/toc_filters_texture.html
|
||||
- wienerfilter — https://www.mvtec.com/doc/halcon/2411/en/toc_filters_wienerfilter.html
|
||||
- **graphics** — https://www.mvtec.com/doc/halcon/2411/en/toc_graphics.html
|
||||
- 3dscene — https://www.mvtec.com/doc/halcon/2411/en/toc_graphics_3dscene.html
|
||||
- drawing — https://www.mvtec.com/doc/halcon/2411/en/toc_graphics_drawing.html
|
||||
- lut — https://www.mvtec.com/doc/halcon/2411/en/toc_graphics_lut.html
|
||||
- mouse — https://www.mvtec.com/doc/halcon/2411/en/toc_graphics_mouse.html
|
||||
- object — https://www.mvtec.com/doc/halcon/2411/en/toc_graphics_object.html
|
||||
- output — https://www.mvtec.com/doc/halcon/2411/en/toc_graphics_output.html
|
||||
- parameters — https://www.mvtec.com/doc/halcon/2411/en/toc_graphics_parameters.html
|
||||
- text — https://www.mvtec.com/doc/halcon/2411/en/toc_graphics_text.html
|
||||
- window — https://www.mvtec.com/doc/halcon/2411/en/toc_graphics_window.html
|
||||
- **identification** — https://www.mvtec.com/doc/halcon/2411/en/toc_identification.html
|
||||
- barcode — https://www.mvtec.com/doc/halcon/2411/en/toc_identification_barcode.html
|
||||
- datacode — https://www.mvtec.com/doc/halcon/2411/en/toc_identification_datacode.html
|
||||
- **image** — https://www.mvtec.com/doc/halcon/2411/en/toc_image.html
|
||||
- access — https://www.mvtec.com/doc/halcon/2411/en/toc_image_access.html
|
||||
- acquisition — https://www.mvtec.com/doc/halcon/2411/en/toc_image_acquisition.html
|
||||
- channel — https://www.mvtec.com/doc/halcon/2411/en/toc_image_channel.html
|
||||
- creation — https://www.mvtec.com/doc/halcon/2411/en/toc_image_creation.html
|
||||
- domain — https://www.mvtec.com/doc/halcon/2411/en/toc_image_domain.html
|
||||
- features — https://www.mvtec.com/doc/halcon/2411/en/toc_image_features.html
|
||||
- format — https://www.mvtec.com/doc/halcon/2411/en/toc_image_format.html
|
||||
- manipulation — https://www.mvtec.com/doc/halcon/2411/en/toc_image_manipulation.html
|
||||
- typeconversion — https://www.mvtec.com/doc/halcon/2411/en/toc_image_typeconversion.html
|
||||
- **inspection** — https://www.mvtec.com/doc/halcon/2411/en/toc_inspection.html
|
||||
- beadinspection — https://www.mvtec.com/doc/halcon/2411/en/toc_inspection_beadinspection.html
|
||||
- ocv — https://www.mvtec.com/doc/halcon/2411/en/toc_inspection_ocv.html
|
||||
- structuredlight — https://www.mvtec.com/doc/halcon/2411/en/toc_inspection_structuredlight.html
|
||||
- texture — https://www.mvtec.com/doc/halcon/2411/en/toc_inspection_texture.html
|
||||
- variationmodel — https://www.mvtec.com/doc/halcon/2411/en/toc_inspection_variationmodel.html
|
||||
- **legacy** — https://www.mvtec.com/doc/halcon/2411/en/toc_legacy.html
|
||||
- 2dmetrology — https://www.mvtec.com/doc/halcon/2411/en/toc_legacy_2dmetrology.html
|
||||
- classification — https://www.mvtec.com/doc/halcon/2411/en/toc_legacy_classification.html
|
||||
- control — https://www.mvtec.com/doc/halcon/2411/en/toc_legacy_control.html
|
||||
- develop — https://www.mvtec.com/doc/halcon/2411/en/toc_legacy_develop.html
|
||||
- filters — https://www.mvtec.com/doc/halcon/2411/en/toc_legacy_filters.html
|
||||
- graphics — https://www.mvtec.com/doc/halcon/2411/en/toc_legacy_graphics.html
|
||||
- identification — https://www.mvtec.com/doc/halcon/2411/en/toc_legacy_identification.html
|
||||
- legdlclassification — https://www.mvtec.com/doc/halcon/2411/en/toc_legacy_legdlclassification.html
|
||||
- legmatchcomp — https://www.mvtec.com/doc/halcon/2411/en/toc_legacy_legmatchcomp.html
|
||||
- matching — https://www.mvtec.com/doc/halcon/2411/en/toc_legacy_matching.html
|
||||
- morphology — https://www.mvtec.com/doc/halcon/2411/en/toc_legacy_morphology.html
|
||||
- ocr — https://www.mvtec.com/doc/halcon/2411/en/toc_legacy_ocr.html
|
||||
- regions — https://www.mvtec.com/doc/halcon/2411/en/toc_legacy_regions.html
|
||||
- segmentation — https://www.mvtec.com/doc/halcon/2411/en/toc_legacy_segmentation.html
|
||||
- tools — https://www.mvtec.com/doc/halcon/2411/en/toc_legacy_tools.html
|
||||
- xld — https://www.mvtec.com/doc/halcon/2411/en/toc_legacy_xld.html
|
||||
- **matching** — https://www.mvtec.com/doc/halcon/2411/en/toc_matching.html
|
||||
- correlationbased — https://www.mvtec.com/doc/halcon/2411/en/toc_matching_correlationbased.html
|
||||
- deepcounting — https://www.mvtec.com/doc/halcon/2411/en/toc_matching_deepcounting.html
|
||||
- deformable — https://www.mvtec.com/doc/halcon/2411/en/toc_matching_deformable.html
|
||||
- descriptorbased — https://www.mvtec.com/doc/halcon/2411/en/toc_matching_descriptorbased.html
|
||||
- shapebased — https://www.mvtec.com/doc/halcon/2411/en/toc_matching_shapebased.html
|
||||
- **matrix** — https://www.mvtec.com/doc/halcon/2411/en/toc_matrix.html
|
||||
- access — https://www.mvtec.com/doc/halcon/2411/en/toc_matrix_access.html
|
||||
- arithmetic — https://www.mvtec.com/doc/halcon/2411/en/toc_matrix_arithmetic.html
|
||||
- creation — https://www.mvtec.com/doc/halcon/2411/en/toc_matrix_creation.html
|
||||
- decomposition — https://www.mvtec.com/doc/halcon/2411/en/toc_matrix_decomposition.html
|
||||
- eigenvalues — https://www.mvtec.com/doc/halcon/2411/en/toc_matrix_eigenvalues.html
|
||||
- features — https://www.mvtec.com/doc/halcon/2411/en/toc_matrix_features.html
|
||||
- file — https://www.mvtec.com/doc/halcon/2411/en/toc_matrix_file.html
|
||||
- **morphology** — https://www.mvtec.com/doc/halcon/2411/en/toc_morphology.html
|
||||
- grayvalues — https://www.mvtec.com/doc/halcon/2411/en/toc_morphology_grayvalues.html
|
||||
- region — https://www.mvtec.com/doc/halcon/2411/en/toc_morphology_region.html
|
||||
- **object** — https://www.mvtec.com/doc/halcon/2411/en/toc_object.html
|
||||
- information — https://www.mvtec.com/doc/halcon/2411/en/toc_object_information.html
|
||||
- manipulation — https://www.mvtec.com/doc/halcon/2411/en/toc_object_manipulation.html
|
||||
- **ocr** — https://www.mvtec.com/doc/halcon/2411/en/toc_ocr.html
|
||||
- convolutionalneuralnets — https://www.mvtec.com/doc/halcon/2411/en/toc_ocr_convolutionalneuralnets.html
|
||||
- deepocr — https://www.mvtec.com/doc/halcon/2411/en/toc_ocr_deepocr.html
|
||||
- knearestneighbor — https://www.mvtec.com/doc/halcon/2411/en/toc_ocr_knearestneighbor.html
|
||||
- lexica — https://www.mvtec.com/doc/halcon/2411/en/toc_ocr_lexica.html
|
||||
- neuralnets — https://www.mvtec.com/doc/halcon/2411/en/toc_ocr_neuralnets.html
|
||||
- segmentation — https://www.mvtec.com/doc/halcon/2411/en/toc_ocr_segmentation.html
|
||||
- supportvectormachines — https://www.mvtec.com/doc/halcon/2411/en/toc_ocr_supportvectormachines.html
|
||||
- trainingfiles — https://www.mvtec.com/doc/halcon/2411/en/toc_ocr_trainingfiles.html
|
||||
- **regions** — https://www.mvtec.com/doc/halcon/2411/en/toc_regions.html
|
||||
- access — https://www.mvtec.com/doc/halcon/2411/en/toc_regions_access.html
|
||||
- creation — https://www.mvtec.com/doc/halcon/2411/en/toc_regions_creation.html
|
||||
- features — https://www.mvtec.com/doc/halcon/2411/en/toc_regions_features.html
|
||||
- geometrictransformations — https://www.mvtec.com/doc/halcon/2411/en/toc_regions_geometrictransformations.html
|
||||
- sets — https://www.mvtec.com/doc/halcon/2411/en/toc_regions_sets.html
|
||||
- tests — https://www.mvtec.com/doc/halcon/2411/en/toc_regions_tests.html
|
||||
- transformations — https://www.mvtec.com/doc/halcon/2411/en/toc_regions_transformations.html
|
||||
- **segmentation** — https://www.mvtec.com/doc/halcon/2411/en/toc_segmentation.html
|
||||
- classification — https://www.mvtec.com/doc/halcon/2411/en/toc_segmentation_classification.html
|
||||
- edges — https://www.mvtec.com/doc/halcon/2411/en/toc_segmentation_edges.html
|
||||
- mser — https://www.mvtec.com/doc/halcon/2411/en/toc_segmentation_mser.html
|
||||
- regiongrowing — https://www.mvtec.com/doc/halcon/2411/en/toc_segmentation_regiongrowing.html
|
||||
- threshold — https://www.mvtec.com/doc/halcon/2411/en/toc_segmentation_threshold.html
|
||||
- topography — https://www.mvtec.com/doc/halcon/2411/en/toc_segmentation_topography.html
|
||||
- **system** — https://www.mvtec.com/doc/halcon/2411/en/toc_system.html
|
||||
- computedevices — https://www.mvtec.com/doc/halcon/2411/en/toc_system_computedevices.html
|
||||
- database — https://www.mvtec.com/doc/halcon/2411/en/toc_system_database.html
|
||||
- encrypteditem — https://www.mvtec.com/doc/halcon/2411/en/toc_system_encrypteditem.html
|
||||
- errorhandling — https://www.mvtec.com/doc/halcon/2411/en/toc_system_errorhandling.html
|
||||
- information — https://www.mvtec.com/doc/halcon/2411/en/toc_system_information.html
|
||||
- iodevices — https://www.mvtec.com/doc/halcon/2411/en/toc_system_iodevices.html
|
||||
- memoryblock — https://www.mvtec.com/doc/halcon/2411/en/toc_system_memoryblock.html
|
||||
- multithreading — https://www.mvtec.com/doc/halcon/2411/en/toc_system_multithreading.html
|
||||
- operatingsystem — https://www.mvtec.com/doc/halcon/2411/en/toc_system_operatingsystem.html
|
||||
- parallelization — https://www.mvtec.com/doc/halcon/2411/en/toc_system_parallelization.html
|
||||
- parameters — https://www.mvtec.com/doc/halcon/2411/en/toc_system_parameters.html
|
||||
- serial — https://www.mvtec.com/doc/halcon/2411/en/toc_system_serial.html
|
||||
- serializeditem — https://www.mvtec.com/doc/halcon/2411/en/toc_system_serializeditem.html
|
||||
- sockets — https://www.mvtec.com/doc/halcon/2411/en/toc_system_sockets.html
|
||||
- **tools** — https://www.mvtec.com/doc/halcon/2411/en/toc_tools.html
|
||||
- backgroundestimator — https://www.mvtec.com/doc/halcon/2411/en/toc_tools_backgroundestimator.html
|
||||
- function — https://www.mvtec.com/doc/halcon/2411/en/toc_tools_function.html
|
||||
- geometry — https://www.mvtec.com/doc/halcon/2411/en/toc_tools_geometry.html
|
||||
- gridrectification — https://www.mvtec.com/doc/halcon/2411/en/toc_tools_gridrectification.html
|
||||
- hough — https://www.mvtec.com/doc/halcon/2411/en/toc_tools_hough.html
|
||||
- interpolation — https://www.mvtec.com/doc/halcon/2411/en/toc_tools_interpolation.html
|
||||
- lines — https://www.mvtec.com/doc/halcon/2411/en/toc_tools_lines.html
|
||||
- mosaicking — https://www.mvtec.com/doc/halcon/2411/en/toc_tools_mosaicking.html
|
||||
- **transformations** — https://www.mvtec.com/doc/halcon/2411/en/toc_transformations.html
|
||||
- 2dtransformations — https://www.mvtec.com/doc/halcon/2411/en/toc_transformations_2dtransformations.html
|
||||
- 3dtransformations — https://www.mvtec.com/doc/halcon/2411/en/toc_transformations_3dtransformations.html
|
||||
- dualquaternions — https://www.mvtec.com/doc/halcon/2411/en/toc_transformations_dualquaternions.html
|
||||
- misc — https://www.mvtec.com/doc/halcon/2411/en/toc_transformations_misc.html
|
||||
- poses — https://www.mvtec.com/doc/halcon/2411/en/toc_transformations_poses.html
|
||||
- quaternions — https://www.mvtec.com/doc/halcon/2411/en/toc_transformations_quaternions.html
|
||||
- **tuple** — https://www.mvtec.com/doc/halcon/2411/en/toc_tuple.html
|
||||
- arithmetic — https://www.mvtec.com/doc/halcon/2411/en/toc_tuple_arithmetic.html
|
||||
- bitoperations — https://www.mvtec.com/doc/halcon/2411/en/toc_tuple_bitoperations.html
|
||||
- comparison — https://www.mvtec.com/doc/halcon/2411/en/toc_tuple_comparison.html
|
||||
- containers — https://www.mvtec.com/doc/halcon/2411/en/toc_tuple_containers.html
|
||||
- conversion — https://www.mvtec.com/doc/halcon/2411/en/toc_tuple_conversion.html
|
||||
- creation — https://www.mvtec.com/doc/halcon/2411/en/toc_tuple_creation.html
|
||||
- elementorder — https://www.mvtec.com/doc/halcon/2411/en/toc_tuple_elementorder.html
|
||||
- features — https://www.mvtec.com/doc/halcon/2411/en/toc_tuple_features.html
|
||||
- logicaloperations — https://www.mvtec.com/doc/halcon/2411/en/toc_tuple_logicaloperations.html
|
||||
- manipulation — https://www.mvtec.com/doc/halcon/2411/en/toc_tuple_manipulation.html
|
||||
- selection — https://www.mvtec.com/doc/halcon/2411/en/toc_tuple_selection.html
|
||||
- sets — https://www.mvtec.com/doc/halcon/2411/en/toc_tuple_sets.html
|
||||
- stringoperations — https://www.mvtec.com/doc/halcon/2411/en/toc_tuple_stringoperations.html
|
||||
- type — https://www.mvtec.com/doc/halcon/2411/en/toc_tuple_type.html
|
||||
- **xld** — https://www.mvtec.com/doc/halcon/2411/en/toc_xld.html
|
||||
- access — https://www.mvtec.com/doc/halcon/2411/en/toc_xld_access.html
|
||||
- creation — https://www.mvtec.com/doc/halcon/2411/en/toc_xld_creation.html
|
||||
- features — https://www.mvtec.com/doc/halcon/2411/en/toc_xld_features.html
|
||||
- geometrictransformations — https://www.mvtec.com/doc/halcon/2411/en/toc_xld_geometrictransformations.html
|
||||
- sets — https://www.mvtec.com/doc/halcon/2411/en/toc_xld_sets.html
|
||||
- transformations — https://www.mvtec.com/doc/halcon/2411/en/toc_xld_transformations.html
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -0,0 +1,96 @@
|
||||
# Remote HALCON over MCP (`halcon-remote`)
|
||||
|
||||
A **remote** HALCON compute service exposed as an MCP server. Use it when there is
|
||||
**no local HALCON** (e.g. MacOS, a plain Linux box, a colleague's machine) — it runs
|
||||
HALCON 24.11 on a headless Linux server and is reachable over the public internet.
|
||||
Client needs only network + a bearer token; **no HALCON, no minio creds, no VPN/tailnet.**
|
||||
|
||||
- Endpoint: `https://halcon-mcp.totoro.studio/mcp` (Streamable HTTP, Bearer auth)
|
||||
- Token: server-side `/opt/halcon-mcp/.env` (`HALCON_MCP_TOKEN`); in configs reference `${HALCON_MCP_TOKEN}`, never hardcode.
|
||||
- Source/ops: repo `halcon-mcp-remote/`; server `192.168.1.13:/opt/halcon-mcp` (systemd `halcon-mcp`). Full deploy facts: repo `halcon-tools.yaml` → `halcon_mcp_remote`.
|
||||
|
||||
## Register the server (client side)
|
||||
|
||||
```bash
|
||||
# user scope (works across all projects)
|
||||
claude mcp add --scope user --transport http halcon-remote \
|
||||
https://halcon-mcp.totoro.studio/mcp --header "Authorization: Bearer $HALCON_MCP_TOKEN"
|
||||
claude mcp list # expect: halcon-remote ... ✔ Connected
|
||||
```
|
||||
Or project `.mcp.json`: `{ "type":"http", "url":".../mcp", "headers":{"Authorization":"Bearer ${HALCON_MCP_TOKEN}"} }`.
|
||||
|
||||
## Tools (full names: `mcp__halcon-remote__<tool>`)
|
||||
|
||||
| Tool | Does | Key args |
|
||||
|---|---|---|
|
||||
| `halcon_get_env` | Self-check: version/hostid/arch | — |
|
||||
| `halcon_create_upload` | Presigned PUT URL to upload one file (image or zip), no creds | `filename`, `expires_minutes` |
|
||||
| `halcon_find_circles` | Subpixel find circles → list + preview | `image` or `image_b64` |
|
||||
| `halcon_measure_overlay` | Bullseye overlay: Top/Bottom center deviation (µm) | `image` or `image_b64`, `apply_registration` |
|
||||
| `halcon_overlay_batch` | Batch overlay over a minio prefix → CSV | `prefix`, `max_images` |
|
||||
| `halcon_find_circles_zip` | Batch find circles: image zip → 4 ring-mark centers (TL/TR/BL/BR) → CSV | `zip_key`, `min/max_radius` |
|
||||
| `halcon_exec_hdev` | Run an HDevelop script via hrun → stdout (destructive) | `script_text` |
|
||||
|
||||
## Image I/O — how images get in and results out
|
||||
|
||||
An `image` argument accepts one of:
|
||||
- `file:/abs/path` — a file **on the server** (testing only; e.g. `file:/tmp/amm_test/2-zuoshang.bmp`).
|
||||
- `<key>` — a minio object key in the default bucket `halcon` (e.g. `inbox/die.png`).
|
||||
- `minio://<bucket>/<key>` — explicit bucket.
|
||||
|
||||
Or pass `image_b64` (inline base64, may include `data:` prefix) — best for a **single small image**, no upload step.
|
||||
|
||||
Results: numeric metrics come back **inline** (structuredContent). Heavy artifacts (preview jpg, CSV) are
|
||||
uploaded to minio and returned as a **key + presigned URL** on the **public** host `minio-home.totoro.studio`
|
||||
(openable from anywhere). Small files (preview/CSV) — just GET the URL.
|
||||
|
||||
## Three usage patterns (pick by size)
|
||||
|
||||
**1. Single small image → inline (simplest).**
|
||||
```
|
||||
halcon_measure_overlay(image_b64="<base64 of the bullseye image>")
|
||||
→ {status:"ok", overlay_dX_um, overlay_dY_um, top/bottom centers, n_circles}
|
||||
```
|
||||
|
||||
**2. Single/few images from an external client → presigned PUT (no creds).**
|
||||
```
|
||||
k = halcon_create_upload(filename="die.bmp") # → {put_url, key}
|
||||
curl -T die.bmp "<put_url>" # public PUT, no creds
|
||||
halcon_measure_overlay(image=k.key)
|
||||
```
|
||||
|
||||
**3. Large batch (hundreds–thousands) → zip once, then process (recommended).**
|
||||
Zip is the right move: one file = one upload = works with presigned PUT (external users too),
|
||||
vs mirroring many files (needs minio creds).
|
||||
```
|
||||
zip -0 -q -j batch.zip *.png # store mode (PNG already compressed)
|
||||
k = halcon_create_upload(filename="batch.zip")
|
||||
curl -T batch.zip "<k.put_url>" # one PUT
|
||||
halcon_find_circles_zip(zip_key=k.key) # server unzips + batch + CSV
|
||||
→ {total, ok, seconds, per_image_ms, csv_key, csv_url}
|
||||
# then GET csv_url
|
||||
```
|
||||
CSV columns: `file,status,n_found,TL_col,TL_row,TL_r,TR_...,BL_...,BR_...` (4 ring-mark centers per image, ordered by position).
|
||||
|
||||
## D2W overlay conventions (this project's domain)
|
||||
|
||||
- Axes: **X = image right +, Y = image up +**; pixel size **271.048 nm/px**; overlay = **Bottom − Top**.
|
||||
- Mark grouping: outer thick ring = **Top Die Mark**; inner dot + mid ring = **Bottom Die Mark**.
|
||||
- `apply_registration=True` adds the +13.5/+9.6 nm offset (0627-JC 2-point calibration; drop for other tools/batches).
|
||||
- Sanity values (die-2 four corners, raw dev µm): TL −0.778/+0.794 · TR −0.265/+0.391 · BL −0.171/+1.022 · BR +0.230/+0.435.
|
||||
|
||||
## Performance (measured, single HALCON process, 16 threads)
|
||||
|
||||
- find_circles on 5312×4608 (24MP): **~92 ms/image** (~11 img/s). 1920 images ≈ **176 s compute**.
|
||||
- 90 MB zip public PUT: ~20 s. End-to-end 1920 images ≈ **3.3 min**.
|
||||
- Circle-center repeatability across 1920 shots: std **0.01–0.04 px**.
|
||||
|
||||
## Gotchas
|
||||
|
||||
- **Sync execution.** `halcon_find_circles_zip` / `halcon_overlay_batch` run synchronously. ~1920 images (~3 min)
|
||||
is near the comfortable ceiling — set a **long client timeout**. For much larger jobs, chunk or use async (not yet built).
|
||||
- **License `SESSIONS=1`** → cannot multi-process; rely on HALCON's internal 16-thread parallelization (already fast).
|
||||
- **Preview/CSV URLs use `minio-home.totoro.studio`** (public), not the internal `192.168.1.2:9000` — openable off-LAN.
|
||||
- **Big batches:** always zip (one PUT). Per-file `create_upload` for N files is N round-trips — only for a handful.
|
||||
- **`file:` paths are server-side**, not the client's filesystem — only for images already on `192.168.1.13`.
|
||||
- Tool errors return `isError` + an actionable message (e.g. "先用 halcon_create_upload 传图") — read it and self-correct.
|
||||
@@ -0,0 +1,197 @@
|
||||
# HALCON task recipes
|
||||
|
||||
Ready-to-adapt pipelines for common vision tasks. Each recipe is a **procedure**
|
||||
(a reusable method), not a one-off — read the operator names, adapt parameters,
|
||||
then run via HDevEngine (`scripts/run_procedure.py`) or `hrun`. For exact
|
||||
parameter semantics open the referenced pages (see `doc-map.md`); for the
|
||||
authoritative operator signature, target `reference_hdevelop.pdf`.
|
||||
|
||||
Conventions used below: `Image` = input, `Region`/`Roi` = ROI, `Contours` = XLD
|
||||
(subpixel contours), `*Handle` = a model handle that must be `clear_*`ed.
|
||||
|
||||
## Meta-pattern: procedure + Python driver (the house style)
|
||||
|
||||
This is how the tested pipeline in `references/examples/` is built — copy it.
|
||||
|
||||
1. Write an `.hdvp` external procedure with **control** inputs/outputs only
|
||||
(paths in, numbers/tuples out). No `draw_*`, no `stop()`. Validate inside and
|
||||
`throw` on unexpected results.
|
||||
2. Persist any human-taught ROI once with `teach_roi.py` → `roi.hobj`; the
|
||||
procedure `read_region`s it.
|
||||
3. Drive from Python with HDevEngine: loop images, `set_input_control_param_by_name`,
|
||||
`execute` (wrapped in `try/except HDevEngineError`), `get_output_control_param_by_name`,
|
||||
aggregate, write CSV.
|
||||
|
||||
Reference implementation (bundled): `references/examples/find_circles.hdvp` +
|
||||
`references/examples/run_compare.py`. Skeleton procedure body:
|
||||
|
||||
```
|
||||
read_image (Image, ImageFile)
|
||||
read_region (Roi, RoiFile)
|
||||
reduce_domain (Image, Roi, ImageReduced) * restrict processing to the ROI
|
||||
* ... task-specific operators ...
|
||||
if (|Result| != Expected)
|
||||
throw ('unexpected count: ' + |Result|) * driver catches & skips
|
||||
endif
|
||||
```
|
||||
|
||||
## Blob analysis (segment by gray value, measure regions)
|
||||
|
||||
Goal: find objects that differ in brightness, count/measure them.
|
||||
|
||||
```
|
||||
threshold (ImageReduced, Region, MinGray, MaxGray) * or auto_threshold / binary_threshold
|
||||
connection (Region, ConnectedRegions) * split into individual blobs
|
||||
select_shape (ConnectedRegions, Selected, 'area', 'and', MinArea, MaxArea)
|
||||
area_center (Selected, Area, Row, Col) * features per blob
|
||||
```
|
||||
|
||||
Key knobs: pick the threshold from the histogram (`gray_histo`), or use
|
||||
`dyn_threshold` against a smoothed copy for uneven lighting. Morphology
|
||||
(`opening_circle`, `closing_circle`) cleans speckle before `connection`.
|
||||
Guide: `solution_guide_i.pdf` ch.4 (p33).
|
||||
|
||||
## Subpixel edges, contours, and shape fitting
|
||||
|
||||
Goal: precise geometry (circle/line/ellipse) from contours.
|
||||
|
||||
```
|
||||
edges_sub_pix (ImageReduced, Edges, 'canny', Alpha, Low, High) * Alpha≈1–3, higher=smoother
|
||||
select_contours_xld (Edges, Sel, 'contour_length', MinLen, MaxLen, -0.5, 0.5)
|
||||
union_adjacent_contours_xld (Sel, Union, 10, 1, 'attr_keep') * join broken arcs
|
||||
sort_contours_xld (Union, Sorted, 'character', 'true', 'column') * deterministic order
|
||||
fit_circle_contour_xld (Sorted, 'algebraic', -1, 0, 0, 3, 2, Row, Col, Radius, S, E, Order)
|
||||
* fit_line_contour_xld / fit_ellipse_contour_xld for other shapes
|
||||
```
|
||||
|
||||
Gotchas: canny thresholds and the length window are the tuning that decides how
|
||||
many contours survive — if the fitted count is wrong, adjust `MinLen/MaxLen` and
|
||||
the ROI tightness before anything else. Guides: `solution_guide_i.pdf` ch.7,9
|
||||
(p63, p79).
|
||||
|
||||
## 2D measuring — metrology model (robust circle/line/rectangle fitting)
|
||||
|
||||
Goal: high-accuracy, repeatable geometry with built-in edge measurement. This is
|
||||
the metrology-model half of the tested `find_circles.hdvp`.
|
||||
|
||||
```
|
||||
create_metrology_model (MetrologyHandle)
|
||||
set_metrology_model_image_size (MetrologyHandle, Width, Height)
|
||||
add_metrology_object_circle_measure (MetrologyHandle, Row, Col, Radius, RadiusTol, \
|
||||
MeasureLen1, MeasureLen2, MeasureSigma, [], [], Indices)
|
||||
set_metrology_object_param (MetrologyHandle, Indices, 'num_instances', 1)
|
||||
set_metrology_object_param (MetrologyHandle, Indices, 'measure_transition', 'positive')
|
||||
set_metrology_object_param (MetrologyHandle, Indices, 'min_score', 0.3)
|
||||
apply_metrology_model (Image, MetrologyHandle)
|
||||
get_metrology_object_result (MetrologyHandle, Indices, 'all', 'result_type', 'all_param', Param)
|
||||
* circle params come back interleaved: Row=Param[0::3], Col=Param[1::3], Radius=Param[2::3]
|
||||
clear_metrology_model (MetrologyHandle)
|
||||
```
|
||||
|
||||
Seed the metrology objects from a rough fit (e.g. `fit_circle_contour_xld`), then
|
||||
let the model refine. Tune `min_score`, `measure_transition`
|
||||
(positive/negative/all), and the radius tolerance. Guide:
|
||||
`solution_guide_iii_b_2d_measuring.pdf` (Basic Tools p11, Tool Selection p27,
|
||||
Examples p35).
|
||||
|
||||
## 1D measuring (calipers along a line or arc)
|
||||
|
||||
Goal: edge positions/widths along a profile (e.g. pin pitch, gap width).
|
||||
|
||||
```
|
||||
gen_measure_rectangle2 (Row, Col, Phi, Length1, Length2, Width, Height, 'nearest_neighbor', Handle)
|
||||
measure_pos (Image, Handle, Sigma, Threshold, 'all', 'all', RowEdge, ColEdge, Amp, Distance)
|
||||
* gen_measure_arc + measure_pos for circular profiles
|
||||
close_measure (Handle)
|
||||
```
|
||||
|
||||
Use the fuzzy measure object (`fuzzy_measure_pos`) when edges are noisy/ambiguous.
|
||||
Guide: `solution_guide_iii_a_1d_measuring.pdf`.
|
||||
|
||||
## 2D matching (locate a known template)
|
||||
|
||||
Goal: find where a trained pattern appears (with rotation/scale), get pose.
|
||||
|
||||
Default = **shape-based matching** (robust to illumination, occlusion):
|
||||
|
||||
```
|
||||
* --- train once, persist the model ---
|
||||
create_shape_model (TemplateImageReduced, 'auto', 0, rad(360), 'auto', 'auto', \
|
||||
'use_polarity', 'auto', 'auto', ModelID)
|
||||
write_shape_model (ModelID, 'model.shm')
|
||||
* --- match at runtime ---
|
||||
read_shape_model ('model.shm', ModelID)
|
||||
find_shape_model (Image, ModelID, 0, rad(360), 0.5, 0, 0.5, 'least_squares', 0, 0.9, \
|
||||
Row, Col, Angle, Score)
|
||||
```
|
||||
|
||||
Alternatives (pick by `solution_guide_ii_b_matching.pdf` ch.3): NCC
|
||||
(`create_ncc_model`) for pure translation/known illumination; component matching
|
||||
for articulated parts; local-deformable/descriptor for deformation/perspective.
|
||||
Guide overview: `solution_guide_i.pdf` ch.10 (p89).
|
||||
|
||||
## 2D data codes (DataMatrix, QR, PDF417) and bar codes
|
||||
|
||||
```
|
||||
create_data_code_2d_model ('Data Matrix ECC 200', [], [], DataCodeHandle)
|
||||
find_data_code_2d (Image, SymbolXLDs, DataCodeHandle, 'stop_after_result_num', 1, \
|
||||
ResultHandles, DecodedStrings)
|
||||
clear_data_code_2d_model (DataCodeHandle)
|
||||
```
|
||||
|
||||
If decoding fails: raise `find_data_code_2d` search effort/timeout params, or
|
||||
preprocess (contrast, `gray_range_rect`, `mean_image`) — see
|
||||
`solution_guide_ii_c_2d_data_codes.pdf` ch.4 (Preprocessing p25), ch.5 (Problem
|
||||
Handling p29). Bar codes: `create_bar_code_model` / `find_bar_code`
|
||||
(`solution_guide_i.pdf` ch.16 p159). Print-quality grading: ch.6 (p45).
|
||||
|
||||
## Camera calibration & world coordinates
|
||||
|
||||
Goal: convert pixel measurements to metric units / correct lens distortion.
|
||||
|
||||
```
|
||||
* grab N images of the HALCON calibration plate at varied poses
|
||||
create_calib_data ('calibration_object', 1, 1, CalibHandle)
|
||||
set_calib_data_cam_param (CalibHandle, 0, [], StartCamPar)
|
||||
set_calib_data_calib_object (CalibHandle, 0, 'caltab.descr')
|
||||
* for each image: find_calib_data_object / set_calib_data_observ_points
|
||||
calibrate_cameras (CalibHandle, Error)
|
||||
get_calib_data (CalibHandle, 'camera', 0, 'params', CamParam)
|
||||
* then set_origin_pose / image_points_to_world_plane for metric measurement in a plane
|
||||
```
|
||||
|
||||
Prefer the **Calibration Assistant** in HDevelop to generate this code
|
||||
(`hdevelop_users_guide.pdf` p184). Theory + full workflow:
|
||||
`solution_guide_iii_c_3d_vision.pdf` ch.2 (p13) and ch.3 (single-camera metric,
|
||||
p59).
|
||||
|
||||
## 3D surface-based matching (point clouds)
|
||||
|
||||
Goal: find the 3D pose of an object in a point cloud / from a CAD model.
|
||||
|
||||
```
|
||||
create_surface_model (ObjectModel3D, RelSamplingDist, [], [], SurfaceModelID)
|
||||
find_surface_model (SurfaceModelID, SceneModel3D, RelSamplingDist, KeyPointFrac, \
|
||||
MinScore, 'true', [], [], Pose, Score, SurfaceMatchingResultID)
|
||||
```
|
||||
|
||||
Data must be a real 3D point cloud with normals. If matches are poor, work
|
||||
through `surface_based_matching.pdf` ch.4 (Troubleshooting p17) and ch.5 (Tips
|
||||
p22); remove the dominant background plane first (ch.6, p26).
|
||||
|
||||
## OCR & classification (brief)
|
||||
|
||||
- **Deep OCR** (default for reading text): `create_deep_ocr` / `apply_deep_ocr`
|
||||
— pretrained, no training needed. `solution_guide_i.pdf` ch.19 (p209).
|
||||
- **Classic OCR**: segment characters → `do_ocr_multi_class_mlp` with a
|
||||
pretrained font. ch.18 (p183).
|
||||
- **Feature classification** (MLP/SVM/GMM/k-NN): train on region features, then
|
||||
classify. `solution_guide_ii_d_classification.pdf` ch.5 (p31).
|
||||
|
||||
## When a recipe isn't enough
|
||||
|
||||
1. Read the matching chapter/pages from `doc-map.md`.
|
||||
2. Confirm exact operator parameters in `reference_hdevelop.pdf` (target pages,
|
||||
don't browse).
|
||||
3. Prototype interactively in HDevelop (or `runScriptInGui`), then freeze the
|
||||
working logic into an `.hdvp` and drive it headless — see the meta-pattern.
|
||||
+40
@@ -0,0 +1,40 @@
|
||||
"""Shared helpers for the HALCON runner scripts."""
|
||||
import re
|
||||
|
||||
_INT_RE = re.compile(r"^[+-]?\d+$")
|
||||
_FLOAT_RE = re.compile(r"^[+-]?(\d+\.\d*|\.\d+|\d+)([eE][+-]?\d+)?$")
|
||||
|
||||
|
||||
def coerce(value: str):
|
||||
"""Turn a CLI string into int/float/str, or a list for comma-separated input.
|
||||
|
||||
Absolute paths (C:/..., /mnt/...) and anything non-numeric stay strings.
|
||||
Use a trailing comma or commas to force a tuple, e.g. '1,2,3' -> [1,2,3].
|
||||
"""
|
||||
if "," in value:
|
||||
return [coerce(v) for v in value.split(",") if v != ""]
|
||||
if _INT_RE.match(value):
|
||||
return int(value)
|
||||
if _FLOAT_RE.match(value) and not value.strip().startswith(("C:", "c:")):
|
||||
return float(value)
|
||||
return value
|
||||
|
||||
|
||||
def jsonable(v):
|
||||
"""Make a HALCON output control value JSON-serializable."""
|
||||
if isinstance(v, (list, tuple)):
|
||||
return [jsonable(x) for x in v]
|
||||
if isinstance(v, (int, float, str, bool)) or v is None:
|
||||
return v
|
||||
return str(v)
|
||||
|
||||
|
||||
def parse_set(pairs):
|
||||
"""['Name=Value', ...] -> [(name, coerced_value), ...]."""
|
||||
out = []
|
||||
for p in pairs or []:
|
||||
if "=" not in p:
|
||||
raise SystemExit(f"--set expects Name=Value, got: {p!r}")
|
||||
name, _, raw = p.partition("=")
|
||||
out.append((name.strip(), coerce(raw)))
|
||||
return out
|
||||
+45
@@ -0,0 +1,45 @@
|
||||
"""Smoke-test the HALCON environment on this machine.
|
||||
|
||||
Verifies: the Python binding loads, the native runtime links, the license is
|
||||
valid (a real operator runs), and HDevEngine imports.
|
||||
|
||||
Run (from the project dir, via uv):
|
||||
/mnt/c/Users/NAURA/.local/bin/uv.exe run python .claude/skills/halcon/scripts/check_env.py
|
||||
"""
|
||||
import sys
|
||||
|
||||
|
||||
def main() -> int:
|
||||
try:
|
||||
import halcon as ha
|
||||
except Exception as e: # binding not installed / wrong interpreter
|
||||
print("FAIL: could not import 'halcon'. Are you running the project venv "
|
||||
"via uv? Error:", e)
|
||||
return 1
|
||||
|
||||
try:
|
||||
print("HALCON library version:", ha.get_system("version"))
|
||||
img = ha.gen_image_const("byte", 64, 48) # exercises the license
|
||||
w = ha.get_image_size(img)
|
||||
print("gen_image_const OK, size (w,h):", w)
|
||||
region = ha.threshold(img, 0, 128)
|
||||
area, _, _ = ha.area_center(region)
|
||||
print("threshold + area_center OK, area:", area)
|
||||
except Exception as e:
|
||||
print("FAIL: an operator call failed. This is usually a LICENSE problem "
|
||||
"(missing/expired monthly .dat in <install>\\license\\). Error:", e)
|
||||
return 2
|
||||
|
||||
try:
|
||||
from halcon.hdevengine import HDevEngine # noqa: F401
|
||||
print("HDevEngine import OK")
|
||||
except Exception as e:
|
||||
print("WARN: HDevEngine import failed:", e)
|
||||
return 3
|
||||
|
||||
print("HALCON environment OK")
|
||||
return 0
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
sys.exit(main())
|
||||
+34
@@ -0,0 +1,34 @@
|
||||
"""Rebuild the bundled PDF table-of-contents index (references/pdf/_toc.json).
|
||||
|
||||
Self-contained: reads every PDF bundled under the skill's references/pdf/ and
|
||||
writes the multi-level TOC next to them. Run after adding/updating manuals.
|
||||
|
||||
/mnt/c/Users/NAURA/.local/bin/uv.exe run --no-project --with pymupdf \
|
||||
python .claude/skills/halcon/scripts/extract_toc.py
|
||||
"""
|
||||
import fitz, os, glob, json
|
||||
|
||||
# references/pdf/ relative to this script (scripts/ -> ../references/pdf)
|
||||
HERE = os.path.dirname(os.path.abspath(__file__))
|
||||
PDF_DIR = os.path.normpath(os.path.join(HERE, "..", "references", "pdf"))
|
||||
OUT = os.path.join(PDF_DIR, "_toc.json")
|
||||
|
||||
out = {}
|
||||
for p in sorted(glob.glob(os.path.join(PDF_DIR, "*.pdf"))):
|
||||
name = os.path.basename(p)
|
||||
try:
|
||||
doc = fitz.open(p)
|
||||
out[name] = {"pages": doc.page_count, "toc": doc.get_toc()} # [level,title,page]
|
||||
doc.close()
|
||||
except Exception as e:
|
||||
out[name] = {"error": str(e)}
|
||||
|
||||
with open(OUT, "w", encoding="utf-8") as f:
|
||||
json.dump(out, f, ensure_ascii=False, indent=1)
|
||||
|
||||
for name, v in out.items():
|
||||
if "error" in v:
|
||||
print(f"{name}: ERROR {v['error']}")
|
||||
else:
|
||||
print(f"{name}: {v['pages']} pages, {len(v['toc'])} toc entries")
|
||||
print("wrote", OUT)
|
||||
+80
@@ -0,0 +1,80 @@
|
||||
"""Run one HDevelop external procedure (.hdvp) via HDevEngine and print outputs.
|
||||
|
||||
This is the generic form of the tested run_compare.py driver. Pass input control
|
||||
params with --set, name the outputs to read with --get; results print as a JSON
|
||||
object on stdout.
|
||||
|
||||
Example:
|
||||
/mnt/c/Users/NAURA/.local/bin/uv.exe run python \
|
||||
.claude/skills/halcon/scripts/run_procedure.py \
|
||||
--proc-path C:/workspace/agent-studio/halcon-001 \
|
||||
--proc find_circles \
|
||||
--set ImageFile=C:/data/a.png \
|
||||
--set RoiFile=C:/workspace/agent-studio/halcon-001/roi.hobj \
|
||||
--get FitRow --get FitCol --get MetroRow --get MetroCol
|
||||
|
||||
Notes:
|
||||
- Always use ABSOLUTE paths for images/ROIs (HDevEngine has no cwd notion).
|
||||
- Numeric --set values are auto-typed; use commas for a tuple (e.g. --set T=10,20).
|
||||
- Wrap in a loop from your own Python for batch processing.
|
||||
"""
|
||||
import argparse
|
||||
import json
|
||||
import sys
|
||||
|
||||
from _common import parse_set, jsonable
|
||||
|
||||
|
||||
def main() -> int:
|
||||
ap = argparse.ArgumentParser(description="Run a HALCON .hdvp via HDevEngine")
|
||||
ap.add_argument("--proc-path", required=True,
|
||||
help="Directory containing the .hdvp (set_procedure_path)")
|
||||
ap.add_argument("--proc", required=True,
|
||||
help="Procedure base name, no extension (e.g. find_circles)")
|
||||
ap.add_argument("--set", dest="sets", action="append", default=[],
|
||||
metavar="Name=Value", help="Input control param (repeatable)")
|
||||
ap.add_argument("--get", dest="gets", action="append", default=[],
|
||||
metavar="Name", help="Output control param to read (repeatable)")
|
||||
args = ap.parse_args()
|
||||
|
||||
try:
|
||||
from halcon.hdevengine import (
|
||||
HDevEngine, HDevProcedure, HDevProcedureCall, HDevEngineError,
|
||||
)
|
||||
except Exception as e:
|
||||
print(f"ERROR: cannot import HDevEngine ({e}). Run via the project venv "
|
||||
f"using uv.", file=sys.stderr)
|
||||
return 1
|
||||
|
||||
eng = HDevEngine()
|
||||
eng.set_procedure_path(args.proc_path)
|
||||
try:
|
||||
proc = HDevProcedure.load_external(args.proc)
|
||||
except HDevEngineError as e:
|
||||
print(f"ERROR: could not load procedure '{args.proc}' from "
|
||||
f"'{args.proc_path}': {e}", file=sys.stderr)
|
||||
return 2
|
||||
|
||||
call = HDevProcedureCall(proc)
|
||||
call.reset()
|
||||
for name, value in parse_set(args.sets):
|
||||
call.set_input_control_param_by_name(name, value)
|
||||
|
||||
try:
|
||||
call.execute()
|
||||
except HDevEngineError as e:
|
||||
print(json.dumps({"ok": False, "error": str(e)}, ensure_ascii=False))
|
||||
return 3
|
||||
|
||||
out = {}
|
||||
for name in args.gets:
|
||||
try:
|
||||
out[name] = jsonable(call.get_output_control_param_by_name(name))
|
||||
except HDevEngineError as e:
|
||||
out[name] = {"error": str(e)}
|
||||
print(json.dumps({"ok": True, "outputs": out}, ensure_ascii=False))
|
||||
return 0
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
sys.exit(main())
|
||||
+56
@@ -0,0 +1,56 @@
|
||||
"""Run a whole HDevelop program (.hdev) via HDevEngine and read control vars back.
|
||||
|
||||
Use when the logic lives in a program's main rather than a parameterized
|
||||
procedure. Outputs print as a JSON object on stdout.
|
||||
|
||||
Example:
|
||||
/mnt/c/Users/NAURA/.local/bin/uv.exe run python \
|
||||
.claude/skills/halcon/scripts/run_program.py \
|
||||
--program C:/workspace/agent-studio/halcon-001/demo_prog.hdev \
|
||||
--get Total --get Area --get Message
|
||||
|
||||
Notes:
|
||||
- The program must be self-contained and non-interactive (no draw_*, no stop()).
|
||||
- Use ABSOLUTE paths inside the program (no cwd notion under HDevEngine).
|
||||
"""
|
||||
import argparse
|
||||
import json
|
||||
import sys
|
||||
|
||||
from _common import jsonable
|
||||
|
||||
|
||||
def main() -> int:
|
||||
ap = argparse.ArgumentParser(description="Run a HALCON .hdev via HDevEngine")
|
||||
ap.add_argument("--program", required=True, help="Absolute path to the .hdev")
|
||||
ap.add_argument("--get", dest="gets", action="append", default=[],
|
||||
metavar="Name", help="Control variable to read (repeatable)")
|
||||
args = ap.parse_args()
|
||||
|
||||
try:
|
||||
from halcon.hdevengine import HDevProgram, HDevProgramCall, HDevEngineError
|
||||
except Exception as e:
|
||||
print(f"ERROR: cannot import HDevEngine ({e}). Run via the project venv "
|
||||
f"using uv.", file=sys.stderr)
|
||||
return 1
|
||||
|
||||
program = HDevProgram(args.program)
|
||||
call = HDevProgramCall(program)
|
||||
try:
|
||||
call.execute()
|
||||
except HDevEngineError as e:
|
||||
print(json.dumps({"ok": False, "error": str(e)}, ensure_ascii=False))
|
||||
return 3
|
||||
|
||||
out = {}
|
||||
for name in args.gets:
|
||||
try:
|
||||
out[name] = jsonable(call.get_control_var_by_name(name))
|
||||
except HDevEngineError as e:
|
||||
out[name] = {"error": str(e)}
|
||||
print(json.dumps({"ok": True, "vars": out}, ensure_ascii=False))
|
||||
return 0
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
sys.exit(main())
|
||||
+192
@@ -0,0 +1,192 @@
|
||||
"""Teach an ROI once (human draws), persist it as a .hobj for headless reuse.
|
||||
|
||||
The rectangle case (default, the common "box a Mark" flow) uses an interactive
|
||||
matplotlib viewer with **pan (right-drag), zoom (scroll wheel), and box-select
|
||||
(left-drag)** — smooth even on multi-megapixel images. circle/region fall back to
|
||||
HALCON's native draw_* window. Downstream procedures read_region + reduce_domain
|
||||
the saved .hobj, so no human is needed after teaching.
|
||||
|
||||
Run (needs a visible desktop — this is the interactive seam):
|
||||
/mnt/c/Users/NAURA/.local/bin/uv.exe run python \
|
||||
.claude/skills/halcon/scripts/teach_roi.py \
|
||||
--image-file "C:/data/frames/a.bmp" \
|
||||
--out C:/workspace/agent-studio/halcon-001/roi.hobj
|
||||
|
||||
Controls (rectangle): left-drag = box · right-drag = pan · wheel = zoom ·
|
||||
Enter = save · q/Esc = cancel.
|
||||
|
||||
Headless (no GUI, scripted): add --box r1,c1,r2,c2 to write a rectangle directly.
|
||||
|
||||
Requires matplotlib + numpy in the venv (one-time):
|
||||
/mnt/c/Users/NAURA/.local/bin/uv.exe pip install matplotlib numpy
|
||||
|
||||
Tip: draw TIGHTLY around the target features. A loose ROI captures extra
|
||||
contours and breaks downstream count checks (e.g. "expected 16 circles").
|
||||
"""
|
||||
import argparse
|
||||
import sys
|
||||
|
||||
|
||||
def pick_reference_image(ha, image_dir, image_file):
|
||||
if image_file:
|
||||
return image_file
|
||||
files = ha.list_files(image_dir, "files")
|
||||
imgs = sorted(ha.tuple_regexp_select(files, r"\.(png|bmp|jpg|jpeg|tif|tiff)$"))
|
||||
if not imgs:
|
||||
raise SystemExit(f"No images found in {image_dir}")
|
||||
return imgs[0]
|
||||
|
||||
|
||||
def load_gray(ha, image_file):
|
||||
# HALCON 默认 clip_region=true 会把区域裁到 128x128,全分辨率坐标建的 region
|
||||
# 会被裁空 -> 写盘回读 bbox=0,0,0,0。建/读区域前务必关掉。
|
||||
ha.set_system("clip_region", "false")
|
||||
img = ha.read_image(image_file)
|
||||
if ha.count_channels(img)[0] >= 3:
|
||||
img = ha.rgb1_to_gray(img)
|
||||
w, h = ha.get_image_size(img)
|
||||
return ha.himage_as_numpy_array(img), int(h[0]), int(w[0])
|
||||
|
||||
|
||||
def pick_rectangle_interactive(arr, max_disp):
|
||||
"""matplotlib pan/zoom/box-select; returns (r1,c1,r2,c2) in image coords or None."""
|
||||
import matplotlib.pyplot as plt
|
||||
from matplotlib.widgets import RectangleSelector
|
||||
|
||||
plt.rcParams["font.sans-serif"] = ["Microsoft YaHei", "SimHei", "DejaVu Sans"]
|
||||
plt.rcParams["axes.unicode_minus"] = False
|
||||
|
||||
# Downsample for display (fast redraws), map coords back to full res via extent.
|
||||
H, W = arr.shape
|
||||
step = max(1, round(max(H, W) / max_disp))
|
||||
disp = arr[::step, ::step]
|
||||
|
||||
fig, ax = plt.subplots()
|
||||
ax.imshow(disp, cmap="gray", origin="upper", extent=(0, W, H, 0),
|
||||
interpolation="nearest", aspect="equal")
|
||||
ax.set_xlim(0, W); ax.set_ylim(H, 0)
|
||||
ax.set_title("left=box right-drag=pan wheel=zoom Enter=save q=cancel")
|
||||
|
||||
box, pan = {}, {}
|
||||
|
||||
def on_select(p, r):
|
||||
box.update(r1=p.ydata, c1=p.xdata, r2=r.ydata, c2=r.xdata)
|
||||
|
||||
# keep the reference or RectangleSelector is GC'd and box-select stops working
|
||||
ax._roi_selector = RectangleSelector(
|
||||
ax, on_select, useblit=True, button=[1], minspanx=3, minspany=3,
|
||||
interactive=True)
|
||||
|
||||
def on_scroll(ev):
|
||||
if ev.inaxes is not ax:
|
||||
return
|
||||
s = 0.8 if ev.button == "up" else 1.25
|
||||
x0, x1 = ax.get_xlim(); y0, y1 = ax.get_ylim()
|
||||
ax.set_xlim(ev.xdata - (ev.xdata - x0) * s, ev.xdata + (x1 - ev.xdata) * s)
|
||||
ax.set_ylim(ev.ydata - (ev.ydata - y0) * s, ev.ydata + (y1 - ev.ydata) * s)
|
||||
fig.canvas.draw_idle()
|
||||
|
||||
def on_press(ev):
|
||||
if ev.button == 3 and ev.inaxes is ax:
|
||||
pan["p"] = (ev.xdata, ev.ydata)
|
||||
|
||||
def on_motion(ev):
|
||||
if "p" in pan and ev.xdata is not None and ev.inaxes is ax:
|
||||
dx, dy = ev.xdata - pan["p"][0], ev.ydata - pan["p"][1]
|
||||
x0, x1 = ax.get_xlim(); y0, y1 = ax.get_ylim()
|
||||
ax.set_xlim(x0 - dx, x1 - dx); ax.set_ylim(y0 - dy, y1 - dy)
|
||||
fig.canvas.draw_idle()
|
||||
|
||||
def on_release(ev):
|
||||
if ev.button == 3:
|
||||
pan.pop("p", None)
|
||||
|
||||
def on_key(ev):
|
||||
if ev.key == "enter" and box:
|
||||
plt.close(fig)
|
||||
elif ev.key in ("q", "escape"):
|
||||
box.clear(); plt.close(fig)
|
||||
|
||||
for name, fn in [("scroll_event", on_scroll), ("button_press_event", on_press),
|
||||
("motion_notify_event", on_motion),
|
||||
("button_release_event", on_release), ("key_press_event", on_key)]:
|
||||
fig.canvas.mpl_connect(name, fn)
|
||||
plt.show()
|
||||
if not box:
|
||||
return None
|
||||
return box["r1"], box["c1"], box["r2"], box["c2"]
|
||||
|
||||
|
||||
def save_rectangle(ha, out, r1, c1, r2, c2, H, W):
|
||||
r1, r2 = sorted((max(0, round(r1)), min(H - 1, round(r2))))
|
||||
c1, c2 = sorted((max(0, round(c1)), min(W - 1, round(c2))))
|
||||
ha.write_region(ha.gen_rectangle1(r1, c1, r2, c2), out)
|
||||
print(f"ROI saved: {out}")
|
||||
print(f"Rectangle Row1={r1} Col1={c1} Row2={r2} Col2={c2}")
|
||||
|
||||
|
||||
def draw_native(ha, ref, shape, out):
|
||||
"""circle / region via HALCON's own draw window (no pan/zoom)."""
|
||||
img = ha.read_image(ref)
|
||||
width, height = ha.get_image_size(img)
|
||||
width, height = width[0], height[0]
|
||||
win = ha.open_window(0, 0, 1024, 768, 0, "visible", "")
|
||||
ha.set_part(win, 0, 0, height - 1, width - 1)
|
||||
ha.disp_obj(img, win)
|
||||
ha.set_color(win, "green")
|
||||
print(f"Draw a {shape} with the left mouse button, release to finish ...", flush=True)
|
||||
if shape == "circle":
|
||||
row, col, radius = ha.draw_circle(win)
|
||||
region = ha.gen_circle(row, col, radius)
|
||||
print(f"Circle Row={row:.1f} Col={col:.1f} Radius={radius:.1f}")
|
||||
else: # freehand region
|
||||
region = ha.draw_region(win)
|
||||
ha.write_region(region, out)
|
||||
ha.close_window(win)
|
||||
print(f"ROI saved: {out}")
|
||||
|
||||
|
||||
def main() -> int:
|
||||
ap = argparse.ArgumentParser(description="Teach an ROI and write it to disk")
|
||||
src = ap.add_mutually_exclusive_group(required=True)
|
||||
src.add_argument("--image-dir", help="Directory; first sorted image is shown")
|
||||
src.add_argument("--image-file", help="Explicit reference image to display")
|
||||
ap.add_argument("--out", required=True, help="Output region file, e.g. .../roi.hobj")
|
||||
ap.add_argument("--shape", choices=["rectangle", "circle", "region"],
|
||||
default="rectangle",
|
||||
help="rectangle = interactive pan/zoom picker; circle/region = HALCON draw")
|
||||
ap.add_argument("--disp", type=int, default=1000,
|
||||
help="rectangle picker: display long-side px cap (smaller=faster/blurrier)")
|
||||
ap.add_argument("--box", help="rectangle headless (no GUI): r1,c1,r2,c2 image coords")
|
||||
args = ap.parse_args()
|
||||
|
||||
try:
|
||||
import halcon as ha
|
||||
except Exception as e:
|
||||
print("ERROR: cannot import 'halcon'. Run via the project venv using uv.",
|
||||
e, file=sys.stderr)
|
||||
return 1
|
||||
|
||||
ref = pick_reference_image(ha, args.image_dir, args.image_file)
|
||||
print(f"Reference image: {ref}")
|
||||
|
||||
if args.shape != "rectangle":
|
||||
draw_native(ha, ref, args.shape, args.out)
|
||||
return 0
|
||||
|
||||
arr, H, W = load_gray(ha, ref)
|
||||
if args.box:
|
||||
r1, c1, r2, c2 = (float(v) for v in args.box.split(","))
|
||||
save_rectangle(ha, args.out, r1, c1, r2, c2, H, W)
|
||||
return 0
|
||||
|
||||
rect = pick_rectangle_interactive(arr, args.disp)
|
||||
if rect is None:
|
||||
print("cancelled, nothing saved")
|
||||
return 0
|
||||
save_rectangle(ha, args.out, *rect, H, W)
|
||||
return 0
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
sys.exit(main())
|
||||
Reference in New Issue
Block a user