From 874196e3840b171f648c097cd71f94f1056e57c8 Mon Sep 17 00:00:00 2001 From: Andrey Kamaev Date: Thu, 4 Aug 2011 14:13:07 +0000 Subject: [PATCH] Implemented read/write methods for FlannBasedMatcher; fixed features2d wrappers for java --- .../include/opencv2/features2d/features2d.hpp | 5 + modules/features2d/src/matchers.cpp | 189 ++++++++++++++++++ .../flann/include/opencv2/flann/miniflann.hpp | 3 + modules/flann/src/miniflann.cpp | 109 ++++++++-- .../FlannBasedDescriptorMatcherTest.java | 135 ++++++++++++- modules/java/src/cpp/features2d_manual.hpp | 19 +- 6 files changed, 429 insertions(+), 31 deletions(-) diff --git a/modules/features2d/include/opencv2/features2d/features2d.hpp b/modules/features2d/include/opencv2/features2d/features2d.hpp index 548b8c012..be41e0a1b 100644 --- a/modules/features2d/include/opencv2/features2d/features2d.hpp +++ b/modules/features2d/include/opencv2/features2d/features2d.hpp @@ -2540,6 +2540,11 @@ public: virtual void add( const vector& descriptors ); virtual void clear(); + // Reads matcher object from a file node + virtual void read( const FileNode& ); + // Writes matcher object to a file storage + virtual void write( FileStorage& ) const; + virtual void train(); virtual bool isMaskSupported() const; diff --git a/modules/features2d/src/matchers.cpp b/modules/features2d/src/matchers.cpp index 5a54fea4d..37371eed0 100755 --- a/modules/features2d/src/matchers.cpp +++ b/modules/features2d/src/matchers.cpp @@ -542,6 +542,195 @@ void FlannBasedMatcher::train() } } +void FlannBasedMatcher::read( const FileNode& fn) +{ + if (indexParams == 0) + indexParams = new flann::IndexParams(); + + FileNode ip = fn["indexParams"]; + CV_Assert(ip.type() == FileNode::SEQ); + + for(size_t i = 0; i < ip.size(); ++i) + { + CV_Assert(ip[i].type() == FileNode::MAP); + std::string name = (std::string)ip[i]["name"]; + int type = (int)ip[i]["type"]; + + switch(type) + { + case CV_8U: + case CV_8S: + case CV_16U: + case CV_16S: + case CV_32S: + indexParams->setInt(name, (int) ip[i]["value"]); + break; + case CV_32F: + indexParams->setFloat(name, (float) ip[i]["value"]); + break; + case CV_64F: + indexParams->setDouble(name, (double) ip[i]["value"]); + break; + case CV_USRTYPE1: + indexParams->setString(name, (std::string) ip[i]["value"]); + break; + case CV_MAKETYPE(CV_USRTYPE1,2): + indexParams->setBool(name, (int) ip[i]["value"]); + break; + case CV_MAKETYPE(CV_USRTYPE1,3): + indexParams->setAlgorithm(name, (int) ip[i]["value"]); + break; + }; + } + + if (searchParams == 0) + searchParams = new flann::SearchParams(); + + FileNode sp = fn["searchParams"]; + CV_Assert(sp.type() == FileNode::SEQ); + + for(size_t i = 0; i < sp.size(); ++i) + { + CV_Assert(sp[i].type() == FileNode::MAP); + std::string name = (std::string)sp[i]["name"]; + int type = (int)sp[i]["type"]; + + switch(type) + { + case CV_8U: + case CV_8S: + case CV_16U: + case CV_16S: + case CV_32S: + searchParams->setInt(name, (int) sp[i]["value"]); + break; + case CV_32F: + searchParams->setFloat(name, (float) ip[i]["value"]); + break; + case CV_64F: + searchParams->setDouble(name, (double) ip[i]["value"]); + break; + case CV_USRTYPE1: + searchParams->setString(name, (std::string) ip[i]["value"]); + break; + case CV_MAKETYPE(CV_USRTYPE1,2): + searchParams->setBool(name, (int) ip[i]["value"]); + break; + case CV_MAKETYPE(CV_USRTYPE1,3): + searchParams->setAlgorithm(name, (int) ip[i]["value"]); + break; + }; + } + + flannIndex.release(); +} + +void FlannBasedMatcher::write( FileStorage& fs) const +{ + fs << "indexParams" << "["; + + if (indexParams != 0) + { + std::vector names; + std::vector types; + std::vector strValues; + std::vector numValues; + + indexParams->getAll(names, types, strValues, numValues); + + for(size_t i = 0; i < names.size(); ++i) + { + fs << "{" << "name" << names[i] << "type" << types[i] << "value"; + switch(types[i]) + { + case CV_8U: + fs << (uchar)numValues[i]; + break; + case CV_8S: + fs << (char)numValues[i]; + break; + case CV_16U: + fs << (ushort)numValues[i]; + break; + case CV_16S: + fs << (short)numValues[i]; + break; + case CV_32S: + case CV_MAKETYPE(CV_USRTYPE1,2): + case CV_MAKETYPE(CV_USRTYPE1,3): + fs << (int)numValues[i]; + break; + case CV_32F: + fs << (float)numValues[i]; + break; + case CV_64F: + fs << (double)numValues[i]; + break; + case CV_USRTYPE1: + fs << strValues[i]; + break; + default: + fs << (double)numValues[i]; + fs << "typename" << strValues[i]; + break; + } + fs << "}"; + } + } + + fs << "]" << "searchParams" << "["; + + if (searchParams != 0) + { + std::vector names; + std::vector types; + std::vector strValues; + std::vector numValues; + + searchParams->getAll(names, types, strValues, numValues); + + for(size_t i = 0; i < names.size(); ++i) + { + fs << "{" << "name" << names[i] << "type" << types[i] << "value"; + switch(types[i]) + { + case CV_8U: + fs << (uchar)numValues[i]; + break; + case CV_8S: + fs << (char)numValues[i]; + break; + case CV_16U: + fs << (ushort)numValues[i]; + break; + case CV_16S: + fs << (short)numValues[i]; + break; + case CV_32S: + case CV_MAKETYPE(CV_USRTYPE1,2): + case CV_MAKETYPE(CV_USRTYPE1,3): + fs << (int)numValues[i]; + break; + case CV_32F: + fs << (float)numValues[i]; + break; + case CV_64F: + fs << (double)numValues[i]; + break; + case CV_USRTYPE1: + fs << strValues[i]; + break; + default: + fs << (double)numValues[i]; + fs << "typename" << strValues[i]; + break; + } + fs << "}"; + } + } + fs << "]"; +} + bool FlannBasedMatcher::isMaskSupported() const { return false; diff --git a/modules/flann/include/opencv2/flann/miniflann.hpp b/modules/flann/include/opencv2/flann/miniflann.hpp index 2d07dc0be..b36cba132 100644 --- a/modules/flann/include/opencv2/flann/miniflann.hpp +++ b/modules/flann/include/opencv2/flann/miniflann.hpp @@ -68,6 +68,9 @@ struct CV_EXPORTS IndexParams void setString(const std::string& key, const std::string& value); void setInt(const std::string& key, int value); void setDouble(const std::string& key, double value); + void setFloat(const std::string& key, float value); + void setBool(const std::string& key, bool value); + void setAlgorithm(const std::string& key, int value); void getAll(std::vector& names, std::vector& types, diff --git a/modules/flann/src/miniflann.cpp b/modules/flann/src/miniflann.cpp index 4107d90ed..54f3c9faa 100644 --- a/modules/flann/src/miniflann.cpp +++ b/modules/flann/src/miniflann.cpp @@ -70,7 +70,21 @@ void IndexParams::setDouble(const std::string& key, double value) { setParam(*this, key, value); } - + +void IndexParams::setFloat(const std::string& key, float value) +{ + setParam(*this, key, value); +} + +void IndexParams::setBool(const std::string& key, bool value) +{ + setParam(*this, key, value); +} + +void IndexParams::setAlgorithm(const std::string& key, int value) +{ + setParam(*this, key, (cvflann::flann_algorithm_t)value); +} void IndexParams::getAll(std::vector& names, std::vector& types, @@ -94,23 +108,88 @@ void IndexParams::getAll(std::vector& names, types.push_back(CV_USRTYPE1); strValues.push_back(val); numValues.push_back(-1); + continue; } - catch (...) + catch (...) {} + + strValues.push_back(it->second.type().name()); + + try { - try - { - double val = it->second.cast(); - strValues.push_back(std::string()); - types.push_back( val == saturate_cast(val) ? CV_32S : CV_64F ); - numValues.push_back(val); - } - catch( ... ) - { - types.push_back(-1); // unknown type - strValues.push_back(std::string()); - numValues.push_back(-1); - } + double val = it->second.cast(); + types.push_back( CV_64F ); + numValues.push_back(val); + continue; } + catch (...) {} + try + { + float val = it->second.cast(); + types.push_back( CV_32F ); + numValues.push_back(val); + continue; + } + catch (...) {} + try + { + int val = it->second.cast(); + types.push_back( CV_32S ); + numValues.push_back(val); + continue; + } + catch (...) {} + try + { + short val = it->second.cast(); + types.push_back( CV_16S ); + numValues.push_back(val); + continue; + } + catch (...) {} + try + { + ushort val = it->second.cast(); + types.push_back( CV_16U ); + numValues.push_back(val); + continue; + } + catch (...) {} + try + { + char val = it->second.cast(); + types.push_back( CV_8S ); + numValues.push_back(val); + continue; + } + catch (...) {} + try + { + uchar val = it->second.cast(); + types.push_back( CV_8U ); + numValues.push_back(val); + continue; + } + catch (...) {} + try + { + bool val = it->second.cast(); + types.push_back( CV_MAKETYPE(CV_USRTYPE1,2) ); + numValues.push_back(val); + continue; + } + catch (...) {} + try + { + cvflann::flann_algorithm_t val = it->second.cast(); + types.push_back( CV_MAKETYPE(CV_USRTYPE1,3) ); + numValues.push_back(val); + continue; + } + catch (...) {} + + + types.push_back(-1); // unknown type + numValues.push_back(-1); } } diff --git a/modules/java/android_test/src/org/opencv/test/features2d/FlannBasedDescriptorMatcherTest.java b/modules/java/android_test/src/org/opencv/test/features2d/FlannBasedDescriptorMatcherTest.java index 9e76e5c6f..d650595b7 100644 --- a/modules/java/android_test/src/org/opencv/test/features2d/FlannBasedDescriptorMatcherTest.java +++ b/modules/java/android_test/src/org/opencv/test/features2d/FlannBasedDescriptorMatcherTest.java @@ -23,7 +23,80 @@ public class FlannBasedDescriptorMatcherTest extends OpenCVTestCase { DescriptorMatcher matcher; int matSize; DMatch[] truth; + + static final String ymlParamsDefault = "%YAML:1.0\n" ++ "indexParams:\n" ++ " -\n" ++ " name: algorithm\n" ++ " type: 23\n" ++ " value: 1\n" ++ " -\n" ++ " name: trees\n" ++ " type: 4\n" ++ " value: 4\n" ++ "searchParams:\n" ++ " -\n" ++ " name: checks\n" ++ " type: 4\n" ++ " value: 32\n" ++ " -\n" ++ " name: eps\n" ++ " type: 5\n" ++ " value: 0.\n" ++ " -\n" ++ " name: sorted\n" ++ " type: 15\n" ++ " value: 1\n"; + + static final String xmlParamsDefault = "\n" ++ "\n" ++ "\n" ++ " <_>\n" ++ " algorithm\n" ++ " 23\n" ++ " 1\n" ++ " <_>\n" ++ " trees\n" ++ " 4\n" ++ " 4\n" ++ "\n" ++ " <_>\n" ++ " checks\n" ++ " 4\n" ++ " 32\n" ++ " <_>\n" ++ " eps\n" ++ " 5\n" ++ " 0.\n" ++ " <_>\n" ++ " sorted\n" ++ " 15\n" ++ " 1\n" ++ "\n"; + static final String ymlParamsModified = "%YAML:1.0\n" ++ "indexParams:\n" ++ " -\n" ++ " name: algorithm\n" ++ " type: 23\n" ++ " value: 6\n"//this line is changed ++ " -\n" ++ " name: trees\n" ++ " type: 4\n" ++ " value: 4\n" ++ "searchParams:\n" ++ " -\n" ++ " name: checks\n" ++ " type: 4\n" ++ " value: 32\n" ++ " -\n" ++ " name: eps\n" ++ " type: 5\n" ++ " value: 0.\n" ++ " -\n" ++ " name: sorted\n" ++ " type: 15\n" ++ " value: 1\n"; protected void setUp() throws Exception { matcher = DescriptorMatcher.create(DescriptorMatcher.FLANNBASED); matSize = 100; @@ -91,6 +164,39 @@ public class FlannBasedDescriptorMatcherTest extends OpenCVTestCase { } }; } + + private Mat getBriefTrainImg() { + Mat img = new Mat(matSize, matSize, CvType.CV_8U, new Scalar(255)); + Core.line(img, new Point(40, 40), new Point(matSize - 40, matSize - 40), new Scalar(0), 8); + return img; + } + + private Mat getBriefQueryImg() { + Mat img = new Mat(matSize, matSize, CvType.CV_8U, new Scalar(255)); + Core.line(img, new Point(40, matSize - 40), new Point(matSize - 50, 50), new Scalar(0), 8); + return img; + } + + private Mat getBriefTestDescriptors(Mat img) { + List keypoints = new ArrayList(); + Mat descriptors = new Mat(); + + FeatureDetector detector = FeatureDetector.create(FeatureDetector.FAST); + DescriptorExtractor extractor = DescriptorExtractor.create(DescriptorExtractor.BRIEF); + + detector.detect(img, keypoints); + extractor.compute(img, keypoints, descriptors); + + return descriptors; + } + + private Mat getBriefQueryDescriptors() { + return getBriefTestDescriptors(getBriefQueryImg()); + } + + private Mat getBriefTrainDescriptors() { + return getBriefTestDescriptors(getBriefTrainImg()); + } public void testAdd() { matcher.add(Arrays.asList(new Mat())); @@ -200,12 +306,21 @@ public class FlannBasedDescriptorMatcherTest extends OpenCVTestCase { } public void testRead() { - fail("https://code.ros.org/trac/opencv/ticket/1253"); String filename = OpenCVTestRunner.getTempFileName("yml"); - writeFile(filename, "%YAML:1.0\n"); - + writeFile(filename, ymlParamsModified); + matcher.read(filename); - assertTrue(true); + + Mat train = getBriefTrainDescriptors(); + Mat query = getBriefQueryDescriptors(); + List matches = new ArrayList(); + + matcher.match(query, train, matches); + + assertListDMatchEquals(Arrays.asList(new DMatch (0, 0, 0, 0), + new DMatch (1, 2, 0, 0), + new DMatch (2, 1, 0, 0), + new DMatch (3, 3, 0, 0)), matches, EPS); } public void testTrain() { @@ -224,13 +339,19 @@ public class FlannBasedDescriptorMatcherTest extends OpenCVTestCase { } public void testWrite() { - fail("https://code.ros.org/trac/opencv/ticket/1253"); + String filename = OpenCVTestRunner.getTempFileName("xml"); + + matcher.write(filename); + + assertEquals(xmlParamsDefault, readFile(filename)); + } + + public void testWriteYml() { String filename = OpenCVTestRunner.getTempFileName("yml"); matcher.write(filename); - String truth = "%YAML:1.0\n!!!!!"; - assertEquals(truth, readFile(filename)); + assertEquals(ymlParamsDefault, readFile(filename)); } } diff --git a/modules/java/src/cpp/features2d_manual.hpp b/modules/java/src/cpp/features2d_manual.hpp index 6fc25e6a9..5246fe0ba 100644 --- a/modules/java/src/cpp/features2d_manual.hpp +++ b/modules/java/src/cpp/features2d_manual.hpp @@ -245,6 +245,7 @@ public: OPPONENTEXTRACTOR = 1000, + OPPONENT_SIFT = OPPONENTEXTRACTOR + SIFT, OPPONENT_SURF = OPPONENTEXTRACTOR + SURF, OPPONENT_ORB = OPPONENTEXTRACTOR + ORB, @@ -313,27 +314,27 @@ public: CV_WRAP virtual void clear(); CV_WRAP virtual bool isMaskSupported(); CV_WRAP virtual void train(); - CV_WRAP void classify( const Mat& queryImage, vector& queryKeypoints, + CV_WRAP void classify( const Mat& queryImage, CV_IN_OUT vector& queryKeypoints, const Mat& trainImage, vector& trainKeypoints ) const; - CV_WRAP void classify( const Mat& queryImage, vector& queryKeypoints ); + CV_WRAP void classify( const Mat& queryImage, CV_IN_OUT vector& queryKeypoints ); CV_WRAP void match( const Mat& queryImage, vector& queryKeypoints, const Mat& trainImage, vector& trainKeypoints, - vector& matches, const Mat& mask=Mat() ) const; + CV_OUT vector& matches, const Mat& mask=Mat() ) const; CV_WRAP void knnMatch( const Mat& queryImage, vector& queryKeypoints, const Mat& trainImage, vector& trainKeypoints, - vector >& matches, int k, + CV_OUT vector >& matches, int k, const Mat& mask=Mat(), bool compactResult=false ) const; CV_WRAP void radiusMatch( const Mat& queryImage, vector& queryKeypoints, const Mat& trainImage, vector& trainKeypoints, - vector >& matches, float maxDistance, + CV_OUT vector >& matches, float maxDistance, const Mat& mask=Mat(), bool compactResult=false ) const; CV_WRAP void match( const Mat& queryImage, vector& queryKeypoints, - vector& matches, const vector& masks=vector() ); + CV_OUT vector& matches, const vector& masks=vector() ); CV_WRAP void knnMatch( const Mat& queryImage, vector& queryKeypoints, - vector >& matches, int k, + CV_OUT vector >& matches, int k, const vector& masks=vector(), bool compactResult=false ); CV_WRAP void radiusMatch( const Mat& queryImage, vector& queryKeypoints, - vector >& matches, float maxDistance, + CV_OUT vector >& matches, float maxDistance, const vector& masks=vector(), bool compactResult=false ); CV_WRAP virtual bool empty() const; #endif @@ -411,7 +412,7 @@ CV_EXPORTS_W void drawMatches( const Mat& img1, const vector& keypoint const Scalar& matchColor=Scalar::all(-1), const Scalar& singlePointColor=Scalar::all(-1), const vector& matchesMask=vector(), int flags=0 ); -CV_EXPORTS_W void drawMatches( const Mat& img1, const vector& keypoints1, +CV_EXPORTS_AS(drawMatches2) void drawMatches( const Mat& img1, const vector& keypoints1, const Mat& img2, const vector& keypoints2, const vector >& matches1to2, Mat& outImg, const Scalar& matchColor=Scalar::all(-1), const Scalar& singlePointColor=Scalar::all(-1),