added reasonable test for MSER (including coverage for http://code.opencv.org/issues/4273, http://code.opencv.org/issues/1723 and http://code.opencv.org/issues/756); also, added some "in-progress" info to the Features2d_Feature2d.no_crash test.

pull/4025/head
Vadim Pisarevsky 10 years ago
parent fede94e979
commit dab78c26b1
  1. 15
      modules/features2d/test/test_descriptors_regression.cpp
  2. 224
      modules/features2d/test/test_mser.cpp

@ -390,45 +390,52 @@ TEST( Features2d_Feature2d, no_crash )
size_t i, n = fnames.size(); size_t i, n = fnames.size();
vector<KeyPoint> keypoints; vector<KeyPoint> keypoints;
Mat descriptors; Mat descriptors;
orb->setMaxFeatures(5000);
for( i = 0; i < n; i++ ) for( i = 0; i < n; i++ )
{ {
printf("%d. image: %s:\n", (int)i, fnames[i].c_str()); printf("%d. image: %s:\n", (int)i, fnames[i].c_str());
if( strstr(fnames[i].c_str(), "MP.png") != 0 )
continue;
bool checkCount = strstr(fnames[i].c_str(), "templ.png") == 0; bool checkCount = strstr(fnames[i].c_str(), "templ.png") == 0;
Mat img = imread(fnames[i], -1); Mat img = imread(fnames[i], -1);
printf("\tAKAZE ... "); fflush(stdout); printf("\tAKAZE ... "); fflush(stdout);
akaze->detectAndCompute(img, noArray(), keypoints, descriptors); akaze->detectAndCompute(img, noArray(), keypoints, descriptors);
printf("(%d keypoints) ", (int)keypoints.size()); fflush(stdout);
if( checkCount ) if( checkCount )
{ {
ASSERT_GT((int)keypoints.size(), 0); EXPECT_GT((int)keypoints.size(), 0);
} }
ASSERT_EQ(descriptors.rows, (int)keypoints.size()); ASSERT_EQ(descriptors.rows, (int)keypoints.size());
printf("ok\n"); printf("ok\n");
printf("\tKAZE ... "); fflush(stdout); printf("\tKAZE ... "); fflush(stdout);
kaze->detectAndCompute(img, noArray(), keypoints, descriptors); kaze->detectAndCompute(img, noArray(), keypoints, descriptors);
printf("(%d keypoints) ", (int)keypoints.size()); fflush(stdout);
if( checkCount ) if( checkCount )
{ {
ASSERT_GT((int)keypoints.size(), 0); EXPECT_GT((int)keypoints.size(), 0);
} }
ASSERT_EQ(descriptors.rows, (int)keypoints.size()); ASSERT_EQ(descriptors.rows, (int)keypoints.size());
printf("ok\n"); printf("ok\n");
printf("\tORB ... "); fflush(stdout); printf("\tORB ... "); fflush(stdout);
orb->detectAndCompute(img, noArray(), keypoints, descriptors); orb->detectAndCompute(img, noArray(), keypoints, descriptors);
printf("(%d keypoints) ", (int)keypoints.size()); fflush(stdout);
if( checkCount ) if( checkCount )
{ {
ASSERT_GT((int)keypoints.size(), 0); EXPECT_GT((int)keypoints.size(), 0);
} }
ASSERT_EQ(descriptors.rows, (int)keypoints.size()); ASSERT_EQ(descriptors.rows, (int)keypoints.size());
printf("ok\n"); printf("ok\n");
printf("\tBRISK ... "); fflush(stdout); printf("\tBRISK ... "); fflush(stdout);
brisk->detectAndCompute(img, noArray(), keypoints, descriptors); brisk->detectAndCompute(img, noArray(), keypoints, descriptors);
printf("(%d keypoints) ", (int)keypoints.size()); fflush(stdout);
if( checkCount ) if( checkCount )
{ {
ASSERT_GT((int)keypoints.size(), 0); EXPECT_GT((int)keypoints.size(), 0);
} }
ASSERT_EQ(descriptors.rows, (int)keypoints.size()); ASSERT_EQ(descriptors.rows, (int)keypoints.size());
printf("ok\n"); printf("ok\n");

@ -41,171 +41,121 @@
//M*/ //M*/
#include "test_precomp.hpp" #include "test_precomp.hpp"
#include "opencv2/imgproc/imgproc_c.h" #include "opencv2/highgui.hpp"
#if 0
#include <vector> #include <vector>
#include <string> #include <string>
using namespace std; using namespace std;
using namespace cv; using namespace cv;
class CV_MserTest : public cvtest::BaseTest #undef RENDER_MSERS
{ #define RENDER_MSERS 0
public:
CV_MserTest();
protected:
void run(int);
int LoadBoxes(const char* path, vector<CvBox2D>& boxes);
int SaveBoxes(const char* path, const vector<CvBox2D>& boxes);
int CompareBoxes(const vector<CvBox2D>& boxes1,const vector<CvBox2D>& boxes2, float max_rel_diff = 0.01f);
};
CV_MserTest::CV_MserTest()
{
}
int CV_MserTest::LoadBoxes(const char* path, vector<CvBox2D>& boxes) #if defined RENDER_MSERS && RENDER_MSERS
static void renderMSERs(const Mat& gray, Mat& img, const vector<vector<Point> >& msers)
{ {
boxes.clear(); cvtColor(gray, img, COLOR_GRAY2BGR);
FILE* f = fopen(path,"r"); RNG rng((uint64)1749583);
for( int i = 0; i < (int)msers.size(); i++ )
if (f==NULL)
{ {
return 0; uchar b = rng.uniform(0, 256);
} uchar g = rng.uniform(0, 256);
uchar r = rng.uniform(0, 256);
Vec3b color(b, g, r);
while (!feof(f)) const Point* pt = &msers[i][0];
{ size_t j, n = msers[i].size();
CvBox2D box; for( j = 0; j < n; j++ )
int values_read = fscanf(f,"%f,%f,%f,%f,%f\n",&box.angle,&box.center.x,&box.center.y,&box.size.width,&box.size.height); img.at<Vec3b>(pt[j]) = color;
CV_Assert(values_read == 5);
boxes.push_back(box);
} }
fclose(f);
return 1;
}
int CV_MserTest::SaveBoxes(const char* path, const vector<CvBox2D>& boxes)
{
FILE* f = fopen(path,"w");
if (f==NULL)
{
return 0;
}
for (int i=0;i<(int)boxes.size();i++)
{
fprintf(f,"%f,%f,%f,%f,%f\n",boxes[i].angle,boxes[i].center.x,boxes[i].center.y,boxes[i].size.width,boxes[i].size.height);
}
fclose(f);
return 1;
} }
#endif
int CV_MserTest::CompareBoxes(const vector<CvBox2D>& boxes1,const vector<CvBox2D>& boxes2, float max_rel_diff) TEST(Features2d_MSER, cases)
{ {
if (boxes1.size() != boxes2.size()) uchar buf[] =
return 0; {
255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
for (int i=0; i<(int)boxes1.size();i++) 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
{ 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
float rel_diff; 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
if (!((boxes1[i].angle == 0.0f) && (abs(boxes2[i].angle) < max_rel_diff))) 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
{ 255, 255, 255, 255, 255, 0, 0, 0, 0, 255, 255, 255, 255, 255, 255, 255, 255, 255, 0, 0, 0, 0, 255, 255, 255, 255,
float angle_diff = (float)fmod(boxes1[i].angle - boxes2[i].angle, 180); 255, 255, 255, 255, 255, 0, 0, 0, 0, 0, 255, 255, 255, 255, 255, 255, 255, 255, 0, 0, 0, 0, 255, 255, 255, 255,
// for angular correctness, it makes no sense to use a "relative" error. 255, 255, 255, 255, 255, 0, 0, 0, 0, 0, 255, 255, 255, 255, 255, 255, 255, 255, 0, 0, 0, 0, 255, 255, 255, 255,
// a 1-degree error around 5 degrees is equally bas as around 250 degrees. 255, 255, 255, 255, 255, 0, 0, 0, 0, 255, 255, 255, 255, 255, 255, 255, 255, 255, 0, 0, 0, 0, 255, 255, 255, 255,
// in correct cases, angle_diff can now be a bit above 0 or a bit below 180 255, 255, 255, 255, 255, 255, 0, 0, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 0, 0, 255, 255, 255, 255, 255,
if (angle_diff > 90.0f) 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
{ 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
angle_diff -= 180.0f; 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
} 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255
rel_diff = (float)fabs(angle_diff); };
if (rel_diff > max_rel_diff) Mat big_image = imread(cvtest::TS::ptr()->get_data_path() + "mser/puzzle.png", 0);
return i; Mat small_image(14, 26, CV_8U, buf);
} static const int thresharr[] = { 0, 70, 120, 180, 255 };
const int kDelta = 5;
Ptr<MSER> mserExtractor = MSER::create( kDelta );
vector<vector<Point> > msers;
vector<Rect> boxes;
if (!((boxes1[i].center.x == 0.0f) && (abs(boxes2[i].center.x) < max_rel_diff))) RNG& rng = theRNG();
{
rel_diff = abs(boxes1[i].center.x-boxes2[i].center.x)/abs(boxes1[i].center.x);
if (rel_diff > max_rel_diff)
return i;
}
if (!((boxes1[i].center.y == 0.0f) && (abs(boxes2[i].center.y) < max_rel_diff))) for( int i = 0; i < 30; i++ )
{ {
rel_diff = abs(boxes1[i].center.y-boxes2[i].center.y)/abs(boxes1[i].center.y); bool use_big_image = rng.uniform(0, 7) != 0;
if (rel_diff > max_rel_diff) bool invert = rng.uniform(0, 2) != 0;
return i; bool binarize = use_big_image ? rng.uniform(0, 5) != 0 : false;
} bool blur = rng.uniform(0, 2) != 0;
if (!((boxes1[i].size.width == 0.0f) && (abs(boxes2[i].size.width) < max_rel_diff))) int thresh = thresharr[rng.uniform(0, 5)];
{
rel_diff = abs(boxes1[i].size.width-boxes2[i].size.width)/abs(boxes1[i].size.width);
if (rel_diff > max_rel_diff)
return i;
}
if (!((boxes1[i].size.height == 0.0f) && (abs(boxes2[i].size.height) < max_rel_diff))) /*if( i == 0 )
{ {
rel_diff = abs(boxes1[i].size.height-boxes2[i].size.height)/abs(boxes1[i].size.height); use_big_image = true;
if (rel_diff > max_rel_diff) invert = binarize = blur = false;
return i; }*/
}
}
return -1; const Mat& src0 = use_big_image ? big_image : small_image;
} Mat src = src0.clone();
void CV_MserTest::run(int) int kMinArea = use_big_image ? 256 : 10;
{ int kMaxArea = (int)src.total()/4;
string image_path = string(ts->get_data_path()) + "mser/puzzle.png";
Mat img = imread( image_path ); mserExtractor->setMinArea(kMinArea);
if (img.empty()) mserExtractor->setMaxArea(kMaxArea);
{
ts->printf( cvtest::TS::LOG, "Unable to open image mser/puzzle.png\n");
ts->set_failed_test_info(cvtest::TS::FAIL_MISSING_TEST_DATA);
return;
}
Mat yuv; if( invert )
cvtColor(img, yuv, COLOR_BGR2YCrCb); bitwise_not(src, src);
vector<vector<Point> > msers; if( binarize )
MSER()(yuv, msers); threshold(src, src, thresh, 255, THRESH_BINARY);
if( blur )
GaussianBlur(src, src, Size(5, 5), 1.5, 1.5);
vector<CvBox2D> boxes; int minRegs = use_big_image ? 10 : 2;
vector<CvBox2D> boxes_orig; int maxRegs = use_big_image ? 1000 : 10;
for ( size_t i = 0; i < msers.size(); i++ ) if( binarize && (thresh == 0 || thresh == 255) )
{ minRegs = maxRegs = 0;
RotatedRect box = fitEllipse(msers[i]);
box.angle=(float)CV_PI/2-box.angle;
boxes.push_back(box);
}
string boxes_path = string(ts->get_data_path()) + "mser/boxes.txt"; mserExtractor->detectRegions( src, msers, boxes );
string calc_boxes_path = string(ts->get_data_path()) + "mser/boxes.calc.txt"; int nmsers = (int)msers.size();
ASSERT_EQ(nmsers, (int)boxes.size());
if (!LoadBoxes(boxes_path.c_str(),boxes_orig)) if( maxRegs < nmsers || minRegs > nmsers )
{ {
SaveBoxes(boxes_path.c_str(),boxes); printf("%d. minArea=%d, maxArea=%d, nmsers=%d, minRegs=%d, maxRegs=%d, "
ts->printf( cvtest::TS::LOG, "Unable to open data file mser/boxes.txt\n"); "image=%s, invert=%d, binarize=%d, thresh=%d, blur=%d\n",
ts->set_failed_test_info(cvtest::TS::FAIL_MISSING_TEST_DATA); i, kMinArea, kMaxArea, nmsers, minRegs, maxRegs, use_big_image ? "big" : "small",
return; (int)invert, (int)binarize, thresh, (int)blur);
#if defined RENDER_MSERS && RENDER_MSERS
Mat image;
imshow("source", src);
renderMSERs(src, image, msers);
imshow("result", image);
waitKey();
#endif
} }
const float dissimularity = 0.01f; ASSERT_LE(minRegs, nmsers);
int n_box = CompareBoxes(boxes_orig,boxes,dissimularity); ASSERT_GE(maxRegs, nmsers);
if (n_box < 0)
{
ts->set_failed_test_info(cvtest::TS::OK);
}
else
{
SaveBoxes(calc_boxes_path.c_str(), boxes);
ts->set_failed_test_info(cvtest::TS::FAIL_BAD_ACCURACY);
ts->printf( cvtest::TS::LOG, "Incorrect correspondence in box %d\n",n_box);
} }
} }
TEST(Features2d_MSER, DISABLED_regression) { CV_MserTest test; test.safe_run(); }
#endif

Loading…
Cancel
Save