added GC_COLOR_GRAD cost function type into opencv_stitching
authorAlexey Spizhevoy <no@email>
Fri, 27 May 2011 11:41:35 +0000 (11:41 +0000)
committerAlexey Spizhevoy <no@email>
Fri, 27 May 2011 11:41:35 +0000 (11:41 +0000)
modules/stitching/exposure_compensate.cpp
modules/stitching/exposure_compensate.hpp
modules/stitching/main.cpp
modules/stitching/matchers.cpp
modules/stitching/seam_finders.cpp
modules/stitching/seam_finders.hpp
modules/stitching/util_inl.hpp

index 040b6a8..d91d573 100644 (file)
@@ -45,6 +45,7 @@
 \r
 using namespace std;\r
 using namespace cv;\r
+using namespace cv::gpu;\r
 \r
 \r
 Ptr<ExposureCompensator> ExposureCompensator::createDefault(int type)\r
@@ -53,6 +54,8 @@ Ptr<ExposureCompensator> ExposureCompensator::createDefault(int type)
         return new NoExposureCompensator();
     if (type == OVERLAP)
         return new OverlapExposureCompensator();
+    if (type == SEGMENT)
+        return new SegmentExposureCompensator();
     CV_Error(CV_StsBadArg, "unsupported exposure compensation method");
     return NULL;\r
 }\r
@@ -61,13 +64,15 @@ Ptr<ExposureCompensator> ExposureCompensator::createDefault(int type)
 void OverlapExposureCompensator::feed(const vector<Point> &corners, const vector<Mat> &images, \r
                                       const vector<Mat> &masks)\r
 {\r
+    CV_Assert(corners.size() == images.size() && images.size() == masks.size());\r
+\r
     const int num_images = static_cast<int>(images.size());\r
     Mat_<int> N(num_images, num_images); N.setTo(0);\r
     Mat_<double> I(num_images, num_images); I.setTo(0);\r
 \r
     Rect dst_roi = resultRoi(corners, images);\r
     Mat subimg1, subimg2;\r
-    Mat_<uchar> submask1, submask2, overlap;\r
+    Mat_<uchar> submask1, submask2, intersect;\r
 \r
     for (int i = 0; i < num_images; ++i)\r
     {\r
@@ -81,9 +86,9 @@ void OverlapExposureCompensator::feed(const vector<Point> &corners, const vector
 \r
                 submask1 = masks[i](Rect(roi.tl() - corners[i], roi.br() - corners[i]));\r
                 submask2 = masks[j](Rect(roi.tl() - corners[j], roi.br() - corners[j]));\r
-                overlap = submask1 & submask2;\r
+                intersect = submask1 & submask2;\r
 \r
-                N(i, j) = N(j, i) = countNonZero(overlap);\r
+                N(i, j) = N(j, i) = countNonZero(intersect);\r
 \r
                 double Isum1 = 0, Isum2 = 0;\r
                 for (int y = 0; y < roi.height; ++y)\r
@@ -92,7 +97,7 @@ void OverlapExposureCompensator::feed(const vector<Point> &corners, const vector
                     const Point3_<uchar>* r2 = subimg2.ptr<Point3_<uchar> >(y);\r
                     for (int x = 0; x < roi.width; ++x)\r
                     {\r
-                        if (overlap(y, x))\r
+                        if (intersect(y, x))\r
                         {\r
                             Isum1 += sqrt(static_cast<double>(sqr(r1[x].x) + sqr(r1[x].y) + sqr(r1[x].z)));\r
                             Isum2 += sqrt(static_cast<double>(sqr(r2[x].x) + sqr(r2[x].y) + sqr(r2[x].z)));\r
@@ -122,7 +127,7 @@ void OverlapExposureCompensator::feed(const vector<Point> &corners, const vector
         }\r
     }\r
 \r
-    solve(A, b, gains_, DECOMP_SVD);\r
+    solve(A, b, gains_);\r
 }\r
 \r
 \r
@@ -130,3 +135,14 @@ void OverlapExposureCompensator::apply(int index, Point /*corner*/, Mat &image,
 {\r
     image *= gains_(index, 0);\r
 }\r
+\r
+\r
+void SegmentExposureCompensator::feed(const vector<Point> &/*corners*/, const vector<Mat> &/*images*/, \r
+                                      const vector<Mat> &/*masks*/)\r
+{\r
+}\r
+\r
+\r
+void SegmentExposureCompensator::apply(int /*index*/, Point /*corner*/, Mat &/*image*/, const Mat &/*mask*/)\r
+{\r
+}
\ No newline at end of file
index 5aec7c7..5112bc5 100644 (file)
@@ -48,7 +48,7 @@
 class ExposureCompensator
 {
 public:
-    enum { NO, OVERLAP };
+    enum { NO, OVERLAP, SEGMENT };
     static cv::Ptr<ExposureCompensator> createDefault(int type);
 
     virtual void feed(const std::vector<cv::Point> &corners, const std::vector<cv::Mat> &images, 
@@ -78,4 +78,12 @@ private:
 };
 
 
+class SegmentExposureCompensator : public ExposureCompensator
+{
+public:
+    void feed(const std::vector<cv::Point> &corners, const std::vector<cv::Mat> &images, 
+              const std::vector<cv::Mat> &masks);
+    void apply(int index, cv::Point corner, cv::Mat &image, const cv::Mat &mask);
+};
+
 #endif // __OPENCV_EXPOSURE_COMPENSATE_HPP__
\ No newline at end of file
index 4f97eca..4c22fb8 100644 (file)
@@ -71,7 +71,7 @@ void printUsage()
         << "\t[--wavecorrect (no|yes)]\n"\r
         << "\t[--warp (plane|cylindrical|spherical)]\n" \r
         << "\t[--exposcomp (no|overlap)]\n"\r
-        << "\t[--seam (no|voronoi|graphcut)]\n" \r
+        << "\t[--seam (no|voronoi|gc_color|gc_colorgrad)]\n" \r
         << "\t[--blend (no|feather|multiband)]\n"\r
         << "\t[--numbands <int>]\n"\r
         << "\t[--output <result_img>]\n\n";\r
@@ -95,7 +95,7 @@ int warp_type = Warper::SPHERICAL;
 int expos_comp_type = ExposureCompensator::OVERLAP;\r
 bool user_match_conf = false;\r
 float match_conf = 0.6f;\r
-int seam_find_type = SeamFinder::GRAPH_CUT;\r
+int seam_find_type = SeamFinder::GC_COLOR;\r
 int blend_type = Blender::MULTI_BAND;\r
 int numbands = 5;\r
 string result_name = "result.png";\r
@@ -201,6 +201,8 @@ int parseCmdArgs(int argc, char** argv)
                 expos_comp_type = ExposureCompensator::NO;\r
             else if (string(argv[i + 1]) == "overlap")\r
                 expos_comp_type = ExposureCompensator::OVERLAP;\r
+            else if (string(argv[i + 1]) == "segment")\r
+                expos_comp_type = ExposureCompensator::SEGMENT;\r
             else\r
             {\r
                 cout << "Bad exposure compensation method\n";\r
@@ -214,8 +216,10 @@ int parseCmdArgs(int argc, char** argv)
                 seam_find_type = SeamFinder::NO;\r
             else if (string(argv[i + 1]) == "voronoi")\r
                 seam_find_type = SeamFinder::VORONOI;\r
-            else if (string(argv[i + 1]) == "graphcut")\r
-                seam_find_type = SeamFinder::GRAPH_CUT;\r
+            else if (string(argv[i + 1]) == "gc_color")\r
+                seam_find_type = SeamFinder::GC_COLOR;\r
+            else if (string(argv[i + 1]) == "gc_colorgrad")\r
+                seam_find_type = SeamFinder::GC_COLOR_GRAD;\r
             else\r
             {\r
                 cout << "Bad seam finding method\n";\r
index a6a8964..9301306 100644 (file)
@@ -65,8 +65,8 @@ namespace
     class CpuSurfFeaturesFinder : public FeaturesFinder
     {
     public:
-        inline CpuSurfFeaturesFinder(double hess_thresh, int num_octaves, int num_layers, 
-                                     int num_octaves_descr, int num_layers_descr) 
+        CpuSurfFeaturesFinder(double hess_thresh, int num_octaves, int num_layers, 
+                              int num_octaves_descr, int num_layers_descr) 
         {
             detector_ = new SurfFeatureDetector(hess_thresh, num_octaves, num_layers);
             extractor_ = new SurfDescriptorExtractor(num_octaves_descr, num_layers_descr);
@@ -80,20 +80,12 @@ namespace
         Ptr<DescriptorExtractor> extractor_;
     };
 
-    void CpuSurfFeaturesFinder::find(const Mat &image, ImageFeatures &features)
-    {
-        Mat gray_image;
-        CV_Assert(image.depth() == CV_8U);
-        cvtColor(image, gray_image, CV_BGR2GRAY);
-        detector_->detect(gray_image, features.keypoints);
-        extractor_->compute(gray_image, features.keypoints, features.descriptors);
-    }
-    
+
     class GpuSurfFeaturesFinder : public FeaturesFinder
     {
     public:
-        inline GpuSurfFeaturesFinder(double hess_thresh, int num_octaves, int num_layers, 
-                                     int num_octaves_descr, int num_layers_descr) 
+        GpuSurfFeaturesFinder(double hess_thresh, int num_octaves, int num_layers, 
+                              int num_octaves_descr, int num_layers_descr) 
         {
             surf_.keypointsRatio = 0.1f;
             surf_.hessianThreshold = hess_thresh;
@@ -113,6 +105,17 @@ namespace
         int num_octaves_descr_, num_layers_descr_;
     };
 
+
+    void CpuSurfFeaturesFinder::find(const Mat &image, ImageFeatures &features)
+    {
+        Mat gray_image;
+        CV_Assert(image.depth() == CV_8U);
+        cvtColor(image, gray_image, CV_BGR2GRAY);
+        detector_->detect(gray_image, features.keypoints);
+        extractor_->compute(gray_image, features.keypoints, features.descriptors);
+    }
+  
+
     void GpuSurfFeaturesFinder::find(const Mat &image, ImageFeatures &features)
     {
         GpuMat gray_image;
@@ -132,7 +135,8 @@ namespace
 
         d_descriptors.download(features.descriptors);
     }
-}
+} // anonymous namespace
+
 
 SurfFeaturesFinder::SurfFeaturesFinder(bool try_use_gpu, double hess_thresh, int num_octaves, int num_layers, 
                                        int num_octaves_descr, int num_layers_descr)
index 89f7394..c2eb8eb 100644 (file)
@@ -52,8 +52,10 @@ Ptr<SeamFinder> SeamFinder::createDefault(int type)
         return new NoSeamFinder();
     if (type == VORONOI)
         return new VoronoiSeamFinder();
-    if (type == GRAPH_CUT)
-        return new GraphCutSeamFinder();
+    if (type == GC_COLOR)
+        return new GraphCutSeamFinder(GraphCutSeamFinder::COST_COLOR);
+    if (type == GC_COLOR_GRAD)
+        return new GraphCutSeamFinder(GraphCutSeamFinder::COST_COLOR_GRAD);
     CV_Error(CV_StsBadArg, "unsupported seam finding method");
     return NULL;
 }
@@ -64,25 +66,33 @@ void PairwiseSeamFinder::find(const vector<Mat> &src, const vector<Point> &corne
 {
     if (src.size() == 0)
         return;
+
+    images_ = src;
+    corners_ = corners;
+    masks_ = masks;
+
     for (size_t i = 0; i < src.size() - 1; ++i)
     {
         for (size_t j = i + 1; j < src.size(); ++j)
         {
             Rect roi;
             if (overlapRoi(corners[i], corners[j], src[i].size(), src[j].size(), roi))
-                findInPair(src[i], src[j], corners[i], corners[j], roi, masks[i], masks[j]);
+                findInPair(i, j, roi);
         }
     }
 }
 
 
-void VoronoiSeamFinder::findInPair(const Mat &img1, const Mat &img2, Point tl1, Point tl2,
-                                   Rect roi, Mat &mask1, Mat &mask2)
+void VoronoiSeamFinder::findInPair(size_t first, size_t second, Rect roi)
 {
     const int gap = 10;
     Mat submask1(roi.height + 2 * gap, roi.width + 2 * gap, CV_8U);
     Mat submask2(roi.height + 2 * gap, roi.width + 2 * gap, CV_8U);
 
+    Mat img1 = images_[first], img2 = images_[second];
+    Mat mask1 = masks_[first], mask2 = masks_[second];
+    Point tl1 = corners_[first], tl2 = corners_[second];
+
     // Cut submasks with some gap
     for (int y = -gap; y < roi.height + gap; ++y)
     {
@@ -127,27 +137,62 @@ void VoronoiSeamFinder::findInPair(const Mat &img1, const Mat &img2, Point tl1,
 }
 
 
-class GraphCutSeamFinder::Impl
+class GraphCutSeamFinder::Impl : public PairwiseSeamFinder
 {
 public:
     Impl(int cost_type, float terminal_cost, float bad_region_penalty)
         : cost_type_(cost_type), terminal_cost_(terminal_cost), bad_region_penalty_(bad_region_penalty) {}
 
-    void findInPair(const Mat &img1, const Mat &img2, Point tl1, Point tl2,
-                    Rect roi, Mat &mask1, Mat &mask2);
+    void find(const vector<Mat> &src, const vector<Point> &corners, vector<Mat> &masks);
+    void findInPair(size_t first, size_t second, Rect roi);
 
 private:
-    void setGraphWeightsColor(const Mat &img1, const Mat &img2, const Mat &mask1, const Mat &mask2,
-                              GCGraph<float> &graph);
+    void setGraphWeightsColor(const Mat &img1, const Mat &img2, \r
+                              const Mat &mask1, const Mat &mask2, GCGraph<float> &graph);
+    void setGraphWeightsColorGrad(const Mat &img1, const Mat &img2, const Mat &dx1, const Mat &dx2, \r
+                                  const Mat &dy1, const Mat &dy2, const Mat &mask1, const Mat &mask2, 
+                                  GCGraph<float> &graph);
 
+    vector<Mat> dx_, dy_;
     int cost_type_;
     float terminal_cost_;
     float bad_region_penalty_;
 };
 
 
-void GraphCutSeamFinder::Impl::setGraphWeightsColor(const Mat &img1, const Mat &img2, const Mat &mask1, const Mat &mask2,
-                                                    GCGraph<float> &graph)
+void GraphCutSeamFinder::Impl::find(const vector<Mat> &src, const vector<Point> &corners, 
+                                    vector<Mat> &masks)
+{
+    // Compute gradients
+    dx_.resize(src.size());
+    dy_.resize(src.size());
+    Mat dx, dy;
+    for (size_t i = 0; i < src.size(); ++i)
+    {
+        CV_Assert(src[i].channels() == 3);
+        Sobel(src[i], dx, CV_32F, 1, 0);
+        Sobel(src[i], dy, CV_32F, 0, 1);
+        dx_[i].create(src[i].size(), CV_32F);
+        dy_[i].create(src[i].size(), CV_32F);
+        for (int y = 0; y < src[i].rows; ++y)
+        {
+            const Point3f* dx_row = dx.ptr<Point3f>(y);
+            const Point3f* dy_row = dy.ptr<Point3f>(y);
+            float* dx_row_ = dx_[i].ptr<float>(y);
+            float* dy_row_ = dy_[i].ptr<float>(y);
+            for (int x = 0; x < src[i].cols; ++x)
+            {
+                dx_row_[x] = normL2(dx_row[x]);
+                dy_row_[x] = normL2(dy_row[x]);
+            }
+        }
+    }
+    PairwiseSeamFinder::find(src, corners, masks);
+}
+
+
+void GraphCutSeamFinder::Impl::setGraphWeightsColor(const Mat &img1, const Mat &img2, \r
+                                                    const Mat &mask1, const Mat &mask2, GCGraph<float> &graph)
 {
     const Size img_size = img1.size();
 
@@ -162,9 +207,8 @@ void GraphCutSeamFinder::Impl::setGraphWeightsColor(const Mat &img1, const Mat &
         }
     }
 
-    const float weight_eps = 1e-3f;
-
     // Set regular edge weights
+    const float weight_eps = 1e-3f;
     for (int y = 0; y < img_size.height; ++y)
     {
         for (int x = 0; x < img_size.width; ++x)
@@ -175,11 +219,9 @@ void GraphCutSeamFinder::Impl::setGraphWeightsColor(const Mat &img1, const Mat &
                 float weight = normL2(img1.at<Point3f>(y, x), img2.at<Point3f>(y, x)) +
                                normL2(img1.at<Point3f>(y, x + 1), img2.at<Point3f>(y, x + 1)) +
                                weight_eps;
-
                 if (!mask1.at<uchar>(y, x) || !mask1.at<uchar>(y, x + 1) ||
                     !mask2.at<uchar>(y, x) || !mask2.at<uchar>(y, x + 1))
                     weight += bad_region_penalty_;
-
                 graph.addEdges(v, v + 1, weight, weight);
             }
             if (y < img_size.height - 1)
@@ -187,11 +229,63 @@ void GraphCutSeamFinder::Impl::setGraphWeightsColor(const Mat &img1, const Mat &
                 float weight = normL2(img1.at<Point3f>(y, x), img2.at<Point3f>(y, x)) +
                                normL2(img1.at<Point3f>(y + 1, x), img2.at<Point3f>(y + 1, x)) +
                                weight_eps;
-
                 if (!mask1.at<uchar>(y, x) || !mask1.at<uchar>(y + 1, x) ||
                     !mask2.at<uchar>(y, x) || !mask2.at<uchar>(y + 1, x))
                     weight += bad_region_penalty_;
+                graph.addEdges(v, v + img_size.width, weight, weight);
+            }
+        }
+    }
+}
+
+
+void GraphCutSeamFinder::Impl::setGraphWeightsColorGrad(\r
+        const Mat &img1, const Mat &img2, const Mat &dx1, const Mat &dx2, 
+        const Mat &dy1, const Mat &dy2, const Mat &mask1, const Mat &mask2, 
+        GCGraph<float> &graph)
+{
+    const Size img_size = img1.size();
+
+    // Set terminal weights
+    for (int y = 0; y < img_size.height; ++y)
+    {
+        for (int x = 0; x < img_size.width; ++x)
+        {
+            int v = graph.addVtx();
+            graph.addTermWeights(v, mask1.at<uchar>(y, x) ? terminal_cost_ : 0.f,
+                                    mask2.at<uchar>(y, x) ? terminal_cost_ : 0.f);
+        }
+    }
 
+    // Set regular edge weights
+    const float weight_eps = 1e-3f;
+    for (int y = 0; y < img_size.height; ++y)
+    {
+        for (int x = 0; x < img_size.width; ++x)
+        {
+            int v = y * img_size.width + x;
+            if (x < img_size.width - 1)
+            {
+                float grad = dx1.at<float>(y, x) + dx1.at<float>(y, x + 1) +\r
+                             dx2.at<float>(y, x) + dx2.at<float>(y, x + 1) + weight_eps;
+                float weight = (normL2(img1.at<Point3f>(y, x), img2.at<Point3f>(y, x)) +
+                                normL2(img1.at<Point3f>(y, x + 1), img2.at<Point3f>(y, x + 1))) / grad + 
+                               weight_eps;
+                if (!mask1.at<uchar>(y, x) || !mask1.at<uchar>(y, x + 1) ||
+                    !mask2.at<uchar>(y, x) || !mask2.at<uchar>(y, x + 1))
+                    weight += bad_region_penalty_;
+                graph.addEdges(v, v + 1, weight, weight);
+            }
+            if (y < img_size.height - 1)
+            {
+                float grad = dy1.at<float>(y, x) + dy1.at<float>(y + 1, x) + \r
+                             dy2.at<float>(y, x) + dy2.at<float>(y + 1, x) + weight_eps;
+                float weight = (normL2(img1.at<Point3f>(y, x), img2.at<Point3f>(y, x)) + 
+                                normL2(img1.at<Point3f>(y + 1, x), img2.at<Point3f>(y + 1, x))) / grad + 
+                               weight_eps;
+                if (!mask1.at<uchar>(y, x) || !mask1.at<uchar>(y + 1, x) ||
+                    !mask2.at<uchar>(y, x) || !mask2.at<uchar>(y + 1, x))
+                    weight += bad_region_penalty_;
                 graph.addEdges(v, v + img_size.width, weight, weight);
             }
         }
@@ -199,15 +293,23 @@ void GraphCutSeamFinder::Impl::setGraphWeightsColor(const Mat &img1, const Mat &
 }
 
 
-void GraphCutSeamFinder::Impl::findInPair(const Mat &img1, const Mat &img2, Point tl1, Point tl2,
-                                          Rect roi, Mat &mask1, Mat &mask2)
+void GraphCutSeamFinder::Impl::findInPair(size_t first, size_t second, Rect roi)
 {
-    const int gap = 10;
+    Mat img1 = images_[first], img2 = images_[second];
+    Mat dx1 = dx_[first], dx2 = dx_[second];
+    Mat dy1 = dy_[first], dy2 = dy_[second];
+    Mat mask1 = masks_[first], mask2 = masks_[second];
+    Point tl1 = corners_[first], tl2 = corners_[second];
 
+    const int gap = 10;
     Mat subimg1(roi.height + 2 * gap, roi.width + 2 * gap, CV_32FC3);
     Mat subimg2(roi.height + 2 * gap, roi.width + 2 * gap, CV_32FC3);
     Mat submask1(roi.height + 2 * gap, roi.width + 2 * gap, CV_8U);
     Mat submask2(roi.height + 2 * gap, roi.width + 2 * gap, CV_8U);
+    Mat subdx1(roi.height + 2 * gap, roi.width + 2 * gap, CV_32F);
+    Mat subdy1(roi.height + 2 * gap, roi.width + 2 * gap, CV_32F);
+    Mat subdx2(roi.height + 2 * gap, roi.width + 2 * gap, CV_32F);
+    Mat subdy2(roi.height + 2 * gap, roi.width + 2 * gap, CV_32F);
 
     // Cut subimages and submasks with some gap
     for (int y = -gap; y < roi.height + gap; ++y)
@@ -220,11 +322,15 @@ void GraphCutSeamFinder::Impl::findInPair(const Mat &img1, const Mat &img2, Poin
             {
                 subimg1.at<Point3f>(y + gap, x + gap) = img1.at<Point3f>(y1, x1);
                 submask1.at<uchar>(y + gap, x + gap) = mask1.at<uchar>(y1, x1);
+                subdx1.at<float>(y + gap, x + gap) = dx1.at<float>(y1, x1);
+                subdy1.at<float>(y + gap, x + gap) = dy1.at<float>(y1, x1);
             }
             else
             {
                 subimg1.at<Point3f>(y + gap, x + gap) = Point3f(0, 0, 0);
                 submask1.at<uchar>(y + gap, x + gap) = 0;
+                subdx1.at<float>(y + gap, x + gap) = 0.f;
+                subdy1.at<float>(y + gap, x + gap) = 0.f;
             }
 
             int y2 = roi.y - tl2.y + y;
@@ -233,11 +339,15 @@ void GraphCutSeamFinder::Impl::findInPair(const Mat &img1, const Mat &img2, Poin
             {
                 subimg2.at<Point3f>(y + gap, x + gap) = img2.at<Point3f>(y2, x2);
                 submask2.at<uchar>(y + gap, x + gap) = mask2.at<uchar>(y2, x2);
+                subdx2.at<float>(y + gap, x + gap) = dx2.at<float>(y2, x2);
+                subdy2.at<float>(y + gap, x + gap) = dy2.at<float>(y2, x2);
             }
             else
             {
                 subimg2.at<Point3f>(y + gap, x + gap) = Point3f(0, 0, 0);
                 submask2.at<uchar>(y + gap, x + gap) = 0;
+                subdx2.at<float>(y + gap, x + gap) = 0.f;
+                subdy2.at<float>(y + gap, x + gap) = 0.f;
             }
         }
     }
@@ -252,6 +362,10 @@ void GraphCutSeamFinder::Impl::findInPair(const Mat &img1, const Mat &img2, Poin
     case GraphCutSeamFinder::COST_COLOR:
         setGraphWeightsColor(subimg1, subimg2, submask1, submask2, graph);
         break;
+    case GraphCutSeamFinder::COST_COLOR_GRAD:
+        setGraphWeightsColorGrad(subimg1, subimg2, subdx1, subdx2, subdy1, subdy2, 
+                                 submask1, submask2, graph);
+        break;
     default:
         CV_Error(CV_StsBadArg, "unsupported pixel similarity measure");
     }
@@ -281,8 +395,8 @@ GraphCutSeamFinder::GraphCutSeamFinder(int cost_type, float terminal_cost, float
     : impl_(new Impl(cost_type, terminal_cost, bad_region_penalty)) {}
 
 
-void GraphCutSeamFinder::findInPair(const Mat &img1, const Mat &img2, Point tl1, Point tl2,
-                                    Rect roi, Mat &mask1, Mat &mask2)
+void GraphCutSeamFinder::find(const vector<Mat> &src, const vector<Point> &corners,
+                              vector<Mat> &masks)
 {
-    impl_->findInPair(img1, img2, tl1, tl2, roi, mask1, mask2);
+    impl_->find(src, corners, masks);
 }
index b9dca85..66c678d 100644 (file)
@@ -47,7 +47,7 @@
 class SeamFinder
 {
 public:
-    enum { NO, VORONOI, GRAPH_CUT };
+    enum { NO, VORONOI, GC_COLOR, GC_COLOR_GRAD };
     static cv::Ptr<SeamFinder> createDefault(int type);
 
     virtual ~SeamFinder() {}
@@ -66,34 +66,36 @@ public:
 class PairwiseSeamFinder : public SeamFinder
 {
 public:
-    void find(const std::vector<cv::Mat> &src, const std::vector<cv::Point> &corners,
-              std::vector<cv::Mat> &masks);
+    virtual void find(const std::vector<cv::Mat> &src, const std::vector<cv::Point> &corners,
+                      std::vector<cv::Mat> &masks);
+
 protected:
-    virtual void findInPair(const cv::Mat &img1, const cv::Mat &img2, cv::Point tl1, cv::Point tl2,
-                            cv::Rect roi, cv::Mat &mask1, cv::Mat &mask2) = 0;
+    virtual void findInPair(size_t first, size_t second, cv::Rect roi) = 0;
+
+    std::vector<cv::Mat> images_;
+    std::vector<cv::Point> corners_;
+    std::vector<cv::Mat> masks_;
 };
 
 
 class VoronoiSeamFinder : public PairwiseSeamFinder
 {
 private:
-    void findInPair(const cv::Mat &img1, const cv::Mat &img2, cv::Point tl1, cv::Point tl2,
-                    cv::Rect roi, cv::Mat &mask1, cv::Mat &mask2);
+    void findInPair(size_t first, size_t second, cv::Rect roi);
 };
 
 
-class GraphCutSeamFinder : public PairwiseSeamFinder
+class GraphCutSeamFinder : public SeamFinder
 {
 public:
-    // TODO add COST_COLOR_GRAD support
-    enum { COST_COLOR };
-    GraphCutSeamFinder(int cost_type = COST_COLOR, float terminal_cost = 10000.f,
+    enum { COST_COLOR, COST_COLOR_GRAD };
+    GraphCutSeamFinder(int cost_type = COST_COLOR_GRAD, float terminal_cost = 10000.f,
                        float bad_region_penalty = 1000.f);
 
-private:
-    void findInPair(const cv::Mat &img1, const cv::Mat &img2, cv::Point tl1, cv::Point tl2,
-                    cv::Rect roi, cv::Mat &mask1, cv::Mat &mask2);
+    void find(const std::vector<cv::Mat> &src, const std::vector<cv::Point> &corners,
+              std::vector<cv::Mat> &masks);
 
+private:
     class Impl;
     cv::Ptr<Impl> impl_;
 };
index 12f8396..e96b153 100644 (file)
@@ -92,9 +92,16 @@ B Graph::walkBreadthFirst(int from, B body) const
 // Some auxiliary math functions
 
 static inline
+float normL2(const cv::Point3f& a)
+{
+    return a.x * a.x + a.y * a.y + a.z * a.z;
+}
+
+
+static inline
 float normL2(const cv::Point3f& a, const cv::Point3f& b)
 {
-    return (a.x - b.x) * (a.x - b.x) + (a.y - b.y) * (a.y - b.y) + (a.z - b.z) * (a.z - b.z);
+    return normL2(a - b);
 }