cmtkScalarImageIO.cxx

Go to the documentation of this file.
00001 /*
00002 //
00003 //  Copyright 1997-2009 Torsten Rohlfing
00004 //
00005 //  Copyright 2004-2010 SRI International
00006 //
00007 //  This file is part of the Computational Morphometry Toolkit.
00008 //
00009 //  http://www.nitrc.org/projects/cmtk/
00010 //
00011 //  The Computational Morphometry Toolkit is free software: you can
00012 //  redistribute it and/or modify it under the terms of the GNU General Public
00013 //  License as published by the Free Software Foundation, either version 3 of
00014 //  the License, or (at your option) any later version.
00015 //
00016 //  The Computational Morphometry Toolkit is distributed in the hope that it
00017 //  will be useful, but WITHOUT ANY WARRANTY; without even the implied
00018 //  warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00019 //  GNU General Public License for more details.
00020 //
00021 //  You should have received a copy of the GNU General Public License along
00022 //  with the Computational Morphometry Toolkit.  If not, see
00023 //  <http://www.gnu.org/licenses/>.
00024 //
00025 //  $Revision: 2464 $
00026 //
00027 //  $LastChangedDate: 2010-10-19 09:54:33 -0700 (Tue, 19 Oct 2010) $
00028 //
00029 //  $LastChangedBy: torsten_at_home $
00030 //
00031 */
00032 
00033 #include "cmtkScalarImageIO.h"
00034 
00035 #include <stdio.h>
00036 
00037 #include <Base/cmtkTypes.h>
00038 #include <System/cmtkCompressedStream.h>
00039 #include <IO/cmtkFileHeader.h>
00040 #include <IO/cmtkAnalyze.h>
00041 
00042 namespace
00043 cmtk
00044 {
00045 
00048 
00049 ScalarImage* 
00050 ScalarImageIO::ReadAnalyze( const char* pathHdr )
00051 {
00052 #ifdef _MSC_VER
00053   FILE *hdrFile = fopen( pathHdr, "rb" );
00054 #else
00055   FILE *hdrFile = fopen( pathHdr, "r" );
00056 #endif
00057   if ( !hdrFile ) 
00058     {
00059     StdErr.printf( "ERROR: could not open Analyze header file %s\n",
00060                       pathHdr );
00061     return NULL;
00062     }
00063   
00064   char buffer[348];
00065   if ( 348 != fread( buffer, 1, 348, hdrFile ) ) 
00066     {
00067     StdErr.printf( "ERROR: could not read 348 bytes from header file %s\n", pathHdr );
00068     fclose( hdrFile );
00069     return NULL;
00070     }
00071   fclose( hdrFile );
00072 
00073   const bool bigEndian = (buffer[3] == '\x5C');
00074   FileHeader header( buffer, bigEndian );
00075 
00076   short ndims = header.GetField<short>( 40 );
00077   if ( ndims < 2 ) 
00078     {
00079     StdErr.printf( "ERROR: image dimension %d is smaller than 2 in file "
00080                       "%s\n", ndims, pathHdr );
00081     return NULL;
00082     }
00083   
00084   int dims[4];
00085   dims[0] = header.GetField<short>( 42 );
00086   dims[1] = header.GetField<short>( 44 );
00087   dims[2] = header.GetField<short>( 46 );
00088   dims[3] = header.GetField<short>( 48 );
00089 
00090   if ( (ndims > 2) && ((dims[2] > 1) || (dims[3] > 1)) ) 
00091     {
00092     StdErr.printf( "WARNING: dimension %d is greater than 2 in file %s\n",
00093                       ndims, pathHdr );
00094     }
00095   
00096   float pixelDim[2];
00097   header.GetArray( pixelDim, 80, 2 );
00098 
00099   ScalarImage* image = new ScalarImage( dims[0], dims[1] );
00100   image->SetPixelSize( pixelDim[0], pixelDim[1] );
00101 
00102   ScalarDataType dtype;
00103   switch ( header.GetField<short>( 70 ) ) 
00104     {
00105     case cmtk::ANALYZE_TYPE_NONE:
00106     case cmtk::ANALYZE_TYPE_BINARY:
00107     case cmtk::ANALYZE_TYPE_COMPLEX:
00108     case cmtk::ANALYZE_TYPE_RGB:
00109     case cmtk::ANALYZE_TYPE_ALL:
00110     default:
00111     StdErr.printf( "ERROR: unsupported data type in Analyze file %s\n",
00112                       pathHdr );
00113     return NULL;
00114     case cmtk::ANALYZE_TYPE_UNSIGNED_CHAR:
00115       dtype = TYPE_BYTE;
00116       break;
00117     case cmtk::ANALYZE_TYPE_SIGNED_SHORT:
00118       dtype = TYPE_SHORT;
00119       break;
00120     case cmtk::ANALYZE_TYPE_SIGNED_INT:
00121       dtype = TYPE_INT;
00122       break;
00123     case cmtk::ANALYZE_TYPE_FLOAT:
00124       dtype = TYPE_FLOAT;
00125       break;
00126     case cmtk::ANALYZE_TYPE_DOUBLE:
00127       dtype = TYPE_DOUBLE;
00128       break;
00129     }  
00130   image->CreatePixelData( dtype );
00131   
00132   size_t offset = static_cast<size_t>( header.GetField<float>( 108 ) );
00133 
00134   char* pathImg = Memory::AllocateArray<char>(  4 + strlen( pathHdr )  );
00135   strcpy( pathImg, pathHdr );
00136   char* suffix = strstr( pathImg, ".hdr" );
00137   if ( suffix ) *suffix = 0;
00138   strcat( pathImg, ".img" );
00139 
00140   CompressedStream stream( pathImg );
00141   if ( stream.IsValid() ) 
00142     {
00143     stream.Seek( offset, SEEK_CUR );
00144     
00145     TypedArray::SmartPtr data = image->GetPixelData();
00146     stream.Read
00147       ( data->GetDataPtr(), data->GetItemSize(), data->GetDataSize() );
00148     
00149 #ifdef WORDS_BIGENDIAN
00150     if ( ! bigEndian ) data->ChangeEndianness();
00151 #else
00152     if ( bigEndian ) data->ChangeEndianness();
00153 #endif
00154     
00155     } 
00156   else 
00157     {
00158     StdErr.printf( "WARNING: could not open Analyze image file %s\n",
00159                       pathImg );
00160     }
00161   
00162   Memory::DeleteArray( pathImg );
00163 
00164   return image;
00165 }
00166 
00167 void
00168 ScalarImageIO::WriteAnalyze
00169 ( const char* pathHdr, const ScalarImage* image )
00170 {
00171   const TypedArray* data = image->GetPixelData();
00172   if ( ! data ) return;
00173 
00174   char buffer[348];
00175 #ifdef WORDS_BIGENDIAN
00176   FileHeader header( buffer, true /*bigEndian*/ );
00177 #else
00178   FileHeader header( buffer, false /*bigEndian*/ );
00179 #endif
00180 
00181   header.StoreField<int>( 0, 348 ); // header size
00182   header.StoreField<int>( 32, 16384 ); // extents
00183   header.StoreField<short>( 36, 0 ); // session error
00184   header.StoreField<char>( 38, 'r' ); // regular
00185 
00186   // ndims
00187   header.StoreField<short>( 40, 4 );
00188 
00189   // dimensions
00190   header.StoreField<short>( 42, image->GetDims()[AXIS_X] );
00191   header.StoreField<short>( 44, image->GetDims()[AXIS_Y] );
00192   header.StoreField<short>( 46, 1 );
00193   header.StoreField<short>( 48, 1 ); // write dims 3-7
00194   header.StoreField<short>( 50, 0 ); // just for safety
00195   header.StoreField<short>( 52, 0 ); // just for safety
00196   header.StoreField<short>( 54, 0 ); // just for safety
00197 
00198   header.StoreField<float>( 68, 0.0 ); // vox_offset
00199   switch ( data->GetType() ) 
00200     {
00201     default:
00202       header.StoreField<short>( 70, cmtk::ANALYZE_TYPE_NONE );
00203       header.StoreField<short>( 72, 0 );
00204       break;
00205     case TYPE_BYTE:
00206       header.StoreField<short>( 70, cmtk::ANALYZE_TYPE_UNSIGNED_CHAR );
00207       header.StoreField<short>( 72, 8 * sizeof( unsigned char ) );
00208       break;
00209     case TYPE_SHORT:
00210     case TYPE_USHORT:
00211       header.StoreField<short>( 70, cmtk::ANALYZE_TYPE_SIGNED_SHORT );
00212       header.StoreField<short>( 72, 8 * sizeof( short ) );
00213       break;
00214     case TYPE_INT:
00215       header.StoreField<short>( 70, cmtk::ANALYZE_TYPE_SIGNED_INT );
00216       header.StoreField<short>( 72, 8 * sizeof( int ) );
00217       break;
00218     case TYPE_FLOAT:
00219       header.StoreField<short>( 70, cmtk::ANALYZE_TYPE_FLOAT );
00220       header.StoreField<short>( 72, 8 * sizeof( float ) );
00221       break;
00222     case TYPE_DOUBLE:
00223       header.StoreField<short>( 70, cmtk::ANALYZE_TYPE_DOUBLE );
00224       header.StoreField<short>( 72, 8 * sizeof( double ) );
00225       break;
00226     }  
00227   
00228   header.StoreField<float>( 80, (float)image->GetPixelSize( AXIS_X ) );
00229   header.StoreField<float>( 84, (float)image->GetPixelSize( AXIS_Y ) );
00230   header.StoreField<float>( 88, 1.0f );
00231   header.StoreField<float>( 92, 1.0f ); // write sizes in dims 3 and
00232   header.StoreField<float>( 96, 1.0f ); // 4 just to be safe
00233 
00234   // set zero offset for binary file.
00235   header.StoreField<float>( 108, 0.0f );
00236 
00237   // determine data range;
00238   const Types::DataItemRange dataRange = data->GetRange();
00239 
00240   header.StoreField<float>( 124, static_cast<float>( dataRange.m_UpperBound ) ); // cal_max
00241   header.StoreField<float>( 128, static_cast<float>( dataRange.m_LowerBound ) ); // cal_min
00242 
00243   header.StoreField<int>( 140, static_cast<int>( dataRange.m_UpperBound ) );
00244   header.StoreField<int>( 144, static_cast<int>( dataRange.m_LowerBound ) );
00245 
00246   // slice orientation always axial from caudal to cranial
00247   header.StoreField<byte>( 252, 0 );
00248 
00249   // write header info
00250 #ifdef MSC_VER
00251   FILE *hdrFile = fopen( pathHdr, "wb" );
00252 #else
00253   FILE *hdrFile = fopen( pathHdr, "w" );
00254 #endif
00255   if ( hdrFile )
00256     {
00257     if ( 348 != fwrite( buffer, 1, 348, hdrFile ) ) 
00258       {
00259       StdErr.printf( "ERROR: could not write 348 bytes to header file %s\n",
00260                         pathHdr );
00261       }
00262     fclose( hdrFile );
00263     }
00264 
00265   // write binary data
00266   char* pathImg = Memory::AllocateArray<char>(  4 + strlen( pathHdr )  );
00267   strcpy( pathImg, pathHdr );
00268   char* suffix = strstr( pathImg, ".hdr" );
00269   if ( suffix ) *suffix = 0;
00270   strcat( pathImg, ".img" );
00271 
00272 #ifdef _MSC_VER
00273   FILE *imgFile = fopen( pathImg, "wb" );
00274 #else
00275   FILE *imgFile = fopen( pathImg, "w" );
00276 #endif
00277   if ( imgFile ) 
00278     {
00279     fwrite( data->GetDataPtr(), data->GetItemSize(), data->GetDataSize(), imgFile );
00280     fclose( imgFile );
00281     }
00282 
00283   Memory::DeleteArray( pathImg );
00284 }
00285 
00286 } // namespace cmtk
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Defines