00001
00002
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029 #include <hugin_version.h>
00030
00031 #include <fstream>
00032 #include <sstream>
00033 #include <getopt.h>
00034 #ifndef WIN32
00035 #include <unistd.h>
00036 #endif
00037 #include <panodata/Panorama.h>
00038 #include <algorithms/nona/CenterHorizontally.h>
00039 #include <algorithms/basic/StraightenPanorama.h>
00040 #include <algorithms/basic/RotatePanorama.h>
00041 #include <algorithms/basic/TranslatePanorama.h>
00042 #include <algorithms/nona/FitPanorama.h>
00043 #include <algorithms/basic/CalculateOptimalScale.h>
00044 #include <algorithms/basic/CalculateOptimalROI.h>
00045 #include <algorithms/basic/LayerStacks.h>
00046
00047 using namespace std;
00048 using namespace HuginBase;
00049 using namespace AppBase;
00050
00051 static void usage(const char * name)
00052 {
00053 cout << name << ": change output parameters of project file" << endl
00054 << "pano_modify version " << DISPLAY_VERSION << endl
00055 << endl
00056 << "Usage: " << name << " [options] input.pto" << endl
00057 << endl
00058 << " Options:" << endl
00059 << " -o, --output=file.pto Output Hugin PTO file. Default: <filename>_mod.pto" << endl
00060 << " -p, --projection=x Sets the output projection to number x" << endl
00061 << " --fov=AUTO|HFOV|HFOVxVFOV Sets field of view" << endl
00062 << " AUTO: calculates optimal fov" << endl
00063 << " HFOV|HFOVxVFOV: set to given fov" << endl
00064 << " -s, --straighten Straightens the panorama" << endl
00065 << " -c, --center Centers the panorama" << endl
00066 << " --canvas=AUTO|num%|WIDTHxHEIGHT Sets the output canvas size" << endl
00067 << " AUTO: calculate optimal canvas size" << endl
00068 << " num%: scales the optimal size by given percent" << endl
00069 << " WIDTHxHEIGHT: set to given size" << endl
00070 << " --crop=AUTO|AUTOHDR|left,right,top,bottom Sets the crop rectangle" << endl
00071 << " AUTO: autocrop panorama" << endl
00072 << " AUTOHDR: autocrop HDR panorama" << endl
00073 << " left,right,top,bottom: to given size" << endl
00074 << " --rotate=yaw,pitch,roll Rotates the whole panorama with the given angles" << endl
00075 << " --translate=x,y,z Translate the whole panorama with the given values" << endl
00076 << " -h, --help Shows this help" << endl
00077 << endl;
00078 }
00079
00080
00081 inline char toupper_2(char c)
00082 {
00083 return toupper(c);
00084 }
00085
00087 std::string strToUpper(const std::string& aString)
00088 {
00089 std::string result(aString);
00090 std::transform(aString.begin(), aString.end(), result.begin(), toupper_2);
00091 return result;
00092 };
00093
00094 int main(int argc, char *argv[])
00095 {
00096
00097 const char * optstring = "o:p:sch";
00098
00099 enum
00100 {
00101 SWITCH_FOV=1000,
00102 SWITCH_CANVAS=1001,
00103 SWITCH_CROP=1002,
00104 SWITCH_ROTATE=1003,
00105 SWITCH_TRANSLATE=1004
00106 };
00107 static struct option longOptions[] = {
00108 {"output", required_argument, NULL, 'o' },
00109 {"projection", required_argument, NULL, 'p' },
00110 {"fov", optional_argument, NULL, SWITCH_FOV },
00111 {"straighten", no_argument, NULL, 's' },
00112 {"center", no_argument, NULL, 'c' },
00113 {"canvas", optional_argument, NULL, SWITCH_CANVAS },
00114 {"crop", optional_argument, NULL, SWITCH_CROP },
00115 {"rotate", required_argument, NULL, SWITCH_ROTATE },
00116 {"translate", required_argument, NULL, SWITCH_TRANSLATE },
00117 {"help", no_argument, NULL, 'h' },
00118 0
00119 };
00120
00121 int projection=-1;
00122 double newHFOV=-1;
00123 double newVFOV=-1;
00124 int scale=100;
00125 int newWidth=-1;
00126 int newHeight=-1;
00127 vigra::Rect2D newROI(0,0,0,0);
00128 bool doFit=false;
00129 bool doStraighten=false;
00130 bool doCenter=false;
00131 bool doOptimalSize=false;
00132 bool doAutocrop=false;
00133 bool autocropHDR=false;
00134 int c;
00135 int optionIndex = 0;
00136 double yaw = 0;
00137 double pitch = 0;
00138 double roll = 0;
00139 double x = 0;
00140 double y = 0;
00141 double z = 0;
00142 string output;
00143 string param;
00144 while ((c = getopt_long (argc, argv, optstring, longOptions,&optionIndex)) != -1)
00145 {
00146 switch (c)
00147 {
00148 case 'o':
00149 output = optarg;
00150 break;
00151 case 'h':
00152 usage(argv[0]);
00153 return 0;
00154 case 'p':
00155
00156 projection=atoi(optarg);
00157 if((projection==0) && (strcmp(optarg,"0")!=0))
00158 {
00159 cerr << "Could not parse projection number.";
00160 return 1;
00161 };
00162 if(projection>=panoProjectionFormatCount())
00163 {
00164 cerr << "projection " << projection << " is an invalid projection number.";
00165 return 1;
00166 };
00167 break;
00168 case SWITCH_FOV:
00169
00170 param=optarg;
00171 param=strToUpper(param);
00172 if(param=="AUTO")
00173 {
00174 doFit=true;
00175 }
00176 else
00177 {
00178 int hfov, vfov;
00179 int n=sscanf(optarg, "%dx%d", &hfov, &vfov);
00180 if(n==1)
00181 {
00182 if(hfov>0)
00183 {
00184 newHFOV=hfov;
00185 }
00186 else
00187 {
00188 cerr << "Invalid field of view" << endl;
00189 return 1;
00190 };
00191 }
00192 else
00193 {
00194 if (n==2)
00195 {
00196 if(hfov>0 && vfov>0)
00197 {
00198 newHFOV=hfov;
00199 newVFOV=vfov;
00200 }
00201 else
00202 {
00203 cerr << "Invalid field of view" << endl;
00204 return 1;
00205 };
00206 }
00207 else
00208 {
00209 cerr << "Could not parse field of view" << endl;
00210 return 1;
00211 };
00212 };
00213 };
00214 break;
00215 case 's':
00216 doStraighten=true;
00217 break;
00218 case 'c':
00219 doCenter=true;
00220 break;
00221 case SWITCH_CANVAS:
00222
00223 param=optarg;
00224 param=strToUpper(param);
00225 if(param=="AUTO")
00226 {
00227 doOptimalSize=true;
00228 }
00229 else
00230 {
00231 int pos=param.find("%");
00232 if(pos!=string::npos)
00233 {
00234 param=param.substr(0,pos);
00235 scale=atoi(param.c_str());
00236 if(scale==0)
00237 {
00238 cerr << "No valid scale factor given." << endl;
00239 return 1;
00240 };
00241 doOptimalSize=true;
00242 }
00243 else
00244 {
00245 int width, height;
00246 int n=sscanf(optarg, "%dx%d", &width, &height);
00247 if (n==2)
00248 {
00249 if(width>0 && height>0)
00250 {
00251 newWidth=width;
00252 newHeight=height;
00253 }
00254 else
00255 {
00256 cerr << "Invalid canvas size" << endl;
00257 return 1;
00258 };
00259 }
00260 else
00261 {
00262 cerr << "Could not parse canvas size" << endl;
00263 return 1;
00264 };
00265 };
00266 };
00267 break;
00268 case SWITCH_CROP:
00269
00270 param=optarg;
00271 param=strToUpper(param);
00272 if(param=="AUTO" || param=="AUTOHDR")
00273 {
00274 doAutocrop=true;
00275 if(param=="AUTOHDR")
00276 {
00277 autocropHDR=true;
00278 };
00279 }
00280 else
00281 {
00282 int left, right, top, bottom;
00283 int n=sscanf(optarg, "%d,%d,%d,%d", &left, &right, &top, &bottom);
00284 if (n==4)
00285 {
00286 if(right>left && bottom>top && left>=0 && top>=0)
00287 {
00288 newROI.setUpperLeft(vigra::Point2D(left,top));
00289 newROI.setLowerRight(vigra::Point2D(right,bottom));
00290 }
00291 else
00292 {
00293 cerr << "Invalid crop area" << endl;
00294 return 1;
00295 };
00296 }
00297 else
00298 {
00299 cerr << "Could not parse crop values" << endl;
00300 return 1;
00301 };
00302 };
00303 break;
00304 case SWITCH_ROTATE:
00305 {
00306 int n=sscanf(optarg, "%lf,%lf,%lf", &yaw, &pitch, &roll);
00307 if(n!=3)
00308 {
00309 cerr << "Could not parse rotate angles values. Given: \"" << optarg << "\"" << endl;
00310 return 1;
00311 };
00312 };
00313 break;
00314 case SWITCH_TRANSLATE:
00315 {
00316 int n=sscanf(optarg, "%lf,%lf,%lf", &x, &y, &z);
00317 if(n!=3)
00318 {
00319 cerr << "Could not parse translation values. Given: \"" << optarg << "\"" << endl;
00320 return 1;
00321 };
00322 };
00323 break;
00324 case ':':
00325 cerr <<"Option " << longOptions[optionIndex].name << " requires a number" << endl;
00326 return 1;
00327 break;
00328 case '?':
00329 break;
00330 default:
00331 abort ();
00332 }
00333 }
00334
00335 if (argc - optind != 1)
00336 {
00337 cout << "Warning: pano_modify can only work on one project file at one time" << endl << endl;
00338 usage(argv[0]);
00339 return 1;
00340 };
00341
00342
00343 if(doStraighten)
00344 {
00345 doCenter=false;
00346 doFit=true;
00347 };
00348 if(doCenter)
00349 {
00350 doFit=true;
00351 };
00352
00353 string input=argv[optind];
00354
00355 Panorama pano;
00356 ifstream prjfile(input.c_str());
00357 if (!prjfile.good()) {
00358 cerr << "could not open script : " << input << endl;
00359 return 1;
00360 }
00361 pano.setFilePrefix(hugin_utils::getPathPrefix(input));
00362 DocumentData::ReadWriteError err = pano.readData(prjfile);
00363 if (err != DocumentData::SUCCESSFUL) {
00364 cerr << "error while parsing panos tool script: " << input << endl;
00365 cerr << "DocumentData::ReadWriteError code: " << err << endl;
00366 return 1;
00367 }
00368
00369
00370 if(projection!=-1)
00371 {
00372 PanoramaOptions opt=pano.getOptions();
00373 opt.setProjection((PanoramaOptions::ProjectionFormat)projection);
00374 pano_projection_features proj;
00375 if (panoProjectionFeaturesQuery(projection, &proj))
00376 cout << "Setting projection to " << proj.name << endl;
00377 pano.setOptions(opt);
00378 };
00379 if(abs(yaw) + abs(pitch) + abs(roll) > 0.0)
00380 {
00381 cout << "Rotate panorama (yaw=" << yaw << ", pitch= " << pitch << ", roll=" << roll << ")" << endl;
00382 RotatePanorama(pano, yaw, pitch, roll).run();
00383 };
00384 if(abs(x) + abs(y) + abs(z) > 0.0)
00385 {
00386 cout << "Translate panorama (x=" << x << ", y=" << y << ", z=" << z << ")" << endl;
00387 TranslatePanorama(pano, x, y, z).run();
00388 };
00389
00390 if(doStraighten)
00391 {
00392 cout << "Straighten panorama" << endl;
00393 StraightenPanorama(pano).run();
00394 CenterHorizontally(pano).run();
00395 };
00396
00397 if(doCenter)
00398 {
00399 cout << "Center panorama" << endl;
00400 CenterHorizontally(pano).run();
00401 }
00402
00403 if(doFit)
00404 {
00405 cout << "Fit panorama field of view to best size" << endl;
00406 PanoramaOptions opt=pano.getOptions();
00407 CalculateFitPanorama fitPano = CalculateFitPanorama(pano);
00408 fitPano.run();
00409 opt.setHFOV(fitPano.getResultHorizontalFOV());
00410 opt.setHeight(roundi(fitPano.getResultHeight()));
00411 cout << "Setting field of view to " << opt.getHFOV() << " x " << opt.getVFOV() << endl;
00412 pano.setOptions(opt);
00413 };
00414
00415 if(newHFOV>0)
00416 {
00417 PanoramaOptions opt=pano.getOptions();
00418 opt.setHFOV(newHFOV);
00419 if(opt.fovCalcSupported(opt.getProjection()) && newVFOV>0)
00420 opt.setVFOV(newVFOV);
00421 cout << "Setting field of view to " << opt.getHFOV() << " x " << opt.getVFOV() << endl;
00422 pano.setOptions(opt);
00423 };
00424
00425 if(doOptimalSize)
00426 {
00427 cout << "Calculate optimal size of panorama" << endl;
00428 double s = CalculateOptimalScale::calcOptimalScale(pano);
00429 PanoramaOptions opt=pano.getOptions();
00430 opt.setWidth(roundi(opt.getWidth()*s*scale/100), true);
00431 cout << "Setting canvas size to " << opt.getWidth() << " x " << opt.getHeight() << endl;
00432 pano.setOptions(opt);
00433 };
00434
00435 if(newWidth>0 && newHeight>0)
00436 {
00437 PanoramaOptions opt=pano.getOptions();
00438 opt.setWidth(newWidth);
00439 opt.setHeight(newHeight);
00440 cout << "Setting canvas size to " << opt.getWidth() << " x " << opt.getHeight() << endl;
00441 pano.setOptions(opt);
00442 };
00443
00444 if(doAutocrop)
00445 {
00446 cout << "Searching for best crop rectangle" << endl;
00447 CalculateOptimalROI cropPano(pano);
00448 if(autocropHDR)
00449 {
00450 cropPano.setStacks(getHDRStacks(pano,pano.getActiveImages(), pano.getOptions()));
00451 }
00452 cropPano.run();
00453
00454 vigra::Rect2D roi=cropPano.getResultOptimalROI();
00455 PanoramaOptions opt = pano.getOptions();
00456
00457 if(roi.right() != 0 && roi.bottom() != 0)
00458 {
00459 opt.setROI(roi);
00460 cout << "Set crop size to " << roi.left() << "," << roi.top() << "," << roi.right() << "," << roi.bottom() << endl;
00461 pano.setOptions(opt);
00462 }
00463 else
00464 cout << "Could not find best crop rectangle" << endl;
00465 };
00466
00467 if(newROI.right() != 0 && newROI.bottom() != 0)
00468 {
00469 PanoramaOptions opt = pano.getOptions();
00470 opt.setROI(newROI);
00471 cout << "Set crop size to " << newROI.left() << "," << newROI.right() << "," << newROI.top() << "," << newROI.bottom() << endl;
00472 pano.setOptions(opt);
00473 };
00474
00475
00476 OptimizeVector optvec = pano.getOptimizeVector();
00477 UIntSet imgs;
00478 fill_set(imgs,0, pano.getNrOfImages()-1);
00479
00480 if (output=="")
00481 {
00482 output=input.substr(0,input.length()-4).append("_mod.pto");
00483 }
00484 ofstream of(output.c_str());
00485 pano.printPanoramaScript(of, optvec, pano.getOptions(), imgs, false, hugin_utils::getPathPrefix(input));
00486
00487 cout << endl << "Written output to " << output << endl;
00488 return 0;
00489 }