OpenCV - How to implement FeatureDetector interface - c++

I am using the C++ implementation of OpenCV 2.4.6.1 for Ubuntu 12.10 on a x86_64 architecture. I am working on wrapping this code of the Agast Corner Detector inside a class inheriting from cv::FeatureDetector.
Inspecting the feature2d module header code and observing other implementations, I found I should mandatory implement the detectImpl method:
virtual void detectImpl( const Mat& image, std::vector<KeyPoint>& keypoints, const Mat& mask=Mat() ) const = 0;
Usually it is also implementented a method named operator having the following signature:
CV_WRAP_AS(detect) void operator()(const Mat& image, CV_OUT std::vector<KeyPoint>& keypoints) const;
Looking at other implementations I cannot say exactly what each of this methods should do. The second one operator I guess is somehow related to the detect method that is called for detecting keypoints:
cv::Ptr<cv::FeatureDetector> detector = cv::FeatureDetector::create("...");
detector->detect(img, keypoints);
According to your experience what's the difference between this two methods and what should each of them implement?
Related to the detector's instantiation using the factory method cv::FeatureDetector::create I have some clues related to the attribute info of type AlgorithmInfo* usually put as a public attribute of the detector class implementation, and using the CV_INIT_ALGORITHM in the features2d_init source file.
What should I implement in order to be able to instantiate my custom FeatureDetector using the factory method?

Finally after a few days of work I succeeded on my commitment and learned a few lessons about implementing cv::FeatureDetector interface:
Include the wrapping class into the cv namespace.
The only method mandatory to implement is detectImpl using the signature of the method on the OpenCV version you are using.
Implementing the operator method is optional, in other implementations where it is used (e.g. MserFeatureDetector and StarDetector) this method is called from detectImpl through the class instance:
void ...::detectImpl( const Mat& image, std::vector<KeyPoint>& keypoints, const Mat& mask ) const {
...
(*this)(grayImage, keypoints);
...
}
void ...::operator()(const Mat& img, std::vector<KeyPoint>& keypoints) const{
...
}
Be aware that detectImpl is a const method and hence it cannot modify instance parameters so It might turn useful defining the concrete behavior of the detector on a side function as done in other detector implementations (e.g. FastFeatureDetector or StarDetector)
To enable the wrapper to be instantiated using the factory method cv::FeatureDetector::create you should add to your class declaration the public method AlgorithmInfo* info() const; and initialize the class as an algorithm inside OpenCV using the CV_INIT_ALGORITHM as follows:
namespace cv{
CV_INIT_ALGORITHM(AgastFeatureDetector, "Feature2D.AGAST", obj.info()->addParam(obj, "threshold", obj.threshold); obj.info()->addParam(obj, "nonmaxsuppression", obj.nonmaxsuppression); obj.info()->addParam(obj, "type", obj.type));
}
If your class doesn't needs any parameter you can simply substitute all the params part by obj.info()
Remind also to do this outside the source files where you are declaring (.h) or defining (.cpp) your wrapper and include the opencv2/core/internal.hpp library.

Related

C++ more than one instance of overloaded function matches the argument list when creating a header file

Within my main file of my program I have the following declarations
int main()
{
Customer c;
Part p;
Builder b;
auto partsVec = readpartFile();
auto customerVec = readcustomerFile();
auto builderVec = readbuilderFile();
fexists("Parts.txt");
complexity(c, partsVec);
robotComplexity(partsVec,customerVec);
writeFile(buildAttempt(b, complexity(c, partsVec), variability(customerVec, builderVec)));
}
My header file consists of the following
vector<Part> readpartFile();
vector<Customer> readcustomerFile();
vector<Builder> readbuilderFile();
float complexity(const Customer& c, const std::vector<Part>& parts);
void robotComplexity(vector<Part> vecB, vector<Customer> vecC);
double variability(const vector<Customer>& customerList, const vector<Builder>& builderList);
vector<double> buildAttempt(Builder b, double variaiblity, double complexityRobot);
void writeFile(vector<double> build);
All functions link up except for robotComplexity. My declaration of this function in main creates the following error.
more than one instance of overloaded function "robotComplexity" matches the argument list: -- function "robotComplexity(const std::vector> &parts, const std::vector> &customers)" -- function "robotComplexity(std::vector> vecB, std::vector> vecC)" -- argument types are: (std::vector>, std::vector>)
im not sure why im getting this error or how to resolve it
You have a mismatch between declaration in header and definition (which also serves as declaration):
void robotComplexity(vector<Part> vecB, vector<Customer> vecC);
void robotComplexity(const vector<Part>& vecB, const vector<Customer>& vecC);
Whereas parameter names can mismatch, types shouldn't, else, you create another overload.
Jarod42's Answer is quite correct, but I want to add to it and provide a helpful methodology for future C++ coding.
When function signatures differ, the compiler will not complain. At best, you will receive a cryptic or hard to read linker error. This is especially common with inheritance and virtual functions. Even worse, sometimes they will work but actually call a new function with a different signature on a child class that doesn't match the base class.
There is a keyword in C++11 (and newer versions) called override. Here is a more in depth discussion about what they keyword does: OverrideKeywordLink
When this keyword is used on a virtual function, it becomes a compile error when the intended virtual function override does not match the base class function signature. Also, it gives a very human readable reason why the function override did not occur.
You mentioned in a comment that 'How come const made it different"? The answer is it all comes down to function signatures. Consider these two functions within a class.
class MyClass {
int CalculateSomething();
int CalculateSomething() const;
}
The const actually changes the function signature. They are considered two different functions. The bottom line is, always try to make errors compile errors over run-time errors. Use keywords that protect you from some few tribal C++ knowledge traps that exist.

export opencv Gaussian mixture model of backgroundsubtractorMOG2

I'm using the MOG2 algorithm for background subtration in opencv 3.2. I want to look at the learned gaussian mixture models(weights, variance, mean...), however opencv does not provide built-in function to look at the values.
In bgfg_gaussmix2.cpp source code, I found the variables I need in class BackgroundSubtractorMOG2Impl:
UMat u_weight;
UMat u_variance;
UMat u_mean;
UMat u_bgmodelUsedMod
So what I did is just put some functions that can return the variables(in the same format as the built-in functions)
virtual UMat getWeight() const { return u_weight; }
virtual UMat getVariance() const { return u_variance; }
virtual UMat getMean() const { return u_mean; }
virtual UMat getNmodes() const {return u_bgmodelUsedModes;}
Then I also added the following to the background_segm.hpp file, in class CV_EXPORTS_W BackgroundSubtractorMOG2:
CV_WRAP virtual UMat getWeight() const = 0;
CV_WRAP virtual UMat getVariance() const = 0;
CV_WRAP virtual UMat getMean() const = 0;
CV_WRAP virtual UMat getNmodes() const = 0;
After this, I build and install the modified opencv source code. Then I wrote my own program to run the backgroundubtractorMOG2 algorithm. I can call the new functions I added to the opencv source code, but the returned UMats are just full of zeros.
So my question is how to get the UMats in the right way?

OpenCV C++, Define a background model

I am busy converting and interpreting software used in previous years of my final year project.
I would just like to check if it is possible to define a background model in a header file, as i am currently getting an error.
class CWaterFill
{
public:
void Initialise();
Mat ContourFilter(Mat Img, int minSize);
Mat superminImg;
protected:
BackgroundSubtractorMOG2 m_bg_model;//Define the background model.
};
It is then used in the .cpp file in the following function:
void CWaterFill::GMM2(Mat InputImg, int nFrame, double learnRate)
{
m_bg_model(InputImg, m_fgmask, learnRate);//m_fgmask outlook is
}
Use a pointer to an abstract BackgroundSubtractor object:
...
protected:
cv::Ptr<BackgroundSubtractor> m_bg_model;//Define the background model.
And then create the concrete type, e.g.:
m_bg_model = createBackgroundSubtractorMOG2(20, 16, true);

OpenCV trackbar callback in C++ class

I have a question about how to define the callback for trackbars in OpenCV when working with classes in C++.
When I define my trackbar let's say in the constructor method of my .cpp class how can I define the callback?
I have been trying to work with function pointers but it doesn't work out. I guess I must be doing something very wrong :-)
This is my header file:
class SliderwithImage {
public:
SliderwithImage(void);
~SliderwithImage(void);
void sliderCallBack(int pos);
};
This is the implementation file:
#include "SliderwithImage.h"
void SliderwithImage::sliderCallBack(int pos) {
}
SliderwithImage::SliderwithImage(void) {
const char* windowName = "window";
int lowvalue =1;
namedWindow(windowName, CV_GUI_EXPANDED);
createTrackbar("mytrackbar", windowName, &lowvalue, 255, sliderCallBack);
}
SliderwithImage::~SliderwithImage(void) {
}
Obviously the createTrackbar method does not recognize sliderCallBack... I guess it's a problem of scope. But I am not sure how to solve this?
Any help would be appreciated.
Thank you very much.
The callback function must be static or global, but you can pass it a reference to an object you want to operate on (see this post on the OpenCV Users mailing list).
The createTrackbar method has a userdata parameter which is passed to the calling function. In C there is an undocumented cvCreateTrackbar2 method, defined in highgui_c.h, which has the same functionality:
CVAPI(int) cvCreateTrackbar2( const char* trackbar_name, const char* window_name,
int* value, int count, CvTrackbarCallback2 on_change,
void* userdata CV_DEFAULT(0));
These methods let you create a class with a static callback function that takes a pointer to an object of that class. You can create the trackbar like so:
cv:createTrackbar("Label", "Window" &variable, MAX_VAL, &MyClass::func, this);
The callback would look something like this:
void MyClass:func(int newValue, void * object) {
MyClass* myClass = (MyClass*) object;
// ...do stuff.
}
Note that you don't need to explicitly update the variable yourself as long as you provided a pointer to it when creating the trackbar (as above), but if you need to process it first I suggest you set it explicitly in the callback function.
You have to implement the callback function either as a global function or a static member function. To make it more OOP look, you might prefer to implement it as a static member function:)
I am using a different solution to obtain the slider value in a class variable (in my case to obtain chosen rotation angle of a live video stream). The int* value in the createTrackbar function is a public class variable which is then used within a loop (while the video is acquired, but this might messily work repeatedly redrawing a single image).
Not the best solution but it works for me.
cv::createTrackbar("Rotation Angle(deg)", "Preview", &rotationAngle,
alpha_slider_max, NULL);
for(;;)
{
int rotAngle = this -> rotationAngle;
cv::Mat frame;
cv::Mat rot_frame;
this -> capture >> frame;
rot_frame = rotateVideo (frame, rotAngle);
imshow("Preview", rot_frame);
if(cv::waitKey(30) >= 0) break;
}

was not declared in this scope

I am new in C++ and working on a project with QT. I created a header file called imageconvert.h which is as follow:
class ImageConvert
{
private:
IplImage *imgHeader;
uchar* newdata;
public:
ImageConvert();
~ImageConvert();
IplImage* QImage2IplImage(QImage *qimg);
QImage* IplImage2QImage(IplImage *iplImg);
};
also I defined those public methods in imageconvert.cpp file.
Now, I want to call QImage2IplImage and IplImage2QImage from other cpp file. So i include imageconvert.h in that CPP file and called those two functions.
it gives the the following errors:
error: 'QImage2IplImage' was not declared in this scope
error: 'IplImage2QImage' was not declared in this scope
Any help would be greatly appreciated.
The functions you've defined are member functions of the ImageConvert class. You need an instance of that class to be able to call them.
Something like:
ImageConvert ic;
ic.QImage2IplImage(your_QImage_object);
If you don't need state to do the conversion, you should make those helper functions static. Then you can call them with:
ImageConvert::QImage2IplImage(your_QImage_object);
without first creating an instance of ImageConvert. But please note that you will not be able to use imgHeader or newData in those static functions - they are member variables, only usable within an instance of that class.
You could also remove these functions from your class and put them in a namespace.
Your question...
How exactly do you call those functions? Given your ImageConverter class, this is how you should be doing it:
// First create a new converter
ImageConverter conv;
IplImage* ipl = conv.QImage2IplImage(qimg);
qimg = conv.IplImage2QImage(ipl);
... And some advice on using classes
Do you by any chance come from a Java or C# background? If so, you should know that in C++ you can also have free functions (that don't belong to any class). You should only use classes when you need to abstract a certain (real world) concept, and not simply as a way to group functions:
// image_converter.h
IplImage* QImage2IplImage(const QImage* qimg);
QImage* IplImage2QImage(const IplImage* iplImg);
// someother.cpp
IplImage* ipl = QImage2IplImage(qimg);
qimg = IplImage2QImage(ipl);
Notice I added const to the function parameters — it's a good thing to be const correct. Additionaly, you can group your functions in a namespace:
// image_converter.h
namespace converter
{
IplImage* QImage2IplImage(const QImage* qimg);
QImage* IplImage2QImage(const IplImage* iplImg);
}
// someother.cpp
IplImage* ipl = converter::QImage2IplImage(qimg);
qimg = converter::IplImage2QImage(ipl);