Skip to content

Commit

Permalink
initial release
Browse files Browse the repository at this point in the history
  • Loading branch information
taylorhanayikVBC committed Aug 26, 2024
0 parents commit 4f0ff6b
Show file tree
Hide file tree
Showing 15 changed files with 1,782 additions and 0 deletions.
21 changes: 21 additions & 0 deletions .github/workflows/ghpages.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
name: Build and Deploy
on:
push:
branches:
- main
jobs:
build-and-publish-live-demo:
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v4

- name: Install and Build
run: |
npm install
npm run build
- name: Deploy
uses: JamesIves/github-pages-deploy-action@v4
with:
branch: demo # The branch the action should deploy to.
folder: dist # The folder the action should deploy.
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
node_modules
dist
.DS_Store
Binary file added CTmesh.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
24 changes: 24 additions & 0 deletions LICENSE
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
BSD 2-Clause License

Copyright (c) 2024, Chris Rorden

Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:

1. Redistributions of source code must retain the above copyright notice, this
list of conditions and the following disclaimer.

2. Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
41 changes: 41 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
### ct2print voxels to mesh

A basic example of converting a voxel-based image to a simplified mesh. This interactive drag-and-drop web page allows you to create meshes that can be used with a 3D printer.

![Example mesh from CT scan of a human header](CTmesh.png)

### Usage

1. Open the [live demo](https://niivue.github.io/ct2print/).
2. **Option 1** Use the `Volume` pull-down menu to select an image.
3. **Option 2** If your image is in NIfTI format, drag and drop the file onto the web page.
4. **Option 3** If your image is in DICOM format, use the `Select DICOM` button to import your image.
5. Note when you click on the image, the voxel intensity is shown in the status bar at the bottom-left of the web page. You can decide a nice intensity threshold to segment your image (e.g. for a CT scan, bone will be brighter than soft tissue).
6. Press the `Create Mesh` button and select your preferred settings:
![settings dialog](settings.png)
- The [Isosurface](https://en.wikipedia.org/wiki/Marching_cubes) is the voxel intensity used to discriminate the mesh surface. See the previous step for detials. By default, this value is set to the [Otsu threshold](https://en.wikipedia.org/wiki/Otsu%27s_method).
- [Closing](https://en.wikipedia.org/wiki/Closing_(morphology)) removes small crevices and cavities in your mesh which can plague printing.
- Fill bubbles will remove any cavities, this includes large cavities for example the ventricles for a brain scan.
- The `Largest cluster only` will only extract a single mesh. For example, with the `Iguana` demo this extracts only the skull without the [scleral rings](https://en.wikipedia.org/wiki/Scleral_Ring).
- You can choose `Smoothing` to make the surfaces less jagged (note this can create self intersecting triangles that can confound some printers).
- You can choose to `Simplify` [reduce the number of triangles](https://github.com/sp4cerat/Fast-Quadric-Mesh-Simplification) to create smaller files (note this can create self intersecting triangles that can confound some printers).
7. Once you have set your preferences, press `Apply`.
8. You will see the mesh appear and can interactively view it. If you are unhappy with the result, repeat step 6 with different settings. If you want to print the results, press the `Save Mesh` button.


### For Developers

You can serve a hot-reloadable web page that allows you to interactively modify the source code.

```bash
git clone https://github.com/niivue/ct2print
cd ct2print
npm install
npm run dev
```

### Links

- [Will Usher](https://github.com/Twinklebear/webgl-marching-cubes) ported [Marching Cubes](https://paulbourke.net/geometry/polygonise/) to JavaScript.
- This project includes a pure JavaScript port of Sven Forstmann's [Fast Quadric Mesh Simplification](https://github.com/sp4cerat/Fast-Quadric-Mesh-Simplification)
- [Tim Knip](https://github.com/timknip/mesh-decimate/tree/master) provides a ThreeJS project that provides both WASM and native JavaScript mesh decimation. Try the [live demo](https://neurolabusc.github.io/simplifyjs/).
121 changes: 121 additions & 0 deletions index.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,121 @@
<!doctype html>
<html lang="en">

<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<link rel="stylesheet" href="./niivue.css" />
<title>ct2print</title>
</head>

<body>
<header>
<label for="volumeSelect">Volume</label>
<select id="volumeSelect">
<option selected>tinyT1</option>
<option>bet</option>
<option>Iguana</option>
<option>CT_Philips</option>
<option>mni152</option>
<option>wm.mgz</option>
<option>lh.pial</option>
<option>fs_LR.32k.L.inflated.surf.gii</option>
</select>
<label for="shaderSelect">Shader</label>
<select id="shaderSelect">
<option value="Flat">Flat</option>
<option value="Matcap" selected>Matcap</option>
<option value="Matte">Matte</option>
<option value="Phong">Phong</option>
</select>
<label for="visibleCheck">Mesh Visible</label>
<input type="checkbox" id="visibleCheck" checked />
<button id="remeshBtn">Create Mesh</button>
<button id="simplifyBtn">Simplify Mesh</button>
<button id="saveBtn">Save Mesh</button>
<button id="aboutBtn">About</button>
<div id="loadingCircle" class="loading-circle hidden"></div>
</header>
<main id="canvas-container">
<canvas id="gl1"></canvas>
</main>
<footer id="location">&nbsp;</footer>
<dialog id="remeshDialog">
<form method="dialog">
<p>
<label id="isoLabel">Isosurface Threshold</label>
<input id="isoNumber" type="text" value="100">
<p>
<p>
<label>Closing (mm)</label>
<input id="closeMM" type="number" min="0" value="4" max="100">
</p>
<p>
<label>
Hollow:
<select id="hollowSelect">
<option value="0" selected>False: solid</option>
<option value="-1">1mm</option>
<option value="-2">2mm</option>
<option value="-4">4mm</option>
<option value="-8">8mm</option>
<option value="-16">16mm</option>
</select>
</label>
</p>
<p>
<input type="checkbox" id="bubbleCheck" unchecked/>
<label>Fill bubbles</label>
</p>
<p>
<input type="checkbox" id="largestCheck" unchecked/>
<label>Largest cluster only</label>
</p>
<p>
<label for="smoothSlide">Smoothing</label>
<input
type="range"
min="0"
max="20"
value="5"
class="slider"
id="smoothSlide"
/>
</p>
<p>
<label>Simplify Percent (1..100)</label>
<input id="shrinkPct" type="number" min="1" value="30" max="100">
</p>
<button id="cancelBtn" formmethod="dialog">Cancel</button>
<button autofocus id="applyBtn" value="default">Apply</button>
</form>
</dialog>
<dialog id="simplifyDialog">
<form method="dialog">
<p>
<label>Simplify Percent (1..100)</label>
<input id="shrinkSimplePct" type="number" min="1" value="30" max="100">
</p>
<button id="cancelBtn" formmethod="dialog">Cancel</button>
<button autofocus id="applySimpleBtn" value="default">Apply</button>
</form>
</dialog>
<dialog id="saveDialog">
<form method="dialog">
<p>
<label>
Format:
<select id="formatSelect">
<option>MZ3 small and precise</option>
<option selected>OBJ widely supported</option>
<option>STL popular for printing</option>
</select>
</label>
</p>
<button id="cancelSaveBtn" formmethod="dialog">Cancel</button>
<button autofocus id="applySaveBtn" value="default">Save</button>
</form>
</dialog>
<script type="module" src="/main.js"></script>
</body>
</html>
Loading

0 comments on commit 4f0ff6b

Please sign in to comment.