First of all, this is my first time using C++. I'm using C++ because OpenCV is very limited in C.
OpenCV documentation isn't the most explicative I've seen.
I have tried to rewrite this ORB example for use in my project.
The code is:
img_orb.cpp
:
/******************************************************************************
******* headers **************************************************************
******************************************************************************/
/* Standard (C++) ------------------------------------------------------------*/
/* std::vector */
#include <vector>
/* Packages ------------------------------------------------------------------*/
/* opencv */
#include <opencv2/opencv.hpp>
#include <opencv2/features2d/features2d.hpp>
/* Project -------------------------------------------------------------------*/
#include "img_orb.hpp"
/******************************************************************************
******* macros ***************************************************************
******************************************************************************/
# define MAX_FEATURES (500)
# define GOOD_MATCH_P (0.15)
/******************************************************************************
******* main *****************************************************************
******************************************************************************/
void img_orb_align (struct _IplImage *pattern,
struct _IplImage *imgptr)
{
/* Transform (struct _IplImage *) to (class cv::Mat) */
/* Make a copy so that they aren't modified */
class cv::Mat img_0;
class cv::Mat img_1;
img_0 = cv::cvarrToMat(pattern, true);
img_1 = cv::cvarrToMat(imgptr, true);
/* Variables to store keypoints & descriptors */
std::vector <class cv::KeyPoint> keypoints_0;
std::vector <class cv::KeyPoint> keypoints_1;
class cv::Mat descriptors_0;
class cv::Mat descriptors_1;
/* Detect ORB features & compute descriptors */
class cv::Ptr <class cv::Feature2D> orb;
orb = cv::ORB::create(MAX_FEATURES);
orb->detectAndCompute(img_0, cv::Mat(), keypoints_0, descriptors_0);
orb->detectAndCompute(img_1, cv::Mat(), keypoints_1, descriptors_1);
/* Match structures */
std::vector <struct cv::DMatch> matches;
cv::Ptr <class cv::DescriptorMatcher> matcher;
matcher = cv::DescriptorMatcher::create("BruteForce-Hamming");
matcher->match(descriptors_1, descriptors_0, matches, cv::Mat());
/* Sort matches by score */
std::sort(matches.begin(), matches.end());
/* Remove not so good matches */
int good_matches;
good_matches = GOOD_MATCH_P * matches.size();
matches.erase(matches.begin() + good_matches, matches.end());
/* Draw top matches */
class cv::Mat img_matches;
cv::drawMatches(img_1, keypoints_1, img_0, keypoints_0, matches,
img_matches);
cv::imwrite("matches.jpg", img_matches);
/* Extract location of good matches */
std::vector <class cv::Point_ <float>> points_0;
std::vector <class cv::Point_ <float>> points_1;
int i;
for (i = 0; i < matches.size(); i++) {
points_1.push_back(keypoints_1[matches[i].queryIdx].pt);
points_0.push_back(keypoints_0[matches[i].trainIdx].pt);
}
/* Find homography */
class cv::Mat img_hg;
img_hg = cv::findHomography(points_1, points_0, CV_RANSAC);
/* Use homography to warp image */
class cv::Mat img_align;
cv::warpPerspective(img_1, img_align, img_hg, img_0.size());
/* Write img_align into imgptr */
*imgptr = img_align;
}
/******************************************************************************
******* end of file **********************************************************
******************************************************************************/
Note: When I write C, I always try to follow the Linux Kernel Coding Style; that's the reason I avoided typedef
s, namespace
s, and wrote class
and all that stuff before everything; I like to have everything be very explicit.
The first thing is that I had to remove #include "opencv2/xfeatures2d.hpp"
because that header does not exist on my system (Debian Stretch). However, I read that header here, and it doesn't seem to contain the solution to my problem.
When I compile that file, I get the following errors:
/.../img_orb.cpp: In function ‘void img_orb_align(_IplImage*, _IplImage*)’:
/.../img_orb.cpp:78:36: error: no matching function for call to ‘cv::ORB::create(int)’
orb = cv::ORB::create(MAX_FEATURES);
^
In file included from /usr/include/opencv2/opencv.hpp:53:0,
from /.../img_orb.cpp:19:
/usr/include/opencv2/features2d/features2d.hpp:269:35: note: candidate: static cv::Ptr<cv::Feature2D> cv::Feature2D::create(const string&)
CV_WRAP static Ptr<Feature2D> create( const string& name );
^~~~~~
/usr/include/opencv2/features2d/features2d.hpp:269:35: note: no known conversion for argument 1 from ‘int’ to ‘const string& {aka const std::__cxx11::basic_string<char>&}’
/.../img_orb.cpp:79:7: error: ‘class cv::Feature2D’ has no member named ‘detectAndCompute’; did you mean ‘detectImpl’?
orb->detectAndCompute(img_0, cv::Mat(), keypoints_0, descriptors_0);
^~~~~~~~~~~~~~~~
/.../img_orb.cpp:80:7: error: ‘class cv::Feature2D’ has no member named ‘detectAndCompute’; did you mean ‘detectImpl’?
orb->detectAndCompute(img_1, cv::Mat(), keypoints_1, descriptors_1);
^~~~~~~~~~~~~~~~
Makefile:101: recipe for target 'img_orb.s' failed
Is the example I took simply broken? Does it fail because I lack one header? Does it fail because I didn't understand some C++ stuff? Else?
EDIT:
Installed OpenCV like this: apt-get install libopencv-dev
Version in debian stretch is: 2.4.9.1+dfsg1-2
Change the following parts of the code:
void img_orb_align (struct _IplImage *pattern,
struct _IplImage **imgptr2)
...
substitute imgptr
by *imgptr2
...
/* Detect ORB features & compute descriptors */
/* This works in openCV 2.4, but does not work in openCV 3.x */
class cv::ORB orb;
orb(img_0, cv::Mat(), keypoints_0, descriptors_0);
orb(img_1, cv::Mat(), keypoints_1, descriptors_1);
#if 0
/* This did not work in openCV 2.4; It does work in openCV 3.x */
class cv::Ptr <class cv::Feature2D> orb;
orb = cv::ORB::create(MAX_FEATURES);
orb->detectAndCompute(img_0, cv::Mat(), keypoints_0, descriptors_0);
orb->detectAndCompute(img_1, cv::Mat(), keypoints_1, descriptors_1);
#endif
...
/* Write img_align into imgptr (need a tmp img; don't know why) */
struct _IplImage imgtmp;
int cols;
int rows;
int depth;
int chan;
cols = img_align.cols;
rows = img_align.rows;
depth = (*imgptr2)->depth;
chan = (*imgptr2)->nChannels;
cvReleaseImage(imgptr2);
*imgptr2 = cvCreateImage(cvSize(cols, rows), depth, chan);
imgtmp = img_align;
cvCopy(&imgtmp, *imgptr2);
img_align.release();
#if 0
/* This did not work */
*imgptr = img_align;
#endif