PanoramaOptions.cpp

Go to the documentation of this file.
00001 // -*- c-basic-offset: 4 -*-
00002 
00051 #include <hugin_config.h>
00052 
00053 #include "PanoramaOptions.h"
00054 
00055 #include <hugin_utils/utils.h>
00056 #include <hugin_math/hugin_math.h>
00057 #include <panotools/PanoToolsInterface.h>
00058 
00059 
00060 namespace HuginBase {
00061 
00062 using namespace hugin_utils;
00063 using namespace vigra;
00064 
00065 
00066 const std::string & PanoramaOptions::getFormatName(FileFormat f)
00067 {
00068     assert((int)f <= (int)FILEFORMAT_NULL);
00069     return fileformatNames[(int) f];
00070 }
00071 
00072 const std::string & PanoramaOptions::getOutputExtension() const
00073 {
00074     assert((int)outputFormat < (int)FILEFORMAT_NULL);
00075     return fileformatExt[(int) outputFormat];
00076 }
00077 
00078 PanoramaOptions::FileFormat PanoramaOptions::getFormatFromName(const std::string & name)
00079 {
00080     int max = (int) FILEFORMAT_NULL;
00081     int i;
00082     for (i=0; i<max; i++) {
00083         if (name == fileformatNames[i]) {
00084             break;
00085         }
00086     }
00087     if (i+1 == max) {
00088         DEBUG_ERROR("could not parse format " << name );
00089         return TIFF_m;
00090     }
00091     return (FileFormat) i;
00092 }
00093 
00094 
00095 void PanoramaOptions::printScriptLine(std::ostream & o, bool forPTOptimizer) const
00096 {
00097     o << "p f" << m_projectionFormat << " w" << getWidth()<< " h" << getHeight()
00098             << " v" << getHFOV() << " ";
00099 
00100     if (! forPTOptimizer) {
00101         switch (colorCorrection) {
00102         case NONE:
00103             break;
00104         case BRIGHTNESS_COLOR:
00105             o << " k" << colorReferenceImage;
00106             break;
00107         case BRIGHTNESS:
00108             o << " b" << colorReferenceImage;
00109             break;
00110         case COLOR:
00111             o << " d" << colorReferenceImage;
00112             break;
00113         }
00114 
00115         // the new exposure options
00116         o << " E" << outputExposureValue;
00117         o << " R" << outputMode;
00118         if (outputPixelType.size() > 0) {
00119             o << " T" << outputPixelType;
00120         }
00121         if (m_roi != vigra::Rect2D(m_size)) {
00122             o << " S" << m_roi.left() << "," << m_roi.right() << "," << m_roi.top() << "," << m_roi.bottom();
00123         }
00124     }
00125 
00126     if (m_projectionParams.size() > 0) {
00127         o << " P\"";
00128         for (int i=0; i < (int) m_projectionParams.size(); i++) {
00129             o << m_projectionParams[i];
00130             if (i+1 < (int)m_projectionParams.size())
00131                 o << " ";
00132         }
00133         o << "\"";
00134     }
00135     o << " n\"" << getFormatName(outputFormat);
00136     if ( outputFormat == JPEG ) {
00137         o << " q" << quality;
00138     } else if ( outputFormat == TIFF ||
00139                 outputFormat == TIFF_m ||
00140                 outputFormat == TIFF_mask ||
00141                 outputFormat == TIFF_multilayer ||
00142                 outputFormat == TIFF_multilayer_mask)
00143     {
00144         o << " c:" << tiffCompression;
00145         if (tiff_saveROI) {
00146             o << " r:CROP";
00147         }
00148     }
00149     o << "\"";
00150     o << std::endl;
00151 
00152     // misc options
00153     o << "m g" << gamma << " i" << interpolator;
00154     switch (remapAcceleration) {
00155     case NO_SPEEDUP:
00156         break;
00157     case MAX_SPEEDUP:
00158         o << " f0";
00159         break;
00160     case MEDIUM_SPEEDUP:
00161         o << " f1";
00162     }
00163     o << " m" << huberSigma;
00164 
00165     // options for photometric estimation.
00166     o << " p" << photometricHuberSigma;
00167     if (photometricSymmetricError) 
00168         o << " s1";
00169 
00170     o << std::endl;
00171 }
00172 
00173 void PanoramaOptions::setProjection(ProjectionFormat f)
00174 {
00175   // post new projection type
00176    if ((int) f >= panoProjectionFormatCount()) {
00177         // reset to equirect if this projection is not known
00178         f = EQUIRECTANGULAR;
00179     }
00180         m_projectionFormat = f;
00181 
00182         /* Load constant features of the new projection */
00183         panoProjectionFeaturesQuery(f, &m_projFeatures);
00184         /* post default projection parameters and corresponding FOV limits */
00185     m_projectionParams.resize(m_projFeatures.numberOfParameters);
00186     // reset projection parameters to default, determine also new fov limits, clip current fovs...
00187     resetProjectionParameters();
00188 }
00189 
00190 
00191 void PanoramaOptions::setProjectionParameters(const std::vector<double> & params)
00192 {
00193     assert(m_projFeatures.numberOfParameters == (int) params.size());
00194     // check if the parameters are good.
00195     if (m_projFeatures.numberOfParameters == (int) params.size()) {
00196         m_projectionParams = params;
00197         // enforce limits.
00198         for (size_t i=0; i < params.size(); i++) {
00199             if (m_projectionParams[i] > m_projFeatures.parm[i].maxValue) {
00200                 m_projectionParams[i] = m_projFeatures.parm[i].maxValue;
00201             }
00202             if (m_projectionParams[i] < m_projFeatures.parm[i].minValue) {
00203                 m_projectionParams[i] = m_projFeatures.parm[i].minValue;
00204             }
00205         }
00206     }
00207         /* get dynamic FOV limits corresponding to the new parameters,
00208            clip current fovs to those limits, and post the results
00209         */
00210     double parms[PANO_PROJECTION_MAX_PARMS];
00211         double fovs[2];
00212         int i;
00213         for( i = 0; i < m_projFeatures.numberOfParameters; i++){
00214                 parms[i] = m_projectionParams[i];
00215         }
00216         if( queryFOVLimits((int)m_projectionFormat, parms, fovs )){
00217                 m_projFeatures.maxHFOV = fovs[0];
00218                 m_projFeatures.maxVFOV = fovs[1];
00219         }
00220         setHFOV( m_hfov, false );
00221         setVFOV( getVFOV() );
00222 }
00223 
00224 void PanoramaOptions::resetProjectionParameters()
00225 {
00226     std::vector<double> defParam(m_projFeatures.numberOfParameters);
00227     for(int i = 0; i < m_projFeatures.numberOfParameters; i++)
00228     {
00229         defParam[i] = m_projFeatures.parm[i].defValue;
00230     };
00231     setProjectionParameters(defParam);
00232 };
00233 
00234 bool PanoramaOptions::fovCalcSupported(ProjectionFormat f) const
00235 {
00236     /* Ideally this attribute should come from libpano */
00237     return ( f == RECTILINEAR
00238              || f == CYLINDRICAL
00239              || f == EQUIRECTANGULAR
00240              || f == MERCATOR
00241              || f == SINUSOIDAL 
00242              || f == MILLER_CYLINDRICAL
00243              || f == PANINI
00244              || f == ARCHITECTURAL
00245              || f == EQUI_PANINI
00246                          || f == BIPLANE
00247                          || f == TRIPLANE
00248              || f == GENERAL_PANINI
00249                          );
00250 }
00251 
00252 
00253 void PanoramaOptions::setWidth(unsigned int w, bool keepView)
00254 {
00255     if (m_projectionFormat == EQUIRECTANGULAR || m_projectionFormat == SINUSOIDAL) {
00256         if (w%2 == 1) {
00257             w = w+1;
00258         }
00259     }
00260     bool nocrop =  (m_roi == vigra::Rect2D(m_size));
00261     double scale = w / (double) m_size.x;
00262     m_size.x = w;
00263     if (nocrop) {
00264         m_roi = vigra::Rect2D(m_size);
00265     } else {
00266         // for now, do a simple proportional scaling
00267         m_roi.setUpperLeft(vigra::Point2D(roundi(scale*m_roi.left()), m_roi.top()));
00268         m_roi.setLowerRight(vigra::Point2D(roundi(scale*m_roi.right()), m_roi.bottom()));
00269         // ensure ROI is inside the panorama
00270         m_roi &= vigra::Rect2D(m_size);
00271     }
00272 
00273     if (keepView) {
00274         m_size.y = hugin_utils::roundi(m_size.y*scale);
00275         if (nocrop) {
00276             m_roi = vigra::Rect2D(m_size);
00277         } else {
00278             m_roi.setUpperLeft(vigra::Point2D(m_roi.left(), roundi(scale*m_roi.top())));
00279             m_roi.setLowerRight(vigra::Point2D(m_roi.right(), roundi(scale*m_roi.bottom())));
00280             // ensure ROI is inside the panorama
00281             m_roi &= Rect2D(m_size);
00282         }
00283         if (fovCalcSupported(m_projectionFormat)) {
00284             if (getVFOV() > getMaxVFOV()) {
00285                 setVFOV(getMaxVFOV());
00286             }
00287         }
00288     }
00289 
00290     DEBUG_DEBUG(" HFOV: " << m_hfov << " size: " << m_size << " roi: " << m_roi << "  => vfov: " << getVFOV());
00291 }
00292 
00293 void PanoramaOptions::setHeight(unsigned int h) 
00294 {
00295     bool nocrop =  (m_roi == vigra::Rect2D(m_size));
00296 
00297     if (h == 0) {
00298         h = 1;
00299     }
00300     int dh = h - m_size.y;
00301     m_size.y = h;
00302     if (nocrop) {
00303         m_roi = vigra::Rect2D(m_size);
00304     } else {
00305         // move ROI
00306         m_roi.moveBy(0,dh/2);
00307         m_roi &= vigra::Rect2D(m_size);
00308     }
00309 
00310     DEBUG_DEBUG(" HFOV: " << m_hfov << " size: " << m_size << " roi:" << m_roi << "  => vfov: " << getVFOV() );
00311 }
00312 
00313 void PanoramaOptions::setHFOV(double h, bool keepView)
00314 {
00315     if (keepView && !fovCalcSupported(m_projectionFormat)) {
00316         DEBUG_NOTICE("Ignoring keepView");
00317         keepView = false;
00318     }
00319 
00320     if (h <= 0) {
00321         h = 1;
00322     }
00323     double vfov;
00324     if (keepView) {
00325         vfov = getVFOV();
00326     }
00327     m_hfov = std::min(h, getMaxHFOV());
00328     if (keepView) {
00329         setVFOV(std::min(vfov, getMaxVFOV()));
00330     }
00331 }
00332 
00333 void PanoramaOptions::setVFOV(double VFOV)
00334 {
00335     VFOV = std::min(VFOV, getMaxVFOV());
00336 
00337     if (! fovCalcSupported(m_projectionFormat)) {
00338         return;
00339     }
00340 
00341     bool nocrop =  (m_roi == vigra::Rect2D(m_size));
00342 
00343     if (VFOV <= 0) {
00344         VFOV = 1;
00345     }
00346     // TODO: create transform from equirect to target projection and
00347     // set additional
00348     PTools::Transform transf;
00349     SrcPanoImage src;
00350     src.setProjection(SrcPanoImage::EQUIRECTANGULAR);
00351     src.setHFOV(360);
00352     src.setSize(vigra::Size2D(360,180));
00353     transf.createInvTransform(src, *this);
00354 
00355     FDiff2D pmiddle;
00356 
00357     if (VFOV>180 && getMaxVFOV() > 180) {
00358         // we have crossed the pole
00359         transf.transform(pmiddle, FDiff2D(180, 180-VFOV/2 - 0.01));
00360     } else {
00361         transf.transform(pmiddle, FDiff2D(0, VFOV/2));
00362     }
00363     // try to keep the same ROI
00364     vigra::Size2D oldSize = m_size;
00365     m_size.y = abs(hugin_utils::roundi(2*pmiddle.y));
00366 
00367     if (nocrop) {
00368         m_roi = vigra::Rect2D(m_size);
00369     } else {
00370         // adjust ROI to stay in previous position
00371         int dh = m_size.y - oldSize.y;
00372         m_roi.moveBy(0, dh/2);
00373         // ensure ROI is visible
00374         m_roi &= vigra::Rect2D(m_size);
00375     }
00376 
00377     DEBUG_DEBUG(" HFOV: " << m_hfov << " size: " << m_size << " roi: " << m_roi << "  => vfov: " << VFOV);
00378 
00379 }
00380 
00381 double PanoramaOptions::getVFOV() const
00382 {
00383     // calcuale VFOV based on current panorama
00384     PTools::Transform transf;
00385     SrcPanoImage src;
00386     src.setProjection(SrcPanoImage::EQUIRECTANGULAR);
00387     src.setHFOV(360);
00388     src.setSize(vigra::Size2D(360,180));
00389     transf.createTransform(src, *this);
00390 
00391     FDiff2D pmiddle;
00392     FDiff2D pcorner;
00393     transf.transform(pmiddle, FDiff2D(0, m_size.y/2.0));
00394 //    transf.transform(pcorner, FDiff2D(m_size.x/2.0, m_size.y/2.0));
00395     double VFOV;
00396     if (pmiddle.x > 90 ||pmiddle.y < -90) {
00397         // the pole has been crossed
00398         VFOV = 2*(180-pmiddle.y);
00399     } else {
00400         VFOV = 2*pmiddle.y;
00401     }
00402     //double VFOV = 2.0*std::max(pcorner.y, pmiddle.y);
00403 
00404     /*
00405     double VFOV;
00406     switch (m_projectionFormat) {
00407         case PanoramaOptions::RECTILINEAR:
00408             VFOV = 2.0 * atan( (double)m_height * tan(DEG_TO_RAD(m_hfov)/2.0) / m_width);
00409             VFOV = RAD_TO_DEG(VFOV);
00410             break;
00411         case PanoramaOptions::CYLINDRICAL:
00412         {
00413             // equations: w = f * v (f: focal length, in pixel)
00414             double f = m_width / DEG_TO_RAD(m_hfov);
00415             VFOV = 2*atan(m_height/(2.0*f));
00416             VFOV = RAD_TO_DEG(VFOV);
00417             break;
00418         }
00419         case PanoramaOptions::EQUIRECTANGULAR:
00420             // FIXME: This is wrong!
00421         case TRANSVERSE_MERCATOR:
00422         case MERCATOR:
00423             VFOV = m_hfov * m_height / m_width;
00424             break;
00425         case PanoramaOptions::FULL_FRAME_FISHEYE:
00426             VFOV = m_hfov * m_height / m_width;
00427             break;
00428     }
00429     */
00430     DEBUG_DEBUG(" HFOV: " << m_hfov << " size: " << m_size << " roi: " << m_roi << "  => vfov: " << VFOV);
00431 
00432     return VFOV;
00433 }
00434 
00435 const std::string PanoramaOptions::fileformatNames[] =
00436 {
00437     "JPEG",
00438     "PNG",
00439     "TIFF",
00440     "TIFF_m",
00441     "TIFF_mask",
00442     "TIFF_multilayer",
00443     "TIFF_multilayer_mask",
00444     "PICT",
00445     "PSD",
00446     "PSD_m",
00447     "PSD_mask",
00448     "PAN",
00449     "IVR",
00450     "IVR_java",
00451     "VRML",
00452     "QTVR",
00453     "HDR",
00454     "HDR_m",
00455     "EXR",
00456     "EXR_m"
00457 };
00458 
00459 
00460 const std::string PanoramaOptions::fileformatExt[] =
00461 {
00462     "jpg",
00463     "png",
00464     "tif",
00465     "tif",
00466     "tif",
00467     "tif",
00468     "tif",
00469     "pict",
00470     "psd",
00471     "psd",
00472     "psd",
00473     "pan",
00474     "ivr",
00475     "IVR_java",
00476     "wrl",
00477     "mov",
00478     "hdr",
00479     "hdr",
00480     "exr",
00481     "exr"
00482 };
00483 
00484 
00485 
00486 
00487 
00488 } //namespace

Generated on Thu Sep 18 01:25:36 2014 for Hugintrunk by  doxygen 1.3.9.1