Basic Image AlgorithmS Library  2.8.0
 All Classes Namespaces Functions Variables Typedefs Enumerations Enumerator Friends Groups Pages
biasimagecalc.cpp
1 /*
2 This file is part of the BIAS library (Basic ImageAlgorithmS).
3 
4 Copyright (C) 2003-2009 (see file CONTACT for details)
5  Multimediale Systeme der Informationsverarbeitung
6  Institut fuer Informatik
7  Christian-Albrechts-Universitaet Kiel
8 
9 
10 BIAS is free software; you can redistribute it and/or modify
11 it under the terms of the GNU Lesser General Public License as published by
12 the Free Software Foundation; either version 2.1 of the License, or
13 (at your option) any later version.
14 
15 BIAS is distributed in the hope that it will be useful,
16 but WITHOUT ANY WARRANTY; without even the implied warranty of
17 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 GNU Lesser General Public License for more details.
19 
20 You should have received a copy of the GNU Lesser General Public License
21 along with BIAS; if not, write to the Free Software
22 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
23 */
24 
25 #include <Utils/Param.hh>
26 #include <Base/Image/ImageBase.hh>
27 #include <Base/Image/ImageIO.hh>
28 #include <Base/Image/ImageConvert.hh>
29 
30 #include <Base/ImageUtils/ImageCalc.hh>
31 
32 using namespace std;
33 using namespace BIAS;
34 
35 // operations for two input images
36 #define OP_ADD 0
37 #define OP_SUBTRACT 1
38 #define OP_MULTIPLY 2
39 #define OP_DIVIDE 3
40 #define OP_AND 4
41 #define OP_NAND 5
42 #define OP_OR 6
43 #define OP_NOR 7
44 #define OP_XOR 8
45 // operations for one image and a scalar
46 #define OP_ADD_SCALAR 9
47 #define OP_SUBTRACT_SCALAR 10
48 #define OP_MULTIPLY_SCALAR 11
49 #define OP_DIVIDE_SCALAR 12
50 // operations for one image
51 #define OP_LOG 13
52 #define OP_LOG10 14
53 // the total number of operations
54 #define NUM_OPS 15
55 
56 /**
57  * @brief Loads the image given by filename and returns it as image
58  *
59  * @param filename
60  * the path of the file to load
61  * @param image
62  * the returned image
63  * @param floatOutput
64  * if set to true, the loaded image is converted to float
65  *
66  * @return true on success or false otherwise
67  *
68  * @author rwulff
69  * @date 03/2010
70  * @file biasimagecalc
71  * @internal
72  */
73 bool LoadImage(const string &filename, ImageBase &image,
74  const bool *floatOutput) {
75  if (filename.empty()) {
76  cerr << "ERROR: please specify an input image. try '-h' for help"
77  << endl;
78  return false;
79  }
80  else { // image specified -> try to load it
81  // convert to float, if floatOutput is true
82  if (*floatOutput) {
83  ImageBase tempIm;
84 
85  if (ImageIO::Load(filename, tempIm)!= 0) {
86  cerr << "ERROR: image (" << filename << ") could not be loaded"
87  << endl;
88  return false;
89  }
90 
91  ImageConvert::ConvertST(tempIm, image, ImageBase::ST_float);
92  }
93  else { // floatOuput is false
94  if (ImageIO::Load(filename, image)!= 0) {
95  cerr << "ERROR: image (" << filename << ") could not be loaded"
96  << endl;
97  return false;
98  }
99  }
100  }
101 
102  return true;
103 }
104 
105 /**
106  * @brief Helper function. Performs the calculations on two images.
107  *
108  * @param imagesInPath
109  * filenames of the two input images
110  * @param output
111  * filename of the output image
112  * @param operation
113  * the operation to perform between the input images
114  * @param floatOutput
115  * if set to true, the operation will be performed on float images
116  *
117  * @return true on success or false otherwise
118  *
119  * @author rwulff
120  * @date 03/2010
121  * @file biasimagecalc
122  * @internal
123  */
124 bool CalculateOnTwoImages(string *imagesInPath[2], const string *output,
125  const int *operation,
126  const bool *floatOutput) {
127  ImageBase imagesIn[2];
128  ImageBase imageOut;
129 
130  // load images
131  if (!LoadImage(*imagesInPath[0], imagesIn[0], floatOutput)) {
132  return false;
133  }
134 
135  if (!LoadImage(*imagesInPath[1], imagesIn[1], floatOutput)) {
136  return false;
137  }
138 
139  // assert same size
140  BIASASSERT( imagesIn[0].GetWidth() == imagesIn[1].GetWidth()
141  && imagesIn[0].GetHeight() == imagesIn[1].GetHeight()
142  && imagesIn[0].GetChannelCount() == imagesIn[1].GetChannelCount())
143 
144  // ensure same storage type
145  if (imagesIn[0].GetStorageType() != imagesIn[1].GetStorageType()) {
146  cout << "ERROR: input images must have same storage type" << endl;
147  return false;
148  }
149 
150  // initialise output image with correct size, channel count and storage type
151  imageOut.Init(imagesIn[0].GetWidth(), imagesIn[0].GetHeight(),
152  imagesIn[0].GetChannelCount(), imagesIn[0].GetStorageType());
153 
154  // perform operation
155  switch (*operation) {
156  case OP_ADD: // ADD
157  switch (imagesIn[0].GetStorageType()) {
158  case ImageBase::ST_unsignedchar:
160  (const Image<unsigned char> &)imagesIn[1],
161  (Image<unsigned char> &)imageOut);
162  break;
163  case ImageBase::ST_float:
164  ImageCalc<float>::Add((const Image<float> &)imagesIn[0],
165  (const Image<float> &)imagesIn[1],
166  (Image<float> &)imageOut);
167  break;
168  default:
169  cout << "ERROR: operation not implemented for this storage type" << endl;
170  return false;
171  } // end of storage type switch
172  break;
173  case OP_SUBTRACT: // SUBTRACT
174  switch (imagesIn[0].GetStorageType()) {
175  case ImageBase::ST_unsignedchar:
177  (const Image<unsigned char> &)imagesIn[1],
178  (Image<unsigned char> &)imageOut);
179  break;
180  case ImageBase::ST_float:
181  ImageCalc<float>::Subtract((const Image<float> &)imagesIn[0],
182  (const Image<float> &)imagesIn[1],
183  (Image<float> &)imageOut);
184  break;
185  default:
186  cout << "ERROR: operation not implemented for this storage type" << endl;
187  return false;
188  } // end of storage type switch
189  break;
190  case OP_MULTIPLY: // MULTIPLY
191  switch (imagesIn[0].GetStorageType()) {
192  case ImageBase::ST_unsignedchar:
194  (const Image<unsigned char> &)imagesIn[1],
195  (Image<unsigned char> &)imageOut);
196  break;
197  case ImageBase::ST_float:
198  ImageCalc<float>::Multiply((const Image<float> &)imagesIn[0],
199  (const Image<float> &)imagesIn[1],
200  (Image<float> &)imageOut);
201  break;
202  default:
203  cout << "ERROR: operation not implemented for this storage type" << endl;
204  return false;
205  } // end of storage type switch
206  break;
207  case OP_DIVIDE: // DIVIDE
208  switch (imagesIn[0].GetStorageType()) {
209  case ImageBase::ST_unsignedchar:
211  (const Image<unsigned char> &)imagesIn[1],
212  (Image<unsigned char> &)imageOut);
213  break;
214  case ImageBase::ST_float:
215  ImageCalc<float>::Divide((const Image<float> &)imagesIn[0],
216  (const Image<float> &)imagesIn[1],
217  (Image<float> &)imageOut);
218  break;
219  default:
220  cout << "ERROR: operation not implemented for this storage type" << endl;
221  return false;
222  } // end of storage type switch
223  break;
224  case OP_AND: // AND
225  switch (imagesIn[0].GetStorageType()) {
226  case ImageBase::ST_unsignedchar:
228  (const Image<unsigned char> &)imagesIn[1],
229  (Image<unsigned char> &)imageOut);
230  break;
231  case ImageBase::ST_float:
232  ImageCalc<float>::And((const Image<float> &)imagesIn[0],
233  (const Image<float> &)imagesIn[1],
234  (Image<float> &)imageOut);
235  break;
236  default:
237  cout << "ERROR: operation not implemented for this storage type" << endl;
238  return false;
239  } // end of storage type switch
240  break;
241  case OP_NAND: // NAND
242  switch (imagesIn[0].GetStorageType()) {
243  case ImageBase::ST_unsignedchar:
245  (const Image<unsigned char> &)imagesIn[1],
246  (Image<unsigned char> &)imageOut);
247  break;
248  case ImageBase::ST_float:
249  ImageCalc<float>::Nand((const Image<float> &)imagesIn[0],
250  (const Image<float> &)imagesIn[1],
251  (Image<float> &)imageOut);
252  break;
253  default:
254  cout << "ERROR: operation not implemented for this storage type" << endl;
255  return false;
256  } // end of storage type switch
257  break;
258  case OP_OR: // OR
259  switch (imagesIn[0].GetStorageType()) {
260  case ImageBase::ST_unsignedchar:
262  (const Image<unsigned char> &)imagesIn[1],
263  (Image<unsigned char> &)imageOut);
264  break;
265  case ImageBase::ST_float:
266  ImageCalc<float>::Or((const Image<float> &)imagesIn[0],
267  (const Image<float> &)imagesIn[1],
268  (Image<float> &)imageOut);
269  break;
270  default:
271  cout << "ERROR: operation not implemented for this storage type" << endl;
272  return false;
273  } // end of storage type switch
274  break;
275  case OP_NOR: // NOR
276  switch (imagesIn[0].GetStorageType()) {
277  case ImageBase::ST_unsignedchar:
279  (const Image<unsigned char> &)imagesIn[1],
280  (Image<unsigned char> &)imageOut);
281  break;
282  case ImageBase::ST_float:
283  ImageCalc<float>::Nor((const Image<float> &)imagesIn[0],
284  (const Image<float> &)imagesIn[1],
285  (Image<float> &)imageOut);
286  break;
287  default:
288  cout << "ERROR: operation not implemented for this storage type" << endl;
289  return false;
290  } // end of storage type switch
291  break;
292  case OP_XOR: // XOR
293  switch (imagesIn[0].GetStorageType()) {
294  case ImageBase::ST_unsignedchar:
296  (const Image<unsigned char> &)imagesIn[1],
297  (Image<unsigned char> &)imageOut);
298  break;
299  case ImageBase::ST_float:
300  ImageCalc<float>::Xor((const Image<float> &)imagesIn[0],
301  (const Image<float> &)imagesIn[1],
302  (Image<float> &)imageOut);
303  break;
304  default:
305  cout << "ERROR: operation not implemented for this storage type" << endl;
306  return false;
307  } // end of storage type switch
308  break;
309  }
310 
311  // save output image
312  ImageIO::Save(*output, imageOut);
313 
314  return true;
315 }
316 
317 
318 /**
319  * @brief Helper function. Performs the calculations on the images and the
320  * scalar.
321  *
322  * @param imageInPath
323  * filename of the input images
324  * @param scalar
325  * the scalar value
326  * @param output
327  * filename of the output image
328  * @param operation
329  * the operation to perform on the input image and the scalar
330  * @param floatOutput
331  * if set to true, the operation will be performed on float images
332  *
333  * @return true on success or false otherwise
334  *
335  * @author rwulff
336  * @date 03/2010
337  * @file biasimagecalc
338  * @internal
339  */
340 bool CalculateOnOneImageAndScalar(const string *imageInPath,
341  const double *scalar,
342  const string *output,
343  const int *operation,
344  const bool *floatOutput) {
345  ImageBase imageIn;
346  ImageBase imageOut;
347 
348  // load image
349  if (!LoadImage(*imageInPath, imageIn, floatOutput)) {
350  return false;
351  }
352 
353  // initialise output image with correct size, channel count and storage type
354  imageOut.Init(imageIn.GetWidth(), imageIn.GetHeight(),
355  imageIn.GetChannelCount(), imageIn.GetStorageType());
356 
357  // perform operation
358  switch (*operation) {
359  case OP_ADD_SCALAR: // ADD_SCALAR
360  switch (imageIn.GetStorageType()) {
361  case ImageBase::ST_unsignedchar:
363  (unsigned char)*scalar,
364  (Image<unsigned char> &)imageOut);
365  break;
366  case ImageBase::ST_float:
367  ImageCalc<float>::AddScalar((const Image<float> &)imageIn,
368  (float)*scalar,
369  (Image<float> &)imageOut);
370  break;
371  default:
372  cout << "ERROR: operation not implemented for this storage type" << endl;
373  return false;
374  } // end of storage type switch
375  break;
376  case OP_SUBTRACT_SCALAR: // SUBTRACT_SCALAR
377  switch (imageIn.GetStorageType()) {
378  case ImageBase::ST_unsignedchar:
380  (unsigned char)*scalar,
381  (Image<unsigned char> &)imageOut);
382  break;
383  case ImageBase::ST_float:
385  (float)*scalar,
386  (Image<float> &)imageOut);
387  break;
388  default:
389  cout << "ERROR: operation not implemented for this storage type" << endl;
390  return false;
391  } // end of storage type switch
392  break;
393  case OP_MULTIPLY_SCALAR: // MULTIPLY_SCALAR
394  switch (imageIn.GetStorageType()) {
395  case ImageBase::ST_unsignedchar:
397  (unsigned char)*scalar,
398  (Image<unsigned char> &)imageOut);
399  break;
400  case ImageBase::ST_float:
402  (float)*scalar,
403  (Image<float> &)imageOut);
404  break;
405  default:
406  cout << "ERROR: operation not implemented for this storage type" << endl;
407  return false;
408  } // end of storage type switch
409  break;
410  case OP_DIVIDE_SCALAR: // DIVIDE_SCALAR
411  switch (imageIn.GetStorageType()) {
412  // the scalar must not be 0
413  if (*scalar == 0) {
414  cout << "ERROR: the scalar must not be 0" << endl;
415  return false;
416  }
417 
418  case ImageBase::ST_unsignedchar:
420  (unsigned char)*scalar,
421  (Image<unsigned char> &)imageOut);
422  break;
423  case ImageBase::ST_float:
425  (float)*scalar,
426  (Image<float> &)imageOut);
427  break;
428  default:
429  cout << "ERROR: operation not implemented for this storage type" << endl;
430  return false;
431  } // end of storage type switch
432  break;
433  }
434 
435  // save output image
436  ImageIO::Save(*output, imageOut);
437 
438  return true;
439 }
440 
441 
442 /**
443  * @brief Helper function. Performs the calculations on the image.
444  *
445  * @param imageInPath
446  * filename of the input image
447  * @param output
448  * filename of the output image
449  * @param operation
450  * the operation to perform on the input image
451  * @param floatOutput
452  * if set to true, the operation will be performed on float images
453  *
454  * @return true on success or false otherwise
455  *
456  * @author rwulff
457  * @date 03/2010
458  * @file biasimagecalc
459  * @internal
460  */
461 bool CalculateOnOneImage(const string *imageInPath,
462  const string *output,
463  const int *operation,
464  const bool *floatOutput) {
465  ImageBase imageIn;
466  ImageBase imageOut;
467 
468  // load image
469  if (!LoadImage(*imageInPath, imageIn, floatOutput)) {
470  return false;
471  }
472 
473  // initialise output image with correct size, channel count and storage type
474  imageOut.Init(imageIn.GetWidth(), imageIn.GetHeight(),
475  imageIn.GetChannelCount(), imageIn.GetStorageType());
476 
477  // perform operation
478  switch (*operation) {
479  case OP_LOG: // LOG
480  switch (imageIn.GetStorageType()) {
481  case ImageBase::ST_unsignedchar:
483  (Image<unsigned char> &)imageOut);
484  break;
485  case ImageBase::ST_float:
486  ImageCalc<float>::Log((const Image<float> &)imageIn,
487  (Image<float> &)imageOut);
488  break;
489  default:
490  cout << "ERROR: operation not implemented for this storage type" << endl;
491  return false;
492  } // end of storage type switch
493  break;
494  case OP_LOG10: // LOG10
495  switch (imageIn.GetStorageType()) {
496  case ImageBase::ST_unsignedchar:
498  (Image<unsigned char> &)imageOut);
499  break;
500  case ImageBase::ST_float:
501  ImageCalc<float>::Log10((const Image<float> &)imageIn,
502  (Image<float> &)imageOut);
503  break;
504  default:
505  cout << "ERROR: operation not implemented for this storage type" << endl;
506  return false;
507  } // end of storage type switch
508  break;
509  }
510 
511  // save output image
512  ImageIO::Save(*output, imageOut);
513 
514  return true;
515 }
516 
517 
518 /**
519  * @brief Main function. Evaluates the command line parameters and calls one
520  * of the helper functions.
521  *
522  * @author rwulff
523  * @date 03/2010
524  * @file biasimagecalc
525  */
526 int main(int argc, char *argv[]) {
527  // init command line parameters
528  Param param;
529 
530  bool *help = param.AddParamBool("help",
531  "print help information and exit",
532  false,
533  'h',
534  1);
535 
536  string *imagesInPath[2];
537  imagesInPath[0] = param.AddParamString("input1",
538  "path to the first output image (mandatory for all operations)",
539  "",
540  'i',
541  1);
542  imagesInPath[1] = param.AddParamString("input2",
543  "path to the second output image (must have same size and storage type as first input image)",
544  "",
545  'j',
546  1);
547  double *scalar = param.AddParamDouble("scalar",
548  "the scalar value (will be cast to the storage type of the input image)",
549  0.0,
550  -DBL_MAX,
551  DBL_MAX,
552  's',
553  1);
554  string *output = param.AddParamString("output",
555  "path to the output image (default: out.mip)"
556  " will be initialised with same storage type and size as first input image"
557  " (except if param '--float' is set)",
558  "out.mip",
559  'o',
560  1);
561 
562  bool *floatOutput = param.AddParamBool("float",
563  "convert input images to float and perform the operations on these float images. output image will be of type float as well.",
564  false,
565  'f',
566  1);
567 
568  // init string representations of operations
569  vector<string> operations(NUM_OPS);
570 
571  // operations for two input images
572  operations[OP_ADD] = "add";
573  operations[OP_SUBTRACT] = "subtract";
574  operations[OP_MULTIPLY] = "multiply";
575  operations[OP_DIVIDE] = "divide";
576  operations[OP_AND] = "and";
577  operations[OP_NAND] = "nand";
578  operations[OP_OR] = "or";
579  operations[OP_NOR] = "nor";
580  operations[OP_XOR] = "xor";
581  // operations for one image and a scalar
582  operations[OP_ADD_SCALAR] = "addScalar";
583  operations[OP_SUBTRACT_SCALAR] = "subtractScalar";
584  operations[OP_MULTIPLY_SCALAR] = "multiplyScalar";
585  operations[OP_DIVIDE_SCALAR] = "divideScalar";
586  // operations for one image
587  operations[OP_LOG] = "log";
588  operations[OP_LOG10] = "log10";
589 
590  int *operation =
591  param.AddParamEnum("operation",
592  "the arithmetic operation to perform.\n"
593  "\toperations that require TWO IMAGES:\n"
594  "\t- add: computes the pixelwise sum\n"
595  "\t- subtract: computes the pixelwise difference\n"
596  "\t- multiply: computes the pixelwise product\n"
597  "\t- divide: computes the pixelwise quotient\n"
598  "\t- and: computes the pixelwise AND\n"
599  "\t- nand: computes the pixelwise NAND\n"
600  "\t- or: computes the pixelwise OR\n"
601  "\t- nor: computes the pixelwise NOR\n"
602  "\t- xor: computes the pixelwise XOR\n"
603  "\toperations that require ONE IMAGE AND A SCALAR:\n"
604  "\t- addScalar: adds the scalar to each pixel\n"
605  "\t- subtractScalar: subtracts the scalar from each pixel\n"
606  "\t- multiplyScalar: multiplies the scalar with each pixel\n"
607  "\t- divideScalar: divides each pixel by the scalar\n"
608  "\toperations that require ONE IMAGE:\n"
609  "\t- log: computes the natural logarithm (base e) for each pixel\n"
610  "\t- log10: computes the common logarithm (base 10) for each pixel",
611  operations,
612  -1,
613  NULL,
614  'p',
615  1);
616 
617  param.SetGroupName(1, "parameters");
618 
619  param.ParseCommandLine(argc, argv);
620 
621  // print help?
622  if (*help) {
623  cout << endl
624  << "This tool performs pixelwise calculations on images."
625  << endl;
626  param.Usage();
627  cout << "Examples:" << endl
628  << "\tbiasimagecalc -i im1.jpg -j im2.jpg -p add -o sum.jpg" << endl
629  << "\tbiasimagecalc -i im.mip -s 2 -p multiply -o product.mip" << endl
630  << "\tbiasimagecalc -i im.mip -p log -o logarithm.mip" << endl
631  << endl;
632  return -1;
633  }
634 
635  // perform calculations
636  switch (*operation) {
637  case OP_ADD: // operations that need two input images
638  case OP_SUBTRACT:
639  case OP_MULTIPLY:
640  case OP_DIVIDE:
641  case OP_AND:
642  case OP_NAND:
643  case OP_OR:
644  case OP_NOR:
645  case OP_XOR:
646  CalculateOnTwoImages(imagesInPath, output, operation, floatOutput);
647  break;
648  case OP_ADD_SCALAR: // operations that need one input image and a scalar
649  case OP_SUBTRACT_SCALAR:
650  case OP_MULTIPLY_SCALAR:
651  case OP_DIVIDE_SCALAR:
652  CalculateOnOneImageAndScalar(imagesInPath[0], scalar,
653  output,
654  operation, floatOutput);
655  break;
656  case OP_LOG: // operations that need only one image
657  case OP_LOG10:
658  CalculateOnOneImage(imagesInPath[0], output, operation, floatOutput);
659  break;
660  default: // default case
661  cout << "ERROR: operation not specified or unknown. try '-h' for help" << endl;
662  return -1;
663  }
664 
665  return 0;
666 }
bool * AddParamBool(const std::string &name, const std::string &help, bool deflt=false, char cmdshort=0, int Group=GRP_NOSHOW)
Definition: Param.cpp:305
double * AddParamDouble(const std::string &name, const std::string &help, double deflt=0.0, double min=-DBL_MAX, double max=DBL_MAX, char cmdshort=0, int Group=GRP_NOSHOW)
Definition: Param.cpp:351
int * AddParamEnum(const std::string &name, const std::string &help, const std::vector< std::string > &enums, const int deflt=0, const std::vector< int > *IDs=NULL, const char cmdshort=0, const int Group=GRP_NOSHOW)
Definition: Param.cpp:468
unsigned int GetWidth() const
Definition: ImageBase.hh:312
int ParseCommandLine(int &argc, char *argv[])
scan command line arguments for valid parameters
Definition: Param.cpp:1028
void Usage(std::ostream &os=std::cout)
print Help-Information to stdout
Definition: Param.cpp:176
Performs pixelwise arithmetic and boolean operations on images.
Definition: ImageCalc.hh:52
unsigned int GetChannelCount() const
returns the number of Color channels, e.g.
Definition: ImageBase.hh:382
unsigned int GetHeight() const
Definition: ImageBase.hh:319
This class Param provides generic support for parameters.
Definition: Param.hh:231
int SetGroupName(const int group_id, const std::string &name)
sets the name for a group
Definition: Param.cpp:1448
void Init(unsigned int width, unsigned int height, unsigned int nChannels=1, enum EStorageType storageType=ST_unsignedchar, const bool interleaved=true)
Initialize image size and channels.
Definition: ImageBase.cpp:229
enum EStorageType GetStorageType() const
Definition: ImageBase.hh:414
This is the base class for images in BIAS.
Definition: ImageBase.hh:102
std::string * AddParamString(const std::string &name, const std::string &help, std::string deflt="", char cmdshort=0, int Group=GRP_NOSHOW)
Definition: Param.cpp:327