//--------------------------------------------------------------------------- // // Project: OpenWalnut ( http://www.openwalnut.org ) // // Copyright 2009 OpenWalnut Community, BSV@Uni-Leipzig and CNCF@MPI-CBS // For more information see http://www.openwalnut.org/copying // // This file is part of OpenWalnut. // // OpenWalnut is free software: you can redistribute it and/or modify // it under the terms of the GNU Lesser General Public License as published by // the Free Software Foundation, either version 3 of the License, or // (at your option) any later version. // // OpenWalnut is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU Lesser General Public License for more details. // // You should have received a copy of the GNU Lesser General Public License // along with OpenWalnut. If not, see . // //--------------------------------------------------------------------------- #include #include #include #include #include #include #include #include "../../common/WAssert.h" #include "../../common/WStringUtils.h" #include "../../dataHandler/WGridRegular3D.h" #include "../../kernel/WKernel.h" #include "../../common/math/WPosition.h" #include "../../common/math/WVector3D.h" #include "../data/WMData.h" #include "../../dataHandler/io/nifti/nifti1_io.h" #include "WMWriteNIfTI.h" WMWriteNIfTI::WMWriteNIfTI() : WModule(), m_write( new WCondition() ) { // WARNING: initializing connectors inside the constructor will lead to an exception. // Implement WModule::initializeConnectors instead. } WMWriteNIfTI::~WMWriteNIfTI() { // cleanup removeConnectors(); } boost::shared_ptr< WModule > WMWriteNIfTI::factory() const { return boost::shared_ptr< WModule >( new WMWriteNIfTI() ); } const char** WMWriteNIfTI::getXPMIcon() const { static const char * disc_xpm[] = { "16 16 7 1", " c None", ". c #000080", "+ c #000000", "@ c #FFFF00", "# c #E0E0E0", "$ c #FFFFFF", "% c #C0C0C0", "..+++++++++++..+", "..@@@@@@@@@@@..+", "..###########..+", "..$$$$$$$$$$$..+", "..###########..+", "..$$$$$$$$$$$..+", "..###########..+", "..$$$$$$$$$$$..+", "...............+", "....%%%%%%%....+", "....%..%%%%....+", "....%..%%%%....+", "....%..%%%%....+", "....%..%%%%....+", "+...%%%%%%%....+", "++++++++++++++++" }; return disc_xpm; } const std::string WMWriteNIfTI::getName() const { return "Write NIfTI"; } const std::string WMWriteNIfTI::getDescription() const { return "Writes a data set to a NIfTI file."; } void WMWriteNIfTI::moduleMain() { // use the m_input "data changed" flag m_moduleState.setResetable( true, true ); m_moduleState.add( m_input->getDataChangedCondition() ); m_moduleState.add( m_write ); // signal ready state ready(); // loop until the module container requests the module to quit while( !m_shutdownFlag() ) { // acquire data from the input connector m_dataSet = m_input->getData(); if( !m_dataSet ) { // ok, the output has not yet sent data // NOTE: see comment at the end of this while loop for m_moduleState debugLog() << "Waiting for data ..."; m_moduleState.wait(); continue; } writeToFile(); // this waits for m_moduleState to fire. By default, this is only the m_shutdownFlag condition. // NOTE: you can add your own conditions to m_moduleState using m_moduleState.add( ... ) m_moduleState.wait(); } } void WMWriteNIfTI::connectors() { // initialize connectors m_input = boost::shared_ptr< WModuleInputData< WDataSetSingle > >( new WModuleInputData< WDataSetSingle > ( shared_from_this(), "in", "The dataset to filter" ) ); // add it to the list of connectors. Please note, that a connector NOT added via addConnector will not work as expected. addConnector( m_input ); // call WModules initialization WModule::connectors(); } void WMWriteNIfTI::properties() { m_filename = m_properties->addProperty( "Filename", "Filename where to write the NIfTI file to.", WKernel::getAppPathObject(), m_write ); } template< typename T > void WMWriteNIfTI::castData( void*& returnData ) { boost::shared_ptr< WValueSetBase > valsB = ( *m_dataSet ).getValueSet(); boost::shared_ptr< WValueSet< T > > vals = boost::shared_dynamic_cast< WValueSet< T > >( ( *m_dataSet ).getValueSet() ); WAssert( vals, "Seems that value set type is not yet supported." ); T* data = new T[vals->size()]; for( unsigned int i = 0; i < vals->size(); ++i ) { data[i] = static_cast< T > ( vals->getScalar( i ) ); } returnData = static_cast< void* > ( data ); } void WMWriteNIfTI::writeToFile() { infoLog() << "Writing Data to " << m_filename->get().file_string(); nifti_image *outField = nifti_simple_init_nim(); boost::shared_ptr< WGridRegular3D > grid = boost::shared_dynamic_cast< WGridRegular3D >( m_dataSet->getGrid() ); WAssert( grid, "Seems that grid is of wrong type." ); size_t nbValues = ( *m_dataSet ).getValueSet()->size(); outField->nx = grid->getNbCoordsX(); outField->ny = grid->getNbCoordsY(); outField->nz = grid->getNbCoordsZ(); WAssert( grid->getNbCoordsX() * grid->getNbCoordsY() * grid->getNbCoordsZ() == nbValues, "Overall size incompatible with size in axis directions." ); // TODO(wiebel): only able to handle scalars now. outField->nt = 1; outField->nvox = nbValues; outField->dx = grid->getOffsetX(); outField->dy = grid->getOffsetY(); outField->dz = grid->getOffsetZ(); outField->nifti_type = 1; // 1==NIFTI-1 (1 file) outField->freq_dim = 1; outField->phase_dim = 2; outField->slice_dim = 3; outField->qform_code = 1; outField->sform_code = 0; wmath::WMatrix< double > matrix = grid->getTransformationMatrix(); for( size_t i = 0; i < 4; ++i ) { for( size_t j = 0; j < 4; ++j ) { outField->qto_xyz.m[i][j] = matrix( i, j ); } } { float dx, dy, dz; nifti_mat44_to_quatern( outField->qto_xyz, &( outField->quatern_b ), &( outField->quatern_c ), &( outField->quatern_d ), &( outField->qoffset_x ), &( outField->qoffset_y ), &( outField->qoffset_z ), &dx, &dy, &dz, &( outField->qfac ) ); } outField->qto_ijk = nifti_mat44_inverse( outField->qto_xyz ); void* data = 0; switch( ( *m_dataSet ).getValueSet()->getDataType() ) { case W_DT_DOUBLE: outField->datatype = DT_DOUBLE; castData< double > ( data ); outField->nbyper = 8; break; case W_DT_FLOAT: outField->datatype = DT_FLOAT; castData< float > ( data ); outField->nbyper = 4; break; case W_DT_UNSIGNED_CHAR: outField->datatype = DT_UNSIGNED_CHAR; castData< unsigned char > ( data ); outField->nbyper = 1; break; case W_DT_UINT16: outField->datatype = DT_UINT16; castData< uint16_t > ( data ); outField->nbyper = 2; break; default: WAssert( false, "Data set type not yet supported." ); } outField->data = data; if( nifti_set_filenames( outField, m_filename->get().file_string().c_str(), 0, 1 ) ) { throw WException( std::string( "NIfTI filename Problem" ) ); } nifti_image_write( outField ); nifti_image_free( outField ); infoLog() << "Writing data completed."; }