1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207
|
/*=========================================================================
Program: Insight Segmentation & Registration Toolkit
Module: VisibleHumanStreamReadWrite.cxx
Language: C++
Date: $Date$
Version: $Revision$
Copyright (c) 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 "itkRawImageIO.h"
#include "itkNumericSeriesFileNames.h"
#include "itkImageSeriesReader.h"
#include "itkImageFileWriter.h"
#include "itkSimpleFilterWatcher.h"
#include "itkShrinkImageFilter.h"
#include "itkComposeRGBImageFilter.h"
#include "itkExtractImageFilter.h"
#include "itkShrinkImageFilter.h"
#include "itkMeanImageFilter.h"
// The Insight Toolkit was originally motivated by a need for software
// tools to segment and register the National Library of Medicine’s
// Visible Human Project data sets. The data is freely available
// through NLM’s website [3]. The original Visible Male cryosectional
// images are non-interlaced 24-bit RGB pixels with a resolution of
// 2048x1216 pixels by 1871 slices with a physical spacing of
// approximately 0.33 mm in slice and 1.0 mm between slices. Theses
// dimensions results in about 13 gigabytes of data, which is an
// appropriate size to demonstrate streaming. The following are two
// examples of streaming which shows all three IO classes capable of
// streaming along with the two types of streaming supported by the
// writer.
//
// A coronal slice is a classic view of the Visible Male. The
// following is an example that reads the entire raw dataset and
// generates that classic image:
int main(int argc, char *argv[])
{
if ( argc < 3 )
{
std::cerr << "Missing Parameters " << std::endl;
std::cerr << "Usage: " << argv[0];
std::cerr << " visibleHumanPath outputImageFile" << std::endl;
return EXIT_FAILURE;
}
std::string visibleHumanPath = argv[1];
std::string outputImageFile = argv[2];
typedef itk::RGBPixel<unsigned char> RGBPixelType;
typedef unsigned char PixelType;
typedef itk::Image<PixelType, 3> ImageType;
typedef itk::Image<RGBPixelType, 3> RGB3DImageType;
typedef itk::Image<RGBPixelType, 2> RGB2DImageType;
// genderate the names of the decompressed Visible Male images
typedef itk::NumericSeriesFileNames NameGeneratorType;
NameGeneratorType::Pointer nameGenerator = NameGeneratorType::New();
nameGenerator->SetSeriesFormat( visibleHumanPath+"a_vm%04d.raw" );
nameGenerator->SetStartIndex( 1001 );
nameGenerator->SetEndIndex( 2878 );
nameGenerator->SetIncrementIndex( 1 );
// create a ImageIO for the red channel
typedef itk::RawImageIO<PixelType, 2> ImageIOType;
ImageIOType::Pointer rimageio = ImageIOType::New();
rimageio->SetDimensions( 0, 2048 );
rimageio->SetDimensions( 1, 1216 );
rimageio->SetSpacing( 0, .33 );
rimageio->SetSpacing( 1, .33 );
rimageio->SetHeaderSize(rimageio->GetImageSizeInPixels()*0);
// create a ImageIO for the green channel
ImageIOType::Pointer gimageio = ImageIOType::New();
gimageio->SetDimensions( 0, 2048 );
gimageio->SetDimensions( 1, 1216 );
gimageio->SetSpacing( 0, .33 );
gimageio->SetSpacing( 1, .33 );
gimageio->SetHeaderSize(gimageio->GetImageSizeInPixels()*1);
// create a ImageIO for the blue channel
ImageIOType::Pointer bimageio = ImageIOType::New();
bimageio->SetDimensions( 0, 2048 );
bimageio->SetDimensions( 1, 1216 );
bimageio->SetSpacing( 0, .33 );
bimageio->SetSpacing( 1, .33 );
bimageio->SetHeaderSize(bimageio->GetImageSizeInPixels()*2);
typedef itk::ImageSeriesReader< ImageType > SeriesReaderType;
SeriesReaderType::Pointer rreader = SeriesReaderType::New();
rreader->SetFileNames ( nameGenerator->GetFileNames() );
rreader->SetImageIO( rimageio );
// the z-spacing will default to be correctly 1mm
SeriesReaderType::Pointer greader = SeriesReaderType::New();
greader->SetFileNames ( nameGenerator->GetFileNames() );
greader->SetImageIO( gimageio );
SeriesReaderType::Pointer breader = SeriesReaderType::New();
breader->SetFileNames ( nameGenerator->GetFileNames() );
breader->SetImageIO( bimageio );
typedef itk::ComposeRGBImageFilter< ImageType, RGB3DImageType > ComposeRGBFilterType;
ComposeRGBFilterType::Pointer composeRGB = ComposeRGBFilterType::New();
composeRGB->SetInput1( rreader->GetOutput() );
composeRGB->SetInput2( greader->GetOutput() );
composeRGB->SetInput3( breader->GetOutput() );
// this filter is needed if square pixels are needed
// const int xyShrinkFactor = 3;
// typedef itk::ShrinkImageFilter< RGB3DImageType, RGB3DImageType > ShrinkImageFilterType;
// ShrinkImageFilterType::Pointer shrinker = ShrinkImageFilterType::New();
// shrinker->SetInput( composeRGB->GetOutput() );
// shrinker->SetShrinkFactors( xyShrinkFactor );
// shrinker->SetShrinkFactor( 2, 1 );
// update output information to know propagate the size of the largest
// possible region
composeRGB->UpdateOutputInformation();
RGB3DImageType::RegionType coronalSlice = composeRGB->GetOutput()->GetLargestPossibleRegion();
coronalSlice.SetIndex( 1, 448 );
coronalSlice.SetSize( 1, 0 );
// another interesting view
// RGB3DImageType::RegionType sagittalSlice = shrinker->GetOutput()->GetLargestPossibleRegion();
// sagittalSlice.SetIndex( 0, 1024 );
// sagittalSlice.SetSize( 0, 0 );
// create a 2D coronal slice from the volume
typedef itk::ExtractImageFilter< RGB3DImageType, RGB2DImageType > ExtractFilterType;
ExtractFilterType::Pointer extract = ExtractFilterType::New();
extract->SetInput( composeRGB->GetOutput() );
extract->SetExtractionRegion(coronalSlice);
typedef itk::ImageFileWriter< RGB2DImageType > ImageWriterType;
ImageWriterType::Pointer writer = ImageWriterType::New();
writer->SetFileName( outputImageFile );
// this line is a request for the number of regions
// the image will be broken into
writer->SetNumberOfStreamDivisions( 200 );
writer->SetInput( extract->GetOutput() );
itk::SimpleFilterWatcher watcher1(writer, "stream writing");
try
{
// update by streaming
writer->Update();
}
catch( itk::ExceptionObject & err )
{
std::cerr << "ExceptionObject caught !" << std::endl;
std::cerr << err << std::endl;
return EXIT_FAILURE;
}
// This example creates a RawImageIO and ImageSeriesReader for each
// color channel in the data. Notice that there are no special methods
// that are needed to enable streaming; it will just respond correctly
// to requests from the pipeline. In the ComposeRGBImageFilter, the
// channels are composited into a single color image. Then the
// information is updated to initialize the coronal slice region to be
// extracted. The final filter, ImageFileWriter, writes out the file
// as a Meta Image type, which fully supports IO streaming.
//
// The most interesting aspect of this example is not the filters
// used, but how ITK’s pipeline manages its execution. The final
// output image is 2048 by 1878 pixels. The ImageFileWriter breaks
// this 2D image into 200 separate regions, which have the size of
// about 2048 by 10 pixels; each region is streamed and processes
// through the pipeline. The writer makes 200 calls to its ImageIO
// object to write the individual regions. The extractor converts this
// 2D region into a 3D region of 2048 by 1 by 10 pixels, which is
// propagated to the ImageSeriesReader. Then the reader reads the
// entire slice, but only copies the requested sub-region to its
// output. This pipeline is so efficient because very little data is
// actually processed at any one stage of the pipeline due to
// streaming IO.
return EXIT_SUCCESS;
}
|