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, see
00026  *  <http://www.gnu.org/licenses/>.
00027  *
00028  */
00029 
00030 // for debugging
00031 #include <iostream>
00032 #include <stdio.h>
00033 #include <stdexcept>
00034 //#include <wx/wxprec.h>
00035 
00036 #include "SrcPanoImage.h"
00037 
00038 #include <iostream>
00039 #include <vector>
00040 #include <vigra/diff2d.hxx>
00041 #include <vigra/imageinfo.hxx>
00042 #include <hugin_utils/utils.h>
00043 #include <exiv2/exif.hpp>
00044 #include <exiv2/image.hpp>
00045 #include <exiv2/easyaccess.hpp>
00046 #include <lensdb/LensDB.h>
00047 #include "Exiv2Helper.h"
00048 
00049 #ifdef __FreeBSD__
00050 #define log2(x)        (log(x) / M_LN2)
00051 #endif /* __FreeBSD__ */
00052 
00053 #include "ImageVariableTranslate.h"
00054 
00055 namespace HuginBase {
00056 
00057 using namespace hugin_utils;
00058     
00059 void SrcPanoImage::resize(const vigra::Size2D & sz)
00060 {
00061         // TODO: check if images have the same orientation.
00062         // calculate scaling ratio
00063         const double scale = (double) sz.x / m_Size.getData().x;
00064         
00065         // center shift
00066         m_RadialDistortionCenterShift.setData(m_RadialDistortionCenterShift.getData() * scale);
00067         m_Shear.setData(m_Shear.getData() * scale);
00068         
00069         // crop
00070         // ensure the scaled rectangle is inside the new image size
00071         switch (m_CropMode.getData())
00072         {
00073             case NO_CROP:
00074                 m_CropRect.setData(vigra::Rect2D(sz));
00075                 break;
00076             case CROP_RECTANGLE:
00077                 {
00078                     vigra::Rect2D rect(m_CropRect.getData());
00079                     rect *= scale;
00080                     rect &= vigra::Rect2D(sz);
00081                     m_CropRect.setData(rect);
00082                 }
00083                 break;
00084             case CROP_CIRCLE:
00085                 {
00086                     vigra::Rect2D rect(m_CropRect.getData());
00087                     rect *= scale;
00088                     m_CropRect.setData(rect);
00089                 }
00090                 break;
00091         }
00092         
00093         m_Size.setData(sz);
00094         // vignetting correction
00095         m_RadialVigCorrCenterShift.setData(m_RadialVigCorrCenterShift.getData() *scale);
00096         // resize masks
00097         MaskPolygonVector scaledMasks=m_Masks.getData();
00098         for(unsigned int i=0;i<scaledMasks.size();i++)
00099             scaledMasks[i].scale(scale);
00100         m_Masks.setData(scaledMasks);
00101         scaledMasks.clear();
00102         scaledMasks=m_ActiveMasks.getData();
00103         for(unsigned int i=0;i<scaledMasks.size();i++)
00104             scaledMasks[i].scale(scale);
00105         m_ActiveMasks.setData(scaledMasks);
00106 }
00107 
00108 bool SrcPanoImage::horizontalWarpNeeded()
00109 {
00110     switch (m_Projection.getData())
00111     {
00112         case PANORAMIC:
00113         case EQUIRECTANGULAR:
00114             if (m_HFOV.getData() == 360) return true;
00115         case FULL_FRAME_FISHEYE:
00116         case CIRCULAR_FISHEYE:
00117         case RECTILINEAR:
00118         case FISHEYE_ORTHOGRAPHIC:
00119         case FISHEYE_STEREOGRAPHIC:
00120         case FISHEYE_EQUISOLID:
00121         case FISHEYE_THOBY:
00122         default:
00123             break;
00124     }
00125     return false;
00126 }
00127 
00128 void BaseSrcPanoImage::setDefaults()
00129 {
00130     /* Some of the vectors are difficult to initalise with the variables list
00131      * header, so we make some local variables which are used in it.
00132      */
00133     // Radial Distortion defaults
00134     std::vector<double> distortion_default(4, 0.0);
00135     distortion_default[3] = 1;
00136     
00137     std::vector<double> RadialVigCorrCoeff_default(4, 0.0);
00138     RadialVigCorrCoeff_default[0] = 1;
00139     HuginBase::MaskPolygonVector defaultMaskVector;
00140 #define image_variable( name, type, default_value ) m_##name.setData(default_value);
00141 #include "image_variables.h"
00142 #undef image_variable
00143 }
00144 
00145 bool SrcPanoImage::isInside(vigra::Point2D p, bool ignoreMasks) const
00146 {
00147     bool insideCrop=false;
00148     switch(m_CropMode.getData()) {
00149         case NO_CROP:
00150         case CROP_RECTANGLE:
00151             insideCrop = m_CropRect.getData().contains(p);
00152             break;
00153         case CROP_CIRCLE:
00154         {
00155             if (0 > p.x || 0 > p.y || p.x >= m_Size.getData().x || p.y >= m_Size.getData().y) {
00156                 // outside image
00157                 return false;
00158             }
00159             FDiff2D cropCenter;
00160             cropCenter.x = m_CropRect.getData().left() + m_CropRect.getData().width()/2.0;
00161             cropCenter.y = m_CropRect.getData().top() + m_CropRect.getData().height()/2.0;
00162             double radius2 = std::min(m_CropRect.getData().width()/2.0, m_CropRect.getData().height()/2.0);
00163             radius2 = radius2 * radius2;
00164             FDiff2D pf = FDiff2D(p) - cropCenter;
00165             insideCrop = (radius2 > pf.x*pf.x+pf.y*pf.y );
00166         }
00167     }
00168     if(insideCrop && !ignoreMasks)
00169         return !(isInsideMasks(p));
00170     else
00171         return insideCrop;
00172 }
00173 
00174 bool SrcPanoImage::isCircularCrop() const
00175 {
00176     HuginBase::BaseSrcPanoImage::Projection projection=m_Projection.getData();
00177     return (projection==CIRCULAR_FISHEYE || projection==FISHEYE_THOBY || projection==FISHEYE_ORTHOGRAPHIC);
00178 };
00179 
00180 bool SrcPanoImage::getCorrectTCA() const
00181 { 
00182     bool nr = (m_RadialDistortionRed.getData()[0] == 0.0 && m_RadialDistortionRed.getData()[1] == 0.0 &&
00183                m_RadialDistortionRed.getData()[2] == 0.0 && m_RadialDistortionRed.getData()[3] == 1);
00184     bool nb = (m_RadialDistortionBlue.getData()[0] == 0.0 && m_RadialDistortionBlue.getData()[1] == 0.0 &&
00185                m_RadialDistortionBlue.getData()[2] == 0.0 && m_RadialDistortionBlue.getData()[3] == 1);
00186     return !(nr && nb);
00187 }
00188 
00189 
00190 FDiff2D SrcPanoImage::getRadialDistortionCenter() const
00191 { return FDiff2D(m_Size.getData())/2.0 + m_RadialDistortionCenterShift.getData(); }
00192 
00193 
00194 FDiff2D SrcPanoImage::getRadialVigCorrCenter() const
00195 { return (FDiff2D(m_Size.getData())-FDiff2D(1,1))/2.0 + m_RadialVigCorrCenterShift.getData(); }
00196 
00197 void SrcPanoImage::setCropMode(CropMode val)
00198 {
00199     m_CropMode.setData(val);
00200     if (val == NO_CROP) {
00201         m_CropRect.setData(vigra::Rect2D(m_Size.getData()));
00202     }
00203 }
00204 
00205 void SrcPanoImage::setSize(vigra::Size2D val)
00206 {
00207     m_Size.setData(val);
00208     if (m_CropMode.getData() == NO_CROP) {
00209         m_CropRect.setData(vigra::Rect2D(val));
00210     }
00211 }
00212 
00213 double SrcPanoImage::getExposure() const
00214 { return 1.0/pow(2.0, m_ExposureValue.getData()); }
00215 
00216 void SrcPanoImage::setExposure(const double & val)
00217 { m_ExposureValue.setData(log2(1/val)); }
00218 
00219 
00220 bool BaseSrcPanoImage::operator==(const BaseSrcPanoImage & other) const
00221 {
00222     DEBUG_TRACE("");
00223     return (
00224 #define image_variable( name, type, default_value ) \
00225     m_##name.getData() == other.m_##name.getData() &&
00226 #include "image_variables.h"
00227 #undef image_variable
00228     true // All the variable checks above end with && so we need this.
00229     );
00230 }
00231 
00232 // convinience functions to extract a set of variables
00233 double SrcPanoImage::getVar(const std::string & code) const
00234 {
00235     DEBUG_TRACE("");
00236     assert(code.size() > 0);
00237 #define image_variable( name, type, default_value ) \
00238     if (PTOVariableConverterFor##name::checkApplicability(code)) \
00239         return PTOVariableConverterFor##name::getValueFromVariable(code, m_##name );\
00240     else 
00241 #include "image_variables.h"
00242 #undef image_variable
00243     {// this is for the final else.
00244         DEBUG_ERROR("Unknown variable " << code);
00245     }
00246     return 0;
00247 }
00248 
00249 void SrcPanoImage::setVar(const std::string & code, double val)
00250 {
00251     DEBUG_TRACE("Var:" << code << " value: " << val);
00252     assert(code.size() > 0);
00253 #define image_variable( name, type, default_value ) \
00254     if (PTOVariableConverterFor##name::checkApplicability(code)) \
00255         {PTOVariableConverterFor##name::setValueFromVariable(code, m_##name, val);}\
00256     else 
00257 #include "image_variables.h"
00258 #undef image_variable
00259     {// this is for the final else.
00260         DEBUG_ERROR("Unknown variable " << code);
00261     }
00262 }
00263 
00264 VariableMap SrcPanoImage::getVariableMap() const
00265 {
00266     // make a variable map vector
00267     
00268     // fill variable map with details about this image.
00269     // position
00270     DEBUG_TRACE("");
00271 
00272     VariableMap vars;
00273 #define image_variable( name, type, default_value ) \
00274     PTOVariableConverterFor##name::addToVariableMap(m_##name, vars);
00275 #include "image_variables.h"
00276 #undef image_variable
00277 
00278     return vars;
00279 }
00280 
00281 bool SrcPanoImage::checkImageSizeKnown()
00282 {
00283     if(getWidth()<=0 || getHeight()<=0)
00284     {
00285         try
00286         {
00287             vigra::ImageImportInfo info(getFilename().c_str());
00288             setSize(info.size());
00289             // save pixeltype for later, so we don't need to parse the file again
00290             const std::string pixeltype(info.getPixelType());
00291             FileMetaData metaData = getFileMetadata();
00292             metaData["pixeltype"] = pixeltype;
00293             setFileMetadata(metaData);
00294         }
00295         catch(std::exception & )
00296         {
00297             return false;
00298         }
00299     };
00300     return true;
00301 
00302 };
00303 
00304 bool SrcPanoImage::readEXIF()
00305 {
00306     std::string filename = getFilename();
00307     double roll = 0;
00308     // clear all old values
00309     setFileMetadata(FileMetaData());
00310     setExifExposureTime(0);
00311     setExifAperture(0);
00312     setExifExposureMode(0);
00313     setExifISO(0);
00314     setExifMake(std::string(""));
00315     setExifModel(std::string(""));
00316     setExifLens(std::string(""));
00317     setExifOrientation(0);
00318     setExifFocalLength(0);
00319     setExifFocalLength35(0);
00320     setExifCropFactor(0);
00321     setExifDistance(0);
00322     setExifDate(std::string(""));
00323     setExifRedBalance(1);
00324     setExifBlueBalance(1);
00325 
00326     if(!checkImageSizeKnown())
00327     {
00328         return false;
00329     };
00330 
00331     // if width==2*height assume equirectangular image
00332     if (getWidth() == 2 * getHeight())
00333     {
00334         FileMetaData metaData = getFileMetadata();
00335         metaData["projection"] = "equirectangular";
00336         metaData["HFOV"] = "360";
00337         setFileMetadata(metaData);
00338     };
00339 
00340     Exiv2::Image::AutoPtr image;
00341     try {
00342         image = Exiv2::ImageFactory::open(filename.c_str());
00343     }catch(...) {
00344         std::cerr << __FILE__ << " " << __LINE__ << " Error opening file" << std::endl;
00345         return false;
00346     }
00347     if (image.get() == 0) {
00348         std::cerr << "Unable to open file to read EXIF data: " << filename << std::endl;
00349         return false;
00350     }
00351 
00352     image->readMetadata();
00353 
00354     // look into XMP metadata
00355     Exiv2::XmpData& xmpData = image->xmpData();
00356     if (!xmpData.empty())
00357     {
00358         // we need to catch exceptions in case file does not contain any GPano tags
00359         try
00360         {
00361             Exiv2::XmpData::iterator pos = xmpData.findKey(Exiv2::XmpKey("Xmp.GPano.ProjectionType"));
00362             FileMetaData metaData = getFileMetadata();
00363             if (pos != xmpData.end())
00364             {
00365                 if (hugin_utils::tolower(pos->toString()) == "equirectangular")
00366                 {
00367                     long croppedWidth = 0;
00368                     long croppedHeight = 0;
00369                     pos = xmpData.findKey(Exiv2::XmpKey("Xmp.GPano.CroppedAreaImageWidthPixels"));
00370                     if (pos != xmpData.end())
00371                     {
00372                         croppedWidth = pos->toLong();
00373                     }
00374                     else
00375                     {
00376                         // tag is required
00377                         throw std::logic_error("Required tag CroppedAreaImageWidthPixels missing");
00378                     };
00379                     pos = xmpData.findKey(Exiv2::XmpKey("Xmp.GPano.CroppedAreaImageHeightPixels"));
00380                     if (pos != xmpData.end())
00381                     {
00382                         croppedHeight = pos->toLong();
00383                     }
00384                     else
00385                     {
00386                         // tag is required
00387                         throw std::logic_error("Required tag CroppedAreaImageHeightPixels missing");
00388                     };
00389                     // check if sizes matches, if not ignore all tags
00390                     if (getWidth() == croppedWidth && getHeight() == croppedHeight)
00391                     {
00392                         pos = xmpData.findKey(Exiv2::XmpKey("Xmp.GPano.FullPanoWidthPixels"));
00393                         double hfov = 0;
00394                         if (pos != xmpData.end())
00395                         {
00396                             hfov = 360 * croppedWidth / (double)pos->toLong();
00397                         }
00398                         else
00399                         {
00400                             // tag is required
00401                             throw std::logic_error("Required tag FullPanoWidthPixels missing");
00402                         };
00403                         long fullHeight = 0;
00404                         pos = xmpData.findKey(Exiv2::XmpKey("Xmp.GPano.FullPanoHeightPixels"));
00405                         if (pos != xmpData.end())
00406                         {
00407                             fullHeight = pos->toLong();
00408                         }
00409                         else
00410                         {
00411                             // tag is required
00412                             throw std::logic_error("Required tag FullPanoHeightPixels missing");
00413                         };
00414                         long cropTop = 0;
00415                         pos = xmpData.findKey(Exiv2::XmpKey("Xmp.GPano.CroppedAreaTopPixels"));
00416                         if (pos != xmpData.end())
00417                         {
00418                             cropTop = pos->toLong();
00419                         }
00420                         else
00421                         {
00422                             // tag is required
00423                             throw std::logic_error("Required tag CroppedAreaTopPixels missing");
00424                         };
00425 
00426                         // all found, remember for later
00427                         metaData["projection"] = "equirectangular";
00428                         metaData["HFOV"] = hugin_utils::doubleToString(hfov, 3);
00429                         metaData["e"] = hugin_utils::doubleToString(-cropTop - ((getHeight() - fullHeight) / 2.0), 4);
00430                         setFileMetadata(metaData);
00431                     };
00432                 };
00433             };
00434         }
00435         catch (std::exception& e)
00436         {
00437             // just to catch error when image contains no GPano tags
00438             std::cerr << "Error reading GPano tags from " << filename << "(" << e.what() << ")" << std::endl;
00439         };
00440     };
00441 
00442     Exiv2::ExifData &exifData = image->exifData();
00443     if (exifData.empty()) {
00444         std::cerr << "Unable to read EXIF data from opened file:" << filename << std::endl;
00445         return !getFileMetadata().empty();
00446     }
00447 
00448     setExifExposureTime(Exiv2Helper::getExiv2ValueDouble(exifData, Exiv2::exposureTime(exifData)));
00449     setExifAperture(Exiv2Helper::getExiv2ValueDouble(exifData, Exiv2::fNumber(exifData)));
00450     
00451     //read exposure mode
00452     setExifExposureMode(Exiv2Helper::getExiv2ValueLong(exifData, "Exif.Photo.ExposureMode"));
00453 
00454     // read ISO from EXIF or makernotes
00455     setExifISO(Exiv2Helper::getExiv2ValueDouble(exifData, Exiv2::isoSpeed(exifData)));
00456 
00457     setExifMake(Exiv2Helper::getExiv2ValueString(exifData, Exiv2::make(exifData)));
00458     setExifModel(Exiv2Helper::getExiv2ValueString(exifData, Exiv2::model(exifData)));
00459 
00460     //reading lens
00461     setExifLens(Exiv2Helper::getLensName(exifData));
00462 
00463     long orientation = Exiv2Helper::getExiv2ValueLong(exifData, "Exif.Image.Orientation");
00464     if (orientation>0 && trustExivOrientation())
00465     {
00466         switch (orientation) {
00467             case 3:  // rotate 180
00468                 roll = 180;
00469                 break;
00470             case 6: // rotate 90
00471                 roll = 90;
00472                 break;
00473             case 8: // rotate 270
00474                 roll = 270;
00475                 break;
00476             default:
00477                 break;
00478         }
00479     }
00480 
00481     long pixXdim = Exiv2Helper::getExiv2ValueLong(exifData,"Exif.Photo.PixelXDimension");
00482     long pixYdim = Exiv2Helper::getExiv2ValueLong(exifData,"Exif.Photo.PixelYDimension");
00483 
00484     if (pixXdim !=0 && pixYdim !=0 )
00485     {
00486         double ratioExif = pixXdim/(double)pixYdim;
00487         double ratioImage = getWidth()/(double)getHeight();
00488         if (fabs( ratioExif - ratioImage) > 0.1)
00489         {
00490             // Image has been modified without adjusting exif tags.
00491             // Assume user has rotated to upright pose
00492             roll = 0;
00493         }
00494     }
00495     // save for later
00496     setExifOrientation(roll);
00497     
00498     double cropFactor = 0;
00499     DEBUG_DEBUG("cropFactor: " << cropFactor);
00500 
00501     float eFocalLength = Exiv2Helper::getExiv2ValueDouble(exifData, Exiv2::focalLength(exifData));
00502     float eFocalLength35 = Exiv2Helper::getExiv2ValueLong(exifData,"Exif.Photo.FocalLengthIn35mmFilm");
00503     float focalLength=0;
00504     //The various methods to detmine crop factor
00505     if (eFocalLength35 > 0 && eFocalLength > 0)
00506     {
00507         cropFactor = eFocalLength35 / eFocalLength;
00508         focalLength = eFocalLength;
00509     }
00510     else
00511     {
00512         if (eFocalLength35 > 0)
00513         {
00514             // 35 mm equiv focal length available, crop factor unknown.
00515             // do not ask for crop factor, assume 1.  Probably a full frame sensor
00516             cropFactor = 1;
00517             focalLength = eFocalLength35;
00518         }
00519         else
00520         {
00521             focalLength = (eFocalLength > 0) ? eFocalLength : 0;
00522             // alternative way to calculate crop factor
00523             cropFactor = Exiv2Helper::getCropFactor(exifData, getWidth(), getHeight());
00524             // check result
00525             if (cropFactor < 0.1)
00526             {
00527                 cropFactor = 0;
00528             };
00529         };
00530     };
00531  
00532     setExifFocalLength(focalLength);
00533     setExifFocalLength35(eFocalLength35);
00534     setExifCropFactor(cropFactor);
00535 
00536     setExifDistance(Exiv2Helper::getExiv2ValueDouble(exifData, Exiv2::subjectDistance(exifData)));
00537     setExifDate(Exiv2Helper::getExiv2ValueString(exifData, "Exif.Photo.DateTimeOriginal"));
00538 
00539     double redBalance, blueBalance;
00540     Exiv2Helper::readRedBlueBalance(exifData, redBalance, blueBalance);
00541     setExifRedBalance(redBalance);
00542     setExifBlueBalance(blueBalance);
00543 
00544     DEBUG_DEBUG("Results for:" << filename);
00545     DEBUG_DEBUG("Focal Length: " << getExifFocalLength());
00546     DEBUG_DEBUG("Crop Factor:  " << getCropFactor());
00547     DEBUG_DEBUG("Roll:         " << getExifOrientation());
00548 
00549     return true;
00550 }
00551 
00552 bool SrcPanoImage::applyEXIFValues(bool applyEVValue)
00553 {
00554     setRoll(getExifOrientation());
00555     if(applyEVValue)
00556     {
00557         setExposureValue(calcExifExposureValue());
00558     };
00559     // special handling for GPano tags
00560     FileMetaData metaData = getFileMetadata();
00561     if (!metaData.empty())
00562     {
00563         FileMetaData::const_iterator pos = metaData.find("projection");
00564         if (pos != metaData.end())
00565         {
00566             if (pos->second == "equirectangular")
00567             {
00568                 pos = metaData.find("HFOV");
00569                 if (pos != metaData.end())
00570                 {
00571                     double hfov = 0;
00572                     hugin_utils::stringToDouble(pos->second, hfov);
00573                     double e = 0;
00574                     pos = metaData.find("e");
00575                     if (pos != metaData.end())
00576                     {
00577                         hugin_utils::stringToDouble(pos->second, e);
00578                     };
00579                     if (hfov != 0)
00580                     {
00581                         setProjection(EQUIRECTANGULAR);
00582                         setHFOV(hfov);
00583                         setCropFactor(1.0);
00584                         hugin_utils::FDiff2D p = getRadialDistortionCenterShift();
00585                         p.y = e;
00586                         setRadialDistortionCenterShift(p);
00587                         return true;
00588                     };
00589                 };
00590             };
00591         };
00592     };
00593     double cropFactor=getExifCropFactor();
00594     double focalLength=getExifFocalLength();
00595     if(cropFactor>0.1)
00596     {
00597         setCropFactor(cropFactor);
00598     };
00599     if (focalLength > 0 && cropFactor > 0.1)
00600     {
00601         setHFOV(calcHFOV(getProjection(), focalLength, cropFactor, getSize()));
00602         DEBUG_DEBUG("HFOV:         " << getHFOV());
00603         return true;
00604     }
00605     else
00606     {
00607         return false;
00608     }
00609 }
00610 
00611 bool SrcPanoImage::readCropfactorFromDB()
00612 {
00613     // finally search in lens database
00614     if(getCropFactor()<0.1 && !getExifMake().empty() && !getExifModel().empty())
00615     {
00616         double dbCrop=0;
00617         if(LensDB::LensDB::GetSingleton().GetCropFactor(getExifMake(),getExifModel(),dbCrop))
00618         {
00619             if(dbCrop>0.1)
00620             {
00621                 setCropFactor(dbCrop);
00622                 setExifCropFactor(dbCrop);
00623                 if (getExifFocalLength() > 0)
00624                 {
00625                     setHFOV(calcHFOV(getProjection(), getExifFocalLength(), dbCrop, getSize()));
00626                 };
00627                 return true;
00628             };
00629         };
00630     };
00631     return false;
00632 };
00633 
00634 std::string SrcPanoImage::getDBLensName() const
00635 {
00636     std::string lens(getExifLens());
00637     if (!lens.empty())
00638     {
00639         return lens;
00640     }
00641     lens = getExifMake();
00642     if (!lens.empty())
00643     {
00644         if (!getExifModel().empty())
00645         {
00646             lens.append("|");
00647             lens.append(getExifModel());
00648             return lens;
00649         };
00650     };
00651     return std::string();
00652 };
00653 
00654 bool SrcPanoImage::readProjectionFromDB()
00655 {
00656     bool success=false;
00657     const std::string lensname = getDBLensName();
00658     const double focal = getExifFocalLength();
00659     if (!lensname.empty())
00660     {
00661         const LensDB::LensDB& lensDB=LensDB::LensDB::GetSingleton();
00662         Projection dbProjection;
00663         if(lensDB.GetProjection(lensname, dbProjection))
00664         {
00665             setProjection(dbProjection);
00666             success=true;
00667         };
00668         if (focal>0)
00669         {
00670             double fov;
00671             if (lensDB.GetFov(lensname, focal, fov))
00672             {
00673                 // calculate FOV for given image, take different aspect ratios into account
00674                 const double newFocal = calcFocalLength(getProjection(), fov, getCropFactor(), vigra::Size2D(3000,2000));
00675                 const double newFov = calcHFOV(getProjection(), newFocal, getCropFactor(), getSize());
00676                 setHFOV(newFov);
00677             };
00678             vigra::Rect2D dbCropRect;
00679             if (lensDB.GetCrop(lensname, focal, getSize(), dbCropRect))
00680             {
00681                 setCropMode(isCircularCrop() ? CROP_CIRCLE : CROP_RECTANGLE);
00682                 setCropRect(dbCropRect);
00683             };
00684         };
00685     };
00686     return success;
00687 };
00688 
00689 bool SrcPanoImage::readDistortionFromDB()
00690 {
00691     const std::string lensname = getDBLensName();
00692     const double focal = getExifFocalLength();
00693     if (!lensname.empty() && focal > 0)
00694     {
00695         const LensDB::LensDB& lensDB=LensDB::LensDB::GetSingleton();
00696         std::vector<double> dist;
00697         if(lensDB.GetDistortion(lensname, focal, dist))
00698         {
00699             if(dist.size()==3)
00700             {
00701                 dist.push_back(1.0-dist[0]-dist[1]-dist[2]);
00702                 setRadialDistortion(dist);
00703                 return true;
00704             };
00705         };
00706     };
00707     return false;
00708 };
00709 
00710 bool SrcPanoImage::readVignettingFromDB()
00711 {
00712     const std::string lensname = getDBLensName();
00713     const double focal = getExifFocalLength();
00714     if (!lensname.empty() && focal > 0)
00715     {
00716         const LensDB::LensDB& lensDB=LensDB::LensDB::GetSingleton();
00717         std::vector<double> vig;
00718         if(lensDB.GetVignetting(lensname, focal, getExifAperture(), getExifDistance(), vig))
00719         {
00720             if (vig.size() == 4)
00721             {
00722                 setRadialVigCorrCoeff(vig);
00723                 return true;
00724             };
00725         };
00726     };
00727     return false;
00728 };
00729 
00730 double SrcPanoImage::calcHFOV(SrcPanoImage::Projection proj, double fl, double crop, vigra::Size2D imageSize)
00731 {
00732     // calculate diagonal of film
00733     double d = sqrt(36.0*36.0 + 24.0*24.0) / crop;
00734     double r = (double)imageSize.x / imageSize.y;
00735     
00736     // calculate the sensor width and height that fit the ratio
00737     // the ratio is determined by the size of our image.
00738     FDiff2D sensorSize;
00739     sensorSize.x = d / sqrt(1 + 1/(r*r));
00740     sensorSize.y = sensorSize.x / r;
00741     
00742     double hfov = 360;
00743     
00744     switch (proj) {
00745         case SrcPanoImage::RECTILINEAR:
00746             hfov = 2*atan((sensorSize.x/2.0)/fl)  * 180.0/M_PI;
00747             break;
00748         case SrcPanoImage::CIRCULAR_FISHEYE:
00749         case SrcPanoImage::FULL_FRAME_FISHEYE:
00750             hfov = sensorSize.x / fl * 180/M_PI;
00751             break;
00752         case SrcPanoImage::EQUIRECTANGULAR:
00753         case SrcPanoImage::PANORAMIC:
00754             hfov = (sensorSize.x / fl) / M_PI * 180;
00755             break;
00756         case SrcPanoImage::FISHEYE_ORTHOGRAPHIC:
00757             {
00758                 double val=(sensorSize.x/2.0)/fl;
00759                 double n;
00760                 double frac=modf(val, &n);
00761                 hfov = 2 * asin(frac) * 180.0/M_PI + n * 180.0;
00762             }
00763             break;
00764         case SrcPanoImage::FISHEYE_EQUISOLID:
00765             hfov = 4 * asin(std::min<double>(1.0, (sensorSize.x/4.0)/fl)) * 180.0/M_PI;
00766             break;
00767         case SrcPanoImage::FISHEYE_STEREOGRAPHIC:
00768             hfov = 4 * atan((sensorSize.x/4.0)/fl) * 180.0/M_PI;
00769             break;
00770         case SrcPanoImage::FISHEYE_THOBY:
00771             hfov = 2 * asin(std::min<double>(1.0, sensorSize.x/(2.0*fl*1.47))) * 180.0/M_PI/0.713;
00772             break;
00773         default:
00774             hfov = 360;
00775             // TODO: add formulas for other projections
00776             DEBUG_WARN("Focal length calculations only supported with rectilinear and fisheye images");
00777     }
00778     return hfov;
00779 }
00780 
00781 double SrcPanoImage::calcFocalLength(SrcPanoImage::Projection proj, double hfov, double crop, vigra::Size2D imageSize)
00782 {
00783     // calculate diagonal of film
00784     double d = sqrt(36.0*36.0 + 24.0*24.0) / crop;
00785     double r = (double)imageSize.x / imageSize.y;
00786     
00787     // calculate the sensor width and height that fit the ratio
00788     // the ratio is determined by the size of our image.
00789     FDiff2D sensorSize;
00790     sensorSize.x = d / sqrt(1 + 1/(r*r));
00791     sensorSize.y = sensorSize.x / r;
00792     
00793     switch (proj)
00794     {
00795         case SrcPanoImage::RECTILINEAR:
00796             return (sensorSize.x/2.0) / tan(hfov/180.0*M_PI/2);
00797             break;
00798         case SrcPanoImage::CIRCULAR_FISHEYE:
00799         case SrcPanoImage::FULL_FRAME_FISHEYE:
00800             // same projection equation for both fisheye types,
00801             // assume equal area projection.
00802             return sensorSize.x / (hfov/180*M_PI);
00803             break;
00804         case SrcPanoImage::EQUIRECTANGULAR:
00805         case SrcPanoImage::PANORAMIC:
00806             return  (sensorSize.x / (hfov/180*M_PI));
00807             break;
00808         case SrcPanoImage::FISHEYE_ORTHOGRAPHIC:
00809             {
00810                 int t=(int)ceil((hfov-180)/360);
00811                 return (sensorSize.x /2.0) / (2 * t + pow ( -1.0, t) * sin(hfov/180.0*M_PI/2.0));
00812             };
00813         case SrcPanoImage::FISHEYE_STEREOGRAPHIC:
00814             return (sensorSize.x/4.0) / tan(hfov/180.0*M_PI/4.0);
00815         case SrcPanoImage::FISHEYE_EQUISOLID:
00816             return (sensorSize.x/4.0) / sin(hfov/180.0*M_PI/4.0);
00817         case SrcPanoImage::FISHEYE_THOBY:
00818             return (sensorSize.x/2.0) / (1.47 * sin(hfov/180.0*M_PI * 0.713 / 2.0));
00819         default:
00820             // TODO: add formulas for other projections
00821             DEBUG_WARN("Focal length calculations only supported with rectilinear and fisheye images");
00822             return 0;
00823     }
00824 }
00825 
00826 double SrcPanoImage::calcCropFactor(SrcPanoImage::Projection proj, double hfov, double focalLength, vigra::Size2D imageSize)
00827 {
00828     // calculate diagonal of film
00829     double r = (double)imageSize.x / imageSize.y;
00830 
00831     double x = 36;
00832     switch (proj)
00833     {
00834         case SrcPanoImage::RECTILINEAR:
00835             x = focalLength * tan(hfov/180.0*M_PI/2);
00836             break;
00837         case SrcPanoImage::CIRCULAR_FISHEYE:
00838         case SrcPanoImage::FULL_FRAME_FISHEYE:
00839         case SrcPanoImage::EQUIRECTANGULAR:
00840         case SrcPanoImage::FISHEYE_ORTHOGRAPHIC:
00841         case SrcPanoImage::FISHEYE_STEREOGRAPHIC:
00842         case SrcPanoImage::FISHEYE_EQUISOLID:
00843         case SrcPanoImage::FISHEYE_THOBY:
00844         case SrcPanoImage::PANORAMIC:
00845             // same projection equation for both fisheye types,
00846             // assume equal area projection.
00847             x = focalLength * (hfov/180*M_PI);
00848             break;
00849         default:
00850             // TODO: add formulas for other projections
00851             DEBUG_WARN("Focal length calculations only supported with rectilinear and fisheye images");
00852             return 0;
00853     }
00854     // diagonal of sensor
00855     double diag = x * sqrt(1+ 1/(r*r));
00856     return sqrt(36.0*36.0 + 24.0*24.0) / diag;
00857 }
00858 
00859 double SrcPanoImage::calcExifExposureValue()
00860 {
00861     double ev=0;
00862     double photoFNumber=getExifAperture();
00863     if(photoFNumber==0)
00864     {
00865         //if no F-number was found in EXIF data assume a f stop of 3.5 to get
00866         //a reasonable ev value if shutter time, e. g. for manual lenses is found
00867         photoFNumber=3.5;
00868     };
00869     if (getExifExposureTime() > 0)
00870     {
00871         double gain = 1;
00872         if (getExifISO()> 0)
00873         {
00874             gain = getExifISO() / 100.0;
00875         }
00876         ev = log2(photoFNumber * photoFNumber / (gain * getExifExposureTime()));
00877     };
00878     return ev;
00879 };
00880 
00881 void SrcPanoImage::updateFocalLength(double newFocalLength)
00882 {
00883     double newHFOV=calcHFOV(getProjection(),newFocalLength,getCropFactor(),getSize());
00884     if(newHFOV!=0)
00885     {
00886         setHFOV(newHFOV);
00887     };
00888 };
00889 
00890 void SrcPanoImage::updateCropFactor(double focalLength, double newCropFactor)
00891 {
00892     double newHFOV=calcHFOV(getProjection(),focalLength,newCropFactor,getSize());
00893     if(newHFOV!=0)
00894     {
00895         setHFOV(newHFOV);
00896     };
00897     setCropFactor(newCropFactor);
00898 };
00899 
00900 // mask handling stuff
00901 void SrcPanoImage::addMask(MaskPolygon newMask)
00902 {
00903     MaskPolygonVector newMasks=m_Masks.getData();
00904     newMasks.push_back(newMask);
00905     setMasks(newMasks);
00906 };
00907 
00908 void SrcPanoImage::addActiveMask(MaskPolygon newMask)
00909 {
00910     MaskPolygonVector newMasks=m_ActiveMasks.getData();
00911     newMasks.push_back(newMask);
00912     setActiveMasks(newMasks);
00913 };
00914 
00915 void SrcPanoImage::clearActiveMasks()
00916 {
00917     MaskPolygonVector emptyMaskVector;
00918     m_ActiveMasks.setData(emptyMaskVector);
00919 };
00920 
00921 bool SrcPanoImage::hasMasks() const
00922 {
00923     return m_Masks.getData().size()>0;
00924 };
00925 
00926 bool SrcPanoImage::hasPositiveMasks() const
00927 {
00928     MaskPolygonVector masks=m_Masks.getData();
00929     if(masks.size()>0)
00930     {
00931         for(unsigned int i=0;i<masks.size();i++)
00932         {
00933             if(masks[i].isPositive())
00934             {
00935                 return true;
00936             };
00937         };
00938     };
00939     return false;
00940 };
00941 
00942 bool SrcPanoImage::hasActiveMasks() const
00943 {
00944     return m_ActiveMasks.getData().size()>0;
00945 };
00946  
00947 void SrcPanoImage::printMaskLines(std::ostream &o, unsigned int newImgNr) const
00948 {
00949     if(m_Masks.getData().size()>0)
00950         for(unsigned int i=0;i<m_Masks.getData().size();i++)
00951             m_Masks.getData()[i].printPolygonLine(o, newImgNr);
00952 };
00953 
00954 void SrcPanoImage::changeMaskType(unsigned int index, HuginBase::MaskPolygon::MaskType newType)
00955 {
00956     if(index<m_Masks.getData().size())
00957     {
00958         MaskPolygonVector editedMasks=m_Masks.getData();
00959         editedMasks[index].setMaskType(newType);
00960         m_Masks.setData(editedMasks);
00961     };
00962 };
00963 
00964 void SrcPanoImage::deleteMask(unsigned int index)
00965 {
00966     if(index<m_Masks.getData().size())
00967     {
00968         MaskPolygonVector oldMasks=m_Masks.getData();
00969         oldMasks.erase(oldMasks.begin()+index);
00970         m_Masks.setData(oldMasks);
00971     };
00972 };
00973 
00974 void SrcPanoImage::deleteAllMasks()
00975 {
00976     MaskPolygonVector emptyMaskVector;
00977     m_Masks.setData(emptyMaskVector);
00978 };
00979 
00980 bool SrcPanoImage::isInsideMasks(vigra::Point2D p) const
00981 {
00982     if(!hasActiveMasks())
00983         return false;
00984     bool insideMask=false;
00985     unsigned int i=0;
00986     while(!insideMask && i<m_ActiveMasks.getData().size())
00987     {
00988         insideMask=m_ActiveMasks.getData()[i].isInside(p);
00989         i++;
00990     };
00991     return insideMask;
00992 };
00993 
01000 bool SrcPanoImage::trustExivOrientation()
01001 {
01002     if(getSize().width() < getSize().height())
01003         return false;
01004 
01005     return true;
01006 }
01007 
01008 const int SrcPanoImage::getExifDateTime(struct tm* datetime) const
01009 {
01010     //initialize struct
01011     std::memset(datetime, 0x0, sizeof(*datetime));
01012     //ignore daylight saving flag because it is not saved in EXIF date time format
01013     datetime->tm_isdst=-1;
01014     return Exiv2::exifTime(m_ExifDate.getData().c_str(),datetime);
01015 };
01016 
01017 } // namespace

Generated on 2 Aug 2015 for Hugintrunk by  doxygen 1.4.7