Basic Image AlgorithmS Library  2.8.0
 All Classes Namespaces Functions Variables Typedefs Enumerations Enumerator Friends Groups Pages
ImageAttributes.cpp
1 #include "ImageAttributes.hh"
2 #include <Base/Common/W32Compat.hh>
3 #include <math.h>
4 #include <Base/Debug/DebugSimple.hh>
5 #include <Base/Debug/Error.hh>
6 #include <Base/Common/FileHandling.hh>
7 
8 #include <string>
9 #include <exception>
10 #include <iostream>
11 #include <iterator>
12 #include <climits>
13 #include <typeinfo>
14 #ifdef WIN32
15 #undef max
16 #endif
17 
18 using namespace std;
19 using namespace BIAS;
20 
21 #define METER_PER_INCH 0.0254
22 
23 /** @class TagInfo
24  * @brief compatibility class for ImageMagick/magick/attribute.c:
25  @author Jan Woetzel
26  @date 10/2004 */
27 class TagInfo {
28 public:
29  unsigned short tag;
30  char *description;
31 };
32 
33 /** @brief compatibility class for ImageMagick/magick/attribute.c
34  contains all known EXIF tags
35  @author jan Woetzel */
36 static TagInfo tag_table[] = {
37  { 0x100, (char *) "ImageWidth"},
38  { 0x101, (char *) "ImageLength"},
39  { 0x102, (char *) "BitsPerSample"},
40  { 0x103, (char *) "Compression"},
41  { 0x106, (char *) "PhotometricInterpretation"},
42  { 0x10a, (char *) "FillOrder"},
43  { 0x10d, (char *) "DocumentName"},
44  { 0x10e, (char *) "ImageDescription"},
45  { 0x10f, (char *) "Make"},
46  { 0x110, (char *) "Model"},
47  { 0x111, (char *) "StripOffsets"},
48  { 0x112, (char *) "Orientation"},
49  { 0x115, (char *) "SamplesPerPixel"},
50  { 0x116, (char *) "RowsPerStrip"},
51  { 0x117, (char *) "StripByteCounts"},
52  { 0x11a, (char *) "XResolution"},
53  { 0x11b, (char *) "YResolution"},
54  { 0x11c, (char *) "PlanarConfiguration"},
55  { 0x128, (char *) "ResolutionUnit"},
56  { 0x12d, (char *) "TransferFunction"},
57  { 0x131, (char *) "Software"},
58  { 0x132, (char *) "DateTime"},
59  { 0x13b, (char *) "Artist"},
60  { 0x13e, (char *) "WhitePoint"},
61  { 0x13f, (char *) "PrimaryChromaticities"},
62  { 0x156, (char *) "TransferRange"},
63  { 0x200, (char *) "JPEGProc"},
64  { 0x201, (char *) "JPEGInterchangeFormat"},
65  { 0x202, (char *) "JPEGInterchangeFormatLength"},
66  { 0x211, (char *) "YCbCrCoefficients"},
67  { 0x212, (char *) "YCbCrSubSampling"},
68  { 0x213, (char *) "YCbCrPositioning"},
69  { 0x214, (char *) "ReferenceBlackWhite"},
70  { 0x1000, (char *) "RelatedImageFileFormat"},
71  { 0x1001, (char *) "RelatedImageLength"},
72  { 0x1002, (char *) "RelatedImageWidth"},
73  { 0x828d, (char *) "CFARepeatPatternDim"},
74  { 0x828e, (char *) "CFAPattern"},
75  { 0x828f, (char *) "BatteryLevel"},
76  { 0x8298, (char *) "Copyright"},
77  { 0x829a, (char *) "ExposureTime"},
78  { 0x829d, (char *) "FNumber"},
79  { 0x83Bb, (char *) "IPTC/NAA"},
80  { 0x8769, (char *) "ExifOffset"},
81  { 0x8773, (char *) "InterColorProfile"},
82  { 0x8822, (char *) "ExposureProgram"},
83  { 0x8824, (char *) "SpectralSensitivity"},
84  { 0x8825, (char *) "GPSInfo"},
85  { 0x8827, (char *) "ISOSpeedRatings"},
86  { 0x8828, (char *) "OECF"},
87  { 0x8829, (char *) "Interlace"},
88  { 0x882a, (char *) "TimeZoneOffset"},
89  { 0x882b, (char *) "SelfTimerMode"},
90  { 0x9000, (char *) "ExifVersion"},
91  { 0x9003, (char *) "DateTimeOriginal"},
92  { 0x9004, (char *) "DateTimeDigitized"},
93  { 0x9101, (char *) "ComponentsConfiguration"},
94  { 0x9102, (char *) "CompressedBitsPerPixel"},
95  { 0x9201, (char *) "ShutterSpeedValue"},
96  { 0x9202, (char *) "ApertureValue"},
97  { 0x9203, (char *) "BrightnessValue"},
98  { 0x9204, (char *) "ExposureBiasValue"},
99  { 0x9205, (char *) "MaxApertureValue"},
100  { 0x9206, (char *) "SubjectDistance"},
101  { 0x9207, (char *) "MeteringMode"},
102  { 0x9208, (char *) "LightSrc"},
103  { 0x9209, (char *) "Flash"},
104  { 0x920a, (char *) "FocalLength"},
105  { 0x920b, (char *) "FlashEnergy"},
106  { 0x920c, (char *) "SpatialFrequencyResponse"},
107  { 0x920d, (char *) "Noise"},
108  { 0x9211, (char *) "ImageNumber"},
109  { 0x9212, (char *) "SecurityClassification"},
110  { 0x9213, (char *) "ImageHistory"},
111  { 0x9214, (char *) "SubjectLocation"},
112  { 0x9215, (char *) "ExposureIndex"},
113  { 0x9216, (char *) "TIFF/EPStandardID"},
114  { 0x927c, (char *) "MakerNote"},
115  { 0x9286, (char *) "UserComment"},
116  { 0x9290, (char *) "SubSecTime"},
117  { 0x9291, (char *) "SubSecTimeOriginal"},
118  { 0x9292, (char *) "SubSecTimeDigitized"},
119  { 0xA000, (char *) "FlashPixVersion"},
120  { 0xA001, (char *) "ColorSpace"},
121  { 0xA002, (char *) "ExifImageWidth"},
122  { 0xA003, (char *) "ExifImageLength"},
123  { 0xA005, (char *) "InteroperabilityOffset"},
124  { 0xA20b, (char *) "FlashEnergy"},
125  { 0xA20c, (char *) "SpatialFrequencyResponse"},
126  { 0xA20e, (char *) "FocalPlaneXResolution"},
127  { 0xA20f, (char *) "FocalPlaneYResolution"},
128  { 0xA210, (char *) "FocalPlaneResolutionUnit"},
129  { 0xA214, (char *) "SubjectLocation"},
130  { 0xA215, (char *) "ExposureIndex"},
131  { 0xA217, (char *) "SensingMethod"},
132  { 0xA300, (char *) "FileSource"},
133  { 0xA301, (char *) "SceneType"},
134  { 0xA302, (char *) "CFAPattern"},
135  { 0x0000, (char *) NULL}
136 };
137 
138 /** weblinks:
139 http://www.awaresystems.be/imaging/tiff/tifftags/privateifd/exif/focalplaneresolutionunit.html
140 
141 http://www.stefanheymann.de/homegallery/exif-felder.htm
142 
143 http://www.exif.org/specifications.html
144 
145 */
146 
147 // JW
148 void ImageAttributes::InitExifTags(){
149  // get the number of tags from variable size array:
150 
151 #ifndef WIN32
152  const unsigned int nTags=sizeof(tag_table) / sizeof( __typeof__( *tag_table ));
153 #else
154  /// (JW) no typeof in MS Visual Studio C++ 7.1 compiler
155  const unsigned int nTags = 99; /// \todo loop until 0x0 end symbol
156 #endif
157 
158  //COUT("tag_table contains "<<nTags<<" tags.");
159  for (unsigned int i=0; i<nTags; i++){
160  if ((tag_table[i].tag!=0x0) && (tag_table[i].description!=NULL)){
161  // valid tag
162  this->push_back(ExifTag(tag_table[i].tag,
163  tag_table[i].description) );
164  };
165  };
166 }
167 
168 // JW
169 int ImageAttributes::Read(const std::string & filename){
170  return ReadMagickPP(filename);
171 }
172 
173 
174 // JW
175 int ImageAttributes::ReadMagickPP(const std::string & filename){
176  if(BIAS::FileHandling::Extension(filename) == "mip")
177  return -3;
178 
179 #ifndef BIAS_HAVE_IMAGEMAGICKLIB
180  BIASERR("BIAS_HAVE_IMAGEMAGICKLIB not defined. Please recompile BIAS with USE_IMAGEMAGICK enabled to load "<<filename);
181  return -2;
182 #else
183  try {
184 # ifdef WIN32
185  // initialize DLL loaded library (not required on Linux but once on Windows)
186  Magick::InitializeMagick(NULL);
187 # endif
188  Magick::Image img;
189  // get image header data without reading the raw image data:
190  img.ping(filename);
191  return ReadMagickPP(img); // OK so far
192  } catch ( Magick::Exception &error_ ) {
193  BIASERR("Getting Image attributes from "<<filename<<" with Magick++ failed."<<endl
194  <<" Caught exception: "<<endl
195  <<" "<<error_.what()<<endl );
196  return -1; // error
197  } catch (...) {
198  BIASERR("Getting Image attributes from "<<filename<<" with Magick++ failed."<<endl
199  <<" Caught unspecied (...) exception."<<endl);
200  return -2; // error
201  };
202 #endif
203 }
204 
205 // JW
206 #ifdef BIAS_HAVE_IMAGEMAGICKLIB
207 int ImageAttributes::ReadMagickPP(Magick::Image & img){
208  try {
209  ImageAttributes::iterator it;
210  string name;
211  string val;
212  unsigned int index = 0;
213  for (it=this->begin(); it!=this->end(); it++, index++){
214  name = "EXIF:";
215  name += it->name;
216  val=img.attribute(name);
217  if (it->GoodValue( val )){
218  it->value = val;
219  mapValidTags_[it->name]=index;
220  //cout<<"Found tag "<<it->name<<" with value "<<it->value<<endl;
221  //} else {
222  //COUT("skipped EXIF tag "<<it->name<<". invalid value= "<<it->value<<endl);
223  };
224  };
225 
226  } catch ( Magick::Exception &error_ ) {
227  BIASERR("Getting Image attributes from Magick::Image with Magick++ failed."<<endl
228  <<" Caught exception: "<<endl
229  <<" "<<error_.what()<<endl );
230  return -1; // error
231  } catch (...) {
232  BIASERR("Getting Image attributes from Magick::Image with Magick++ failed."<<endl
233  <<" Caught unspecified (...) exception."<<endl );
234  return -2; // error
235  };
236  return BIAS_IMAGEATTRIBUTES_SUCCESS; // OK
237 }
238 #endif
239 
240 
241 std::ostream& ImageAttributes::Print(std::ostream& os,
242  const bool printAll) const
243 {
244  os<<"ImageAttributes: size="<<this->size()<<endl;
245  ImageAttributes::const_iterator it=this->begin();
246  for (it=this->begin(); it!=(this->end()); it++){
247  if (printAll || it->GoodValue(it->value) ) {
248  it->Print(os);
249  os<<endl;
250  //} else {os<<"skipped "<<it->name<<endl;
251  };
252  };
253  return os;
254 }
255 
256 
257 std::ostream& operator<<(std::ostream& os,
258  const BIAS::ImageAttributes &attr)
259 {
260  return attr.Print(os);
261 }
262 
263 
264 bool ImageAttributes::GetString_(const string& key, string& value) {
265  map<string, unsigned int>::iterator it;
266  if ((it = mapValidTags_.find(key))==mapValidTags_.end()) {
267  BIASDOUT(D_EXIF,"failed to find "<<key);
268  return false;
269  }
270  value = (*this)[it->second].value;
271  BIASDOUT(D_EXIF,"Found "<<key<<"="<<value);
272  return true;
273 }
274 
275 bool ImageAttributes::GetRational_(const string& key, double& value) {
276  string thevalue;
277  if (!GetString_(key, thevalue)) return false;
278  string::size_type slashpos = thevalue.find('/');
279  string second, first = thevalue.substr(0, slashpos);
280  if (slashpos>=0 && slashpos<(string::size_type)thevalue.size()-1)
281  second = thevalue.substr(slashpos+1,thevalue.size()-1);
282  double dfirst = atof(first.c_str());
283  double dsecond = atof(second.c_str());
284  value = dfirst/dsecond;
285  return true;
286 }
287 
288 bool ImageAttributes::GetShort_(const string& key, int& value){
289  string thevalue;
290 #ifdef WIN32
291  # ifdef max
292  # undef max
293  # endif // max
294 #endif //WIN32
295 
296  if (!GetString_(key,thevalue)) return false;
297  value = numeric_limits<int>::max();
298  value = atoi(thevalue.c_str());
299  if (value==numeric_limits<int>::max()) return false;
300  return true;
301 }
302 
303 
304 int ImageAttributes::GetFocalLengthMeter(double &fm) {
305  if (!GetRational_("FocalLength",fm)) return -1;
306  // milli meter to meter
307  fm *= 0.001;
308  BIASDOUT(D_EXIF, "focal length in meter is "<<fm);
309  return 0;
310 }
311 
312 
313 int ImageAttributes::GetFocalLengthXPixel(double &fp) {
314  int res = GetFocalLengthMeter(fp);
315  if (res<0) return res;
316  double pixelsize;
317  res = GetPixelSizeXMeter(pixelsize);
318  if (res<0) return res;
319  fp /= pixelsize;
320  BIASDOUT(D_EXIF, "FocalLengthXPixel is "<<fp);
321  return res;
322 }
323 
324 int ImageAttributes::GetFocalLengthYPixel(double &fp) {
325  int res = GetFocalLengthMeter(fp);
326  if (res<0) return res;
327  double pixelsize;
328  res = GetPixelSizeYMeter(pixelsize);
329  if (res<0) return res;
330  fp /= pixelsize;
331  BIASDOUT(D_EXIF, "FocalLengthYPixel is "<<fp);
332  return res;
333 }
334 
335 int ImageAttributes::GetPixelSizeXMeter(double &p) {
336  if (!GetRational_("FocalPlaneXResolution", p)) return -1;
337  BIASDOUT(D_EXIF, "FocalPlaneXResolution is "<<p);
338  int unit = 0;
339  if (!GetShort_("FocalPlaneResolutionUnit", unit)) return -1;
340  switch (unit) {
341  case 2: // Inch.
342  p = METER_PER_INCH / p;
343  break;
344  case 3: // Centimeter.
345  p = 0.01 / p;
346  break;
347  case 1: // No absolute unit of measurement.
348  default:// unknown unit
349  return 1;
350  break;
351  }
352 
353  return 0;
354 }
355 int ImageAttributes::GetPixelSizeYMeter(double &p) {
356  if (!GetRational_("FocalPlaneYResolution", p)) return -1;
357  BIASDOUT(D_EXIF, "FocalPlaneYResolution is "<<p);
358  int unit = 0;
359  if (!GetShort_("FocalPlaneResolutionUnit", unit)) return -1;
360  switch (unit) {
361  case 1: // No absolute unit of measurement.
362  return 1;
363  break;
364  case 2: // Inch.
365  p = METER_PER_INCH / p;
366  break;
367  case 3: // Centimeter.
368  p = 0.01 / p;
369  break;
370  default: // unknown unit
371  return -1;
372  }
373 
374  return 0;
375 }
376 
377 
378 int ImageAttributes::GetFieldOfViewDegree(double &x, double& y) {
379  int width, height;
380  double fp;
381  if (GetImageDimensions(width, height)!=0) return -1;
382  if (GetFocalLengthXPixel(fp)<0) return -2;
383  x = 180.0/M_PI *2.0*atan(double(width)/(2.0*fp));
384  if (GetFocalLengthYPixel(fp)<0) return -3;
385  y = 180.0/M_PI *2.0*atan(double(height)/(2.0*fp));
386 
387  return 0;
388 }
389 
390 
391 int ImageAttributes::GetImageDimensions(int& width, int& height) {
392  if (!GetShort_("ImageWidth", width)) {
393  if (!GetShort_("ExifImageWidth", width)) {
394  return -1;
395  }
396  if (!GetShort_("ExifImageLength", height)) {
397  return -1;
398  }
399  return 0;
400  }
401  if (!GetShort_("ImageLength", height)) return -1;
402  return 0;
403 }
404 
405 
406 int ImageAttributes::GetPrincipalPoint(double& x, double& y) {
407  int width, height;
408  if (GetImageDimensions(width, height)!=0) return -1;
409  x = double(width-1)/2.0;
410  y = double(height-1)/2.0;
411  return 1;
412 }
413 
414 int ImageAttributes::GetHardwareName(string& Make, string& Model){
415  Make = "";
416  Model = "";
417  int res = 0;
418  if (!GetString_("Make",Make)) res -= 1;
419  if (!GetString_("Model",Model)) res -= 2;
420  return res;
421 }
422 
423 
424 std::string ImageAttributes::GetIdentifier()
425 {
426  string id,tmp;
427  if (GetString_("Make",tmp) ) id += tmp;
428  else id += "Unknown";
429  id +=" ";
430  if (GetString_("Model",tmp) ) id += tmp;
431  else id += "Unknown";
432  double focalmeter;
433  GetFocalLengthMeter(focalmeter);
434  ostringstream oss;
435  oss<<focalmeter*1000;
436  id += " "+oss.str()+"mm";
437  return id;
438 
439 
440 }
helper class containing EXIF Tag info and its&#39;s value.
Definition: ExifTag.hh:19
std::ostream & operator<<(std::ostream &os, const Array2D< T > &arg)
Definition: Array2D.hh:260
static std::string Extension(const std::string &fullname)
Get file extension (without dot!) from given path and filename.
contains all atribute info and values of e.g. a file.
std::ostream & Print(std::ostream &os=std::cout, const bool printAll=false) const
print the content of this to os