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

Generated on 4 Dec 2016 for Hugintrunk by  doxygen 1.4.7