SrcPanoImage.cpp

Go to the documentation of this file.
00001 // -*- c-basic-offset: 4 -*-
00002 
00013 /*
00014  *  This program is free software; you can redistribute it and/or
00015  *  modify it under the terms of the GNU General Public
00016  *  License as published by the Free Software Foundation; either
00017  *  version 2 of the License, or (at your option) any later version.
00018  *
00019  *  This software is distributed in the hope that it will be useful,
00020  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
00021  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00022  *  General Public License for more details.
00023  *
00024  *  You should have received a copy of the GNU General Public
00025  *  License along with this software; if not, write to the Free Software
00026  *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
00027  *
00028  */
00029 
00030 // for debugging
00031 #include <iostream>
00032 #include <stdio.h>
00033 //#include <wx/wxprec.h>
00034 
00035 #include "SrcPanoImage.h"
00036 
00037 #include <iostream>
00038 #include <vector>
00039 #include <vigra/diff2d.hxx>
00040 #include <vigra/imageinfo.hxx>
00041 #include <hugin_utils/utils.h>
00042 #include <exiv2/exif.hpp>
00043 #include <exiv2/image.hpp>
00044 #include <exiv2/easyaccess.hpp>
00045 #include <lensdb/LensDB.h>
00046 
00047 #ifdef __FreeBSD__
00048 #define log2(x)        (log(x) / M_LN2)
00049 #endif /* __FreeBSD__ */
00050 
00051 #include "ImageVariableTranslate.h"
00052 
00053 namespace HuginBase {
00054 
00055 using namespace hugin_utils;
00056     
00057 void SrcPanoImage::resize(const vigra::Size2D & sz)
00058 {
00059         // TODO: check if images have the same orientation.
00060         // calculate scaling ratio
00061         double scale = (double) sz.x / m_Size.getData().x;
00062         
00063         // center shift
00064         m_RadialDistortionCenterShift.setData(m_RadialDistortionCenterShift.getData() * scale);
00065         m_Shear.setData(m_Shear.getData() * scale);
00066         
00067         // crop
00068         // ensure the scaled rectangle is inside the new image size
00069         switch (m_CropMode.getData())
00070         {
00071             case NO_CROP:
00072                 m_CropRect.setData(vigra::Rect2D(sz));
00073                 break;
00074             case CROP_RECTANGLE:
00075                 m_CropRect.setData(m_CropRect.getData() * scale);
00076                 m_CropRect.setData(m_CropRect.getData() & vigra::Rect2D(sz));
00077                 break;
00078             case CROP_CIRCLE:
00079                 m_CropRect.setData(m_CropRect.getData() * scale);
00080                 break;
00081         }
00082         
00083         m_Size = sz;
00084         // vignetting correction
00085         m_RadialVigCorrCenterShift.setData(m_RadialVigCorrCenterShift.getData() *scale);
00086         // resize masks
00087         MaskPolygonVector scaledMasks=m_Masks.getData();
00088         for(unsigned int i=0;i<scaledMasks.size();i++)
00089             scaledMasks[i].scale(scale);
00090         m_Masks.setData(scaledMasks);
00091         scaledMasks.clear();
00092         scaledMasks=m_ActiveMasks.getData();
00093         for(unsigned int i=0;i<scaledMasks.size();i++)
00094             scaledMasks[i].scale(scale);
00095         m_ActiveMasks.setData(scaledMasks);
00096 }
00097 
00098 bool SrcPanoImage::horizontalWarpNeeded()
00099 {
00100     switch (m_Projection.getData())
00101     {
00102         case PANORAMIC:
00103         case EQUIRECTANGULAR:
00104             if (m_HFOV.getData() == 360) return true;
00105         case FULL_FRAME_FISHEYE:
00106         case CIRCULAR_FISHEYE:
00107         case RECTILINEAR:
00108         case FISHEYE_ORTHOGRAPHIC:
00109         case FISHEYE_STEREOGRAPHIC:
00110         case FISHEYE_EQUISOLID:
00111         case FISHEYE_THOBY:
00112         default:
00113             break;
00114     }
00115     return false;
00116 }
00117 
00118 void BaseSrcPanoImage::setDefaults()
00119 {
00120     /* Some of the vectors are difficult to initalise with the variables list
00121      * header, so we make some local variables which are used in it.
00122      */
00123     // Radial Distortion defaults
00124     std::vector<double> distortion_default(4, 0.0);
00125     distortion_default[3] = 1;
00126     
00127     std::vector<double> RadialVigCorrCoeff_default(4, 0.0);
00128     RadialVigCorrCoeff_default[0] = 1;
00129     HuginBase::MaskPolygonVector defaultMaskVector;
00130 #define image_variable( name, type, default_value ) m_##name.setData(default_value);
00131 #include "image_variables.h"
00132 #undef image_variable
00133 }
00134 
00135 bool SrcPanoImage::isInside(vigra::Point2D p, bool ignoreMasks) const
00136 {
00137     bool insideCrop=false;
00138     switch(m_CropMode.getData()) {
00139         case NO_CROP:
00140         case CROP_RECTANGLE:
00141             insideCrop = m_CropRect.getData().contains(p);
00142             break;
00143         case CROP_CIRCLE:
00144         {
00145             if (0 > p.x || 0 > p.y || p.x >= m_Size.getData().x || p.y >= m_Size.getData().y) {
00146                 // outside image
00147                 return false;
00148             }
00149             FDiff2D cropCenter;
00150             cropCenter.x = m_CropRect.getData().left() + m_CropRect.getData().width()/2.0;
00151             cropCenter.y = m_CropRect.getData().top() + m_CropRect.getData().height()/2.0;
00152             double radius2 = std::min(m_CropRect.getData().width()/2.0, m_CropRect.getData().height()/2.0);
00153             radius2 = radius2 * radius2;
00154             FDiff2D pf = FDiff2D(p) - cropCenter;
00155             insideCrop = (radius2 > pf.x*pf.x+pf.y*pf.y );
00156         }
00157     }
00158     if(insideCrop && !ignoreMasks)
00159         return !(isInsideMasks(p));
00160     else
00161         return insideCrop;
00162 }
00163 
00164 bool SrcPanoImage::isCircularCrop() const
00165 {
00166     HuginBase::BaseSrcPanoImage::Projection projection=m_Projection.getData();
00167     return (projection==CIRCULAR_FISHEYE || projection==FISHEYE_THOBY || projection==FISHEYE_ORTHOGRAPHIC);
00168 };
00169 
00170 bool SrcPanoImage::getCorrectTCA() const
00171 { 
00172     bool nr = (m_RadialDistortionRed.getData()[0] == 0.0 && m_RadialDistortionRed.getData()[1] == 0.0 &&
00173                m_RadialDistortionRed.getData()[2] == 0.0 && m_RadialDistortionRed.getData()[3] == 1);
00174     bool nb = (m_RadialDistortionBlue.getData()[0] == 0.0 && m_RadialDistortionBlue.getData()[1] == 0.0 &&
00175                m_RadialDistortionBlue.getData()[2] == 0.0 && m_RadialDistortionBlue.getData()[3] == 1);
00176     return !(nr && nb);
00177 }
00178 
00179 
00180 FDiff2D SrcPanoImage::getRadialDistortionCenter() const
00181 { return FDiff2D(m_Size.getData())/2.0 + m_RadialDistortionCenterShift.getData(); }
00182 
00183 
00184 FDiff2D SrcPanoImage::getRadialVigCorrCenter() const
00185 { return (FDiff2D(m_Size.getData())-FDiff2D(1,1))/2.0 + m_RadialVigCorrCenterShift.getData(); }
00186 
00187 void SrcPanoImage::setCropMode(CropMode val)
00188 {
00189     m_CropMode.setData(val);
00190     if (val == NO_CROP) {
00191         m_CropRect.setData(vigra::Rect2D(m_Size.getData()));
00192     }
00193 }
00194 
00195 void SrcPanoImage::setSize(vigra::Size2D val)
00196 {
00197     m_Size.setData(val);
00198     if (m_CropMode.getData() == NO_CROP) {
00199         m_CropRect.setData(vigra::Rect2D(val));
00200     }
00201 }
00202 
00203 double SrcPanoImage::getExposure() const
00204 { return 1.0/pow(2.0, m_ExposureValue.getData()); }
00205 
00206 void SrcPanoImage::setExposure(const double & val)
00207 { m_ExposureValue = log2(1/val); }
00208 
00209 
00210 bool BaseSrcPanoImage::operator==(const BaseSrcPanoImage & other) const
00211 {
00212     DEBUG_TRACE("");
00213     return (
00214 #define image_variable( name, type, default_value ) \
00215     m_##name.getData() == other.m_##name.getData() &&
00216 #include "image_variables.h"
00217 #undef image_variable
00218     true // All the variable checks above end with && so we need this.
00219     );
00220 }
00221 
00222 // convinience functions to extract a set of variables
00223 double SrcPanoImage::getVar(const std::string & code) const
00224 {
00225     DEBUG_TRACE("");
00226     assert(code.size() > 0);
00227 #define image_variable( name, type, default_value ) \
00228     if (PTOVariableConverterFor##name::checkApplicability(code)) \
00229         return PTOVariableConverterFor##name::getValueFromVariable(code, m_##name );\
00230     else 
00231 #include "image_variables.h"
00232 #undef image_variable
00233     {// this is for the final else.
00234         DEBUG_ERROR("Unknown variable " << code);
00235     }
00236     return 0;
00237 }
00238 
00239 void SrcPanoImage::setVar(const std::string & code, double val)
00240 {
00241     DEBUG_TRACE("Var:" << code << " value: " << val);
00242     assert(code.size() > 0);
00243 #define image_variable( name, type, default_value ) \
00244     if (PTOVariableConverterFor##name::checkApplicability(code)) \
00245         {PTOVariableConverterFor##name::setValueFromVariable(code, m_##name, val);}\
00246     else 
00247 #include "image_variables.h"
00248 #undef image_variable
00249     {// this is for the final else.
00250         DEBUG_ERROR("Unknown variable " << code);
00251     }
00252 }
00253 
00254 VariableMap SrcPanoImage::getVariableMap() const
00255 {
00256     // make a variable map vector
00257     
00258     // fill variable map with details about this image.
00259     // position
00260     DEBUG_TRACE("");
00261 
00262     VariableMap vars;
00263 #define image_variable( name, type, default_value ) \
00264     PTOVariableConverterFor##name::addToVariableMap(m_##name, vars);
00265 #include "image_variables.h"
00266 #undef image_variable
00267 
00268     return vars;
00269 }
00270 
00271 bool SrcPanoImage::readEXIF(double & focalLength, double & cropFactor, bool applyEXIFValues, bool applyExposureValue)
00272 {
00273     double eV=0;
00274     return readEXIF(focalLength,cropFactor,eV,applyEXIFValues, applyExposureValue);
00275 };
00276 
00277 bool SrcPanoImage::readEXIF(double & focalLength, double & cropFactor, double & eV, bool applyEXIFValues, bool applyExposureValue)
00278 {
00279     std::string filename = getFilename();
00280     std::string ext = hugin_utils::getExtension(filename);
00281     std::transform(ext.begin(), ext.end(), ext.begin(), (int(*)(int)) toupper);
00282 
00283     double roll = 0;
00284     //double eV = 0;
00285     float isoSpeed = 0;
00286     float photoFNumber = 0;
00287     float exposureTime = 0;
00288     float subjectDistance = 0;
00289 
00290     int width;
00291     int height;
00292     try {
00293         vigra::ImageImportInfo info(filename.c_str());
00294         width = info.width();
00295         height = info.height();
00296     } catch(std::exception & ) {
00297         return false;
00298     }
00299 
00300     // Setup image with default values
00301     setSize(vigra::Size2D(width, height));
00302     if (applyEXIFValues && focalLength > 0 && cropFactor > 0) {
00303         setHFOV(calcHFOV(getProjection(),
00304         focalLength, cropFactor, getSize()));
00305     }
00306 
00307     Exiv2::Image::AutoPtr image;
00308     try {
00309         image = Exiv2::ImageFactory::open(filename.c_str());
00310     }catch(...) {
00311         std::cerr << __FILE__ << " " << __LINE__ << " Error opening file" << std::endl;
00312         return false;
00313     }
00314     if (image.get() == 0) {
00315         std::cerr << "Unable to open file to read EXIF data: " << filename << std::endl;
00316         return false;
00317     }
00318 
00319     image->readMetadata();
00320     Exiv2::ExifData &exifData = image->exifData();
00321     if (exifData.empty()) {
00322         std::cerr << "Unable to read EXIF data from opened file:" << filename << std::endl;
00323         return false;
00324     }
00325 
00326     getExiv2Value(exifData,"Exif.Photo.ExposureTime",exposureTime);
00327     // TODO: reconstruct real exposure value from "rounded" ones saved by the cameras?
00328 
00329     getExiv2Value(exifData,"Exif.Photo.FNumber",photoFNumber);
00330     
00331     //remember aperture for later
00332     setExifAperture(photoFNumber);
00333     
00334     //read exposure mode
00335     long exposureMode=0;
00336     getExiv2Value(exifData,"Exif.Photo.ExposureMode",exposureMode);
00337     setExifExposureMode((int)exposureMode);
00338 
00339     //if no F-number was found in EXIF data assume a f stop of 3.5 to get
00340     //a reasonable ev value if shutter time, e. g. for manual lenses is found
00341     if(photoFNumber==0)
00342     {
00343         photoFNumber=3.5;
00344     };
00345     if (exposureTime > 0 && photoFNumber > 0) {
00346         double gain = 1;
00347         if (getExiv2Value(exifData,"Exif.Photo.ISOSpeedRatings",isoSpeed)) {
00348             if (isoSpeed > 0) {
00349                 gain = isoSpeed / 100.0;
00350             }
00351         }
00352         eV = log2(photoFNumber * photoFNumber / (gain * exposureTime));
00353         DEBUG_DEBUG ("Ev: " << eV);
00354     }
00355 
00356     Exiv2::ExifKey key("Exif.Image.Make");
00357     Exiv2::ExifData::iterator itr = exifData.findKey(key);
00358     if (itr != exifData.end()) {
00359         setExifMake(itr->toString());
00360     } else {
00361         setExifMake("");
00362     }
00363 
00364     Exiv2::ExifKey key2("Exif.Image.Model");
00365     itr = exifData.findKey(key2);
00366     if (itr != exifData.end()) {
00367         setExifModel(itr->toString());
00368     } else {
00369         setExifModel("");
00370     }
00371 
00372     //reading lens
00373     // first we are reading LensModel in Exif section, this is only available
00374     // with EXIF >= 2.3
00375     std::string lensName;
00376 #if EXIV2_TEST_VERSION(0,22,0)
00377     //the string "Exif.Photo.LensModel" is only defined in exiv2 0.22.0 and above
00378     if(getExiv2Value(exifData,"Exif.Photo.LensModel",lensName))
00379 #else
00380     if(getExiv2Value(exifData,0xa434,"Photo",lensName))
00381 #endif
00382     {
00383         if(lensName.length()>0)
00384         {
00385             setExifLens(lensName);
00386         }
00387         else
00388         {
00389             setExifLens("");
00390         }
00391     }
00392     else
00393     {
00394         //no lens in Exif found, now look in makernotes
00395         Exiv2::ExifData::const_iterator itr2 = Exiv2::lensName(exifData);
00396         if (itr2!=exifData.end() && itr2->count())
00397         {
00398             //we are using prettyPrint function to get string of lens name
00399             //it2->toString returns for many cameras only an ID number
00400             setExifLens(itr2->print(&exifData));
00401         }
00402         else
00403         {
00404             setExifLens("");
00405         };
00406     };
00407 
00408     long orientation = 0;
00409     if (getExiv2Value(exifData,"Exif.Image.Orientation",orientation) && trustExivOrientation()) {
00410         switch (orientation) {
00411             case 3:  // rotate 180
00412                 roll = 180;
00413                 break;
00414             case 6: // rotate 90
00415                 roll = 90;
00416                 break;
00417             case 8: // rotate 270
00418                 roll = 270;
00419                 break;
00420             default:
00421                 break;
00422         }
00423     }
00424 
00425     long pixXdim = 0;
00426     getExiv2Value(exifData,"Exif.Photo.PixelXDimension",pixXdim);
00427 
00428     long pixYdim = 0;
00429     getExiv2Value(exifData,"Exif.Photo.PixelYDimension",pixYdim);
00430 
00431     if (pixXdim !=0 && pixYdim !=0 ) {
00432         double ratioExif = pixXdim/(double)pixYdim;
00433         double ratioImage = width/(double)height;
00434         if (fabs( ratioExif - ratioImage) > 0.1) {
00435             // Image has been modified without adjusting exif tags.
00436             // Assume user has rotated to upright pose
00437             roll = 0;
00438         }
00439     }
00440     
00441     //GWP - CCD info was previously computed by the jhead library.  Migration
00442     //      to exiv2 means we do it here
00443     
00444     // some cameras do not provide Exif.Image.ImageWidth / Length
00445     // notably some Olympus
00446     
00447     long eWidth = 0;
00448     getExiv2Value(exifData,"Exif.Image.ImageWidth",eWidth);
00449 
00450     long eLength = 0;
00451     getExiv2Value(exifData,"Exif.Image.ImageLength",eLength);
00452 
00453     double sensorPixelWidth = 0;
00454     double sensorPixelHeight = 0;
00455     if (eWidth > 0 && eLength > 0) {
00456         sensorPixelHeight = (double)eLength;
00457         sensorPixelWidth = (double)eWidth;
00458     } else {
00459         // No EXIF information, use number of pixels in image
00460         sensorPixelWidth = width;
00461         sensorPixelHeight = height;
00462     }
00463 
00464     // force landscape sensor orientation
00465     if (sensorPixelWidth < sensorPixelHeight ) {
00466         double t = sensorPixelWidth;
00467         sensorPixelWidth = sensorPixelHeight;
00468         sensorPixelHeight = t;
00469     }
00470 
00471     DEBUG_DEBUG("sensorPixelWidth: " << sensorPixelWidth);
00472     DEBUG_DEBUG("sensorPixelHeight: " << sensorPixelHeight);
00473 
00474     // some cameras do not provide Exif.Photo.FocalPlaneResolutionUnit
00475     // notably some Olympus
00476 
00477     long exifResolutionUnits = 0;
00478     getExiv2Value(exifData,"Exif.Photo.FocalPlaneResolutionUnit",exifResolutionUnits);
00479 
00480     float resolutionUnits= 0;
00481     switch (exifResolutionUnits) {
00482         case 3: resolutionUnits = 10.0; break;  //centimeter
00483         case 4: resolutionUnits = 1.0; break;   //millimeter
00484         case 5: resolutionUnits = .001; break;  //micrometer
00485         default: resolutionUnits = 25.4; break; //inches
00486     }
00487 
00488     DEBUG_DEBUG("Resolution Units: " << resolutionUnits);
00489 
00490     // some cameras do not provide Exif.Photo.FocalPlaneXResolution and
00491     // Exif.Photo.FocalPlaneYResolution, notably some Olympus
00492 
00493     float fplaneXresolution = 0;
00494     getExiv2Value(exifData,"Exif.Photo.FocalPlaneXResolution",fplaneXresolution);
00495 
00496     float fplaneYresolution = 0;
00497     getExiv2Value(exifData,"Exif.Photo.FocalPlaneYResolution",fplaneYresolution);
00498 
00499     float CCDWidth = 0;
00500     if (fplaneXresolution != 0) { 
00501 //        CCDWidth = (float)(sensorPixelWidth * resolutionUnits / 
00502 //                fplaneXresolution);
00503         CCDWidth = (float)(sensorPixelWidth / ( fplaneXresolution / resolutionUnits));
00504     }
00505 
00506     float CCDHeight = 0;
00507     if (fplaneYresolution != 0) {
00508         CCDHeight = (float)(sensorPixelHeight / ( fplaneYresolution / resolutionUnits));
00509     }
00510 
00511     DEBUG_DEBUG("CCDHeight:" << CCDHeight);
00512     DEBUG_DEBUG("CCDWidth: " << CCDWidth);
00513 
00514     // calc sensor dimensions if not set and 35mm focal length is available
00515     FDiff2D sensorSize;
00516 
00517     if (CCDHeight > 0 && CCDWidth > 0) {
00518         // read sensor size directly.
00519         sensorSize.x = CCDWidth;
00520         sensorSize.y = CCDHeight;
00521         if (getExifModel() == "Canon EOS 20D") {
00522             // special case for buggy 20D camera
00523             sensorSize.x = 22.5;
00524             sensorSize.y = 15;
00525         }
00526         //
00527         // check if sensor size ratio and image size fit together
00528         double rsensor = (double)sensorSize.x / sensorSize.y;
00529         double rimg = (double) width / height;
00530         if ( (rsensor > 1 && rimg < 1) || (rsensor < 1 && rimg > 1) ) {
00531             // image and sensor ratio do not match
00532             // swap sensor sizes
00533             float t;
00534             t = sensorSize.y;
00535             sensorSize.y = sensorSize.x;
00536             sensorSize.x = t;
00537         }
00538 
00539         DEBUG_DEBUG("sensorSize.y: " << sensorSize.y);
00540         DEBUG_DEBUG("sensorSize.x: " << sensorSize.x);
00541 
00542         cropFactor = sqrt(36.0*36.0+24.0*24.0) /
00543             sqrt(sensorSize.x*sensorSize.x + sensorSize.y*sensorSize.y);
00544         // FIXME: HACK guard against invalid image focal plane definition in EXIF metadata with arbitrarly chosen limits for the crop factor ( 1/100 < crop < 100)
00545         if (cropFactor < 0.01 || cropFactor > 100) {
00546             cropFactor = 0;
00547         }
00548     } else {
00549         // alternative way to calculate the crop factor for Olympus cameras
00550 
00551         // Windows debug stuff
00552         // left in as example on how to get "console output"
00553         // written to a log file    
00554         // freopen ("oly.log","a",stdout);
00555         // fprintf (stdout,"Starting Alternative crop determination\n");
00556         
00557         float olyFPD = 0;
00558         getExiv2Value(exifData,"Exif.Olympus.FocalPlaneDiagonal",olyFPD);
00559 
00560         if (olyFPD > 0.0) {        
00561             // Windows debug stuff
00562             // fprintf(stdout,"Oly_FPD:");
00563             // fprintf(stdout,"%f",olyFPD);
00564             cropFactor = sqrt(36.0*36.0+24.0*24.0) / olyFPD;
00565         }
00566         else {
00567             // for newer Olympus cameras the FocalPlaneDiagonal tag was moved into
00568             // equipment (sub?)-directory, so check also there
00569             getExiv2Value(exifData,"Exif.OlympusEq.FocalPlaneDiagonal",olyFPD);
00570             if (olyFPD > 0.0) {
00571                 cropFactor = sqrt(36.0*36.0+24.0*24.0) / olyFPD;
00572             };
00573         };
00574    
00575     }
00576     DEBUG_DEBUG("cropFactor: " << cropFactor);
00577 
00578     float eFocalLength = 0;
00579     getExiv2Value(exifData,"Exif.Photo.FocalLength",eFocalLength);
00580 
00581     float eFocalLength35 = 0;
00582     getExiv2Value(exifData,"Exif.Photo.FocalLengthIn35mmFilm",eFocalLength35);
00583 
00584     //The various methods to detmine crop factor
00585     if (eFocalLength > 0 && cropFactor > 0) {
00586         // user provided crop factor
00587         focalLength = eFocalLength;
00588     } else if (eFocalLength35 > 0 && eFocalLength > 0) {
00589         cropFactor = eFocalLength35 / eFocalLength;
00590         focalLength = eFocalLength;
00591     } else if (eFocalLength35 > 0) {
00592         // 35 mm equiv focal length available, crop factor unknown.
00593         // do not ask for crop factor, assume 1.  Probably a full frame sensor
00594         cropFactor = 1;
00595         focalLength = eFocalLength35;
00596     } else if (eFocalLength > 0 && cropFactor <= 0) {
00597         // need to redo, this time with crop
00598         focalLength = eFocalLength;
00599         cropFactor = 0;
00600     }
00601     getExiv2Value(exifData,"Exif.Photo.SubjectDistance", subjectDistance);
00602 
00603     std::string captureDate;
00604     getExiv2Value(exifData,"Exif.Photo.DateTimeOriginal",captureDate);
00605 
00606 
00607     // store some important EXIF tags for later usage.
00608     setExifFocalLength(focalLength);
00609     setExifFocalLength35(eFocalLength35);
00610     setExifOrientation(roll);
00611     setExifISO(isoSpeed);
00612     setExifDistance(subjectDistance);
00613     setExifDate(captureDate);
00614     setExifExposureTime(exposureTime);
00615 
00616     DEBUG_DEBUG("Results for:" << filename);
00617     DEBUG_DEBUG("Focal Length: " << getExifFocalLength());
00618     DEBUG_DEBUG("Crop Factor:  " << getExifCropFactor());
00619     DEBUG_DEBUG("Roll:         " << getExifOrientation());
00620 
00621     // Update image with computed values from EXIF
00622     if (applyEXIFValues) {
00623         setRoll(roll);
00624         if (applyExposureValue)
00625             setExposureValue(eV);
00626         if(cropFactor>0)
00627         {
00628             setExifCropFactor(cropFactor);
00629         };
00630         if (focalLength > 0 && cropFactor > 0) {
00631             setHFOV(calcHFOV(getProjection(), focalLength, cropFactor, getSize()));
00632             DEBUG_DEBUG("HFOV:         " << getHFOV());
00633             return true;
00634         } else {
00635             return false;
00636         }
00637     }
00638     return true;
00639 }
00640 
00641 bool SrcPanoImage::readCropfactorFromDB()
00642 {
00643     // finally search in lensfun database
00644     if(getExifCropFactor()<=0 && !getExifMake().empty() && !getExifModel().empty())
00645     {
00646         double dbCrop=0;
00647         if(LensDB::LensDB::GetSingleton().GetCropFactor(getExifMake(),getExifModel(),dbCrop))
00648         {
00649             if(dbCrop>0)
00650             {
00651                 setExifCropFactor(dbCrop);
00652                 return true;
00653             };
00654         };
00655     };
00656     return false;
00657 };
00658 
00659 bool SrcPanoImage::readProjectionFromDB()
00660 {
00661     bool success=false;
00662     if(!getExifLens().empty())
00663     {
00664         LensDB::LensDB& lensDB=LensDB::LensDB::GetSingleton();
00665         if(lensDB.FindLens(getExifMake(), getExifModel(), getExifLens()))
00666         {
00667             Projection dbProjection;
00668             if(lensDB.GetProjection(dbProjection))
00669             {
00670                 setProjection(dbProjection);
00671                 success=true;
00672             };
00673             if(getExifFocalLength()>0)
00674             {
00675                 CropMode dbCropMode;
00676                 FDiff2D cropLeftTop;
00677                 FDiff2D cropRightBottom;
00678                 if(lensDB.GetCrop(getExifFocalLength(),dbCropMode,cropLeftTop,cropRightBottom))
00679                 {
00680                     switch(dbCropMode)
00681                     {
00682                         case NO_CROP:
00683                             setCropMode(NO_CROP);
00684                             break;
00685                         case CROP_CIRCLE:
00686                             if(isCircularCrop())
00687                             {
00688                                 setCropMode(CROP_CIRCLE);
00689                                 int width=getSize().width();
00690                                 int height=getSize().height();
00691                                 if(width>height)
00692                                 {
00693                                     setCropRect(vigra::Rect2D(cropLeftTop.x*width,cropLeftTop.y*height,cropRightBottom.x*width,cropRightBottom.y*height));
00694                                 }
00695                                 else
00696                                 {
00697                                     setCropRect(vigra::Rect2D((1.0-cropRightBottom.y)*width,cropLeftTop.x*height,(1.0-cropLeftTop.y)*width,cropRightBottom.x*height));
00698                                 };
00699                             };
00700                             break;
00701                         case CROP_RECTANGLE:
00702                             if(!isCircularCrop())
00703                             {
00704                                 int width=getSize().width();
00705                                 int height=getSize().height();
00706                                 setCropMode(CROP_RECTANGLE);
00707                                 if(width>height)
00708                                 {
00709                                     setCropRect(vigra::Rect2D(cropLeftTop.x*width,cropLeftTop.y*height,cropRightBottom.x*width,cropRightBottom.y*height));
00710                                 }
00711                                 else
00712                                 {
00713                                     setCropRect(vigra::Rect2D((1.0-cropRightBottom.y)*width,cropLeftTop.x*height,(1.0-cropLeftTop.y*width),cropRightBottom.x*height));
00714                                 };
00715                                 fprintf(stdout,"crop rect set: %f,%f-%f,%f \n",getCropRect().left(),getCropRect().top(),getCropRect().right(),getCropRect().bottom());
00716 
00717                             };
00718                             break;
00719                     };
00720                 };
00721             };
00722         };
00723     };
00724     return success;
00725 };
00726 
00727 bool SrcPanoImage::readDistortionFromDB()
00728 {
00729     bool success=false;
00730     if(!getExifLens().empty() || (!getExifMake().empty() && !getExifModel().empty()))
00731     {
00732         LensDB::LensDB& lensDB=LensDB::LensDB::GetSingleton();
00733         if(lensDB.FindLens(getExifMake(), getExifModel(), getExifLens()))
00734         {
00735             if(getExifFocalLength()>0)
00736             {
00737                 std::vector<double> dist;
00738                 if(lensDB.GetDistortion(getExifFocalLength(),dist))
00739                 {
00740                     if(dist.size()==3)
00741                     {
00742                         dist.push_back(1.0-dist[0]-dist[1]-dist[2]);
00743                         setRadialDistortion(dist);
00744                         success=true;
00745                     };
00746                 };
00747             };
00748         };
00749     };
00750     return success;
00751 };
00752 
00753 bool SrcPanoImage::readVignettingFromDB()
00754 {
00755     bool success=false;
00756     if(!getExifLens().empty() || (!getExifMake().empty() && !getExifModel().empty()))
00757     {
00758         LensDB::LensDB& lensDB=LensDB::LensDB::GetSingleton();
00759         if(lensDB.FindLens(getExifMake(), getExifModel(), getExifLens()))
00760         {
00761             if(getExifFocalLength()>0)
00762             {
00763                 std::vector<double> vig;
00764                 if(lensDB.GetVignetting(getExifFocalLength(),getExifAperture(),getExifDistance(),vig))
00765                 {
00766                     setRadialVigCorrCoeff(vig);
00767                     success=true;
00768                 };
00769             };
00770         };
00771     };
00772     return success;
00773 };
00774 
00775 double SrcPanoImage::calcHFOV(SrcPanoImage::Projection proj, double fl, double crop, vigra::Size2D imageSize)
00776 {
00777     // calculate diagonal of film
00778     double d = sqrt(36.0*36.0 + 24.0*24.0) / crop;
00779     double r = (double)imageSize.x / imageSize.y;
00780     
00781     // calculate the sensor width and height that fit the ratio
00782     // the ratio is determined by the size of our image.
00783     FDiff2D sensorSize;
00784     sensorSize.x = d / sqrt(1 + 1/(r*r));
00785     sensorSize.y = sensorSize.x / r;
00786     
00787     double hfov = 360;
00788     
00789     switch (proj) {
00790         case SrcPanoImage::RECTILINEAR:
00791             hfov = 2*atan((sensorSize.x/2.0)/fl)  * 180.0/M_PI;
00792             break;
00793         case SrcPanoImage::CIRCULAR_FISHEYE:
00794         case SrcPanoImage::FULL_FRAME_FISHEYE:
00795             hfov = sensorSize.x / fl * 180/M_PI;
00796             break;
00797         case SrcPanoImage::EQUIRECTANGULAR:
00798         case SrcPanoImage::PANORAMIC:
00799             hfov = (sensorSize.x / fl) / M_PI * 180;
00800             break;
00801         case SrcPanoImage::FISHEYE_ORTHOGRAPHIC:
00802             {
00803                 double val=(sensorSize.x/2.0)/fl;
00804                 double n;
00805                 double frac=modf(val, &n);
00806                 hfov = 2 * asin(frac) * 180.0/M_PI + n * 180.0;
00807             }
00808             break;
00809         case SrcPanoImage::FISHEYE_EQUISOLID:
00810             hfov = 4 * asin(std::min<double>(1.0, (sensorSize.x/4.0)/fl)) * 180.0/M_PI;
00811             break;
00812         case SrcPanoImage::FISHEYE_STEREOGRAPHIC:
00813             hfov = 4 * atan((sensorSize.x/4.0)/fl) * 180.0/M_PI;
00814             break;
00815         case SrcPanoImage::FISHEYE_THOBY:
00816             hfov = 2 * asin(std::min<double>(1.0, sensorSize.x/(2.0*fl*1.47))) * 180.0/M_PI/0.713;
00817             break;
00818         default:
00819             hfov = 360;
00820             // TODO: add formulas for other projections
00821             DEBUG_WARN("Focal length calculations only supported with rectilinear and fisheye images");
00822     }
00823     return hfov;
00824 }
00825 
00826 double SrcPanoImage::calcFocalLength(SrcPanoImage::Projection proj, double hfov, double crop, vigra::Size2D imageSize)
00827 {
00828     // calculate diagonal of film
00829     double d = sqrt(36.0*36.0 + 24.0*24.0) / crop;
00830     double r = (double)imageSize.x / imageSize.y;
00831     
00832     // calculate the sensor width and height that fit the ratio
00833     // the ratio is determined by the size of our image.
00834     FDiff2D sensorSize;
00835     sensorSize.x = d / sqrt(1 + 1/(r*r));
00836     sensorSize.y = sensorSize.x / r;
00837     
00838     switch (proj)
00839     {
00840         case SrcPanoImage::RECTILINEAR:
00841             return (sensorSize.x/2.0) / tan(hfov/180.0*M_PI/2);
00842             break;
00843         case SrcPanoImage::CIRCULAR_FISHEYE:
00844         case SrcPanoImage::FULL_FRAME_FISHEYE:
00845             // same projection equation for both fisheye types,
00846             // assume equal area projection.
00847             return sensorSize.x / (hfov/180*M_PI);
00848             break;
00849         case SrcPanoImage::EQUIRECTANGULAR:
00850         case SrcPanoImage::PANORAMIC:
00851             return  (sensorSize.x / (hfov/180*M_PI));
00852             break;
00853         case SrcPanoImage::FISHEYE_ORTHOGRAPHIC:
00854             {
00855                 int t=(int)ceil((hfov-180)/360);
00856                 return (sensorSize.x /2.0) / (2 * t + pow ( -1.0, t) * sin(hfov/180.0*M_PI/2.0));
00857             };
00858         case SrcPanoImage::FISHEYE_STEREOGRAPHIC:
00859             return (sensorSize.x/4.0) / tan(hfov/180.0*M_PI/4.0);
00860         case SrcPanoImage::FISHEYE_EQUISOLID:
00861             return (sensorSize.x/4.0) / sin(hfov/180.0*M_PI/4.0);
00862         case SrcPanoImage::FISHEYE_THOBY:
00863             return (sensorSize.x/2.0) / (1.47 * sin(hfov/180.0*M_PI * 0.713 / 2.0));
00864         default:
00865             // TODO: add formulas for other projections
00866             DEBUG_WARN("Focal length calculations only supported with rectilinear and fisheye images");
00867             return 0;
00868     }
00869 }
00870 
00871 double SrcPanoImage::calcCropFactor(SrcPanoImage::Projection proj, double hfov, double focalLength, vigra::Size2D imageSize)
00872 {
00873     // calculate diagonal of film
00874     double r = (double)imageSize.x / imageSize.y;
00875 
00876     double x = 36;
00877     switch (proj)
00878     {
00879         case SrcPanoImage::RECTILINEAR:
00880             x = focalLength * tan(hfov/180.0*M_PI/2);
00881             break;
00882         case SrcPanoImage::CIRCULAR_FISHEYE:
00883         case SrcPanoImage::FULL_FRAME_FISHEYE:
00884         case SrcPanoImage::EQUIRECTANGULAR:
00885         case SrcPanoImage::FISHEYE_ORTHOGRAPHIC:
00886         case SrcPanoImage::FISHEYE_STEREOGRAPHIC:
00887         case SrcPanoImage::FISHEYE_EQUISOLID:
00888         case SrcPanoImage::FISHEYE_THOBY:
00889         case SrcPanoImage::PANORAMIC:
00890             // same projection equation for both fisheye types,
00891             // assume equal area projection.
00892             x = focalLength * (hfov/180*M_PI);
00893             break;
00894         default:
00895             // TODO: add formulas for other projections
00896             DEBUG_WARN("Focal length calculations only supported with rectilinear and fisheye images");
00897             return 0;
00898     }
00899     // diagonal of sensor
00900     double diag = x * sqrt(1+ 1/(r*r));
00901     return sqrt(36.0*36.0 + 24.0*24.0) / diag;
00902 }
00903 
00904 void SrcPanoImage::updateFocalLength(double newFocalLength)
00905 {
00906     double newHFOV=calcHFOV(getProjection(),newFocalLength,getExifCropFactor(),getSize());
00907     if(newHFOV!=0)
00908     {
00909         setHFOV(newHFOV);
00910     };
00911 };
00912 
00913 void SrcPanoImage::updateCropFactor(double focalLength, double newCropFactor)
00914 {
00915     double newHFOV=calcHFOV(getProjection(),focalLength,newCropFactor,getSize());
00916     if(newHFOV!=0)
00917     {
00918         setHFOV(newHFOV);
00919     };
00920     setExifCropFactor(newCropFactor);
00921 };
00922 
00923 // Convenience functions to work with Exiv2
00924 bool SrcPanoImage::getExiv2Value(Exiv2::ExifData& exifData, std::string keyName, long & value)
00925 {
00926     Exiv2::ExifKey key(keyName);
00927     Exiv2::ExifData::iterator itr = exifData.findKey(key);
00928     if (itr != exifData.end() && itr->count()) {
00929         value = itr->toLong();
00930         DEBUG_DEBUG("" << keyName << ": " << value);
00931         return true;
00932     } else {
00933         return false;
00934     }
00935 }
00936 
00937 
00938 bool SrcPanoImage::getExiv2Value(Exiv2::ExifData& exifData, std::string keyName, float & value)
00939 {
00940     Exiv2::ExifKey key(keyName);
00941     Exiv2::ExifData::iterator itr = exifData.findKey(key);
00942     if (itr != exifData.end() && itr->count()) {
00943         value = itr->toFloat();
00944         DEBUG_DEBUG("" << keyName << ": " << value);
00945         return true;
00946     } else {
00947         return false;
00948     }
00949 }
00950 
00951 
00952 bool SrcPanoImage::getExiv2Value(Exiv2::ExifData& exifData, std::string keyName, std::string & value)
00953 {
00954     Exiv2::ExifKey key(keyName);
00955     Exiv2::ExifData::iterator itr = exifData.findKey(key);
00956     if (itr != exifData.end() && itr->count()) {
00957         value = itr->toString();
00958         DEBUG_DEBUG("" << keyName << ": " << value);
00959         return true;
00960     } else {
00961         return false;
00962     }
00963 }
00964 
00965 bool SrcPanoImage::getExiv2Value(Exiv2::ExifData& exifData, uint16_t tagID, std::string groupName, std::string & value)
00966 {
00967     Exiv2::ExifKey key(tagID,groupName);
00968     Exiv2::ExifData::iterator itr = exifData.findKey(key);
00969     if (itr != exifData.end() && itr->count())
00970     {
00971         value = itr->toString();
00972         return true;
00973     }
00974     else
00975     {
00976         return false;
00977     }
00978 }
00979 
00980 // mask handling stuff
00981 void SrcPanoImage::addMask(MaskPolygon newMask)
00982 {
00983     MaskPolygonVector newMasks=m_Masks.getData();
00984     newMasks.push_back(newMask);
00985     setMasks(newMasks);
00986 };
00987 
00988 void SrcPanoImage::addActiveMask(MaskPolygon newMask)
00989 {
00990     MaskPolygonVector newMasks=m_ActiveMasks.getData();
00991     newMasks.push_back(newMask);
00992     setActiveMasks(newMasks);
00993 };
00994 
00995 void SrcPanoImage::clearActiveMasks()
00996 {
00997     MaskPolygonVector emptyMaskVector;
00998     m_ActiveMasks.setData(emptyMaskVector);
00999 };
01000 
01001 bool SrcPanoImage::hasMasks() const
01002 {
01003     return m_Masks.getData().size()>0;
01004 };
01005 
01006 bool SrcPanoImage::hasPositiveMasks() const
01007 {
01008     MaskPolygonVector masks=m_Masks.getData();
01009     if(masks.size()>0)
01010     {
01011         for(unsigned int i=0;i<masks.size();i++)
01012         {
01013             if(masks[i].isPositive())
01014             {
01015                 return true;
01016             };
01017         };
01018     };
01019     return false;
01020 };
01021 
01022 bool SrcPanoImage::hasActiveMasks() const
01023 {
01024     return m_ActiveMasks.getData().size()>0;
01025 };
01026  
01027 void SrcPanoImage::printMaskLines(std::ostream &o, unsigned int newImgNr) const
01028 {
01029     if(m_Masks.getData().size()>0)
01030         for(unsigned int i=0;i<m_Masks.getData().size();i++)
01031             m_Masks.getData()[i].printPolygonLine(o, newImgNr);
01032 };
01033 
01034 void SrcPanoImage::changeMaskType(unsigned int index, HuginBase::MaskPolygon::MaskType newType)
01035 {
01036     if(index<m_Masks.getData().size())
01037     {
01038         MaskPolygonVector editedMasks=m_Masks.getData();
01039         editedMasks[index].setMaskType(newType);
01040         m_Masks.setData(editedMasks);
01041     };
01042 };
01043 
01044 void SrcPanoImage::deleteMask(unsigned int index)
01045 {
01046     if(index<m_Masks.getData().size())
01047     {
01048         MaskPolygonVector oldMasks=m_Masks.getData();
01049         oldMasks.erase(oldMasks.begin()+index);
01050         m_Masks.setData(oldMasks);
01051     };
01052 };
01053 
01054 void SrcPanoImage::deleteAllMasks()
01055 {
01056     MaskPolygonVector emptyMaskVector;
01057     m_Masks.setData(emptyMaskVector);
01058 };
01059 
01060 bool SrcPanoImage::isInsideMasks(vigra::Point2D p) const
01061 {
01062     if(!hasActiveMasks())
01063         return false;
01064     bool insideMask=false;
01065     unsigned int i=0;
01066     while(!insideMask && i<m_ActiveMasks.getData().size())
01067     {
01068         insideMask=m_ActiveMasks.getData()[i].isInside(p);
01069         i++;
01070     };
01071     return insideMask;
01072 };
01073 
01080 bool SrcPanoImage::trustExivOrientation()
01081 {
01082     if(getSize().width() < getSize().height())
01083         return false;
01084 
01085     return true;
01086 }
01087 
01088 const int SrcPanoImage::getExifDateTime(struct tm* datetime) const
01089 {
01090     //initialize struct
01091     std::memset(datetime, 0x0, sizeof(*datetime));
01092     //ignore daylight saving flag because it is not saved in EXIF date time format
01093     datetime->tm_isdst=-1;
01094     return Exiv2::exifTime(m_ExifDate.getData().c_str(),datetime);
01095 };
01096 
01097 } // namespace

Generated on 26 Oct 2014 for Hugintrunk by  doxygen 1.4.7