Commit b07ee870 authored by aylward's avatar aylward
Browse files

ENH: Direct access to tutorials from within Slicer3



git-svn-id: http://svn.slicer.org/Slicer4/trunk@4342 3bd1e089-480b-0410-8dfb-8563597acbee
parent c9d60a81
......@@ -370,6 +370,15 @@ TARGET_LINK_LIBRARIES (${CLP}Lib ITKIO ITKBasicFilters)
SUBDIRS ( Realign )
SUBDIRS( DiffusionApplications )
SUBDIRS( ExtractSkeleton )
IF(USE_MIDAS)
SUBDIRS( MIDASApplications )
ENDIF(USE_MIDAS)
#IF(USE_BatchMake)
#SUBDIRS( BatchMakeApplications )
#ENDIF(USE_BatchMake)
IF (Slicer3_SOURCE_DIR)
# install each target in the production area (where it would appear in an
......
PROJECT (ExtractSkeleton)
# Disable MSVC 8 warnings
IF(WIN32)
OPTION(DISABLE_MSVC8_DEPRECATED_WARNINGS
"Disable Visual Studio 8 deprecated warnings" ON)
MARK_AS_ADVANCED(FORCE DISABLE_MSVC8_DEPRECATED_WARNINGS)
IF(DISABLE_MSVC8_DEPRECATED_WARNINGS)
ADD_DEFINITIONS(-D_CRT_SECURE_NO_DEPRECATE)
ENDIF(DISABLE_MSVC8_DEPRECATED_WARNINGS)
ENDIF(WIN32)
SET ( ExtractSkeleton_SOURCE
ExtractSkeleton.cxx
SkelGraph.h
SkelGraph.cxx
tilg_iso_3D.h
tilg_iso_3D.cxx
coordTypes.h
misc.h
misc.cxx )
GENERATECLP(ExtractSkeleton_SOURCE ExtractSkeleton.xml)
ADD_EXECUTABLE(ExtractSkeleton ${ExtractSkeleton_SOURCE})
TARGET_LINK_LIBRARIES(ExtractSkeleton ITKIO)
ADD_LIBRARY(ExtractSkeletonModule SHARED ${ExtractSkeleton_SOURCE})
SET_TARGET_PROPERTIES (ExtractSkeletonModule PROPERTIES
COMPILE_FLAGS "-Dmain=ModuleEntryPoint")
TARGET_LINK_LIBRARIES(ExtractSkeletonModule ITKIO)
IF (Slicer3_SOURCE_DIR)
SET(TARGET_MODULES ExtractSkeletonModule ExtractSkeleton)
FOREACH(target ${TARGET_MODULES})
INSTALL(TARGETS ${target}
RUNTIME DESTINATION ${SLICER_INSTALL_LIBRARIES_DIR}/Plugins
LIBRARY DESTINATION ${SLICER_INSTALL_LIBRARIES_DIR}/Plugins)
ENDFOREACH(target)
ENDIF (Slicer3_SOURCE_DIR)
/*=========================================================================
Program: Extract Skeleton
Module: $RCSfile: main.cxx,v $
Language: C++
Date: $Date: 2007-07-10 11:35:36 -0400 (Tue, 10 Jul 2007) $
Version: $Revision: 48 $
Copyright (c) 2007 Insight Software Consortium. All rights reserved.
See ITKCopyright.txt or http://www.itk.org/HTML/Copyright.htm for details.
This software is distributed WITHOUT ANY WARRANTY; without even
the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
PURPOSE. See the above copyright notices for more information.
=========================================================================*/
#if defined(_MSC_VER)
#pragma warning ( disable : 4786 )
#endif
#ifdef __BORLANDC__
#define ITK_LEAN_AND_MEAN
#endif
#include <cmath>
#include <iostream>
#include "itkImage.h"
#include "itkImageFileWriter.h"
#include "itkImageFileReader.h"
#include "itkImageRegionIterator.h"
#include "itkImageRegionConstIterator.h"
#include "SkelGraph.h"
#include "coordTypes.h"
#include "tilg_iso_3D.h"
#include "ExtractSkeletonCLP.h"
/** Main command */
int main(int argc, char **argv)
{
std::cout << "Begun." << std::endl;
PARSE_ARGS;
std::cout << "Processed args." << std::endl;
try
{
typedef unsigned char InputPixelType;
typedef itk::Image<InputPixelType,3> InputImageType;
typedef itk::ImageFileReader<InputImageType> ReaderType;
typedef unsigned char OutputPixelType;
typedef itk::Image<OutputPixelType, 3> OutputImageType;
typedef itk::ImageFileWriter<OutputImageType> WriterType;
ReaderType::Pointer Reader = ReaderType::New();
Reader->SetFileName(InputImageFileName.c_str());
Reader->Update();
InputImageType::Pointer inputImage = Reader->GetOutput();
std::cout << "Read image." << std::endl;
OutputImageType::Pointer outputImage = OutputImageType::New();
outputImage->SetRegions(Reader->GetOutput()->GetLargestPossibleRegion());
outputImage->SetSpacing(Reader->GetOutput()->GetSpacing());
outputImage->SetOrigin(Reader->GetOutput()->GetOrigin());
outputImage->Allocate();
itk::Size<3> itkSize = inputImage->GetLargestPossibleRegion().GetSize();
int dim [3];
dim[0] = itkSize[0];
dim[1] = itkSize[1];
dim[2] = itkSize[2];
InputPixelType * inputImageBuffer = inputImage->GetBufferPointer();
OutputPixelType * outputImageBuffer = outputImage->GetBufferPointer();
memset(outputImageBuffer, 0, dim[0]*dim[1]*dim[2]*sizeof(OutputPixelType));
std::cout << "Initialized output image." << std::endl;
int extract2DSheet = 0;
if(SkeletonType == "2D")
{
extract2DSheet = 1;
}
tilg_iso_3D(dim[0], dim[1], dim[2],
inputImageBuffer, outputImageBuffer, extract2DSheet);
std::cout << "Extracted skeleton." << std::endl;
std::list<point> axisPoints;
SkelGraph * graph = new SkelGraph();
graph->Extract_skel_graph(outputImageBuffer, dim);
graph->Extract_max_axis_in_graph();
graph->Sample_along_axis(NumberOfPoints, &axisPoints);
std::ofstream writeOutputFile;
writeOutputFile.open(OutputPointsFileName.c_str());
if(!DontPruneBranches)
{
memset(outputImageBuffer, 0,
dim[0]*dim[1]*dim[2]*sizeof(OutputPixelType));
}
int i = 0;
std::list<point>::iterator iter = axisPoints.begin();
while(iter != axisPoints.end())
{
OutputImageType::IndexType pt;
pt[0] = iter->x;
pt[1] = iter->y;
pt[2] = iter->z;
if(!DontPruneBranches)
{
outputImage->SetPixel(pt, 255);
}
writeOutputFile << i << " " << iter->x
<< " " << iter->y
<< " " << iter->z << std::endl;
iter++;
i++;
}
std::cout << "Wrote points file." << std::endl;
WriterType::Pointer writer = WriterType::New();
writer->SetFileName(OutputImageFileName.c_str());
writer->SetInput(outputImage);
writer->Update();
std::cout << "Wrote output image." << std::endl;
}
catch( itk::ExceptionObject &excep )
{
std::cerr << argv[0] << " : Exception caught!" << std::endl;
std::cerr << excep << std::endl;
return EXIT_FAILURE;
}
return EXIT_SUCCESS;
}
<?xml version="1.0" encoding="utf-8"?>
<executable>
<category>Filtering</category>
<title>Extract Skeleton</title>
<description>
Extract the skeleton of a binary object. The skeleton can be limited to being a 1D curve or allowed to be a full 2D manifold. The branches of the skeleton can be pruned so that only the maximal center skeleton is returned.
</description>
<version>0.1.0.$Revision: 2104 $(alpha)</version>
<documentation-url></documentation-url>
<license></license>
<contributor>Pierre Seroul, Martin Styner, Guido Gerig, and Stephen Aylward
</contributor>
<acknowledgements>
The original implementation of this method was provided by ETH Zurich, Image Analysis Laboratory of Profs Olaf Kuebler, Gabor Szekely and Guido Gerig. Martin Styner at UNC, Chapel Hill made enhancements. Wrapping for Slicer was provided by Pierre Seroul and Stephen Aylward at Kitware, Inc.
</acknowledgements>
<parameters>
<label>IO</label>
<description>Input/output parameters</description>
<image>
<name>InputImageFileName</name>
<label>Input Image</label>
<channel>input</channel>
<index>1</index>
<description>Input image</description>
</image>
<image>
<name>OutputImageFileName</name>
<label>Output Image</label>
<channel>output</channel>
<index>2</index>
<description>Skeleton of the input image</description>
</image>
</parameters>
<parameters>
<label>Skeleton</label>
<description>Skeleton parameters</description>
<string-enumeration>
<name>SkeletonType</name>
<longflag>type</longflag>
<label>Skeleton type</label>
<description>Type of skeleton to create</description>
<default>1D</default>
<element>1D</element>
<element>2D</element>
</string-enumeration>
<boolean>
<name>DontPruneBranches</name>
<longflag>dontPrune</longflag>
<label>Do not prune branches</label>
<description>Return the full skeleton, not just the maximal skeleton</description>
<default>false</default>
</boolean>
<integer>
<name>NumberOfPoints</name>
<longflag>numPoints</longflag>
<label>Number Of Points</label>
<description>Number of points used to represent the skeleton</description>
<default>100</default>
</integer>
<string>
<name>OutputPointsFileName</name>
<longflag>pointsFile</longflag>
<label>Output points file (.txt)</label>
<description>Name of the file to store the coordinates of the central (1D) skeleton points
</description>
<default>skeleton.txt</default>
</string>
</parameters>
</executable>
// ===============================================
// SkelGraph.cc
// Graphs a Thinning-skeleton
// + Processing utilities of the graph
// ===============================================
#include <stdlib.h>
#include <math.h>
#include <iostream>
#include <iterator>
#include "SkelGraph.h"
static char msg[200];
static char tmp_filename[1024];
/*
===============================================
Constructors, Destructor
===============================================
*/
SkelGraph::SkelGraph()
{
graph = NULL;
to_do = NULL;
endpoints = NULL;
image = NULL;
label_image = NULL;
max_node = NULL;
}
SkelGraph::SkelGraph(SkelGraph * skelgraph)
{ // not fully implemented
if (skelgraph == NULL) {
SkelGraph();
return;
}
// Extracted Graph
if (skelgraph->graph)
graph = new list<skel_branch> (*(skelgraph->graph));
else
graph = NULL;
if (skelgraph->to_do)
to_do = new list<skel_branch> (*(skelgraph->to_do));
else
to_do = NULL;
if (skelgraph->endpoints)
endpoints = new list<point> (*(skelgraph->endpoints));
else
endpoints = NULL;
image = skelgraph->image;
label_image = skelgraph->label_image; // only for temporary use, WATCH OUT
for (int i = 0; i < 3; i++) dim[i] = skelgraph->dim[i];
max_length = skelgraph->max_length;
max_node = NULL; // for storage of start of maximal path
// find right max_node
list<skel_branch>::iterator elem, elem_new;
elem_new = graph->begin();
elem = skelgraph->graph->begin();
while (elem_new != graph->end()) {
if (skelgraph->max_node == &(*elem))
max_node = &(*elem_new);
++ elem_new;
++ elem;
}
}
SkelGraph::~SkelGraph()
{
if (image) delete [] image;
if (label_image) delete [] label_image;
ResetGraph();
}
void SkelGraph::ResetGraph()
{
if (graph && !(graph->empty())) {
list<skel_branch>::iterator elem;
elem = graph->begin();
while (elem != graph->end()) {
// delete content
if (elem->end_1_neighbors) delete elem->end_1_neighbors;
if (elem->end_2_neighbors) delete elem->end_2_neighbors;
if (elem->end_1_point) delete elem->end_1_point;
if (elem->end_2_point) delete elem->end_2_point;
if (elem->acc_path) delete elem->acc_path;
if (elem->max_path) delete elem->max_path;
elem++;
}
delete graph; graph = NULL;
}
if (to_do && !(to_do->empty())) {
list<skel_branch>::iterator elem;
elem = to_do->begin();
while (elem != to_do->end()) {
// delete content
if (elem->end_1_neighbors) delete elem->end_1_neighbors;
if (elem->end_2_neighbors) delete elem->end_2_neighbors;
if (elem->end_1_point) delete elem->end_1_point;
if (elem->end_2_point) delete elem->end_2_point;
if (elem->acc_path) delete elem->acc_path;
if (elem->max_path) delete elem->max_path;
elem++;
}
delete to_do; to_do = NULL;
}
if (endpoints)
delete endpoints;
endpoints = NULL;
}
// -------------------------------------------------------------------------
// Public Methods
// -------------------------------------------------------------------------
void SkelGraph::Extract_skel_graph(unsigned char *orig_image, int orig_dim[3])
// Graph compilation of a thinning skeleton
{
if (graph) ResetGraph();
graph = new list<skel_branch>();
if (label_image) delete [] label_image;
image = orig_image;
for (int i = 0; i < 3; i++) dim[i] = orig_dim[i];
int size_image = dim[0]*dim[1]*dim[2];
label_image = new int[size_image];
for (int i = 0; i < size_image; i++) label_image[i] = 0;
// determine endpoints = points that have exactly 1 neighbor
find_endpoints();
// if (DEBUG_VSKEL)
// cout << endpoints->size() << " Endpoints found" << endl;
// if (while) untreated endpoint -> put it into to_do list
// if (while) to_do list non-empty -> follow branches
// following of branch has 1 neighbor -> label, cont
// branch ends -> stop, next
// multiple branches emerge -> stop, put in to_do list
list<point>::iterator act_endpoint;
act_endpoint = endpoints->begin();
// if (while) untreated endpoint -> put it into to_do list
while (act_endpoint != endpoints->end()) {
if (act_endpoint != endpoints->end()) {
// add to to_do list (which should be empty at this point)
to_do = new list<skel_branch>;
skel_branch *branch_elem;
Add_new_elem_to_todo(branch_elem);
branch_elem->end_1_point->x = branch_elem->end_2_point->x = act_endpoint->x;
branch_elem->end_1_point->y = branch_elem->end_2_point->y = act_endpoint->y;
branch_elem->end_1_point->z = branch_elem->end_2_point->z = act_endpoint->z;
list<skel_branch>::iterator act_branch;
act_branch = to_do->begin();
while (!to_do->empty()) {
// act_branch != to_do->end() &&
// if (while) to_do list non-empty -> follow branches
int branch_done = 0;
point * act_point = act_branch->end_2_point;
int branchID = act_branch->branchID;
// label endpoint
label_image[act_point->x +
dim[0] * (act_point->y + dim[1] * act_point->z)] = branchID;
while (!branch_done) {
list<point> * neighbors = new list<point>();
get_valid_neighbors(act_point, neighbors);
int num_nb = neighbors->size();
if (num_nb == 0) {
// branch ends -> stop, next
branch_done = 1;
} if (num_nb == 1) {
// following of branch has 1 neighbor -> label, cont
point * pt = &(*(neighbors->begin()));
// update length
// since act_point->x - pt->x is either [-1,0,1] -> abs == ^2
act_branch->length += sqrt((float) abs(act_point->x - pt->x) +
abs(act_point->y - pt->y) +
abs(act_point->z - pt->z));
act_point->x = pt->x; act_point->y = pt->y; act_point->z = pt->z;
label_image[act_point->x +
dim[0] * (act_point->y + dim[1] * act_point->z)] = branchID;
} else {
// multiple branches emerge -> stop, put in to_do list
branch_done = 1;
skel_branch ** elems = new skel_branch * [num_nb];
list<point>::iterator act_neighbor = neighbors->begin();
int i = 0;
while (act_neighbor != neighbors->end()) {
point * pt = &(*act_neighbor);
Add_new_elem_to_todo(elems[i]);
// label start point
elems[i]->end_1_point->x = elems[i]->end_2_point->x = pt->x;
elems[i]->end_1_point->y = elems[i]->end_2_point->y = pt->y;
elems[i]->end_1_point->z = elems[i]->end_2_point->z = pt->z;
label_image[pt->x + dim[0] *
(pt->y + dim[1] * pt->z)] = elems[i]->branchID;
// update ends with act_branch
if (! elems[i]->end_1_neighbors)
elems[i]->end_1_neighbors = new list<int>();
elems[i]->end_1_neighbors->push_back(act_branch->branchID);
if (! act_branch->end_2_neighbors)
act_branch->end_2_neighbors = new list<int>();
act_branch->end_2_neighbors->push_back(elems[i]->branchID);
++act_neighbor; i++;
}
// update ends of new branches with each other
for (int i = 0; i < num_nb; i++) {
for (int j = 0; j < num_nb; j++) {
if (i != j) {
if (! elems[i]->end_1_neighbors)
elems[i]->end_1_neighbors = new list<int>();
elems[i]->end_1_neighbors->push_back(elems[j]->branchID);
}
}
}
delete elems; elems = NULL;
} // else
delete neighbors; neighbors = NULL;
} // while (! branch_done)
// copy branch from to_do to graph
graph->insert(graph->end(),*act_branch);
// remove it from to_do
to_do->pop_front();
act_branch = to_do->begin();
}
delete to_do; to_do = NULL;
}
// find next valid endpoint -> an yet unlabeled endpoint
while (act_endpoint != endpoints->end() &&
label_image[act_endpoint->x +
dim[0] * (act_endpoint->y + dim[1] * act_endpoint->z)]) {
++act_endpoint;
}
}
// done
delete endpoints; endpoints = NULL;
delete [] label_image; label_image = NULL;
image = NULL; // no delete, since image points to original
// if (DEBUG_VSKEL)
// cout << graph->size() << " Branches found" << endl;
// graph print
//PrintGraph();
}
void SkelGraph::PrintGraph()
// print actual graph
{
list<skel_branch>::iterator act_graph;
list<int>::iterator act_nb;
act_graph = graph->begin();
cout << "Graph : " << endl;
int cnt = 0;
cout << "Number: Branch Br.ID | N 1 | N 2 | Length | End1 | End2 " << endl;
while (act_graph != graph->end()) {
cnt ++;
cout << cnt << ": Br. " << act_graph->branchID;
if (act_graph->end_1_neighbors) {
act_nb = act_graph->end_1_neighbors->begin();
cout << "| ";
while (act_nb != act_graph->end_1_neighbors->end()) {
cout << *act_nb << ", " ;
act_nb ++;
}
} else {
cout << "| None";
}
if (act_graph->end_2_neighbors) {
act_nb = act_graph->end_2_neighbors->begin();
cout << "| ";
while (act_nb != act_graph->end_2_neighbors->end()) {
cout << *act_nb << ", " ;
act_nb ++;
}
} else {
cout << "| None";
}
cout << "| " << act_graph->length << "| " <<
act_graph->end_1_point->x << "," << act_graph->end_1_point->y << "," <<
act_graph->end_1_point->z << " | " <<
act_graph->end_2_point->x << "," << act_graph->end_2_point->y << "," <<
act_graph->end_2_point->z << " | " << endl;
act_graph++;
}
}
void SkelGraph::Extract_max_axis_in_graph()
// extract maximal path between 2 points in the graph
{
<