-
-
Notifications
You must be signed in to change notification settings - Fork 380
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #427 from Kitware/ImageMarchingSquares
feat(ImageMarchingCubes): Added 2D image or slice contouring
- Loading branch information
Showing
7 changed files
with
430 additions
and
0 deletions.
There are no files selected for viewing
This file contains 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
This file contains 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,24 @@ | ||
## Introduction | ||
|
||
vtkImageMarchingSquares - isocontour an image (or slice from a volume) | ||
|
||
Given a specified contour value, generate isolines using the | ||
Marching Squares algorithm (the 2D version of the 3D Marching Cubes | ||
algorithm). | ||
|
||
## Public API | ||
|
||
### contourValues | ||
|
||
Set/Get an array of isocontour values. | ||
|
||
### sliceNumber | ||
|
||
Set/Get the k-slice number of the input volume. By default the | ||
sliceNumber = 0. | ||
|
||
### mergePoints | ||
|
||
As lines forming the isolines are generated, indicate whether | ||
conincident points are to be merged. Merging produces connected polylines | ||
at the cost of additional memory and computation. |
This file contains 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,48 @@ | ||
// ---------------------------------------------------------------------------- | ||
// Marching squares case functions (using lines to generate the 2D tessellation). | ||
// For each case, a list of edge ids that form the triangles. A -1 marks the | ||
// end of the list of edges. Edges are taken three at a time to generate | ||
// triangle points. | ||
// ---------------------------------------------------------------------------- | ||
const MARCHING_SQUARES_CASES = [ | ||
[-1, -1, -1, -1, -1], /* 0 */ | ||
[0, 3, -1, -1, -1], /* 1 */ | ||
[1, 0, -1, -1, -1], /* 2 */ | ||
[1, 3, -1, -1, -1], /* 3 */ | ||
[2, 1, -1, -1, -1], /* 4 */ | ||
[0, 3, 2, 1, -1], /* 5 */ | ||
[2, 0, -1, -1, -1], /* 6 */ | ||
[2, 3, -1, -1, -1], /* 7 */ | ||
[3, 2, -1, -1, -1], /* 8 */ | ||
[0, 2, -1, -1, -1], /* 9 */ | ||
[1, 0, 3, 2, -1], /* 10 */ | ||
[1, 2, -1, -1, -1], /* 11 */ | ||
[3, 1, -1, -1, -1], /* 12 */ | ||
[0, 1, -1, -1, -1], /* 13 */ | ||
[3, 0, -1, -1, -1], /* 14 */ | ||
[-1, -1, -1, -1, -1], /* 15 */ | ||
]; | ||
|
||
const EDGES = [ | ||
[0, 1], | ||
[1, 3], | ||
[2, 3], | ||
[0, 2], | ||
]; | ||
|
||
function getCase(index) { | ||
return MARCHING_SQUARES_CASES[index]; | ||
} | ||
|
||
// Define the four edges of the pixel by the following pairs of vertices | ||
function getEdge(eid) { | ||
return EDGES[eid]; | ||
} | ||
|
||
// ---------------------------------------------------------------------------- | ||
// Static API | ||
// ---------------------------------------------------------------------------- | ||
export default { | ||
getCase, | ||
getEdge, | ||
}; |
20 changes: 20 additions & 0 deletions
20
Sources/Filters/General/ImageMarchingSquares/example/controller.html
This file contains 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,20 @@ | ||
<table> | ||
<tr> | ||
<td>Volume resolution</td> | ||
<td> | ||
<input class='volumeResolution' type="range" min="10" max="100" step="1" value="50" /> | ||
</td> | ||
</tr> | ||
<tr> | ||
<td>Radius</td> | ||
<td> | ||
<input class='sphereRadius' type="range" min="0.01" max="1.0" step="0.01" value="0.025" /> | ||
</td> | ||
</tr> | ||
<tr> | ||
<td>Merge Points</td> | ||
<td> | ||
<input class='mergePoints' type="checkbox" unchecked /> | ||
</td> | ||
</tr> | ||
</table> |
110 changes: 110 additions & 0 deletions
110
Sources/Filters/General/ImageMarchingSquares/example/index.js
This file contains 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,110 @@ | ||
import 'vtk.js/Sources/favicon'; | ||
|
||
import vtkActor from 'vtk.js/Sources/Rendering/Core/Actor'; | ||
import vtkFullScreenRenderWindow from 'vtk.js/Sources/Rendering/Misc/FullScreenRenderWindow'; | ||
import vtkImageMarchingSquares from 'vtk.js/Sources/Filters/General/ImageMarchingSquares'; | ||
import vtkOutlineFilter from 'vtk.js/Sources/Filters/General/OutlineFilter'; | ||
import vtkMapper from 'vtk.js/Sources/Rendering/Core/Mapper'; | ||
import vtkSampleFunction from 'vtk.js/Sources/Imaging/Hybrid/SampleFunction'; | ||
import vtkSphere from 'vtk.js/Sources/Common/DataModel/Sphere'; | ||
// import vtkPlane from 'vtk.js/Sources/Common/DataModel/Plane'; | ||
import vtkImplicitBoolean from 'vtk.js/Sources/Common/DataModel/ImplicitBoolean'; | ||
|
||
import controlPanel from './controller.html'; | ||
|
||
const { Operation } = vtkImplicitBoolean; | ||
|
||
// ---------------------------------------------------------------------------- | ||
// Standard rendering code setup | ||
// ---------------------------------------------------------------------------- | ||
|
||
const fullScreenRenderer = vtkFullScreenRenderWindow.newInstance(); | ||
const renderer = fullScreenRenderer.getRenderer(); | ||
const renderWindow = fullScreenRenderer.getRenderWindow(); | ||
|
||
// ---------------------------------------------------------------------------- | ||
// Example code | ||
// ---------------------------------------------------------------------------- | ||
const actor = vtkActor.newInstance(); | ||
renderer.addActor(actor); | ||
|
||
const mapper = vtkMapper.newInstance(); | ||
actor.setMapper(mapper); | ||
|
||
// Build pipeline | ||
const sphere = vtkSphere.newInstance({ center: [-2.5, 0.0, 0.0], radius: 0.5 }); | ||
const sphere2 = vtkSphere.newInstance({ center: [2.5, 0.0, 0.0], radius: 0.5 }); | ||
// const plane = vtkPlane.newInstance({ origin: [0, 0, 0], normal: [0, 1, 0] }); | ||
const impBool = vtkImplicitBoolean.newInstance({ operation: Operation.UNION, functions: [sphere, sphere2] }); | ||
const sample = vtkSampleFunction.newInstance({ implicitFunction: impBool, sampleDimensions: [5, 3, 3], modelBounds: [-5.0, 5.0, -1.0, 1.0, -1.0, 1.0] }); | ||
|
||
// Isocontour | ||
const mSquares = vtkImageMarchingSquares.newInstance({ slice: 1 }); | ||
|
||
// Connect the pipeline proper | ||
mSquares.setInputConnection(sample.getOutputPort()); | ||
mapper.setInputConnection(mSquares.getOutputPort()); | ||
|
||
// Update the pipeline to obtain metadata (range) about scalars | ||
sample.update(); | ||
const cValues = []; | ||
const [min, max] = sample.getOutputData().getPointData().getScalars().getRange(); | ||
for (let i = 0; i < 20; ++i) { | ||
cValues[i] = min + ((i / 19) * (max - min)); | ||
} | ||
mSquares.setContourValues(cValues); | ||
|
||
// Create an outline | ||
const outline = vtkOutlineFilter.newInstance(); | ||
outline.setInputConnection(sample.getOutputPort()); | ||
const outlineMapper = vtkMapper.newInstance(); | ||
outlineMapper.setInputConnection(outline.getOutputPort()); | ||
const outlineActor = vtkActor.newInstance(); | ||
outlineActor.setMapper(outlineMapper); | ||
renderer.addActor(outlineActor); | ||
|
||
// ---------------------------------------------------------------------------- | ||
// UI control handling | ||
// ---------------------------------------------------------------------------- | ||
fullScreenRenderer.addController(controlPanel); | ||
|
||
// Define the volume resolution | ||
document.querySelector('.volumeResolution').addEventListener('input', (e) => { | ||
const value = Number(e.target.value); | ||
sample.setSampleDimensions(value, value, value); | ||
mSquares.setSlice((value / 2.0)); | ||
renderWindow.render(); | ||
}); | ||
|
||
// Define the sphere radius | ||
document.querySelector('.sphereRadius').addEventListener('input', (e) => { | ||
const value = Number(e.target.value); | ||
sphere.setRadius(value); | ||
sphere2.setRadius(value); | ||
sample.modified(); | ||
renderWindow.render(); | ||
}); | ||
|
||
// Indicate whether to merge conincident points or not | ||
document.querySelector('.mergePoints').addEventListener('change', (e) => { | ||
mSquares.setMergePoints(!!e.target.checked); | ||
renderWindow.render(); | ||
}); | ||
|
||
|
||
// ----------------------------------------------------------- | ||
const cam = renderer.getActiveCamera(); | ||
cam.setFocalPoint(0, 0, 0); | ||
cam.setPosition(0, 0, 1); | ||
renderer.resetCamera(); | ||
renderWindow.render(); | ||
|
||
// ----------------------------------------------------------- | ||
// Make some variables global so that you can inspect and | ||
// modify objects in your browser's developer console: | ||
// ----------------------------------------------------------- | ||
|
||
global.source = sample; | ||
global.filter = mSquares; | ||
global.mapper = mapper; | ||
global.actor = actor; |
Oops, something went wrong.