added scaling of images before seam estimation (opencv_stitching)
authorAlexey Spizhevoy <no@email>
Mon, 23 May 2011 07:10:48 +0000 (07:10 +0000)
committerAlexey Spizhevoy <no@email>
Mon, 23 May 2011 07:10:48 +0000 (07:10 +0000)
modules/stitching/main.cpp

index d5ea7dd..72e54ba 100644 (file)
@@ -15,8 +15,9 @@ void printUsage()
     cout << "Usage: opencv_stitching img1 img2 [...imgN]\n" \r
         << "\t[--trygpu (yes|no)]\n"\r
         << "\t[--work_megapix <float>]\n"\r
+        << "\t[--seam_megapix <float>]\n"\r
         << "\t[--compose_megapix <float>]\n"\r
-        << "\t[--matchconf <float>]\n"\r
+        << "\t[--match_conf <float>]\n"\r
         << "\t[--ba (ray|focal_ray)]\n"\r
         << "\t[--conf_thresh <float>]\n"\r
         << "\t[--wavecorrect (no|yes)]\n"\r
@@ -25,7 +26,7 @@ void printUsage()
         << "\t[--blend (no|feather|multiband)]\n"\r
         << "\t[--numbands <int>]\n"\r
         << "\t[--output <result_img>]\n\n";\r
-    cout << "--matchconf\n"\r
+    cout << "--match_conf\n"\r
         << "\tGood values are in [0.2, 0.8] range usually.\n\n";\r
     cout << "HINT:\n"  \r
         << "\tDefault parameters are for '--trygpu no' configuration.\n"\r
@@ -33,10 +34,11 @@ void printUsage()
 }\r
 \r
 \r
-// Command line args\r
+// Default command line args\r
 vector<string> img_names;\r
 bool trygpu = false;\r
-double work_megapix = 0.2;\r
+double work_megapix = 0.3;\r
+double seam_megapix = 0.1;\r
 double compose_megapix = 1;\r
 int ba_space = BundleAdjuster::FOCAL_RAY_SPACE;\r
 float conf_thresh = 1.f;\r
@@ -59,15 +61,6 @@ int parseCmdArgs(int argc, char** argv)
 \r
     for (int i = 1; i < argc; ++i)\r
     {\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
@@ -82,7 +75,15 @@ int parseCmdArgs(int argc, char** argv)
             i++;\r
         }\r
         else if (string(argv[i]) == "--work_megapix") \r
+        {\r
+            work_megapix = atof(argv[i + 1]);\r
+            i++; \r
+        }\r
+        else if (string(argv[i]) == "--seam_megapix") \r
+        {\r
+            seam_megapix = atof(argv[i + 1]);\r
             i++; \r
+        }\r
         else if (string(argv[i]) == "--compose_megapix") \r
         {\r
             compose_megapix = atof(argv[i + 1]);\r
@@ -93,7 +94,7 @@ int parseCmdArgs(int argc, char** argv)
             result_name = argv[i + 1];\r
             i++;\r
         }\r
-        else if (string(argv[i]) == "--matchconf")\r
+        else if (string(argv[i]) == "--match_conf")\r
         {\r
             user_match_conf = true;\r
             match_conf = static_cast<float>(atof(argv[i + 1]));\r
@@ -205,30 +206,37 @@ int main(int argc, char* argv[])
     int num_images = static_cast<int>(img_names.size());\r
     if (num_images < 2)\r
     {\r
-        cout << "Need more images\n";\r
+        LOGLN("Need more images");\r
         return -1;\r
     }\r
 \r
-    // We do all matching in work_scale sclae, and compositing in compose_scale scale\r
-    double work_scale = 1, compose_scale = 1;\r
-    bool is_work_scale_set = false, is_compose_scale_set = false;\r
+    double work_scale = 1, seam_scale = 1, compose_scale = 1;\r
+    bool is_work_scale_set = false, is_seam_scale_set = false, is_compose_scale_set = false;\r
 \r
     LOGLN("Reading images and finding features...");\r
     int64 t = getTickCount();\r
-    vector<Mat> images(num_images);\r
+\r
     vector<ImageFeatures> features(num_images);\r
     SurfFeaturesFinder finder(trygpu);\r
     Mat full_img, img;\r
+\r
+    vector<Mat> images(num_images);\r
+    double seam_work_aspect = 1;\r
+\r
     for (int i = 0; i < num_images; ++i)\r
     {\r
         full_img = imread(img_names[i]);\r
         if (full_img.empty())\r
         {\r
-            cout << "Can't open image " << img_names[i] << endl;\r
+            LOGLN("Can't open image " << img_names[i]);\r
             return -1;\r
         }\r
         if (work_megapix < 0)\r
+        {\r
             img = full_img;\r
+            work_scale = 1;\r
+            is_work_scale_set = true;\r
+        }\r
         else\r
         {\r
             if (!is_work_scale_set)\r
@@ -238,11 +246,23 @@ int main(int argc, char* argv[])
             }\r
             resize(full_img, img, Size(), work_scale, work_scale);\r
         }\r
-        images[i] = img.clone();\r
+        if (!is_seam_scale_set)\r
+        {\r
+            seam_scale = min(1.0, sqrt(seam_megapix * 1e6 / full_img.size().area()));                    \r
+            seam_work_aspect = seam_scale / work_scale;\r
+            is_seam_scale_set = true;\r
+        }\r
+\r
         finder(img, features[i]);\r
+        LOGLN("Features in image #" << i << ": " << features[i].keypoints.size());\r
+\r
+        resize(full_img, img, Size(), seam_scale, seam_scale);\r
+        images[i] = img.clone();\r
     }\r
+\r
     full_img.release();\r
     img.release();\r
+\r
     LOGLN("Reading images and finding features, time: " << ((getTickCount() - t) / getTickFrequency()) << " sec");\r
 \r
     LOGLN("Pairwise matching... ");\r
@@ -259,18 +279,14 @@ int main(int argc, char* argv[])
     vector<Mat> img_subset;\r
     vector<string> img_names_subset;\r
     for (size_t i = 0; i < indices.size(); ++i)\r
-    {\r
-        img_subset.push_back(images[indices[i]]);\r
         img_names_subset.push_back(img_names[indices[i]]);\r
-    }\r
-    images = img_subset;\r
     img_names = img_names_subset;\r
 \r
     // Check if we still have enough images\r
     num_images = static_cast<int>(img_names.size());\r
     if (num_images < 2)\r
     {\r
-        cout << "Need more images\n";\r
+        LOGLN("Need more images");\r
         return -1;\r
     }\r
 \r
@@ -327,7 +343,7 @@ int main(int argc, char* argv[])
     vector<Size> sizes(num_images);\r
     vector<Mat> masks(num_images);\r
 \r
-    // Preapre original images masks\r
+    // Preapre images masks\r
     for (int i = 0; i < num_images; ++i)\r
     {\r
         masks[i].create(images[i].size(), CV_8U);\r
@@ -335,14 +351,15 @@ int main(int argc, char* argv[])
     }\r
 \r
     // Warp images and their masks\r
-    Ptr<Warper> warper = Warper::createByCameraFocal(camera_focal, warp_type);\r
+    Ptr<Warper> warper = Warper::createByCameraFocal(static_cast<float>(camera_focal * seam_work_aspect), \r
+                                                     warp_type);\r
     for (int i = 0; i < num_images; ++i)\r
     {\r
-        corners[i] = warper->warp(images[i], static_cast<float>(cameras[i].focal), cameras[i].R\r
-                                  images_warped[i]);\r
+        corners[i] = warper->warp(images[i], static_cast<float>(cameras[i].focal * seam_work_aspect)\r
+                                  cameras[i].R, images_warped[i]);\r
         sizes[i] = images_warped[i].size();\r
-        warper->warp(masks[i], static_cast<float>(cameras[i].focal), cameras[i].R, masks_warped[i]\r
-                     INTER_NEAREST, BORDER_CONSTANT);\r
+        warper->warp(masks[i], static_cast<float>(cameras[i].focal * seam_work_aspect)\r
+                     cameras[i].R, masks_warped[i], INTER_NEAREST, BORDER_CONSTANT);\r
     }\r
 \r
     // Convert to float for blending\r
@@ -373,7 +390,8 @@ int main(int argc, char* argv[])
     Mat img_warped, img_warped_f;\r
     Mat dilated_mask, seam_mask, mask, mask_warped;\r
     Ptr<Blender> blender;\r
-    double compose_aspect = 1;\r
+    double compose_seam_aspect = 1;\r
+    double compose_work_aspect = 1;\r
 \r
     for (int img_idx = 0; img_idx < num_images; ++img_idx)\r
     {\r
@@ -386,8 +404,9 @@ int main(int argc, char* argv[])
             if (compose_megapix > 0)\r
                 compose_scale = min(1.0, sqrt(compose_megapix * 1e6 / full_img.size().area()));\r
             is_compose_scale_set = true;\r
-            compose_aspect = compose_scale / work_scale;\r
-            camera_focal *= static_cast<float>(compose_aspect);\r
+            compose_seam_aspect = compose_scale / seam_scale;\r
+            compose_work_aspect = compose_scale / work_scale;\r
+            camera_focal *= static_cast<float>(compose_work_aspect);\r
             warper = Warper::createByCameraFocal(camera_focal, warp_type);\r
         }\r
         if (abs(compose_scale - 1) > 1e-1)\r
@@ -397,7 +416,7 @@ int main(int argc, char* argv[])
         full_img.release();\r
 \r
         // Update cameras paramters\r
-        cameras[img_idx].focal *= compose_aspect;\r
+        cameras[img_idx].focal *= compose_work_aspect;\r
 \r
         // Warp the current image\r
         warper->warp(img, static_cast<float>(cameras[img_idx].focal), cameras[img_idx].R, \r
@@ -429,9 +448,9 @@ int main(int argc, char* argv[])
             Rect dst_roi = resultRoi(corners, sizes);\r
             for (int i = 0; i < num_images; ++i)\r
             {\r
-                corners[i] = dst_roi.tl() + (corners[i] - dst_roi.tl()) * compose_aspect;\r
-                sizes[i] = Size(static_cast<int>((sizes[i].width + 1) * compose_aspect), \r
-                                static_cast<int>((sizes[i].height + 1) * compose_aspect));\r
+                corners[i] = dst_roi.tl() + (corners[i] - dst_roi.tl()) * compose_seam_aspect;\r
+                sizes[i] = Size(static_cast<int>((sizes[i].width + 1) * compose_seam_aspect), \r
+                                static_cast<int>((sizes[i].height + 1) * compose_seam_aspect));\r
             }\r
             blender->prepare(corners, sizes);\r
         }\r