1

I am trying to read parameters of Feature Detector (e.g.: SIFT) from an YAML file in OpenCV3.

I am trying to use the propose code in the Documentation. But it does not compile at all. So, I make it to compile, changing a little

#include "opencv2/opencv.hpp"
#include <opencv2/core/persistence.hpp>
#include "opencv2/xfeatures2d.hpp"
using namespace cv::xfeatures2d;


int main () {

  cv::Ptr<cv::Feature2D> surf = SURF::create();
  cv::FileStorage fs("../surf_params.yaml", cv::FileStorage::WRITE);

  if( fs.isOpened() ) // if we have file with parameters, read them
  {
      std::cout << "reading parameters" << std::endl;

      surf->read(fs["surf_params"]);
  }
  else // else modify the parameters and store them; user can later edit the file to use different parameters
  {
      std::cout << "writing parameters" << std::endl;
      cv::Ptr<cv::xfeatures2d::SURF> aux_ptr;
      aux_ptr = surf.dynamicCast<cv::xfeatures2d::SURF>();
      aux_ptr->setNOctaves(3); // lower the contrast threshold, compared to the default value
      {
          cv::internal::WriteStructContext ws(fs, "surf_params", CV_NODE_MAP);
          aux_ptr->write(fs);
      }
  }
  fs.release();

//  cv::Mat image = cv::imread("myimage.png", 0), descriptors;
//  std::vector<cv::KeyPoint> keypoints;
//  sift->detectAndCompute(image, cv::noArray(), keypoints, descriptors);

return 0;

} 

But the the parameters are not read or wrote at all.

I also checked this Transition Guide, and in section "Algorithm interfaces" says that:

General algorithm usage pattern has changed: now it must be created on heap wrapped in smart pointer cv::Ptr. Version 2.4 allowed both stack and heap allocations, directly or via smart pointer.

get and set methods have been removed from the cv::Algorithm class along with CV_INIT_ALGORITHM macro. In 3.0 all properties have been converted to the pairs of getProperty/setProperty pure virtual methods. As a result it is not possible to create and use cv::Algorithm instance by name (using generic Algorithm::create(String) method), one should call corresponding factory method explicitly.

Maybe this means that it is not possible to read and write parameters from an XML/YAML files with read() and write() functions.

Can you give me some axample of how can I read parameters of Feature Detector algorithm from XML/YAML file in OpenCV3?

Thanks in advance!

taihu
  • 72
  • 1
  • 7

1 Answers1

1

If the specific algorithm overrides the methods cv::Algorithm::read and cv::Algorithm::write, then you can use then as described, for example, here.

However, cv::xfeatures2d::SURF doesn't overrides these methods, so you can't use this approach.

You can, however, store the properties you need to modify in a FileStorage, read and write them as usual, and modify the SURF object:

#include <opencv2/opencv.hpp>
#include <opencv2/xfeatures2d.hpp>
#include <opencv2/xfeatures2d/nonfree.hpp>
#include <iostream>

int main() 
{
    cv::Ptr<cv::Feature2D> surf = cv::xfeatures2d::SURF::create();

    {
        // Try to read from file
        cv::FileStorage fs("surf_params.yaml", cv::FileStorage::READ);
        if (fs.isOpened()) 
        {
            std::cout << "reading parameters" << std::endl;

            // Read the parameters
            int nOctaves = fs["nOctaves"];
            surf.dynamicCast<cv::xfeatures2d::SURF>()->setNOctaves(nOctaves);
        }
        else 
        {
            // Close the file in READ mode
            fs.release();

            // Open the file in WRITE mode
            cv::FileStorage fs("surf_params.yaml", cv::FileStorage::WRITE);

            std::cout << "writing parameters" << std::endl;

            fs << "nOctaves" << 3;

            // fs in WRITE mode automatically released
        }
        // fs in READ mode automatically released
    }
}

You can make the surf object a pointer to cv::xfeatures2d::SURF to avoid casts:

cv::Ptr<cv::xfeatures2d::SURF> surf = ...

If you need to support different Features2D, you can store in the FileStorage also an identifier for the particular feature, such as:

 fs << "Type" << "SURF";

and then conditionally read the options to restore its properties:

 string type;
 FileNode fn_type = fs.root();
 type = fn_type["Type"];

 if(type == "SURF") {
     // Read SURF properties...
 } else if(type == "SIFT") {
     // Read SIFT properties...
 }
Community
  • 1
  • 1
Miki
  • 40,887
  • 13
  • 123
  • 202
  • Thanks Miki! You confirm what I thought. So, It is not possible to read in a general way parameters from XML/YML files. I will use the answer that you propose. – taihu Mar 30 '16 at 13:51