ISIS Core Library 0.7.2 (api 3.0.0)
|
00001 // 00002 // C++ Implementation: common (DataStorage) 00003 // 00004 // Description: 00005 // 00006 // 00007 // Author: Thomas Pröger <proeger@cbs.mpg.de>, (C) 2010 00008 // 00009 // Copyright: See COPYING file that comes with this distribution 00010 // 00011 // 00012 00013 #include "common.hpp" 00014 #include "image.hpp" 00015 #include <boost/numeric/ublas/io.hpp> 00016 00017 namespace isis 00018 { 00019 00020 namespace data 00021 { 00022 00023 namespace _internal 00024 { 00025 00026 00027 bool transformCoords( isis::util::PropertyMap &properties, util::vector4<size_t> size, boost::numeric::ublas::matrix<float> transform, bool transformCenterIsImageCenter ) 00028 { 00029 LOG_IF( !properties.hasProperty( "rowVec" ) || !properties.hasProperty( "columnVec" ) || !properties.hasProperty( "sliceVec" ) 00030 || !properties.hasProperty( "voxelSize" ) || !properties.hasProperty( "indexOrigin" ), Debug, error ) 00031 << "Missing one of the properties (rowVec, columnVec, sliceVec, voxelSize, indexOrigin)"; 00032 00033 using namespace boost::numeric::ublas; 00034 // this implementation assumes that the PropMap properties is either a 00035 // data::Chunk or a data::Image object. Hence it should contain the 00036 // properties rowVec, columnVec, sliceVec and indexOrigin. 00037 // get row, column and slice vector from property map 00038 isis::util::fvector3 row = properties.getPropertyAs<util::fvector3>( "rowVec" ); 00039 isis::util::fvector3 column = properties.getPropertyAs<util::fvector3>( "columnVec" ); 00040 isis::util::fvector3 slice = properties.getPropertyAs<util::fvector3>( "sliceVec" ); 00041 // get index origin from property map 00042 isis::util::fvector3 indexorig = properties.getPropertyAs<util::fvector3>( "indexOrigin" ); 00043 vector<float> origin_out = vector<float>( 3 ); 00044 //check if we have a property "voxelGap" to prevent isis from throwing a warning "blabla" 00045 isis::util::fvector3 scaling; 00046 00047 if( properties.hasProperty( "voxelGap" ) ) { 00048 scaling = properties.getPropertyAs<util::fvector3>( "voxelSize" ) + properties.getPropertyAs<util::fvector3>( "voxelGap" ); 00049 } else { 00050 scaling = properties.getPropertyAs<util::fvector3>( "voxelSize" ); 00051 } 00052 00053 // create boost::numeric data structures 00054 // STEP 1 transform orientation matrix 00055 // input matrix 00056 matrix<float> R_in( 3, 3 ); 00057 00058 for( int i = 0; i < 3; i++ ) { 00059 R_in( i, 0 ) = row[i]; 00060 R_in( i, 1 ) = column[i]; 00061 R_in( i, 2 ) = slice[i]; 00062 } 00063 00064 matrix<float> R_out( 3, 3 ); 00065 00066 if( transformCenterIsImageCenter ) { 00067 R_out = prod( R_in, transform ); 00068 } else { 00069 R_out = prod( transform, R_in ); 00070 } 00071 00072 for ( int i = 0; i < 3; i++ ) { 00073 row[i] = R_out( i, 0 ); 00074 column[i] = R_out( i, 1 ); 00075 slice[i] = R_out( i, 2 ); 00076 } 00077 00078 vector<float> origin_in( 3 ); 00079 00080 for( int i = 0; i < 3; i++ ) { 00081 origin_in( i ) = indexorig[i]; 00082 } 00083 00084 //the center of the transformation is the image center (eg. spm transformation) 00085 if( transformCenterIsImageCenter ) { 00086 matrix<float> R_in_inverse( R_in ); 00087 00088 if( !_internal::inverseMatrix<float>( R_in, R_in_inverse ) ) { 00089 LOG( Runtime, error ) << "Can not inverse orientation matrix: " << R_in; 00090 return false; 00091 } 00092 00093 //we have to map the indexes of the image size into the scanner space 00094 00095 vector<float> physicalSize( 3 ); 00096 vector<float> boostScaling( 3 ); 00097 00098 for ( unsigned short i = 0; i < 3; i++ ) { 00099 physicalSize( i ) = size[i] * scaling[i]; 00100 boostScaling( i ) = scaling[i]; 00101 } 00102 00103 // now we have to calculate the center of the image in physical space 00104 vector<float> half_image( 3 ); 00105 00106 for ( unsigned short i = 0; i < 3; i++ ) { 00107 half_image( i ) = ( physicalSize( i ) - boostScaling( i ) ) * 0.5; 00108 } 00109 00110 vector<float> center_image = prod( R_in, half_image ) + origin_in ; 00111 //now translate this center to the center of the physical space and get the new image origin 00112 vector<float> io_translated = origin_in - center_image; 00113 //now multiply this translated origin with the inverse of the orientation matrix of the image 00114 vector<float> io_ortho = prod( R_in_inverse, io_translated ); 00115 //now transform this matrix with the actual transformation matrix 00116 vector<float> transformed_io_ortho = prod( io_ortho, transform ); 00117 //now transform ths point back with the orientation matrix of the image 00118 vector<float> transformed_io = prod( R_in, transformed_io_ortho ); 00119 //and finally we have to retranslate this origin to get the image to our old position in physical space 00120 origin_out = transformed_io + center_image; 00121 00122 } else { 00123 origin_out = prod( transform, origin_in ); 00124 } 00125 00126 for( int i = 0; i < 3; i++ ) { 00127 indexorig[i] = origin_out( i ); 00128 } 00129 00130 // write modified values back into property map 00131 properties.setPropertyAs( "indexOrigin", indexorig ); 00132 properties.setPropertyAs( "rowVec", row ); 00133 properties.setPropertyAs( "columnVec", column ); 00134 properties.setPropertyAs( "sliceVec", slice ); 00135 return true; 00136 } 00137 00138 } 00139 00140 boost::filesystem::path getCommonSource( std::list<boost::filesystem::path> sources ) 00141 { 00142 sources.erase( std::unique( sources.begin(), sources.end() ), sources.end() ); 00143 00144 if( sources.empty() ) { 00145 LOG( Runtime, error ) << "Failed to get common source"; 00146 return boost::filesystem::path(); 00147 } else if( sources.size() == 1 ) 00148 return sources.front(); 00149 else { 00150 BOOST_FOREACH( boost::filesystem::path & ref, sources ) 00151 ref.remove_leaf();//@todo switch to ref.remove_filename() as soon as we drop support for boost < 1.44 00152 return getCommonSource( sources ); 00153 } 00154 } 00155 boost::filesystem::path getCommonSource( const std::list<data::Image> &imgs ) 00156 { 00157 std::list<boost::filesystem::path> sources; 00158 BOOST_FOREACH( const data::Image & img, imgs ) { 00159 if( img.hasProperty( "source" ) ) 00160 sources.push_back( img.getPropertyAs<std::string>( "source" ) ); 00161 else { 00162 BOOST_FOREACH( const util::PropertyValue & ref, img.getChunksProperties( "source", true ) ) { 00163 sources.push_back( ref.as<std::string>() ); 00164 } 00165 } 00166 } 00167 sources.sort(); 00168 return getCommonSource( sources ); 00169 } 00170 boost::filesystem::path getCommonSource( const data::Image &img ) 00171 { 00172 return getCommonSource( std::list<data::Image>( 1, img ) ); 00173 } 00174 00175 } 00176 }