-
-
Notifications
You must be signed in to change notification settings - Fork 48
feat(contour tracing): Suzuki-Abe-style contour tracing #219
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
Merged
Changes from all commits
Commits
Show all changes
38 commits
Select commit
Hold shift + click to select a range
e25087a
refactor(kmeans, RGBPixel): general cleanup for clarity
Ryan-Millard 272e02d
Merge branch 'main' of https://github.com/Ryan-Millard/Img2Num into f…
Ryan-Millard c0c50a3
Merge branch 'main' of https://github.com/Ryan-Millard/Img2Num into f…
Ryan-Millard aa5d17f
feat(anti-contours): this labels every non-countour pixel - nice :'(
Ryan-Millard 8f8094b
fix(find_contours): better labelling and border-following - very slow :(
Ryan-Millard ab83ef5
feat(contour visualization): add diff color borders and simple viewin…
Ryan-Millard b81809a
fix(contour tracing): never skip a contour pixel
Ryan-Millard 98cf144
KMeans + graph based merging
Krasner a46c8e8
bug fixes
Krasner 51e3b4a
Move Graph and Node to seperate .h and .cpp files
Krasner 1a19dc1
suppress debug prints
Krasner 315507d
Use each Node as binary image to compute contours from, then recombin…
Krasner 96a457f
fix small edge bug
Krasner 44dfaa9
address some PR review
Krasner 00aaf90
Move bounding box and binary image creation to methods for Node
Krasner 3c22c71
remove(find_contours files): old buggy contour tracing
Ryan-Millard fda539c
refactor(kmeans_clustering): new API style to preserve original data …
Ryan-Millard f1507ff
fix(kmeans out params): properly handle WASM boundary for int32
Ryan-Millard ade79f4
refactor(kmeans_graph): use updated kmeans function instead of kmeans…
Ryan-Millard ee5a61c
docs(JS-WASM interop): document entire process from function declarat…
Ryan-Millard bb81a67
Merge branch 'main' into feat/contour-tracing
Ryan-Millard 6e5c3b9
chore(mergeSmallRegionsInPlace): remove legacy function - handled by …
Ryan-Millard fccd968
fix(node, graph): enforce const-correctness, use explicit types, fix …
Ryan-Millard f15868d
refactor(image): switch RGBXY to use RGBPixel for color + XY for posi…
Ryan-Millard 0aecc33
refactor(kmeans): clean up dead code
Ryan-Millard f3f923b
chore(cleanup kmeans_graph, kmeans): remove debug prints & move heade…
Ryan-Millard 5c1903a
refactor(kmeans_graph): split into visualize contours function & opti…
Ryan-Millard a2aca6f
fix(contours.cpp): Multiplication result converted to larger type
Ryan-Millard 7466a46
fix(kmeans_graph.cpp): Multiplication result converted to larger type
Ryan-Millard d1be25a
style: lint & format code
Ryan-Millard 3a006b7
fix(ipynb format error): remove ipynb file
Ryan-Millard 84093ea
fix(node.cpp): Multiplication result converted to larger type
Ryan-Millard 3e0a586
fix(worker): prevent prototype pollution from dynamic buffer keys
Ryan-Millard 02dd5a1
docs(wasmWorker): update to match code changes
Ryan-Millard 1701afa
fix(wasm,image)!: correct int sizes, prevent UB, and harden graph/kme…
Ryan-Millard fea31a2
Merge branch 'main' into feat/contour-tracing
Ryan-Millard 9a7623f
Merge branch 'feat/contour-tracing' of https://github.com/Ryan-Millar…
Ryan-Millard ade7590
style: update to match repository reqs
Ryan-Millard File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,6 +1,5 @@ | ||
| { | ||
| "label": "Components", | ||
| "position": 3, | ||
| "link": { | ||
| "type": "generated-index", | ||
| "title": "React Components", | ||
|
|
||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,6 +1,5 @@ | ||
| { | ||
| "label": "CSS - Styling", | ||
| "position": 4, | ||
| "link": { | ||
| "type": "generated-index", | ||
| "title": "React CSS - Styling", | ||
|
|
||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,6 +1,5 @@ | ||
| { | ||
| "label": "Hooks", | ||
| "position": 2, | ||
| "link": { | ||
| "type": "generated-index", | ||
| "title": "React Hooks", | ||
|
|
||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,4 +1,3 @@ | ||
| { | ||
| "label": "useTheme", | ||
| "position": 1 | ||
| "label": "useTheme" | ||
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,168 @@ | ||
| --- | ||
| id: use-wasm-worker | ||
| title: useWasmWorker | ||
| hide_title: false | ||
| description: A custom React hook for asynchronously calling functions exported by the Image WASM module via a web worker. | ||
| --- | ||
|
|
||
| # useWasmWorker Hook | ||
|
|
||
| The `useWasmWorker` hook provides a **React-friendly interface** to the [**WASM Web Worker**](../../workers/wasm-worker) ([`wasmWorker.js`](https://github.com/Ryan-Millard/Img2Num/blob/main/src/workers/wasmWorker.js)). | ||
| It allows you to asynchronously invoke any **function exported by the WASM module** from your React components while keeping heavy computation off the main thread. | ||
|
|
||
| This hook abstracts: | ||
|
|
||
| - Posting messages to the worker. | ||
| - Allocating memory for `TypedArrays`. | ||
| - Calling WASM functions dynamically. | ||
| - Retrieving results. | ||
| - Cleaning up memory. | ||
|
|
||
| ## How WASM Functions Are Exposed | ||
|
|
||
| All functions exported from the WASM module are available via the hook’s **generic `call` method**: | ||
|
|
||
| ```js | ||
| const { call } = useWasmWorker(); | ||
|
|
||
| const result = await call('myWasmFunction', { arg1, arg2 }, ['arg1', 'arg2']); | ||
| ``` | ||
|
|
||
| - `'myWasmFunction'` is the **exact name of the C++ function** (without the `_` prefix added by Emscripten internally). | ||
| - The **second argument** is an object mapping argument names to values. | ||
| - For TypedArrays (e.g., `Uint8ClampedArray`, `Int32Array`), the corresponding keys should be included in the **`bufferKeys` array** (third argument). | ||
|
|
||
| - The **order of arguments in the object must match the order in the C++ function signature**. WASM functions are strict about argument order. | ||
|
|
||
| ### Example | ||
|
|
||
| C++ function: | ||
|
|
||
| ```cpp | ||
| void add_arrays(int* a, int* b, int* out, int length); | ||
| ``` | ||
|
|
||
| Calling from React: | ||
|
|
||
| ```js | ||
| const result = await call( | ||
| 'add_arrays', // must match the function's name | ||
| { | ||
| a: arrayA, // must match the first argument | ||
| b: arrayB, // must match the second argument | ||
| out: outputArray, // must match the third argument | ||
| length: arrayA.length, // must match the last argument | ||
| }, | ||
| ['a', 'b', 'out'] // keys that are TypedArrays (pointers) | ||
| ); | ||
| ``` | ||
|
|
||
| ## Adding New WASM Functions | ||
|
|
||
| import Tabs from '@theme/Tabs'; | ||
| import TabItem from '@theme/TabItem'; | ||
|
|
||
| 1. **Add the function in your C++ module** and ensure it is exported in the build: | ||
| <Tabs> | ||
| <TabItem value="img2num-method" label="Img2Num Method (EXPORTED Macro)"> | ||
| :::tip This is the preferred method | ||
| Use this method instead of the Emscripten method because it reduces bloat in the CMake file and minimizes boilerplate code. | ||
| ::: | ||
| Import and use the `EXPORTED` macro from `exported.h` in your header file (make sure the function is not in a namespace): | ||
|
|
||
| ```cpp | ||
| #include "exported.h" | ||
|
|
||
| EXPORTED void add_arrays(int* a, int* b, int* out, int length); | ||
| ``` | ||
|
|
||
| </TabItem> | ||
|
|
||
| <TabItem value="emscripten-method" label="Emscripten Method"> | ||
| :::caution Don't use this method in Img2Num! | ||
| This method leads to bloat in the CMake file, is difficult to maintain and tough to debug. | ||
|
|
||
| Use the Img2Num method instead because it provides convenience, reduces boilerplate, and saves you from numerous possible bugs. | ||
| ::: | ||
| Add the function to the CMake file's `EXPORTED_FUNCTIONS` flag: | ||
| ```cmake | ||
| "SHELL:-s EXPORTED_FUNCTIONS=['_malloc','_free','_add_arrays']" | ||
| ``` | ||
|
|
||
| </TabItem> | ||
| </Tabs> | ||
|
|
||
| 2. **Call it via the hook** using the `call` method, providing: | ||
| - An object mapping argument names to values **in the same order as the C++ function signature**. | ||
| - A `bufferKeys` array for all `TypedArrays` (pointers) that need WASM memory allocation. | ||
|
|
||
| 3. The hook will handle: | ||
| - Allocating WASM memory. | ||
| - Copying TypedArrays into WASM memory. | ||
| - Calling the function. | ||
| - Copying modified buffers back. | ||
| - Freeing WASM memory. | ||
|
|
||
| ## Potential Pitfalls | ||
|
|
||
| ### 1. Incorrect Argument Order | ||
|
|
||
| WASM functions **require arguments to be in the exact order declared in C++**. | ||
| Passing an object with keys in the wrong order may result in unexpected behavior or crashes. | ||
|
|
||
| ```js title="❌ Wrong order" | ||
| await call('add_arrays', { b: arrayB, a: arrayA, out: outputArray, length: arrayA.length }, ['a', 'b', 'out']); | ||
| ``` | ||
|
|
||
| ```js title="✅ Correct order" | ||
| await call('add_arrays', { a: arrayA, b: arrayB, out: outputArray, length: arrayA.length }, ['a', 'b', 'out']); | ||
| ``` | ||
|
|
||
| ### 2. Missing TypedArray Keys | ||
|
|
||
| All TypedArrays that are modified by the WASM function **must be included in `bufferKeys`**. | ||
| Otherwise, the worker will treat them as simple values, and the function may crash or produce invalid output. | ||
|
|
||
| ### 3. Worker Not Initialized | ||
|
|
||
| Always ensure the WASM worker is **fully initialized** before calling any function. | ||
| `useWasmWorker` handles this internally, but calling functions **immediately on render without waiting for the hook** may fail. | ||
|
|
||
| ### 4. Adding New TypedArray Types | ||
|
|
||
| If you want to pass a new TypedArray type (e.g., `Float32Array`), you must: | ||
|
|
||
| 1. Add support in `wasmWorker.js` for copying the new type into WASM memory. | ||
| 2. Ensure the corresponding **HEAP view** is exported from the C++ module in `EXPORTED_RUNTIME_METHODS` in the CMake file. | ||
|
|
||
| :::tip | ||
| See the [documentation for `wasmWorker.js`](../../workers/wasm-worker/) before adding new types. | ||
| ::: | ||
|
|
||
| ### 5. Memory Management | ||
|
|
||
| - The hook and worker automatically allocate and free WASM memory for TypedArrays. | ||
| - Avoid manually managing WASM pointers outside this mechanism to prevent memory leaks or crashes. | ||
|
|
||
| ## Diagram: React → Worker → WASM Flow | ||
|
|
||
| ```mermaid | ||
| flowchart TD | ||
| A["React component calls hook function"] --> B["useWasmWorker posts message to wasmWorker"] | ||
| B --> C["Worker allocates WASM memory for TypedArrays"] | ||
| C --> D["Worker calls WASM function dynamically"] | ||
| D --> E["Worker reads back modified buffers"] | ||
| E --> F["Worker frees allocated memory"] | ||
| F --> G["Worker posts result back to hook"] | ||
| G --> H["Hook resolves promise and returns output to component"] | ||
| ``` | ||
|
|
||
| - Demonstrates the **end-to-end flow** of calling any WASM function via the hook. | ||
|
|
||
| ## Summary | ||
|
|
||
| - `useWasmWorker` exposes **all WASM functions dynamically** through the generic `call` method. | ||
| - TypedArrays must be specified in `bufferKeys` and argument **order must match C++ signature**. | ||
| - New functions require both **C++ export** and proper handling in `wasmWorker.js`. | ||
| - Handles memory allocation, result copying, and cleanup automatically. | ||
| - Provides safe, asynchronous access to WASM from React. | ||
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.