Xmipp  v3.23.11-Nereus
rwIMAGIC.cpp
Go to the documentation of this file.
1 /***************************************************************************
2  * Authors: Joaquin Oton (joton@cnb.csic.es)
3  *
4  *
5  * Unidad de Bioinformatica of Centro Nacional de Biotecnologia , CSIC
6  *
7  * This program is free software; you can redistribute it and/or modify
8  * it under the terms of the GNU General Public License as published by
9  * the Free Software Foundation; either version 2 of the License, or
10  * (at your option) any later version.
11  *
12  * This program is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15  * GNU General Public License for more details.
16  *
17  * You should have received a copy of the GNU General Public License
18  * along with this program; if not, write to the Free Software
19  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
20  * 02111-1307 USA
21  *
22  * All comments concerning this program package may be sent to the
23  * e-mail address 'xmipp@cnb.csic.es'
24  ***************************************************************************/
25 
26 #include "xmipp_image_base.h"
27 #include "xmipp_error.h"
28 #include "metadata_static.h"
29 #include "multidim_array_base.h"
30 #include <cmath>
31 
32 /*
33  * rwIMAGIC.h
34  *
35  * Created on: May 17, 2010
36  * Author: roberto
37  */
38 /*
39  Base on rwIMAGIC.h
40  Header file for reading and writing Image Science's Imagic files
41  Format: 2D image file format for the program Imagic (Image Science)
42  Author: Bernard Heymann
43  Created: 19990424 Modified: 20011030
44 */
45 
46 #define IMAGICSIZE 1024 // Size of the IMAGIC header for each image
47 
48 #ifndef SIZEOF_INT
49 #define SIZEOF_INT sizeof(int)
50 #endif
51 
54 
58 struct IMAGIChead
59 { // file header for IMAGIC data
60  int imn; // 0 image location number (1,2,...)
61  int ifn; // 1 # images following, only of importance in the first location
62  int ierror; // 2 error code: error if >0
63  int nhfr; // 3 # header records per image
64  int ndate; // 4 creation day
65  int nmonth; // 5 creation month
66  int nyear; // 6 creation year
67  int nhour; // 7 creation hour
68  int nminut; // 8 creation minute
69  int nsec; // 9 creation second
70  int npix2; // 10 # 4-byte reals in image
71  int npixel; // 11 # image elements
72  int ixlp; // 12 lines per image (Y)
73  int iylp; // 13 pixels per line (X)
74  char type[4]; // 14 image type
75  int ixold; // 15 top-left X coordinate
76  int iyold; // 16 top-left Y coordinate
77  float avdens; // 17 average
78  float sigma; // 18 standard deviation
79  float varian; // 19 variance
80  float oldavd; // 20 old average
81  float densmax; // 21 maximum
82  float densmin; // 22 minimum
83  // double sum; // 23+24 sum of densities
84  // double squares; // 25+26 sum of squares
85  float dummy[4]; // 23-26 dummy place holder
86  char lastpr[8]; // 27+28 last program writing file
87  char name[80]; // 29-48 image name
88  float extra_1[8]; // 49-56 additional parameters
89  float eman_alt; // 57 EMAN: equiv to psi & PFT omega
90  float eman_az; // 58 EMAN: equiv to theta
91  float eman_phi; // 59 EMAN: equiv to phi
92  float extra_2[69]; // 60-128 additional parameters
93  float euler_alpha; // 129 Euler angles: psi
94  float euler_beta; // 130 theta
95  float euler_gamma; // 131 phi
96  float proj_weight; // 132 weight of each projection
97  float extra_3[66]; // 133-198 additional parameters
98  char history[228]; // 199-255 history
99 } ;
100 
101 /************************************************************************
102 @Function: readIMAGIC
103 @Description:
104  Reading an IMAGIC image format.
105 @Algorithm:
106  A 2D file format for the IMAGIC package.
107  The header is stored in a separate file with extension ".hed" and
108  a fixed size of 1024 bytes per image.
109  The image data is stored in a single block in a file with the
110  extension ".img".
111  Byte order determination: Year and hour values
112  must be less than 256*256.
113  Data types: PACK = byte, INTG = short, REAL = float,
114  RECO,COMP = complex float.
115  Transform type: Centered (COMP data type)
116  RECO is not a transform
117  Note that the x and y dimensions are interchanged (actually a display issue).
118 @Arguments:
119  Bimage* p the image structure.
120  int select image selection in multi-image file (-1 = all images).
121 @Returns:
122  int error code (<0 means failure).
123 **************************************************************************/
127 int ImageBase::readIMAGIC(size_t select_img)
128 {
129 #undef DEBUG
130  //#define DEBUG
131 #ifdef DEBUG
132  printf("DEBUG readIMAGIC: Reading Imagic file\n");
133 #endif
134 
135  IMAGIChead* header = new IMAGIChead;
136 
137  if ( fread( header, IMAGICSIZE, 1, fhed ) < 1 )
138  REPORT_ERROR(ERR_IO_NOREAD,(String)"readIMAGIC: header file of " + filename + " cannot be read");
139 
140  // Determine byte order and swap bytes if from little-endian machine
141  if ( (swap = (( abs(header->nyear) > SWAPTRIG ) || ( header->ixlp > SWAPTRIG ))) )
142  swapPage((char *) header, IMAGICSIZE - 916, DT_Float); // IMAGICSIZE - 916 is to exclude labels from swapping
143 
144  DataType datatype=DT_Float;
145 
146  if ( strstr(header->type,"PACK") )
147  datatype = DT_UChar;
148  else if ( strstr(header->type,"INTG") )
149  datatype = DT_Short;
150  else if ( strstr(header->type,"REAL") )
151  datatype = DT_Float;
152  else if ( strstr(header->type,"RECO") )
153  {
154  datatype = DT_CFloat; // Complex data
155  transform = NoTransform;
156  }
157  else if ( strstr(header->type,"COMP") )
158  {
159  datatype = DT_CFloat; // Complex transform data
160  transform = Centered;
161  }
162 
163  // Set min-max values and other statistical values
164  if ( header->sigma == 0 && header->varian != 0 )
165  header->sigma = std::sqrt(header->varian);
166  if ( header->densmax == 0 && header->densmin == 0 && header->sigma != 0 )
167  {
168  header->densmin = header->avdens - header->sigma;
169  header->densmax = header->avdens + header->sigma;
170  }
171 
172  offset = 0; // separate header file
173 
174  MDMainHeader.setValue(MDL_MIN,(double)header->densmin);
175  MDMainHeader.setValue(MDL_MAX,(double)header->densmax);
176  MDMainHeader.setValue(MDL_AVG,(double)header->avdens);
177  MDMainHeader.setValue(MDL_STDDEV,(double)header->sigma);
178  MDMainHeader.setValue(MDL_SAMPLINGRATE_X,(double)1.);
179  MDMainHeader.setValue(MDL_SAMPLINGRATE_Y,(double)1.);
180  MDMainHeader.setValue(MDL_SAMPLINGRATE_Z,(double)1.);
181  MDMainHeader.setValue(MDL_DATATYPE,(int)datatype);
182 
183  int _xDim,_yDim,_zDim;
184  size_t _nDim;
185  _xDim = (int) header->iylp;
186  _yDim = (int) header->ixlp;
187  _zDim = (int) 1;
188  _nDim = (size_t) header->ifn + 1 ;
189 
190  if ( select_img > _nDim )
191  REPORT_ERROR(ERR_INDEX_OUTOFBOUNDS, formatString("readImagic: Image number %lu exceeds stack size %lu", select_img, _nDim));
192 
193  if( select_img != ALL_IMAGES )
194  _nDim = 1;
195 
196  replaceNsize = _nDim;
197  setDimensions(_xDim, _yDim, _zDim, _nDim );
198 
199  if (dataMode == HEADER || (dataMode == _HEADER_ALL && _nDim > 1)) // Stop reading if not necessary
200  {
201  delete header;
202  return 0;
203  }
204 
205  // Get the header information
206  fseek( fhed, IMG_INDEX(select_img) * IMAGICSIZE, SEEK_SET );
207 
208  MD.clear();
209  for (size_t i = 0; i < _nDim; i++)
210  MD.push_back(std::unique_ptr<MDRowVec>(new MDRowVec(MDL::emptyHeaderVec())));
211 
212  double daux=1.;
213  for ( size_t i = 0; i < _nDim; ++i )
214  {
215  if ( fread( header, IMAGICSIZE, 1, fhed ) < 1 )
216  return(-2);
217  {
218  if ( swap )
219  swapPage((char *) header, IMAGICSIZE - 916, DT_Float);
220 
221  if (dataMode == _HEADER_ALL || dataMode == _DATA_ALL)
222  {
223  MD[i]->setValue(MDL_SHIFT_X, (double)-1. * header->ixold);
224  MD[i]->setValue(MDL_SHIFT_Y, (double)-1. * header->iyold);
225  MD[i]->setValue(MDL_SHIFT_Z, 0.);
226  MD[i]->setValue(MDL_ANGLE_ROT, (double)-1. * header->euler_alpha);
227  MD[i]->setValue(MDL_ANGLE_TILT,(double)-1. * header->euler_beta);
228  MD[i]->setValue(MDL_ANGLE_PSI, (double)-1. * header->euler_gamma);
229  MD[i]->setValue(MDL_WEIGHT, 1.);
230  MD[i]->setValue(MDL_SCALE, daux);
231  }
232  }
233  }
234  delete header;
235 
236  if (dataMode < DATA) // Don't read the individual header and the data if not necessary
237  return 0;
238 
239  size_t pad = 0;
240  readData(fimg, select_img, datatype, pad );
241 
242  return(0);
243 }
244 
245 /************************************************************************
246 @Function: writeIMAGIC
247 @Description:
248  Writing an IMAGIC image format.
249 @Algorithm:
250  A file format for the IMAGIC package.
251 @Arguments:
252  Bimage* the image structure.
253 @Returns:
254  int error code (<0 means failure).
255 **************************************************************************/
259 int ImageBase::writeIMAGIC(size_t select_img, int mode, const String &bitDepth, CastWriteMode castMode)
260 {
261 #undef DEBUG
262  //#define DEBUG
263 #ifdef DEBUG
264  printf("DEBUG writeIMAGIC: Reading Imagic file\n");
265 #endif
266 
267  IMAGIChead header;
268 
269  // Cast T to datatype without convert data
270  DataType wDType, myTypeID = myT();
271 
272  if (bitDepth == "")
273  {
274  switch(myTypeID)
275  {
276  case DT_Double:
277  case DT_Float:
278  case DT_Int:
279  case DT_UInt:
280  wDType = DT_Float;
281  strncpy(header.type,"REAL", sizeof(header.type));
282  break;
283  case DT_UShort:
284  castMode = CW_CONVERT;
285  /* no break */
286  case DT_Short:
287  wDType = DT_Short;
288  strncpy(header.type,"INTG", sizeof(header.type));
289  break;
290  case DT_SChar:
291  castMode = CW_CONVERT;
292  /* no break */
293  case DT_UChar:
294  wDType = DT_UChar;
295  strncpy(header.type,"PACK", sizeof(header.type));
296  break;
297  case DT_CFloat:
298  case DT_CDouble:
299  wDType = DT_CFloat;
300  strncpy(header.type,"COMP", sizeof(header.type));
301  break;
302  default:
303  wDType = DT_Unknown;
304  (void)wDType; // to suppress dead assignment warning
305  REPORT_ERROR(ERR_TYPE_INCORRECT, "ERROR: Unsupported data type by IMAGIC format.");
306  }
307  }
308  else //Convert to other data type
309  {
310  // Default Value
311  wDType = (bitDepth == "default") ? DT_Float : datatypeRAW(bitDepth);
312 
313  switch (wDType)
314  {
315  case DT_UChar:
316  strncpy(header.type,"PACK", sizeof(header.type));
317  break;
318  case DT_Short:
319  strncpy(header.type,"INTG", sizeof(header.type));
320  break;
321  case DT_Float:
322  (strncpy)(header.type,"REAL", sizeof(header.type));
323  break;
324  case DT_CFloat:
325  strncpy(header.type,"COMP", sizeof(header.type));
326  break;
327  default:
328  REPORT_ERROR(ERR_TYPE_INCORRECT,"ERROR: incorrect IMAGIC bits depth value.");
329  }
330  }
331 
332  if (mmapOnWrite)
333  {
334  MDMainHeader.setValue(MDL_DATATYPE,(int) wDType);
335  if (!checkMmapT(wDType))
336  {
337  if (dataMode < DATA && castMode == CW_CAST) // This means ImageGeneric wants to know which DataType must use in mapFile2Write
338  return 0;
339  else //Mapping is an extra. When not available, go on and do not report an error.
340  {
341  /* In this case we cannot map the file because required and feasible datatypes are
342  * not compatible. Then we denote to MapFile2Write the same incoming datatype to
343  * keep using this Image object as usual, without mapping on write.
344  */
345  mmapOnWrite = false;
346  dataMode = DATA;
347  MDMainHeader.setValue(MDL_DATATYPE,(int) myTypeID);
348 
349  // In case Image size great then, at least, map the multidimarray
350  if (mdaBase->nzyxdim*gettypesize(myTypeID) > tiff_map_min_size)
351  mdaBase->setMmap(true);
352 
353  // Allocate memory for image data (Assume xdim, ydim, zdim and ndim are already set
354  //if memory already allocated use it (no resize allowed)
355  mdaBase->coreAllocateReuse();
356 
357  return 0;
358  }
359  }
360  else
361  dataMode = DATA;
362  }
363 
364  size_t Xdim, Ydim, Zdim, Ndim;
365  getDimensions(Xdim, Ydim, Zdim, Ndim);
366 
367  if (Zdim > 1)
368  REPORT_ERROR(ERR_MULTIDIM_DIM, "writeIMAGIC: Imagic format does not support volumes.");
369 
370  size_t datasize, datasize_n;
371  datasize_n = (size_t)Xdim*Ydim*Zdim;
372  datasize = datasize_n * gettypesize(wDType);
373 
374  // fill in the file header
375  header.nhfr = 1;
376  header.npix2 = Xdim*Ydim;
377  header.npixel = header.npix2;
378  header.iylp = Xdim;
379  header.ixlp = Ydim;
380 
381  time_t timer;
382  time ( &timer );
383  tm* t = localtime(&timer);
384 
385  header.ndate = t->tm_mday;
386  header.nmonth = t->tm_mon + 1;
387  header.nyear = t->tm_year;
388  header.nhour = t->tm_hour;
389  header.nminut = t->tm_min;
390  header.nsec = t->tm_sec;
391 
392  double aux;
393 
394  if (!MDMainHeader.empty())
395  {
396 #define SET_MAIN_HEADER_VALUE(field, label) MDMainHeader.getValueOrDefault(label, aux, 0.); header.field = (float)aux
401  header.varian = header.sigma*header.sigma;
402  }
403 
404  memcpy(header.lastpr, "Xmipp", 5);
405  memcpy(header.name, filename.c_str(), 80);
406 
407  size_t imgStart = IMG_INDEX(select_img);
408 
409  header.ifn = replaceNsize - 1 ;
410  header.imn = 1;
411 
412  if ( mode == WRITE_APPEND )
413  {
414  imgStart = replaceNsize;
415  header.ifn = replaceNsize + Ndim - 1 ;
416  }
417  else if( mode == WRITE_REPLACE && imgStart + Ndim > replaceNsize)
418  header.ifn = imgStart + Ndim - 1;
419  else if (Ndim > replaceNsize)
420  header.ifn = Ndim - 1;
421 
422  /*
423  * BLOCK HEADER IF NEEDED
424  */
425  FileLock flockHead, flockImg;
426  flockHead.lock(fhed);
427  flockImg.lock(fimg);
428 
429  if (replaceNsize == 0) // Header written first time
430  {
431  if ( swapWrite )
432  {
433  IMAGIChead headTemp = header;
434  swapPage((char *) &headTemp, IMAGICSIZE - 916, DT_Float);
435  fwrite( &headTemp, IMAGICSIZE, 1, fhed );
436  }
437  fwrite( &header, IMAGICSIZE, 1, fhed );
438  }
439  else if( header.ifn + 1 > (int)replaceNsize && imgStart > 0 ) // Update number of images when needed
440  {
441  fseek( fhed, sizeof(int), SEEK_SET);
442  if ( swapWrite )
443  {
444  int ifnswp = header.ifn;
445  swapPage((char *) &ifnswp, SIZEOF_INT, DT_Int);
446  fwrite(&(ifnswp),SIZEOF_INT,1,fhed);
447  }
448  else
449  fwrite(&(header.ifn),SIZEOF_INT,1,fhed);
450  }
451 
452  // Jump to the selected imgStart position
453  fseek(fimg, datasize * imgStart, SEEK_SET);
454  fseek(fhed, IMAGICSIZE * imgStart, SEEK_SET);
455 
456  auto it = MD.begin();
457 
458  for (size_t i = 0; i < Ndim; ++i, ++it)
459  {
460  header.iyold=header.ixold=0;
461  header.euler_alpha=header.euler_beta=header.euler_gamma=0.;
462 
463  // Write the individual image header
464  if (it != MD.end() && (dataMode == _HEADER_ALL || dataMode == _DATA_ALL))
465  {
466 #define SET_HEADER_VALUEInt(field, label) (*it)->getValueOrDefault((label), (aux), 0); header.field = -(int)(aux)
467 #define SET_HEADER_VALUEDouble(field, label) (*it)->getValueOrDefault((label), (aux), 0.); header.field = -(float)(aux)
468 
474  }
475  // Update index number of image
476  header.imn = imgStart + i + 1;
477 
478  if ( swapWrite )
479  swapPage((char *) &header, IMAGICSIZE - 916, DT_Float);
480  fwrite( &header, IMAGICSIZE, 1, fhed );
481 
482  if (dataMode >= DATA)
483  {
484  if (mmapOnWrite && Ndim == 1) // Can map one image at a time only
485  {
486  mappedOffset = ftell(fimg);
487  mappedSize = mappedOffset + datasize;
488  fseek(fimg, datasize-1, SEEK_CUR);
489  fputc(0, fimg);
490  }
491  else
492  writeData(fimg, i*datasize_n, wDType, datasize_n, castMode);
493  }
494  else
495  fseek(fimg, datasize, SEEK_CUR);
496  }
497 
498  //Unlock
499  flockHead.unlock();
500  flockImg.unlock();
501 
502  if (mmapOnWrite)
503  mmapFile();
504 
505  return(0);
506 }
Index out of bounds.
Definition: xmipp_error.h:132
tsne coefficients in 2D
Rotation angle of an image (double,degrees)
float avdens
Definition: rwIMAGIC.cpp:77
#define SWAPTRIG
sampling rate in A/pixel (double)
float proj_weight
Definition: rwIMAGIC.cpp:96
sampling rate in A/pixel (double)
char name[80]
Definition: rwIMAGIC.cpp:87
sampling rate in A/pixel (double)
#define REPORT_ERROR(nerr, ErrormMsg)
Definition: xmipp_error.h:211
float sigma
Definition: rwIMAGIC.cpp:78
void sqrt(Image< double > &op)
Maximum value (double)
Tilting angle of an image (double,degrees)
DataType datatypeRAW(String strDT)
Shift for the image in the X axis (double)
int writeIMAGIC(size_t img_select=ALL_IMAGES, int mode=WRITE_OVERWRITE, const String &bitDepth="", CastWriteMode castMode=CW_CAST)
Definition: rwIMAGIC.cpp:259
Special label to be used when gathering MDs in MpiMetadataPrograms.
int readIMAGIC(size_t img_select)
Definition: rwIMAGIC.cpp:127
void abs(Image< double > &op)
if read from file original image datatype, this is an struct defined in image
void unlock()
Unlock.
float eman_az
Definition: rwIMAGIC.cpp:90
int nminut
Definition: rwIMAGIC.cpp:68
float extra_3[66]
Definition: rwIMAGIC.cpp:97
int ierror
Definition: rwIMAGIC.cpp:62
char type[4]
Definition: rwIMAGIC.cpp:74
float densmin
Definition: rwIMAGIC.cpp:82
#define i
Minimum value (double)
float euler_alpha
Definition: rwIMAGIC.cpp:93
if(fabs(c[*nmax+ *nmax *c_dim1])==0.e0)
const size_t tiff_map_min_size
float eman_alt
Definition: rwIMAGIC.cpp:89
float varian
Definition: rwIMAGIC.cpp:79
float extra_2[69]
Definition: rwIMAGIC.cpp:92
float oldavd
Definition: rwIMAGIC.cpp:80
float euler_gamma
Definition: rwIMAGIC.cpp:95
char lastpr[8]
Definition: rwIMAGIC.cpp:86
Couldn&#39;t read from file.
Definition: xmipp_error.h:139
static MDRowVec emptyHeaderVec()
DataType
scaling factor for an image or volume (double)
void mode
#define SET_HEADER_VALUEInt(field, label)
#define SET_HEADER_VALUEDouble(field, label)
float dummy[4]
Definition: rwIMAGIC.cpp:85
void lock(int fileno=0)
Lock file.
#define SET_MAIN_HEADER_VALUE(field, label)
int npixel
Definition: rwIMAGIC.cpp:71
std::string String
Definition: xmipp_strings.h:34
float euler_beta
Definition: rwIMAGIC.cpp:94
#define ALL_IMAGES
String formatString(const char *format,...)
Shift for the image in the Z axis (double)
#define IMAGICSIZE
Definition: rwIMAGIC.cpp:46
#define IMG_INDEX(select_img)
average value (double)
Incorrect MultidimArray dimensions.
Definition: xmipp_error.h:173
float extra_1[8]
Definition: rwIMAGIC.cpp:88
#define SIZEOF_INT
Definition: rwIMAGIC.cpp:49
CastWriteMode
Shift for the image in the Y axis (double)
float densmax
Definition: rwIMAGIC.cpp:81
Incorrect type received.
Definition: xmipp_error.h:190
char history[228]
Definition: rwIMAGIC.cpp:98
int nmonth
Definition: rwIMAGIC.cpp:65
< Score 4 for volumes
float eman_phi
Definition: rwIMAGIC.cpp:91
size_t gettypesize(DataType type)
Returns memory size of datatype.