Xmipp  v3.23.11-Nereus
xmipp_metadata_program.cpp
Go to the documentation of this file.
1 /***************************************************************************
2  *
3  * Authors: David Strelak (davidstrelak@gmail.com)
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_metadata_program.h"
27 #include "xmipp_funcs.h"
28 #include "xmipp_image_generic.h"
29 #include "metadata_extension.h"
30 
33 {
34  oroot = oext = fn_out = fn_in = "";
36  apply_geo = false;
37  allow_apply_geo = false;
38  produces_an_output = false;
39  produces_a_metadata = false;
41  allow_time_bar = true;
42  decompose_stacks = true;
43  delete_output_stack = true;
44  get_image_info = true;
45  remove_disabled = true;
47  mdInSize = 0;
48  ndimOut = zdimOut = ydimOut = xdimOut = 0;
50  delete_mdIn = false;
51  //Flags to store metadata when -o is stack
52  save_metadata_stack = false;
53  keep_input_columns = false;
54  track_origin = false;
55  create_empty_stackfile = false;
57  mdIn = nullptr;
58 }
59 
61 {
62  if (delete_mdIn)
63  delete mdIn;
64 }
65 
66 int XmippMetadataProgram::tryRead(int argc, const char ** argv, bool reportErrors)
67 {
68  this->read( argc, argv, reportErrors );
69  return errorCode;
70 }
71 
73 {}
74 
76 {
78 
79  CommentList comments;
80  comments.addComment("Input file: metadata, stack, volume or image.");
81  defaultComments["-i"]=comments;
82 
83  comments.clear();
84  comments.addComment("Output file: metadata, stack, volume or image.");
85  defaultComments["-o"]=comments;
86 
87  comments.clear();
88  comments.addComment("Rootname of output individual images.");
89  comments.addComment("Output image format can be set adding extension after rootname as \":ext\".");
90  defaultComments["--oroot"]=comments;
91 }
92 
93 
95 {
96  processDefaultComment("-i","-i <input_file>");
97  addParamsLine("alias --input;");
98  addParamsLine(" [--mode+ <mode=overwrite>] : Metadata writing mode.");
99  addParamsLine(" where <mode>");
100  addParamsLine(" overwrite : Replace the content of the file with the Metadata");
101  addParamsLine(" append : Write the Metadata as a new block, removing the old one");
103 
105  produces_an_output = true;
106 
108  {
109  processDefaultComment("-o","[-o <output_file=\"\">]");
110  addParamsLine(" alias --output;");
111  processDefaultComment("--oroot","[--oroot <root=\"\">]");
112  }
113  else if (produces_an_output)
114  {
115  processDefaultComment("-o","[-o <output_file=\"\">]");
116  addParamsLine(" alias --output;");
117  }
118 
119  addParamsLine(" [--save_metadata_stack+ <output_md=\"\">] : Create a metadata when the output (-o) is an stack");
120  addParamsLine(" : if --oroot is used, the metadata can be saved in -o param.");
121  addParamsLine(" : if output_md is empty, the name of the stack will be used, changing the extension to xmd.");
122  addParamsLine(" [--track_origin+] : Store the original image filename in the output ");
123  addParamsLine(" : metadata in column imageOriginal.");
124  addParamsLine(" [--keep_input_columns+] : Preserve the columns from the input metadata.");
125  addParamsLine(" : Some of the column values can be changed by the program.");
126 
127  if (allow_apply_geo)
128  {
129  addParamsLine(" [--dont_apply_geo] : for 2D-images: do not apply transformation stored in metadata");
130  }
131 }//function defineParams
132 
134 {
135  addParamsLine(" [--label+ <image_label=image>] : Label to be used to read/write images.");
136 }
137 
139 {
140  fn_in = getParam("-i");
141  mode = metadataModeConvert(getParam("--mode"));
142 
143  if (produces_an_output)
144  fn_out = checkParam("-o") ? getParam("-o") : "";
145 
147  {
148  fn_out = checkParam("-o") ? getParam("-o") : "";
149  oroot = getParam("--oroot");
150  }
151 
152  if (allow_apply_geo)
153  apply_geo = !checkParam("--dont_apply_geo");
154 
155  // The following flags are an "advanced" options to allow save metadata
156  // when the -o is an stack, each program can define its default value
157  // that's why the || construct before checkParam call
158  save_metadata_stack = save_metadata_stack || checkParam("--save_metadata_stack");
159  track_origin = track_origin || checkParam("--track_origin");
160  keep_input_columns = keep_input_columns || checkParam("--keep_input_columns");
161 
162  MetaData * md = new MetaDataVec();
163  md->read(fn_in, NULL, decompose_stacks);
164  delete_mdIn = true; // Only delete mdIn when called directly from command line
165 
166  setup(md, fn_out, oroot, apply_geo, MDL::str2Label(getParam("--label")));
167 }//function readParams
168 
170  bool applyGeo, MDLabel image_label)
171 {
172  this->mdIn = md;
173  this->fn_out = out;
174  this->oroot = oroot;
175  this->image_label = image_label;
176  this->doRun = true;
177  this->iter = nullptr;
178 
179  if (remove_disabled)
180  mdIn->removeDisabled();
181 
182  if (mdIn->isEmpty())
183  REPORT_ERROR(ERR_MD_NOOBJ, "Empty input Metadata.");
184 
185  mdInSize = mdIn->size();
186 
187  if (mdIn->isMetadataFile)
188  input_is_metadata = true;
189  else
190  {
191  if (mdInSize == 1)
192  single_image = true;
193  else
194  input_is_stack = true;
195  }
196 
197  String labelStr = MDL::label2Str(image_label);
198 
199  if (image_label == MDL_UNDEFINED)
200  REPORT_ERROR(ERR_MD_BADLABEL, formatString("Unknown image label '%s'.", labelStr.c_str()));
201 
202  if (!mdIn->containsLabel(image_label))
204  formatString("Image label '%s' is missing. See option --label.", labelStr.c_str()));
205 
206  /* Output is stack if, given a filename in fn_out, mdIn has multiple images.
207  * In case no output name is given, then input is overwritten and we have to
208  * check if it is stack. */
209  output_is_stack = mdInSize > 1 && oroot.empty() && (!fn_out.empty() || input_is_stack);
210 
211  /* Save metadata related to output stack only if required,
212  * and output is a stack.*/
213  //save_metadata_stack = save_metadata_stack && output_is_stack;
214 
215  // Only delete output stack in case we are not overwriting input
217  !(fn_out.empty() && oroot.empty()) : false;
218 
219  // If the output is a stack, create empty stack file in advance to avoid concurrent access to the header
221 
222  // if create, then we need to read the dimensions of the input stack
224  getImageInfo(*mdIn, xdimOut, ydimOut, zdimOut, ndimOut, datatypeOut, image_label);
225 
226  apply_geo = applyGeo;
227  // if input is volume do not apply geo
228  if (zdimOut > 1)
229  apply_geo = false;
230 }//function setup
231 
233 {
234  if (verbose==0)
235  return;
236  std::cout << "Input File: " << fn_in << std::endl;
237  if (apply_geo)
238  std::cout << "Reading geometrical transformations stored in metadata" << std::endl;
239  if (!fn_out.empty())
240  std::cout << "Output File: " << fn_out << std::endl;
241  if (!oroot.empty())
242  std::cout << "Output Root: " << oroot << std::endl;
243 }
244 
246 {}
247 
249 {}
250 
252 {
254  fn_out.deleteFile();
255 
258 
259  //Show some info
260  show();
261  // Initialize progress bar
265  time_bar_step = CEIL((double)time_bar_size / 60.0);
266  time_bar_done = 0;
267 }
268 
270 {
273  writeOutput();
274 }
275 
277 {
278  if (!single_image && !mdOut.isEmpty() && !fn_out.empty())
279  {
280  if (produces_an_output || produces_a_metadata || !oroot.empty()) // Out as independent images
281  mdOut.write(fn_out.replaceExtension("xmd"));
282  else if (save_metadata_stack) // Output is stack and also save its associated metadata
283  {
284  FileName outFileName = getParam("--save_metadata_stack");
285  if (outFileName.empty())
286  outFileName = fn_out.replaceExtension("xmd");
287  mdOut.write(outFileName);
288  }
289  }
290 }
291 
293 {
296 }
297 
298 void XmippMetadataProgram::setupRowOut(const FileName &fnImgIn, const MDRow &rowIn, const FileName &fnImgOut, MDRow &rowOut) const
299 {
300  rowOut.clear();
301  if (keep_input_columns) {
302  for (const MDObject* col : rowIn)
303  rowOut.setValue(*col);
304  }
305  rowOut.setValue(image_label, fnImgOut);
306  rowOut.setValue(MDL_ENABLED, 1);
307 
308  if (track_origin)
309  rowOut.setValue(MDL_IMAGE_ORIGINAL, fnImgIn);
310 }
311 
313 {
314  // In the serial implementation, we don't have to wait. This will be useful for MPI programs
315 }
316 
318 {
319 }
320 
321 bool XmippMetadataProgram::getImageToProcess(size_t &objId, size_t &objIndex)
322 {
323  if (nullptr == iter) {
324  iter = std::unique_ptr<MetaData::id_iterator>(new MetaData::id_iterator(mdIn->ids().begin()));
325  iterIndex = 0;
326  time_bar_done = 0;
327  } else {
328  if (*iter == mdIn->ids().end()) {
329  throw std::logic_error("Iterating behind the end of the metadata");
330  }
331  ++iterIndex;
332  ++(*iter);
333  }
334  bool isValid = *iter != mdIn->ids().end();
335  if (isValid) {
336  ++time_bar_done;
337  objId = **iter;
338  objIndex = iterIndex;
339  }
340  return isValid;
341 }
342 
344 {
345  FileName fnImg, fnImgOut, fullBaseName;
346  mdOut.clear(); //this allows multiple runs of the same Program object
347 
348  //Perform particular preprocessing
349  preProcess();
350 
351  startProcessing();
352 
353  if (!oroot.empty())
354  {
355  if (oext.empty())
357  oextBaseName = oext;
358  fullBaseName = oroot.removeFileFormat();
359  baseName = fullBaseName.getBaseName();
360  pathBaseName = fullBaseName.getDir();
361  }
362 
363  size_t objId;
364  size_t objIndex;
365  while (getImageToProcess(objId, objIndex))
366  {
367  ++objIndex; //increment for composing starting at 1
368  auto rowIn = mdIn->getRow(objId);
369  rowIn->getValue(image_label, fnImg);
370 
371  if (fnImg.empty())
372  break;
373 
374  fnImgOut = fnImg;
375 
376  MDRowVec rowOut;
377 
379  {
380  if (!oroot.empty()) // Compose out name to save as independent images
381  {
382  if (oext.empty()) // If oext is still empty, then use ext of indep input images
383  {
384  if (input_is_stack)
385  oextBaseName = "spi";
386  else
387  oextBaseName = fnImg.getFileFormat();
388  }
389 
390  if (!baseName.empty() )
391  fnImgOut.compose(fullBaseName, objIndex, oextBaseName);
392  else if (fnImg.isInStack())
393  fnImgOut.compose(pathBaseName + (fnImg.withoutExtension()).getDecomposedFileName(), objIndex, oextBaseName);
394  else
395  fnImgOut = pathBaseName + fnImg.withoutExtension()+ "." + oextBaseName;
396  }
397  else if (!fn_out.empty() )
398  {
399  if (single_image)
400  fnImgOut = fn_out;
401  else
402  fnImgOut.compose(objIndex, fn_out); // Compose out name to save as stacks
403  }
404  else
405  fnImgOut = fnImg;
406  setupRowOut(fnImg, *rowIn.get(), fnImgOut, rowOut);
407  }
408  else if (produces_a_metadata)
409  setupRowOut(fnImg, *rowIn.get(), fnImgOut, rowOut);
410 
411  processImage(fnImg, fnImgOut, *rowIn.get(), rowOut);
412 
414  mdOut.addRow(rowOut);
415 
416  checkPoint();
417  showProgress();
418  }
419  wait();
420 
421  /* Generate name to save mdOut when output are independent images. It uses as prefix
422  * the dirBaseName in order not overwriting files when repeating same command on
423  * different directories. If baseName is set it is used, otherwise, input name is used.
424  * Then, the suffix _oext is added.*/
425  if (fn_out.empty() )
426  {
427  if (!oroot.empty())
428  {
429  if (!baseName.empty() )
430  fn_out = findAndReplace(pathBaseName,"/","_") + baseName + "_" + oextBaseName + ".xmd";
431  else
432  fn_out = findAndReplace(pathBaseName,"/","_") + fn_in.getBaseName() + "_" + oextBaseName + ".xmd";
433  }
434  else if (input_is_metadata)
435  fn_out = fn_in;
436  }
437 
439 
440  postProcess();
441 
442  /* Reset the default values of the program in case
443  * to be reused.*/
444  init();
445 }
void init_progress_bar(long total)
bool delete_output_stack
Delete previous output stack file prior to process images.
WriteModeMetaData metadataModeConvert(String mode)
virtual void read(int argc, const char **argv, bool reportErrors=true)
static MDLabel str2Label(const String &labelName)
size_t mdInSize
Number of input elements.
#define REPORT_ERROR(nerr, ErrormMsg)
Definition: xmipp_error.h:211
FileName removeFileFormat() const
FileName replaceExtension(const String &newExt) const
No exist requested object.
Definition: xmipp_error.h:156
virtual bool containsLabel(const MDLabel label) const =0
virtual int tryRead(int argc, const char **argv, bool reportErrors=true)
void processDefaultComment(const char *param, const char *left)
Unexpected label.
Definition: xmipp_error.h:157
void compose(const String &str, const size_t no, const String &ext="")
void write(const FileName &outFile, WriteModeMetaData mode=MD_OVERWRITE) const
bool single_image
Input is a single image.
bool get_image_info
Get the input image file dimensions to further operations.
virtual IdIteratorProxy< false > ids()
bool isMetadataFile
bool input_is_stack
Input is a stack.
Is this image enabled? (int [-1 or 1])
bool output_is_stack
Output is a stack.
size_t addRow(const MDRow &row) override
void clear() override
XmippMetadataProgram()
Empty constructor.
bool isEmpty() const override
int argc
Original command line arguments.
Definition: xmipp_program.h:86
void getImageInfo(const MetaData &md, size_t &Xdim, size_t &Ydim, size_t &Zdim, size_t &Ndim, DataType &datatype, MDLabel image_label)
Name of an image from which MDL_IMAGE is coming from.
FileName fn_in
Filenames of input and output Metadata.
const char * getParam(const char *param, int arg=0)
virtual bool isEmpty() const
virtual void wait()
Wait for the distributor to finish.
#define CEIL(x)
Definition: xmipp_macros.h:225
virtual void setup(MetaData *md, const FileName &o="", const FileName &oroot="", bool applyGeo=false, MDLabel label=MDL_IMAGE)
String findAndReplace(const String &tInput, const String &tFind, const String &tReplace)
void setupRowOut(const FileName &fnImgIn, const MDRow &rowIn, const FileName &fnImgOut, MDRow &rowOut) const
Prepare rowout.
virtual void clear()=0
void progress_bar(long rlen)
const char ** argv
Definition: xmipp_program.h:87
bool produces_an_output
Indicate that a unique final output is produced.
Missing expected label.
Definition: xmipp_error.h:158
virtual std::unique_ptr< MDRow > getRow(size_t id)=0
virtual void run()
Run over all images.
void createEmptyFile(const FileName &filename, int xdim, int ydim, int Zdim, size_t select_img, bool isStack, int mode, int _swapWrite, const MDRowVec *md)
int verbose
Verbosity level.
virtual size_t size() const =0
MDLabel image_label
MDLabel to be used to read/write images, usually will be MDL_IMAGE.
void deleteFile() const
bool allow_time_bar
Show process time bar.
virtual void processImage(const FileName &fnImg, const FileName &fnImgOut, const MDRow &rowIn, MDRow &rowOut)=0
bool track_origin
Include the original input image filename in the output stack.
bool remove_disabled
Remove disabled images from the input selfile.
virtual void checkPoint()
For very long programs, it may be needed to write checkpoints.
void setValue(MDLabel label, const T &d, bool addLabel=true)
void show() const override
FileName withoutExtension() const
virtual void removeDisabled()
bool save_metadata_stack
Save the associated output metadata when output file is a stack.
bool decompose_stacks
Input Metadata will treat a stack file as a set of images instead of a unique file.
std::string String
Definition: xmipp_strings.h:34
String formatString(const char *format,...)
String getFileFormat() const
virtual void initComments()
FileName getDir() const
bool keep_input_columns
Keep input metadata columns.
bool checkParam(const char *param)
static String label2Str(const MDLabel &label)
bool each_image_produces_an_output
Indicate that an output is produced for each image in the input.
WriteModeMetaData mode
Metadata writing mode: OVERWRITE, APPEND.
size_t ndimOut
Output dimensions.
void addComment(const String &comment, int visible=0, bool wikiVerbatim=false)
idIterator< false > id_iterator
virtual bool getImageToProcess(size_t &objId, size_t &objIndex)
bool input_is_metadata
Input is a metadata.
FileName getBaseName() const
Name of an image (std::string)
MDLabel
bool produces_a_metadata
Indicate that the unique final output file is a Metadata.
void addParamsLine(const String &line)
virtual void read(const FileName &inFile, const std::vector< MDLabel > *desiredLabels=nullptr, bool decomposeStack=true)=0
size_t time_bar_step
Some time bar related counters.
bool isInStack() const
FileName oext
Output extension and root.
std::map< String, CommentList > defaultComments
Definition: xmipp_program.h:83