{\r
cout << "Rotation model images stitcher.\n\n";\r
cout << "Usage: opencv_stitching img1 img2 [...imgN]\n" \r
+ << "\t[--trygpu (yes|no)]\n"\r
+ << "\t[--work_megapix <float>]\n"\r
+ << "\t[--compose_megapix <float>]\n"\r
<< "\t[--matchconf <float>]\n"\r
<< "\t[--ba (ray|focal_ray)]\n"\r
<< "\t[--conf_thresh <float>]\n"\r
<< "\t[--output <result_img>]\n\n";\r
cout << "--matchconf\n"\r
<< "\tGood values are in [0.2, 0.8] range usually.\n\n";\r
- cout << "--conf_thresh\n"\r
- << "\tGood values are in [0.3, 1.0] range usually.\n";\r
}\r
\r
int main(int argc, char* argv[])\r
{\r
cv::setBreakOnError(true);\r
\r
+ vector<string> img_names;\r
vector<Mat> images;\r
- string result_name = "result.png";\r
+ bool trygpu = true;\r
+ double work_megapix = -1;\r
+ double compose_megapix = -1;\r
int ba_space = BundleAdjuster::FOCAL_RAY_SPACE;\r
float conf_thresh = 1.f;\r
bool wave_correct = true;\r
float match_conf = 0.55f;\r
int seam_find_type = SeamFinder::VORONOI;\r
int blend_type = Blender::MULTI_BAND;\r
+ string result_name = "result.png";\r
+\r
+ double work_scale = 1, compose_scale = 1;\r
+ bool is_work_scale_set = false, is_compose_scale_set = true;\r
\r
if (argc == 1)\r
{\r
\r
for (int i = 1; i < argc; ++i)\r
{\r
- if (string(argv[i]) == "--result")\r
+ if (string(argv[i]) == "--work_megapix")\r
+ {\r
+ work_megapix = atof(argv[i + 1]);\r
+ break;\r
+ }\r
+ }\r
+\r
+ for (int i = 1; i < argc; ++i)\r
+ {\r
+ if (string(argv[i]) == "--trygpu")\r
+ {\r
+ if (string(argv[i + 1]) == "no")\r
+ trygpu = false;\r
+ else if (string(argv[i + 1]) == "yes")\r
+ trygpu = true;\r
+ else\r
+ {\r
+ cout << "Bad --trygpu flag value\n";\r
+ return -1;\r
+ }\r
+ i++;\r
+ }\r
+ else if (string(argv[i]) == "--work_megapix") \r
+ i++; \r
+ else if (string(argv[i]) == "--compose_megapix") \r
+ {\r
+ compose_megapix = atof(argv[i + 1]);\r
+ is_compose_scale_set = false;\r
+ i++; \r
+ }\r
+ else if (string(argv[i]) == "--result")\r
{\r
result_name = argv[i + 1];\r
i++;\r
wave_correct = true;\r
else\r
{\r
- cout << "Bad wave correct flag value\n";\r
+ cout << "Bad --wavecorrect flag value\n";\r
return -1;\r
}\r
i++;\r
}\r
else\r
{\r
- Mat img = imread(argv[i]);\r
- if (img.empty())\r
+ img_names.push_back(argv[i]);\r
+ Mat full_img = imread(argv[i]);\r
+ if (full_img.empty())\r
{\r
cout << "Can't open image " << argv[i] << endl;\r
return -1;\r
}\r
- images.push_back(img);\r
+ if (work_megapix < 0)\r
+ images.push_back(full_img);\r
+ else\r
+ {\r
+ if (!is_work_scale_set)\r
+ {\r
+ work_scale = min(1.0, sqrt(work_megapix * 1000000 / full_img.size().area())); \r
+ is_work_scale_set = true;\r
+ }\r
+ Mat img;\r
+ resize(full_img, img, Size(), work_scale, work_scale);\r
+ images.push_back(img);\r
+ }\r
}\r
}\r
\r
\r
LOGLN("Finding features...");\r
vector<ImageFeatures> features;\r
- SurfFeaturesFinder finder;\r
+ SurfFeaturesFinder finder(trygpu);\r
finder(images, features);\r
\r
LOGLN("Pairwise matching...");\r
vector<MatchesInfo> pairwise_matches;\r
- BestOf2NearestMatcher matcher;\r
+ BestOf2NearestMatcher matcher(trygpu);\r
if (user_match_conf)\r
matcher = BestOf2NearestMatcher(true, match_conf);\r
matcher(images, features, pairwise_matches);\r
\r
leaveBiggestComponent(images, features, pairwise_matches, conf_thresh);\r
+\r
num_images = static_cast<int>(images.size());\r
+ if (num_images < 2)\r
+ {\r
+ cout << "Need more images\n";\r
+ return -1;\r
+ }\r
\r
LOGLN("Estimating rotations...");\r
HomographyBasedEstimator estimator;\r
nth_element(focals.begin(), focals.end(), focals.begin() + focals.size() / 2);\r
float camera_focal = static_cast<float>(focals[focals.size() / 2]);\r
\r
+ if (work_megapix > 0 || compose_megapix > 0)\r
+ {\r
+ for (int i = 0; i < num_images; ++i)\r
+ {\r
+ Mat full_img = imread(img_names[i]);\r
+ if (!is_compose_scale_set)\r
+ {\r
+ compose_scale = min(1.0, sqrt(compose_megapix * 1000000 / full_img.size().area())); \r
+ is_compose_scale_set = true;\r
+ }\r
+ Mat img;\r
+ resize(full_img, img, Size(), compose_scale, compose_scale);\r
+ images[i] = img;\r
+ cameras[i].focal *= compose_scale / work_scale;\r
+ }\r
+ camera_focal *= static_cast<float>(compose_scale / work_scale);\r
+ }\r
+\r
vector<Mat> masks(num_images);\r
for (int i = 0; i < num_images; ++i)\r
{\r
LOGLN("Finished");\r
return 0;\r
}\r
+\r
}
}
-SurfFeaturesFinder::SurfFeaturesFinder(bool gpu_hint, double hess_thresh, int num_octaves, int num_layers,
+SurfFeaturesFinder::SurfFeaturesFinder(bool try_use_gpu, double hess_thresh, int num_octaves, int num_layers,
int num_octaves_descr, int num_layers_descr)
{
- if (gpu_hint && getCudaEnabledDeviceCount() > 0)
+ if (try_use_gpu && getCudaEnabledDeviceCount() > 0)
impl_ = new GpuSurfFeaturesFinder(hess_thresh, num_octaves, num_layers, num_octaves_descr, num_layers_descr);
else
impl_ = new CpuSurfFeaturesFinder(hess_thresh, num_octaves, num_layers, num_octaves_descr, num_layers_descr);
}
}
-BestOf2NearestMatcher::BestOf2NearestMatcher(bool gpu_hint, float match_conf, int num_matches_thresh1, int num_matches_thresh2)
+BestOf2NearestMatcher::BestOf2NearestMatcher(bool try_use_gpu, float match_conf, int num_matches_thresh1, int num_matches_thresh2)
{
- if (gpu_hint && getCudaEnabledDeviceCount() > 0)
+ if (try_use_gpu && getCudaEnabledDeviceCount() > 0)
impl_ = new GpuMatcher(match_conf);
else
impl_ = new CpuMatcher(match_conf);