00001
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
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
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
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
00176 if ((int) f >= panoProjectionFormatCount()) {
00177
00178 f = EQUIRECTANGULAR;
00179 }
00180 m_projectionFormat = f;
00181
00182
00183 panoProjectionFeaturesQuery(f, &m_projFeatures);
00184
00185 m_projectionParams.resize(m_projFeatures.numberOfParameters);
00186
00187 resetProjectionParameters();
00188 }
00189
00190
00191 void PanoramaOptions::setProjectionParameters(const std::vector<double> & params)
00192 {
00193 assert(m_projFeatures.numberOfParameters == (int) params.size());
00194
00195 if (m_projFeatures.numberOfParameters == (int) params.size()) {
00196 m_projectionParams = params;
00197
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
00208
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
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
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
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
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
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
00347
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
00359 transf.transform(pmiddle, FDiff2D(180, 180-VFOV/2 - 0.01));
00360 } else {
00361 transf.transform(pmiddle, FDiff2D(0, VFOV/2));
00362 }
00363
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
00371 int dh = m_size.y - oldSize.y;
00372 m_roi.moveBy(0, dh/2);
00373
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
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
00395 double VFOV;
00396 if (pmiddle.x > 90 ||pmiddle.y < -90) {
00397
00398 VFOV = 2*(180-pmiddle.y);
00399 } else {
00400 VFOV = 2*pmiddle.y;
00401 }
00402
00403
00404
00405
00406
00407
00408
00409
00410
00411
00412
00413
00414
00415
00416
00417
00418
00419
00420
00421
00422
00423
00424
00425
00426
00427
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 }