]> rtime.felk.cvut.cz Git - opencv.git/blobdiff - opencv/tests/cv/src/detectors_test.cpp
add surf & start detectors correctness test
[opencv.git] / opencv / tests / cv / src / detectors_test.cpp
index 9f9876cbc15ab72574b988959b5a9885a6a9352a..a9eaf342fd152cdbe67d444de251cf178d4328a0 100644 (file)
@@ -44,6 +44,8 @@
 #include <string>\r
 #include <iostream>\r
 #include <fstream>\r
+#include <numeric>\r
+#include <algorithm>\r
 #include <iterator>\r
 #include "cvaux.h"\r
 \r
@@ -56,7 +58,10 @@ public:
     CV_DetectorsTest();\r
     ~CV_DetectorsTest();    \r
 protected:    \r
-    void run(int);    \r
+    void run(int);  \r
+    template <class T> bool testDedector(const Mat& img, const T& detector, vector<KeyPoint>& expected);\r
+\r
+    void LoadExpected(const string& file, vector<KeyPoint>& out);\r
 };\r
 \r
 CV_DetectorsTest::CV_DetectorsTest(): CvTest( "feature-detectors", "?" )\r
@@ -65,13 +70,71 @@ CV_DetectorsTest::CV_DetectorsTest(): CvTest( "feature-detectors", "?" )
 }\r
 CV_DetectorsTest::~CV_DetectorsTest() {}\r
 \r
-struct OutOfMask\r
+void getRotation(const Mat& img, Mat& aff, Mat& out)\r
 {\r
-    const Mat& msk;\r
-    OutOfMask(const Mat& mask) : msk(mask) {};\r
-    OutOfMask& operator=(const OutOfMask&);\r
-    bool operator()(const KeyPoint& kp) const { return msk.at<uchar>(kp.pt) == 0; }\r
-};\r
+    Point center(img.cols/2, img.rows/2);\r
+    aff = getRotationMatrix2D(center, 30, 1);\r
+    warpAffine( img, out, aff, img.size());\r
+}\r
+\r
+void getZoom(const Mat& img, Mat& aff, Mat& out)\r
+{\r
+    const double mult = 1.2;\r
+\r
+    aff.create(2, 3, CV_64F);\r
+    double *data = aff.ptr<double>();\r
+    data[0] = mult; data[1] =    0; data[2] = 0;\r
+    data[3] =    0; data[4] = mult; data[5] = 0;\r
+    \r
+    warpAffine( img, out, aff, img.size());\r
+}\r
+\r
+void getBlur(const Mat& img, Mat& aff, Mat& out)\r
+{        \r
+    aff.create(2, 3, CV_64F);\r
+    double *data = aff.ptr<double>();\r
+    data[0] = 1; data[1] = 0; data[2] = 0;\r
+    data[3] = 0; data[4] = 1; data[5] = 0;\r
+        \r
+    GaussianBlur(img, out, Size(5, 5), 2);    \r
+}\r
+\r
+void getBrightness(const Mat& img, Mat& aff, Mat& out)\r
+{        \r
+    aff.create(2, 3, CV_64F);\r
+    double *data = aff.ptr<double>();\r
+    data[0] = 1; data[1] = 0; data[2] = 0;\r
+    data[3] = 0; data[4] = 1; data[5] = 0;\r
+        \r
+    add(img, Mat(img.size(), img.type(), Scalar(15)), out);    \r
+}\r
+\r
+void showOrig(const Mat& img, const vector<KeyPoint>& orig_pts)\r
+{\r
+      \r
+    Mat img_color;\r
+    cvtColor(img, img_color, CV_GRAY2BGR); \r
+    \r
+    for(size_t i = 0; i < orig_pts.size(); ++i)    \r
+        circle(img_color, orig_pts[i].pt, (int)orig_pts[i].size/2, CV_RGB(0, 255, 0));                        \r
+    \r
+    namedWindow("O"); imshow("O", img_color);     \r
+}\r
+\r
+void show(const string& name, const Mat& new_img, const vector<KeyPoint>& new_pts, const vector<KeyPoint>& transf_pts)\r
+{\r
+      \r
+    Mat new_img_color;    \r
+    cvtColor(new_img, new_img_color, CV_GRAY2BGR); \r
+\r
+    for(size_t i = 0; i < transf_pts.size(); ++i)\r
+        circle(new_img_color, transf_pts[i].pt, (int)transf_pts[i].size/2, CV_RGB(255, 0, 0));\r
+\r
+    for(size_t i = 0; i < new_pts.size(); ++i)    \r
+        circle(new_img_color, new_pts[i].pt, (int)new_pts[i].size/2, CV_RGB(0, 0, 255));\r
+    \r
+    namedWindow(name + "_T"); imshow(name + "_T", new_img_color); \r
+}\r
 \r
 struct WrapPoint\r
 {\r
@@ -87,78 +150,158 @@ struct WrapPoint
     }\r
 };\r
 \r
-void CV_DetectorsTest::run( int /*start_from*/ )\r
-{             \r
-    Mat oimg = imread(string(ts->get_data_path()) + "shared/baboon.jpg", 0);\r
-    //Mat oimg = imread(string(ts->get_data_path()) + "shared/fruits.jpg", 0);\r
+struct sortByR { bool operator()(const KeyPoint& kp1, const KeyPoint& kp2) { return norm(kp1.pt) < norm(kp2.pt); } };\r
+\r
+template <class T> bool CV_DetectorsTest::testDedector(const Mat& img, const T& detector, vector<KeyPoint>& exp)\r
+{\r
+    vector<KeyPoint> orig_kpts;\r
+    detector(img, orig_kpts);\r
+\r
+    typedef void (*TransfFunc )(const Mat&, Mat&, Mat& FransfFunc);    \r
+    const TransfFunc transfFunc[] = { getRotation, getZoom, getBlur, getBrightness };\r
+    //const string names[] =  { "Rotation", "Zoom", "Blur", "Brightness" };\r
+    const size_t case_num = sizeof(transfFunc)/sizeof(transfFunc[0]);\r
 \r
-    if (oimg.empty())\r
+    vector<Mat> affs(case_num);\r
+    vector<Mat> new_imgs(case_num);\r
+\r
+    vector< vector<KeyPoint> > new_kpts(case_num);\r
+    vector< vector<KeyPoint> > transf_kpts(case_num);\r
+\r
+    //showOrig(img, orig_kpts);\r
+    for(size_t i = 0; i < case_num; ++i)   \r
     {\r
-        ts->set_failed_test_info( CvTS::FAIL_INVALID_TEST_DATA );\r
-        return;\r
-    }    \r
+        transfFunc[i](img, affs[i], new_imgs[i]);\r
+        detector(new_imgs[i], new_kpts[i]);\r
+        transform(orig_kpts.begin(), orig_kpts.end(), back_inserter(transf_kpts[i]), WrapPoint(affs[i]));\r
+        //show(names[i], new_imgs[i], new_kpts[i], transf_kpts[i]);\r
+    }\r
 \r
-    Point center(oimg.cols/2, oimg.rows/2);\r
-              \r
-    Mat aff = getRotationMatrix2D(center, 45, 1);\r
+    const float thres = 3;\r
+    const float nthres = 3;\r
 \r
-    Mat rimg;  \r
-    warpAffine( oimg, rimg, aff, oimg.size());\r
+    vector<KeyPoint> result;\r
+    for(size_t i = 0; i < orig_kpts.size(); ++i)\r
+    {\r
+        const KeyPoint& okp = orig_kpts[i];\r
+        int foundCounter = 0;\r
+        for(size_t j = 0; j < case_num; ++j)\r
+        {            \r
+            const KeyPoint& tkp = transf_kpts[j][i];\r
 \r
-    Mat mask(oimg.size(), CV_8U, Scalar(0));    \r
-    circle(mask, center, std::min(center.x, center.y) - 10, Scalar(255), CV_FILLED);\r
-    Mat inv_mask;\r
-    mask.convertTo(inv_mask, CV_8U, -1, 255);\r
+            size_t k = 0;\r
+            \r
+            for(; k < new_kpts[j].size(); ++k)\r
+                if (norm(new_kpts[j][k].pt - tkp.pt) < nthres && fabs(new_kpts[j][k].size - tkp.size) < thres)\r
+                    break;\r
 \r
-    Mat oimg_color, rimg_color;\r
-    cvtColor(oimg, oimg_color, CV_GRAY2BGR);   oimg_color.setTo(Scalar(0), inv_mask);\r
-    cvtColor(rimg, rimg_color, CV_GRAY2BGR);   rimg_color.setTo(Scalar(0), inv_mask);   \r
+            if (k != new_kpts[j].size())\r
+                ++foundCounter;\r
 \r
-    SURF surf(1536, 2);\r
-    StarDetector star(45, 30, 10, 8, 5);\r
+        }\r
+        if (foundCounter == case_num)\r
+            result.push_back(okp);\r
+    }\r
 \r
-    vector<KeyPoint> opoints_surf, rpoints_surf, opoints_star, rpoints_star;\r
-    surf(oimg, mask, opoints_surf);\r
-    surf(rimg, mask, rpoints_surf);\r
+    sort(result.begin(), result.end(), sortByR());\r
+    sort(exp.begin(), exp.end(), sortByR());    \r
 \r
-    star(oimg, opoints_star);\r
-    star(rimg, rpoints_star);\r
-    \r
-    opoints_star.erase(\r
-        remove_if(opoints_star.begin(), opoints_star.end(), OutOfMask(mask)),   \r
-        opoints_star.end());\r
+    int foundCounter1 = 0;\r
+    for(size_t i = 0; i < exp.size(); ++i)\r
+    {\r
+        const KeyPoint& e = exp[i];                \r
+        size_t j = 0;\r
+        for(; j < result.size(); ++j)\r
+        {\r
+            const KeyPoint& r = result[i];\r
+            if (norm(r.pt-e.pt) < nthres && fabs(r.size - e.size) < thres)\r
+                break;\r
+        }\r
+        if (j != result.size())\r
+            ++foundCounter1;\r
+    }\r
 \r
-    rpoints_star.erase(\r
-        remove_if(rpoints_star.begin(), rpoints_star.end(), OutOfMask(mask)), \r
-        rpoints_star.end());\r
+    int foundCounter2 = 0;\r
+    for(size_t i = 0; i < result.size(); ++i)\r
+    {\r
+        const KeyPoint& r = result[i];                \r
+        size_t j = 0;\r
+        for(; j < exp.size(); ++j)\r
+        {\r
+            const KeyPoint& e = exp[i];\r
+            if (norm(r.pt-e.pt) < nthres && fabs(r.size - e.size) < thres)\r
+                break;\r
+        }\r
+        if (j != exp.size())\r
+            ++foundCounter2;\r
+    }\r
+    //showOrig(img, result); waitKey();\r
 \r
-    vector<KeyPoint> exp_rpoints_surf(opoints_surf.size()), exp_rpoints_star(opoints_star.size());\r
-    transform(opoints_surf.begin(), opoints_surf.end(), exp_rpoints_surf.begin(), WrapPoint(aff));\r
-    transform(opoints_star.begin(), opoints_star.end(), exp_rpoints_star.begin(), WrapPoint(aff));\r
-    \r
-    for(size_t i = 0; i < opoints_surf.size(); ++i)\r
+    const float errorRate = 0.9f;\r
+    if (float(foundCounter1)/exp.size() < errorRate || float(foundCounter2)/result.size() < errorRate)\r
     {\r
-        circle(oimg_color, opoints_surf[i].pt, (int)opoints_surf[i].size/2, CV_RGB(0, 255, 0));\r
-        circle(rimg_color, exp_rpoints_surf[i].pt, (int)exp_rpoints_surf[i].size/2, CV_RGB(255, 0, 0));\r
+        ts->set_failed_test_info( CvTS::FAIL_MISMATCH);\r
+        return false;\r
     }\r
+    return true;        \r
+}\r
 \r
-    for(size_t i = 0; i < rpoints_surf.size(); ++i)\r
-        circle(rimg_color, rpoints_surf[i].pt, (int)rpoints_surf[i].size/2, CV_RGB(0, 255, 0));\r
+struct SurfNoMaskWrap \r
+{\r
+    const SURF& detector;\r
+    SurfNoMaskWrap(const SURF& surf) : detector(surf) {}\r
+    SurfNoMaskWrap& operator=(const SurfNoMaskWrap&);\r
+    void operator()(const Mat& img, vector<KeyPoint>& kpts) const { detector(img, Mat(), kpts); }\r
+};\r
 \r
-    for(size_t i = 0; i < opoints_star.size(); ++i)\r
+void CV_DetectorsTest::LoadExpected(const string& file, vector<KeyPoint>& out)\r
+{     \r
+    Mat mat_exp;\r
+    FileStorage fs(file, FileStorage::READ);    \r
+    if (fs.isOpened())\r
     {\r
-        circle(oimg_color, opoints_star[i].pt, (int)opoints_star[i].size/2, CV_RGB(0, 0, 255));\r
-        circle(rimg_color, exp_rpoints_surf[i].pt, (int)exp_rpoints_surf[i].size/2, CV_RGB(255, 0, 0));\r
+        read( fs["ResultVectorData"], mat_exp, Mat() );           \r
+        out.resize(mat_exp.cols / sizeof(KeyPoint));\r
+        copy(mat_exp.ptr<KeyPoint>(), mat_exp.ptr<KeyPoint>() + out.size(), out.begin());            \r
     }\r
+    else\r
+    {\r
+        ts->set_failed_test_info( CvTS::FAIL_INVALID_TEST_DATA);\r
+        out.clear();\r
+    }    \r
+}\r
+\r
+void CV_DetectorsTest::run( int /*start_from*/ )\r
+{               \r
+    Mat img = imread(string(ts->get_data_path()) + "shared/graffiti.png", 0);\r
+\r
+    if (img.empty())\r
+    {\r
+        ts->set_failed_test_info( CvTS::FAIL_INVALID_TEST_DATA );\r
+        return;\r
+    }\r
+            \r
+    Mat to_test(img.size() * 2, img.type(), Scalar(0));\r
+    Mat roi = to_test(Rect(img.rows/2, img.cols/2, img.cols, img.rows));\r
+    img.copyTo(roi);\r
+    GaussianBlur(to_test, to_test, Size(3, 3), 1.5);\r
+        \r
+    vector<KeyPoint> exp;\r
+    LoadExpected(string(ts->get_data_path()) + "detectors/surf.xml", exp);        \r
+    if (exp.empty())\r
+        return;\r
 \r
-    for(size_t i = 0; i < rpoints_star.size(); ++i)\r
-        circle(rimg_color, rpoints_star[i].pt, (int)rpoints_star[i].size/2, CV_RGB(0, 0, 255));\r
+    if (!testDedector(to_test, SurfNoMaskWrap(SURF(1536+512+512, 2)), exp))\r
+        return;\r
     \r
-  /*  namedWindow("R"); imshow("R", rimg_color); \r
-    namedWindow("O"); imshow("O", oimg_color); \r
-    waitKey();*/\r
+    LoadExpected(string(ts->get_data_path()) + "detectors/star.xml", exp);\r
+    if (exp.empty())\r
+        return;\r
+\r
+    if (!testDedector(to_test, StarDetector(45, 30, 10, 8, 5), exp))\r
+        return;\r
 \r
-    ts->set_failed_test_info( CvTS::FAIL_GENERIC );            \r
+    ts->set_failed_test_info( CvTS::OK);                  \r
 }\r
 \r
 \r