#ifndef RTS_ITKVOLUME_H #define RTS_ITKVOLUME_H #include #include "itkImage.h" #include "itkImageFileReader.h" #include "itkImageFileWriter.h" #include "itkRawImageIO.h" #include "itkImageRegionIterator.h" #include #include "rtsFilename.h" #include "rtsDTGrid3D.h" using namespace std; #include "itkRescaleIntensityImageFilter.h" #include "rts_itkImage.h" void rtsProgressBar(int percent); template class rts_itkVolume { public: typedef int uint; typedef itk::Image ITKVolumeType; typedef typename ITKVolumeType::Pointer PointerType; typedef itk::Image ITKSliceType; //typedef itk::Image ITKVolumeType; private: //pointer to the data PointerType imageData; char* UnicodeToANSI(wchar_t* unicodestr) { int a = wcslen(unicodestr)+1; char *ansistr = new char[a]; ::WideCharToMultiByte(CP_ACP, 0, unicodestr, -1, ansistr, a, NULL, NULL); return ansistr; } BSTR ANSIToUnicode(const char* ansistr) { /*On a side note: This BSTR crap isn't the way to go. Try to use wchar_t (Unicode) where possible. Already changed it in the above function because it was causing a bug.*/ int a = strlen(ansistr); BSTR unicodestr = SysAllocStringLen(NULL, a); ::MultiByteToWideChar(CP_ACP, 0, ansistr, a, unicodestr, a); return unicodestr; } public: //construct an implicit function with a size of 1 rts_itkVolume(); ///GetBufferPointer();} T GetMin(); T GetMax(); void SetITKPointer(PointerType pointer){imageData = pointer;} uint DimX(){return imageData->GetLargestPossibleRegion().GetSize()[0];} uint DimY(){return imageData->GetLargestPossibleRegion().GetSize()[1];} uint DimZ(){return imageData->GetLargestPossibleRegion().GetSize()[2];} float VoxelSizeX(){return imageData->GetSpacing()[0];} float VoxelSizeY(){return imageData->GetSpacing()[1];} float VoxelSizeZ(){return imageData->GetSpacing()[2];} void SetPixel(uint x, uint y, uint z, T value); void SetSlice(rts_itkImage image, int slice); T GetPixel(uint x, uint y, uint z); rts_itkImage GetSlice(int slice); rts_itkVolume SubVolume(uint px, uint py, uint pz, uint sx, uint sy, uint sz); //mathematica operations T operator=(T rhs); rts_itkVolume operator-(T rhs); rts_itkVolume operator+(T rhs); rts_itkVolume operator-(rts_itkVolume rhs); void Print(ostream &os); //simple data processing void Rescale(T new_min, T new_max); void Binary(T threshold, T true_value); ///* grid, bool debug = false); }; template rts_itkVolume rts_itkVolume::SubVolume(uint px, uint py, uint pz, uint sx, uint sy, uint sz) { /*This function returns the sub-volume specified by a corner point and size*/ //first make sure that the sub-volume is contained within the image if(px < 0) {sx += px; px = 0;} if(py < 0) {sy += py; py = 0;} if(pz < 0) {sz += pz; pz = 0;} if(px >= DimX()) px = DimX() - 1; if(py >= DimY()) py = DimY() - 1; if(pz >= DimZ()) pz = DimZ() - 1; if(px + sx > DimX()) sx = DimX() - px - 1; if(py + sy > DimY()) sy = DimY() - py - 1; if(pz + sz > DimZ()) sz = DimZ() - pz - 1; //cout< d(destination.imageData, destination.imageData->GetLargestPossibleRegion()); //get an iterator for the source region ITKVolumeType::RegionType region; ITKVolumeType::IndexType index; ITKVolumeType::SizeType size; index[0] = px; index[1] = py; index[2] = pz; size[0] = sx; size[1] = sy; size[2] = sz; region.SetIndex(index); region.SetSize(size); itk::ImageRegionIterator s(imageData, region); //copy the data from source region to destination volume for(s.GoToBegin(), d.GoToBegin(); !s.IsAtEnd(); s++, d++) d.Set(s.Get()); return destination; } template T rts_itkVolume::operator=(T rhs) { /*itk::ImageRegionIterator i(imageData, imageData->GetLargestPossibleRegion()); for(i.GoToBegin(); !i.IsAtEnd(); i++) i.Set(rhs); */ imageData->FillBuffer(rhs); return rhs; } template rts_itkVolume rts_itkVolume::operator-(T rhs) { rts_itkVolume result(DimX(), DimY(), DimZ()); itk::ImageRegionIterator w(result.imageData, result.imageData->GetLargestPossibleRegion()); itk::ImageRegionIterator r(imageData, imageData->GetLargestPossibleRegion()); for(r.GoToBegin(), w.GoToBegin(); !r.IsAtEnd(); r++, w++) w.Set(r.Get() - rhs); return result; } template rts_itkVolume rts_itkVolume::operator+(T rhs) { rts_itkVolume result(DimX(), DimY(), DimZ()); itk::ImageRegionIterator w(result.imageData, result.imageData->GetLargestPossibleRegion()); itk::ImageRegionIterator r(imageData, imageData->GetLargestPossibleRegion()); for(r.GoToBegin(), w.GoToBegin(); !r.IsAtEnd(); r++, w++) w.Set(r.Get() + rhs); return result; } template rts_itkVolume rts_itkVolume::operator-(rts_itkVolume rhs) { rts_itkVolume result(DimX(), DimY(), DimZ()); itk::ImageRegionIterator w(result.imageData, result.imageData->GetLargestPossibleRegion()); itk::ImageRegionIterator r(rhs.imageData, rhs.imageData->GetLargestPossibleRegion()); itk::ImageRegionIterator l(imageData, imageData->GetLargestPossibleRegion()); for(r.GoToBegin(), l.GoToBegin(), w.GoToBegin(); !r.IsAtEnd(); r++, l++, w++) w.Set(l.Get() - r.Get()); return result; } template void rts_itkVolume::Print(ostream &os) { ITKVolumeType::SizeType size; size = imageData->GetLargestPossibleRegion().GetSize(); int x, y, z; for(z=0; z rts_itkVolume::rts_itkVolume() { imageData = ITKVolumeType::New(); } template rts_itkVolume::rts_itkVolume(uint res_x, uint res_y, uint res_z) { imageData = ITKVolumeType::New(); itk::Image::RegionType region; itk::Image::SizeType size; size[0] = res_x; size[1] = res_y; size[2] = res_z; region.SetSize(size); imageData->SetRegions(region); try { imageData->Allocate(); } catch(itk::ExceptionObject & exp) { std::cout< void rts_itkVolume::Init(uint res_x, uint res_y, uint res_z) { itk::Image::RegionType region; itk::Image::SizeType size; size[0] = res_x; size[1] = res_y; size[2] = res_z; region.SetSize(size); imageData->SetRegions(region); try { imageData->Allocate(); } catch(itk::ExceptionObject & exp) { std::cout< void rts_itkVolume::SetSpacing(float voxel_x, float voxel_y, float voxel_z) { float spacing[3]; spacing[0] = voxel_x; spacing[1]= voxel_y; spacing[2] = voxel_z; imageData->SetSpacing(spacing); } template inline T rts_itkVolume::GetPixel(uint x, uint y, uint z) { T result; if(x < 0 || x >= DimX() || y < 0 || y >= DimY() || z < 0 || z >= DimZ()) { memset(&result, 0, sizeof(T)); return result; } itk::Image::IndexType index; index[0] = x; index[1] = y; index[2] = z; return imageData->GetPixel(index); } template inline T rts_itkVolume::GetMin() { int ix, iy, iz; T currentMin = GetPixel(0, 0, 0); T n; for(ix=0; ix inline T rts_itkVolume::GetMax() { int ix, iy, iz; T currentMax = GetPixel(0, 0, 0); T n; for(ix=0; ix currentMax) currentMax = n; } return currentMax; } template inline T rts_itkVolume::operator ()(uint x, uint y, uint z) { return GetPixel(x, y, z); } template void rts_itkVolume::LoadRAW(uint header_size, uint size_x, uint size_y, uint size_z, string filename) { ITKVolumeType::RegionType region; ITKVolumeType::SizeType size; size[0] = size_x; size[1] = size_y; size[2] = size_z; region.SetSize(size); imageData->SetRegions(region); try { imageData->Allocate(); } catch(itk::ExceptionObject & exp) { std::cout<GetBufferPointer(), DimX()*DimY()*DimZ()*sizeof(T)); infile.close(); } template void rts_itkVolume::LoadRAV(string filename) { //open the file ifstream infile(filename.c_str(), ios::out | ios::binary); //create the files stream if(!infile) return; //first read the header int dimx, dimy, dimz, bytesize; infile.read((char*)&dimx, sizeof(int)); infile.read((char*)&dimy, sizeof(int)); infile.read((char*)&dimz, sizeof(int)); infile.read((char*)&bytesize, sizeof(int)); //allocate space for the image ITKVolumeType::RegionType region; ITKVolumeType::SizeType size; size[0] = dimx; size[1] = dimy; size[2] = dimz; region.SetSize(size); imageData->SetRegions(region); try { imageData->Allocate(); } catch(itk::ExceptionObject & exp) { std::cout<GetBufferPointer(), DimX()*DimY()*DimZ()*sizeof(T)); infile.close(); } template void rts_itkVolume::LoadVOL(string filename) { //open the file ifstream infile(filename.c_str(), ios::out | ios::binary); //create the files stream if(!infile) return; //first read the header int dimx, dimy, dimz, bytesize; infile.read((char*)&dimx, sizeof(int)); infile.read((char*)&dimy, sizeof(int)); infile.read((char*)&dimz, sizeof(int)); //allocate space for the image ITKVolumeType::RegionType region; ITKVolumeType::SizeType size; size[0] = dimx; size[1] = dimy; size[2] = dimz; region.SetSize(size); imageData->SetRegions(region); try { imageData->Allocate(); } catch(itk::ExceptionObject & exp) { std::cout<GetBufferPointer(), DimX()*DimY()*DimZ()*sizeof(T)); infile.close(); } template void rts_itkVolume::LoadStack(string directory, string filename_mask, int max_files = -1) { /*Load a list of file names based on the user-specified mask*/ //create the complete mask if(directory[directory.size() - 1] != '/') directory += '/'; string full_mask = directory; full_mask += filename_mask; //create a temporary vector to store the file names vector fileList; //create a handle for the search HANDLE search_handle; WIN32_FIND_DATA found_data; //start the search BSTR unicodestr = ANSIToUnicode(full_mask.c_str()); search_handle = FindFirstFile(unicodestr, &found_data); ::SysFreeString(unicodestr); //if there are no files, return if(search_handle == INVALID_HANDLE_VALUE) return; string new_file; char* ansistr = UnicodeToANSI(found_data.cFileName); //char* ansistr = (char*)found_data.cFileName; //save the first filename new_file = directory; new_file += ansistr; fileList.push_back(new_file); delete[] ansistr; //now loop through the rest of the files while(FindNextFile(search_handle, &found_data)) { char* ansistr = UnicodeToANSI(found_data.cFileName); new_file = directory; new_file += ansistr; //cout< ReaderType; ReaderType::Pointer reader = ReaderType::New(); reader->SetFileName(fileList[0].getString()); ITKSliceType::Pointer image = reader->GetOutput(); try { reader->Update(); } catch(itk::ExceptionObject & exp) { std::cout<(fileList.size(), max_files); cout<<"Loading: "<GetLargestPossibleRegion().GetSize(); //get the slice size ITKVolumeType::SizeType volSize; //compute the volume size volSize[0] = size[0]; volSize[1] = size[1]; volSize[2] = max_files; imageData = ITKVolumeType::New(); //create the volume ITKVolumeType::RegionType region; region.SetSize(volSize); imageData->SetRegions(region); imageData->Allocate(); //allocate space for(i=0; iSetFileName(fileList[i].getString()); ITKSliceType::Pointer slice = reader->GetOutput(); reader->Update(); InsertSlice(i, slice); //cout< void rts_itkVolume::LoadSlice(string filename, int slice) { //load the specified image typedef itk::ImageFileReader ReaderType; ReaderType::Pointer reader = ReaderType::New(); reader->SetFileName(filename.c_str()); ITKSliceType::Pointer image = reader->GetOutput(); try { reader->Update(); } catch(itk::ExceptionObject & exp) { std::cout< rts_itkImage rts_itkVolume::GetSlice(int slice) { //create a new image rts_itkImage outSlice(DimX(), DimY()); int x, y; for(x=0; x void rts_itkVolume::SetSlice(rts_itkImage image, int slice) { int x, y; for(x=0; x void rts_itkVolume::SaveRAV(string filename) { ofstream outfile(filename.c_str(), ios::out | ios::binary); //create the files stream if(!outfile) return; int dimx = DimX(); int dimy = DimY(); int dimz = DimZ(); int bytesize = sizeof(T); outfile.write((char*)&dimx, sizeof(int)); outfile.write((char*)&dimy, sizeof(int)); outfile.write((char*)&dimz, sizeof(int)); outfile.write((char*)&bytesize, sizeof(int)); outfile.write((char*)imageData->GetBufferPointer(), DimX()*DimY()*DimZ()*sizeof(T)); outfile.close(); } template void rts_itkVolume::SaveVOL(string filename) { ofstream outfile(filename.c_str(), ios::out | ios::binary); //create the files stream if(!outfile) return; int dimx = DimX(); int dimy = DimY(); int dimz = DimZ(); outfile.write((char*)&dimx, sizeof(int)); outfile.write((char*)&dimy, sizeof(int)); outfile.write((char*)&dimz, sizeof(int)); outfile.write((char*)imageData->GetBufferPointer(), DimX()*DimY()*DimZ()*sizeof(T)); outfile.close(); } template void rts_itkVolume::InsertSlice(uint z_position, typename ITKSliceType::Pointer slice) { itk::Image::SizeType size = slice->GetLargestPossibleRegion().GetSize(); itk::Image::IndexType index; int x, y; for(x=0; xGetPixel(index)); } } template void rts_itkVolume::SaveRAW(string filename) { ofstream outfile(filename.c_str(), ios::out | ios::binary); //create the files stream if(!outfile) return; outfile.write((char*)imageData->GetBufferPointer(), DimX()*DimY()*DimZ()*sizeof(T)); outfile.close(); } template void rts_itkVolume::SetPixel(uint x, uint y, uint z, T value) { ITKVolumeType::IndexType index; index[0] = x; index[1] = y; index[2] = z; imageData->SetPixel(index, value); } template void rts_itkVolume::Rescale(T new_min, T new_max) { typedef itk::RescaleIntensityImageFilter RescaleFilterType; RescaleFilterType::Pointer rescaleFilter = RescaleFilterType::New(); rescaleFilter->SetOutputMinimum(new_min); rescaleFilter->SetOutputMaximum(new_max); rescaleFilter->SetInput(imageData); rescaleFilter->Update(); imageData = rescaleFilter->GetOutput(); } template void rts_itkVolume::Binary(T threshold, T true_value) { /** This function converts an implicit function into a binary or characteristic function describing the solid represented by the level set at isovalue "threshold". All values below threshold are set to zero while all values above threshold are set to the specified "true_value". In order to use this function, the data type T must be able to be set to 0. **/ int max_index = DimX() * DimY() * DimZ(); //find the size of the data array int i; T* ptrBits = imageData->GetBufferPointer(); for(i=0; i= threshold) ptrBits[i] = true_value; else ptrBits[i] = 0; } template void rts_itkVolume::InsertDTGrid(rtsDTGrid3D* grid, bool debug = false) { //find the extents of the DT Grid int min_x, min_y, min_z, max_x, max_y, max_z; grid->getBounds(min_x, min_y, min_z, max_x, max_y, max_z); //allocate the appropriate amount of space ITKVolumeType::RegionType region; ITKVolumeType::SizeType size; size[0] = (max_x - min_x) + 1; size[1] = (max_y - min_y) + 1; size[2] = (max_z - min_z) + 1; region.SetSize(size); imageData->SetRegions(region); try { imageData->Allocate(); } catch(itk::ExceptionObject & exp) { std::cout<FillBuffer(grid->background); //copy values from the DT Grid to the image ITKVolumeType::IndexType index; //create an image index rtsDTGrid3D::iterator i; //create an iterator for(i = grid->begin(); i!= grid->after(); i++) { index[0] = i.X1() - min_x; index[1] = i.X2() - min_y; index[2] = i.X3() - min_z; imageData->SetPixel(index, i.Value()); //cout<