WMWriteNIfTI.cpp 8.88 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24
//---------------------------------------------------------------------------
//
// 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 <http://www.gnu.org/licenses/>.
//
//---------------------------------------------------------------------------

ledig's avatar
ledig committed
25 26
#include <stdint.h>

27 28 29 30 31 32 33 34
#include <iostream>
#include <fstream>
#include <string>
#include <vector>
#include <utility>

#include <cmath>

35
#include "../../common/WAssert.h"
36
#include "../../common/WPathHelper.h"
37 38 39
#include "../../common/WStringUtils.h"
#include "../../dataHandler/WGridRegular3D.h"
#include "../../kernel/WKernel.h"
40 41
#include "../../common/math/WPosition.h"
#include "../../common/math/WVector3D.h"
Alexander Wiebel's avatar
Alexander Wiebel committed
42
#include "../../ext/nifti/nifti1_io.h"
43 44
#include "WMWriteNIfTI.h"

45 46 47
// This line is needed by the module loader to actually find your module.
W_LOADABLE_MODULE( WMWriteNIfTI )

48
WMWriteNIfTI::WMWriteNIfTI() :
Alexander Wiebel's avatar
Alexander Wiebel committed
49
    WModule()
50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65
{
    // 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() );
}

66 67 68
const char** WMWriteNIfTI::getXPMIcon() const
{
    static const char * disc_xpm[] =
69 70 71 72 73 74 75
    {
                    "16 16 7 1", "   c None", ".  c #000080", "+  c #000000", "@  c #FFFF00", "#  c #E0E0E0",
                    "$  c #FFFFFF", "%  c #C0C0C0", "..+++++++++++..+", "..@@@@@@@@@@@..+", "..###########..+",
                    "..$$$$$$$$$$$..+", "..###########..+", "..$$$$$$$$$$$..+", "..###########..+", "..$$$$$$$$$$$..+",
                    "...............+", "....%%%%%%%....+", "....%..%%%%....+", "....%..%%%%....+", "....%..%%%%....+",
                    "....%..%%%%....+", "+...%%%%%%%....+", "++++++++++++++++"
    };
76 77 78
    return disc_xpm;
}

79 80 81 82 83 84 85 86 87 88 89 90 91
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
92
    m_moduleState.setResetable( true, true );
93 94 95 96 97 98
    m_moduleState.add( m_input->getDataChangedCondition() );

    // signal ready state
    ready();

    // loop until the module container requests the module to quit
99
    while( !m_shutdownFlag() )
100 101 102
    {
        // acquire data from the input connector
        m_dataSet = m_input->getData();
103
        if( !m_dataSet )
104 105 106 107 108 109 110
        {
            // 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;
        }
111
        writeToFile();
112 113 114 115 116 117 118 119
        // 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()
{
Alexander Wiebel's avatar
Alexander Wiebel committed
120 121
    // this module works for scalar data sets only so far
    m_input = boost::shared_ptr< WModuleInputData< WDataSetScalar > >( new WModuleInputData< WDataSetScalar > (
122
                    shared_from_this(), "in", "The dataset to filter" ) );
123 124 125 126 127 128 129 130 131 132

    // 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()
{
133
    m_filename = m_properties->addProperty( "Filename", "Filename where to write the NIfTI file to.",
134
                                             WPathHelper::getAppPath() );
Alexander Wiebel's avatar
Alexander Wiebel committed
135 136 137
    m_saveTriggerProp = m_properties->addProperty( "Do Save",  "Press!",
                                                  WPVBaseTypes::PV_TRIGGER_READY );
    m_saveTriggerProp->getCondition()->subscribeSignal( boost::bind( &WMWriteNIfTI::writeToFile, this ) );
138 139
}

140 141 142 143
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() );
144
    WAssert( vals, "Seems that value set type is not yet supported." );
145 146 147 148 149 150 151 152 153

    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 );
}

154
void WMWriteNIfTI::writeToFile()
155
{
Alexander Wiebel's avatar
Alexander Wiebel committed
156 157
    m_saveTriggerProp->set( WPVBaseTypes::PV_TRIGGER_READY, false );

158
    infoLog() << "Writing Data to " << m_filename->get().file_string();
159 160 161
    nifti_image *outField = nifti_simple_init_nim();

    boost::shared_ptr< WGridRegular3D > grid = boost::shared_dynamic_cast< WGridRegular3D >( m_dataSet->getGrid() );
162
    WAssert( grid, "Seems that grid is of wrong type." );
163

164
    size_t nbValues = ( *m_dataSet ).getValueSet()->size();
165 166 167 168

    outField->nx = grid->getNbCoordsX();
    outField->ny = grid->getNbCoordsY();
    outField->nz = grid->getNbCoordsZ();
169 170
    WAssert( grid->getNbCoordsX() * grid->getNbCoordsY() * grid->getNbCoordsZ() == nbValues,
             "Overall size incompatible with size in axis directions." );
171 172 173 174 175 176 177 178

    outField->nt = 1;
    outField->nvox = nbValues;

    outField->dx = grid->getOffsetX();
    outField->dy = grid->getOffsetY();
    outField->dz = grid->getOffsetZ();

179
    outField->nifti_type = 1; // 1==NIFTI-1 (1 file)
180 181 182 183 184 185

    outField->freq_dim = 1;
    outField->phase_dim = 2;
    outField->slice_dim = 3;

    outField->qform_code = 1;
186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208
    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 );

209

210 211
    void* data = 0;
    switch( ( *m_dataSet ).getValueSet()->getDataType() )
212
    {
213 214 215
        case W_DT_DOUBLE:
            outField->datatype = DT_DOUBLE;
            castData< double > ( data );
216
            outField->nbyper = 8;
217 218 219 220
            break;
        case W_DT_FLOAT:
            outField->datatype = DT_FLOAT;
            castData< float > ( data );
221
            outField->nbyper = 4;
222 223 224 225
            break;
        case W_DT_UNSIGNED_CHAR:
            outField->datatype = DT_UNSIGNED_CHAR;
            castData< unsigned char > ( data );
226
            outField->nbyper = 1;
227
            break;
228 229 230 231 232
        case W_DT_INT8:
            outField->datatype = DT_INT8;
            castData< char > ( data );
            outField->nbyper = 1;
            break;
233 234 235
        case W_DT_UINT16:
            outField->datatype = DT_UINT16;
            castData< uint16_t > ( data );
236
            outField->nbyper = 2;
237
            break;
238 239 240 241 242 243 244 245 246 247 248 249 250 251 252
        case W_DT_INT16:
            outField->datatype = DT_INT16;
            castData< int16_t > ( data );
            outField->nbyper = 2;
            break;
        case W_DT_UINT32:
            outField->datatype = DT_UINT32;
            castData< uint32_t > ( data );
            outField->nbyper = 4;
            break;
        case W_DT_SIGNED_INT:
            outField->datatype = DT_SIGNED_INT;
            castData< int32_t > ( data );
            outField->nbyper = 4;
            break;
253
        default:
254
            WAssert( false, "Data set type not yet supported." );
255
    }
256
    outField->data = data;
257 258


259
    if( nifti_set_filenames( outField, m_filename->get().file_string().c_str(), 0, 1 ) )
260
    {
ledig's avatar
ledig committed
261
        throw WException( std::string( "NIfTI filename Problem" ) );
262 263 264 265
    }

    nifti_image_write( outField );
    nifti_image_free( outField );
266
    infoLog() << "Writing data completed.";
267
}