diff --git a/Modules/DiffusionCmdApps/FiberProcessing/CMakeLists.txt b/Modules/DiffusionCmdApps/FiberProcessing/CMakeLists.txt index f58e95d..3272d9d 100644 --- a/Modules/DiffusionCmdApps/FiberProcessing/CMakeLists.txt +++ b/Modules/DiffusionCmdApps/FiberProcessing/CMakeLists.txt @@ -1,46 +1,47 @@ option(BUILD_DiffusionFiberProcessingCmdApps "Build commandline tools for diffusion fiber processing" OFF) if(BUILD_DiffusionFiberProcessingCmdApps OR MITK_BUILD_ALL_APPS) # needed include directories include_directories( ${CMAKE_CURRENT_SOURCE_DIR} ${CMAKE_CURRENT_BINARY_DIR} ) # list of diffusion cmdapps # if an app requires additional dependencies # they are added after a "^^" and separated by "_" set( diffusionFiberProcessingcmdapps Sift2WeightCopy^^ FiberExtraction^^ FiberExtractionRoi^^ FiberProcessing^^ FitFibersToImage^^ FiberDirectionExtraction^^ FiberJoin^^ FiberClustering^^ TractDensityFilter^^ + FiberColoring^^ ) foreach(diffusionFiberProcessingcmdapp ${diffusionFiberProcessingcmdapps}) # extract cmd app name and dependencies string(REPLACE "^^" "\\;" cmdapp_info ${diffusionFiberProcessingcmdapp}) set(cmdapp_info_list ${cmdapp_info}) list(GET cmdapp_info_list 0 appname) list(GET cmdapp_info_list 1 raw_dependencies) string(REPLACE "_" "\\;" dependencies "${raw_dependencies}") set(dependencies_list ${dependencies}) mitkFunctionCreateCommandLineApp( NAME ${appname} DEPENDS MitkDiffusionCmdApps MitkMriSimulation MitkFiberTracking ${dependencies_list} PACKAGE_DEPENDS ) endforeach() if(EXECUTABLE_IS_ENABLED) MITK_INSTALL_TARGETS(EXECUTABLES ${EXECUTABLE_TARGET}) endif() endif() diff --git a/Modules/DiffusionCmdApps/FiberProcessing/FiberColoring.cpp b/Modules/DiffusionCmdApps/FiberProcessing/FiberColoring.cpp new file mode 100644 index 0000000..53ab3b0 --- /dev/null +++ b/Modules/DiffusionCmdApps/FiberProcessing/FiberColoring.cpp @@ -0,0 +1,114 @@ +/*=================================================================== + +The Medical Imaging Interaction Toolkit (MITK) + +Copyright (c) German Cancer Research Center. + +All rights reserved. + +This software is distributed WITHOUT ANY WARRANTY; without +even the implied warranty of MERCHANTABILITY or FITNESS FOR +A PARTICULAR PURPOSE. + +See LICENSE.txt or http://www.mitk.org for details. + +===================================================================*/ + +#include +#include +#include +#include + +#include +#include +#include + +#include +#include +#include "mitkDiffusionCommandLineParser.h" +#include +#include +#include +#include +#include +#include + + +mitk::FiberBundle::Pointer LoadFib(std::string filename) +{ + std::vector fibInfile = mitk::IOUtil::Load(filename); + if( fibInfile.empty() ) + std::cout << "File " << filename << " could not be read!"; + mitk::BaseData::Pointer baseData = fibInfile.at(0); + return dynamic_cast(baseData.GetPointer()); +} + +/*! +\brief Modify input tractogram: fiber resampling, compression, pruning and transformation. +*/ +int main(int argc, char* argv[]) +{ + mitkDiffusionCommandLineParser parser; + + parser.setTitle("Fiber Coloring"); + parser.setCategory("Fiber Tracking and Processing Methods"); + parser.setDescription("Color tractogram."); + parser.setContributor("MIC"); + + parser.setArgumentPrefix("--", "-"); + + parser.beginGroup("1. Mandatory arguments:"); + parser.addArgument("", "i", mitkDiffusionCommandLineParser::String, "Input:", "Input fiber bundle (.fib, .trk, .tck)", us::Any(), false, false, false, mitkDiffusionCommandLineParser::Input); + parser.addArgument("", "o", mitkDiffusionCommandLineParser::String, "Output:", "Output fiber bundle (.fib)", us::Any(), false, false, false, mitkDiffusionCommandLineParser::Output); + parser.addArgument("resample", "", mitkDiffusionCommandLineParser::Float, "", ""); + parser.endGroup(); + + parser.beginGroup("2. Color by scalar map:"); + parser.addArgument("scalar_map", "", mitkDiffusionCommandLineParser::String, "", "", us::Any(), true, false, false, mitkDiffusionCommandLineParser::Input); + parser.endGroup(); + + + std::map parsedArgs = parser.parseArguments(argc, argv); + if (parsedArgs.size()==0) + return EXIT_FAILURE; + + std::string inFileName = us::any_cast(parsedArgs["i"]); + std::string outFileName = us::any_cast(parsedArgs["o"]); + + float resample = -1; + if (parsedArgs.count("resample")) + resample = us::any_cast(parsedArgs["resample"]); + + try + { + mitk::FiberBundle::Pointer fib = LoadFib(inFileName); + + if (resample>0) + fib->ResampleSpline(resample); + + if (parsedArgs.count("scalar_map")) + { + auto scalar_map = mitk::IOUtil::Load(us::any_cast(parsedArgs["scalar_map"])); + + fib->ColorFibersByScalarMap(scalar_map, false, false, mitk::LookupTable::MULTILABEL, 1.0); + } + mitk::IOUtil::Save(fib.GetPointer(), outFileName ); + + } + catch (const itk::ExceptionObject& e) + { + std::cout << e.what(); + return EXIT_FAILURE; + } + catch (std::exception& e) + { + std::cout << e.what(); + return EXIT_FAILURE; + } + catch (...) + { + std::cout << "ERROR!?!"; + return EXIT_FAILURE; + } + return EXIT_SUCCESS; +} diff --git a/Modules/DiffusionCore/IODataStructures/mitkTrackvis.cpp b/Modules/DiffusionCore/IODataStructures/mitkTrackvis.cpp index 62bb244..0dbc893 100644 --- a/Modules/DiffusionCore/IODataStructures/mitkTrackvis.cpp +++ b/Modules/DiffusionCore/IODataStructures/mitkTrackvis.cpp @@ -1,282 +1,287 @@ #include #include TrackVisFiberReader::TrackVisFiberReader() { m_Filename = ""; m_FilePointer = nullptr; } TrackVisFiberReader::~TrackVisFiberReader() { if (m_FilePointer) fclose( m_FilePointer ); } // Create a TrackVis file and store standard metadata. The file is ready to append fibers. // --------------------------------------------------------------------------------------- short TrackVisFiberReader::create(std::string filename , mitk::FiberBundle *fib, bool print_header) { m_Header = fib->GetTrackVisHeader(); if (print_header) this->print_header(); // write the header to the file m_FilePointer = fopen(filename.c_str(),"w+b"); if (m_FilePointer == nullptr) { printf("[ERROR] Unable to create file '%s'\n",filename.c_str()); return 0; } if (fwrite((char*)&m_Header, 1, 1000, m_FilePointer) != 1000) MITK_ERROR << "TrackVis::create : Error occurding during writing fiber."; this->m_Filename = filename; return 1; } // Open an existing TrackVis file and read metadata information. // The file pointer is positiond at the beginning of fibers data // ------------------------------------------------------------- short TrackVisFiberReader::open( std::string filename ) { m_FilePointer = std::fopen(filename.c_str(), "rb"); if (m_FilePointer == nullptr) { printf("[ERROR] Unable to open file '%s'\n",filename.c_str()); return 0; } this->m_Filename = filename; return fread((char*)(&m_Header), 1, 1000, m_FilePointer); } short TrackVisFiberReader::write(const mitk::FiberBundle *fib) { vtkSmartPointer poly = fib->GetFiberPolyData(); { mitk::Geometry3D::Pointer geometry = mitk::Geometry3D::New(); vtkSmartPointer< vtkMatrix4x4 > matrix = vtkSmartPointer< vtkMatrix4x4 >::New(); matrix->Identity(); for (int i=0; i<4; ++i) for (int j=0; j<4; ++j) { if (j<3) matrix->SetElement(i, j, m_Header.vox_to_ras[i][j]/m_Header.voxel_size[j]); else matrix->SetElement(i, j, m_Header.vox_to_ras[i][j]); } if (m_Header.voxel_order[0]=='R') { matrix->SetElement(0,0,-matrix->GetElement(0,0)); matrix->SetElement(0,1,-matrix->GetElement(0,1)); matrix->SetElement(0,2,-matrix->GetElement(0,2)); matrix->SetElement(0,3,-matrix->GetElement(0,3)); } if (m_Header.voxel_order[1]=='A') { matrix->SetElement(1,0,-matrix->GetElement(1,0)); matrix->SetElement(1,1,-matrix->GetElement(1,1)); matrix->SetElement(1,2,-matrix->GetElement(1,2)); matrix->SetElement(1,3,-matrix->GetElement(1,3)); } if (m_Header.voxel_order[2]=='I') { matrix->SetElement(2,0,-matrix->GetElement(2,0)); matrix->SetElement(2,1,-matrix->GetElement(2,1)); matrix->SetElement(2,2,-matrix->GetElement(2,2)); matrix->SetElement(2,3,-matrix->GetElement(2,3)); } geometry->SetIndexToWorldTransformByVtkMatrix(matrix); vtkSmartPointer transformFilter = vtkSmartPointer::New(); transformFilter->SetInputData(poly); transformFilter->SetTransform(geometry->GetVtkTransform()->GetInverse()); transformFilter->Update(); poly = transformFilter->GetOutput(); } for (unsigned int i=0; iGetNumFibers(); i++) { vtkCell* cell = poly->GetCell(i); int numPoints = cell->GetNumberOfPoints(); vtkPoints* points = cell->GetPoints(); unsigned int numSaved, pos = 0; //float* tmp = new float[3*maxSteps]; std::vector< float > tmp; tmp.reserve(3*numPoints); numSaved = numPoints; for(unsigned int i=0; iGetPoint(i); - tmp[pos++] = p[0]; - tmp[pos++] = p[1]; - tmp[pos++] = p[2]; + // TRK coordinates are corner based, so we have to shift the center based vtk coordinates by half a voxel + tmp[pos++] = p[0] + m_Header.voxel_size[0]/2; + tmp[pos++] = p[1] + m_Header.voxel_size[1]/2; + tmp[pos++] = p[2] + m_Header.voxel_size[2]/2; } // write the coordinates to the file if ( fwrite((char*)&numSaved, 1, 4, m_FilePointer) != 4 ) { printf( "[ERROR] Problems saving the fiber!\n" ); return 1; } if ( fwrite((char*)&(tmp.front()), 1, 4*pos, m_FilePointer) != 4*pos ) { printf( "[ERROR] Problems saving the fiber!\n" ); return 1; } } return 0; } void TrackVisFiberReader::print_header() { std::cout << "--------------------------------------------------------" << std::endl; std::cout << "see http://trackvis.org/docs/?subsect=fileformat" << std::endl; std::cout << "ONLY vox_to_ras AND voxel_order HEADER ENTRIES ARE USED FOR FIBER COORDINATE TRANSFORMATIONS!" << std::endl; std::cout << "\nid_string (should be \"TRACK\"): " << m_Header.id_string << std::endl; std::cout << "dim: [" << std::defaultfloat << m_Header.dim[0] << " " << m_Header.dim[1] << " " << m_Header.dim[2] << "]" << std::endl; std::cout << "voxel_size: [" << m_Header.voxel_size[0] << " " << m_Header.voxel_size[1] << " " << m_Header.voxel_size[2] << "]" << std::endl; std::cout << "origin: [" << m_Header.origin[0] << " " << m_Header.origin[1] << " " << m_Header.origin[2] << "]" << std::endl; std::cout << "vox_to_world: " << std::scientific << std::endl; std::cout << "[[" << m_Header.vox_to_ras[0][0] << ", " << m_Header.vox_to_ras[0][1] << ", " << m_Header.vox_to_ras[0][2] << ", " << m_Header.vox_to_ras[0][3] << "]" << std::endl; std::cout << " [" << m_Header.vox_to_ras[1][0] << ", " << m_Header.vox_to_ras[1][1] << ", " << m_Header.vox_to_ras[1][2] << ", " << m_Header.vox_to_ras[1][3] << "]" << std::endl; std::cout << " [" << m_Header.vox_to_ras[2][0] << ", " << m_Header.vox_to_ras[2][1] << ", " << m_Header.vox_to_ras[2][2] << ", " << m_Header.vox_to_ras[2][3] << "]" << std::endl; std::cout << " [" << m_Header.vox_to_ras[3][0] << ", " << m_Header.vox_to_ras[3][1] << ", " << m_Header.vox_to_ras[3][2] << ", " << m_Header.vox_to_ras[3][3] << "]]" << std::defaultfloat << std::endl; std::cout << "voxel_order: " << m_Header.voxel_order[0] << m_Header.voxel_order[1] << m_Header.voxel_order[2] << std::endl; std::cout << "pad1: " << m_Header.pad1[0] << m_Header.pad1[1] << std::endl; std::cout << "pad2: " << m_Header.pad2[0] << m_Header.pad2[1] << m_Header.pad2[2] << std::endl; std::cout << "image_orientation_patient: [" << m_Header.image_orientation_patient[0] << " " << m_Header.image_orientation_patient[1] << " " << m_Header.image_orientation_patient[2] << " " << m_Header.image_orientation_patient[3] << " " << m_Header.image_orientation_patient[4] << " " << m_Header.image_orientation_patient[5] << "]" << std::endl; std::cout << "invert_x: " << static_cast(m_Header.invert_x) << std::endl; std::cout << "invert_y: " << static_cast(m_Header.invert_y) << std::endl; std::cout << "invert_z: " << static_cast(m_Header.invert_z) << std::endl; std::cout << "swap_xy: " << static_cast(m_Header.swap_xy) << std::endl; std::cout << "swap_yz: " << static_cast(m_Header.swap_yz) << std::endl; std::cout << "swap_zx: " << static_cast(m_Header.swap_zx) << std::endl; std::cout << "n_count: " << m_Header.n_count << std::endl; std::cout << "version: " << m_Header.version << std::endl; std::cout << "hdr_size: " << m_Header.hdr_size << std::endl; std::cout << "\nNot printed: n_scalars, scalar_name, n_properties, property_name, reserved" << std::endl; std::cout << "--------------------------------------------------------" << std::endl; } short TrackVisFiberReader::read( mitk::FiberBundle* fib, bool use_matrix, bool print_header) { int numPoints; vtkSmartPointer vtkNewPoints = vtkSmartPointer::New(); vtkSmartPointer vtkNewCells = vtkSmartPointer::New(); if (print_header) this->print_header(); while (fread((char*)&numPoints, 1, 4, m_FilePointer)==4) { if ( numPoints <= 0 ) { printf( "[ERROR] Trying to read a fiber with %d points!\n", numPoints ); return -1; } vtkSmartPointer container = vtkSmartPointer::New(); float tmp[3]; for(int i=0; iInsertNextPoint(tmp); container->GetPointIds()->InsertNextId(id); } vtkNewCells->InsertNextCell(container); } vtkSmartPointer fiberPolyData = vtkSmartPointer::New(); fiberPolyData->SetPoints(vtkNewPoints); fiberPolyData->SetLines(vtkNewCells); mitk::Geometry3D::Pointer geometry = mitk::Geometry3D::New(); vtkSmartPointer< vtkMatrix4x4 > matrix = vtkSmartPointer< vtkMatrix4x4 >::New(); matrix->Identity(); if (use_matrix) for (int i=0; i<4; ++i) for (int j=0; j<4; ++j) { if (j<3) matrix->SetElement(i, j, m_Header.vox_to_ras[i][j]/m_Header.voxel_size[j]); else matrix->SetElement(i, j, m_Header.vox_to_ras[i][j]); } if (m_Header.voxel_order[0]=='R') { matrix->SetElement(0,0,-matrix->GetElement(0,0)); matrix->SetElement(0,1,-matrix->GetElement(0,1)); matrix->SetElement(0,2,-matrix->GetElement(0,2)); matrix->SetElement(0,3,-matrix->GetElement(0,3)); } if (m_Header.voxel_order[1]=='A') { matrix->SetElement(1,0,-matrix->GetElement(1,0)); matrix->SetElement(1,1,-matrix->GetElement(1,1)); matrix->SetElement(1,2,-matrix->GetElement(1,2)); matrix->SetElement(1,3,-matrix->GetElement(1,3)); } if (m_Header.voxel_order[2]=='I') { matrix->SetElement(2,0,-matrix->GetElement(2,0)); matrix->SetElement(2,1,-matrix->GetElement(2,1)); matrix->SetElement(2,2,-matrix->GetElement(2,2)); matrix->SetElement(2,3,-matrix->GetElement(2,3)); } geometry->SetIndexToWorldTransformByVtkMatrix(matrix); vtkSmartPointer transformFilter = vtkSmartPointer::New(); transformFilter->SetInputData(fiberPolyData); transformFilter->SetTransform(geometry->GetVtkTransform()); transformFilter->Update(); fib->SetFiberPolyData(transformFilter->GetOutput()); fib->SetTrackVisHeader(geometry.GetPointer()); fib->SetTrackVisHeader(m_Header); return numPoints; } // Update the field in the header to the new FIBER TOTAL. // ------------------------------------------------------ void TrackVisFiberReader::updateTotal( int totFibers ) { fseek(m_FilePointer, 1000-12, SEEK_SET); if (fwrite((char*)&totFibers, 1, 4, m_FilePointer) != 4) MITK_ERROR << "[ERROR] Problems saving the fiber!"; } void TrackVisFiberReader::writeHdr() { fseek(m_FilePointer, 0, SEEK_SET); if (fwrite((char*)&m_Header, 1, 1000, m_FilePointer) != 1000) MITK_ERROR << "[ERROR] Problems saving the fiber!"; } // Close the TrackVis file, but keep the metadata in the header. // ------------------------------------------------------------- void TrackVisFiberReader::close() { fclose(m_FilePointer); m_FilePointer = nullptr; } bool TrackVisFiberReader::IsTransformValid() { if (fabs(m_Header.image_orientation_patient[0])<=0.001 || fabs(m_Header.image_orientation_patient[3])<=0.001 || fabs(m_Header.image_orientation_patient[5])<=0.001) return false; return true; }