Skip to content

Instantly share code, notes, and snippets.

@thorikawa
Created August 19, 2012 23:37
Show Gist options
  • Save thorikawa/3398619 to your computer and use it in GitHub Desktop.
Save thorikawa/3398619 to your computer and use it in GitHub Desktop.
SIFT keypoint matcher using OpenCV C++ interface
#include <opencv2/opencv.hpp>
#include <opencv2/nonfree/nonfree.hpp>
#include <iostream>
#include <vector>
#include <cmath>
using namespace std;
using namespace cv;
const double THRESHOLD = 400;
/**
* Calculate euclid distance
*/
double euclidDistance(Mat& vec1, Mat& vec2) {
double sum = 0.0;
int dim = vec1.cols;
for (int i = 0; i < dim; i++) {
sum += (vec1.at<uchar>(0,i) - vec2.at<uchar>(0,i)) * (vec1.at<uchar>(0,i) - vec2.at<uchar>(0,i));
}
return sqrt(sum);
}
/**
* Find the index of nearest neighbor point from keypoints.
*/
int nearestNeighbor(Mat& vec, vector<KeyPoint>& keypoints, Mat& descriptors) {
int neighbor = -1;
double minDist = 1e6;
for (int i = 0; i < descriptors.rows; i++) {
KeyPoint pt = keypoints[i];
Mat v = descriptors.row(i);
double d = euclidDistance(vec, v);
//printf("%d %f\n", v.cols, d);
if (d < minDist) {
minDist = d;
neighbor = i;
}
}
if (minDist < THRESHOLD) {
return neighbor;
}
return -1;
}
/**
* Find pairs of points with the smallest distace between them
*/
void findPairs(vector<KeyPoint>& keypoints1, Mat& descriptors1,
vector<KeyPoint>& keypoints2, Mat& descriptors2,
vector<Point2f>& srcPoints, vector<Point2f>& dstPoints) {
for (int i = 0; i < descriptors1.rows; i++) {
KeyPoint pt1 = keypoints1[i];
Mat desc1 = descriptors1.row(i);
int nn = nearestNeighbor(desc1, keypoints2, descriptors2);
if (nn >= 0) {
KeyPoint pt2 = keypoints2[nn];
srcPoints.push_back(pt1.pt);
dstPoints.push_back(pt2.pt);
}
}
}
int main(int argc, char** argv) {
if (argc < 2) {
cerr << "Too few arguments" << endl;
return -1;
}
const char* filename = argv[1];
printf("load file:%s\n", filename);
// initialize detector and extractor
FeatureDetector* detector;
detector = new SiftFeatureDetector(
0, // nFeatures
4, // nOctaveLayers
0.04, // contrastThreshold
10, //edgeThreshold
1.6 //sigma
);
DescriptorExtractor* extractor;
extractor = new SiftDescriptorExtractor();
// Compute keypoints and descriptor from the source image in advance
vector<KeyPoint> keypoints2;
Mat descriptors2;
Mat originalGrayImage = imread(filename, CV_LOAD_IMAGE_GRAYSCALE);
if (!originalGrayImage.data) {
cerr << "gray image load error" << endl;
return -1;
}
Mat originalColorImage = imread(filename, CV_LOAD_IMAGE_ANYCOLOR|CV_LOAD_IMAGE_ANYDEPTH);
if (!originalColorImage.data) {
cerr << "color image open error" << endl;
return -1;
}
detector->detect(originalGrayImage, keypoints2);
extractor->compute(originalGrayImage, keypoints2, descriptors2);
printf("original image:%d keypoints are found.\n", (int)keypoints2.size());
VideoCapture capture(0);
capture.set(CV_CAP_PROP_FRAME_WIDTH,640);
capture.set(CV_CAP_PROP_FRAME_HEIGHT,480);
namedWindow("mywindow");
Mat frame;
while (1) {
capture >> frame;
// load gray scale image from camera
Size size = frame.size();
Mat grayFrame(size, CV_8UC1);
cvtColor(frame, grayFrame, CV_BGR2GRAY);
if (!grayFrame.data) {
cerr << "cannot find image file1" << endl;
exit(-1);
}
// Create a image for displaying mathing keypoints
Size sz = Size(size.width + originalColorImage.size().width, size.height + originalColorImage.size().height);
Mat matchingImage = Mat::zeros(sz, CV_8UC3);
// Draw camera frame
Mat roi1 = Mat(matchingImage, Rect(0, 0, size.width, size.height));
frame.copyTo(roi1);
// Draw original image
Mat roi2 = Mat(matchingImage, Rect(size.width, size.height, originalColorImage.size().width, originalColorImage.size().height));
originalColorImage.copyTo(roi2);
vector<KeyPoint> keypoints1;
Mat descriptors1;
vector<DMatch> matches;
// Detect keypoints
detector->detect(grayFrame, keypoints1);
extractor->compute(grayFrame, keypoints1, descriptors1);
printf("image1:%zd keypoints are found.\n", keypoints1.size());
for (int i=0; i<keypoints1.size(); i++){
KeyPoint kp = keypoints1[i];
circle(matchingImage, kp.pt, cvRound(kp.size*0.25), Scalar(255,255,0), 1, 8, 0);
}
// Find nearest neighbor pairs
vector<Point2f> srcPoints;
vector<Point2f> dstPoints;
findPairs(keypoints1, descriptors1, keypoints2, descriptors2, srcPoints, dstPoints);
printf("%zd keypoints are matched.\n", srcPoints.size());
char text[256];
sprintf(text, "%zd/%zd keypoints matched.", srcPoints.size(), keypoints2.size());
putText(matchingImage, text, Point(0, cvRound(size.height + 30)), FONT_HERSHEY_SCRIPT_SIMPLEX, 1, Scalar(0,0,255));
// Draw line between nearest neighbor pairs
for (int i = 0; i < (int)srcPoints.size(); ++i) {
Point2f pt1 = srcPoints[i];
Point2f pt2 = dstPoints[i];
Point2f from = pt1;
Point2f to = Point(size.width + pt2.x, size.height + pt2.y);
line(matchingImage, from, to, Scalar(0, 255, 255));
}
// Display mathing image
imshow("mywindow", matchingImage);
int c = waitKey(2);
if (c == '\x1b')
break;
}
return 0;
}
@kylelk
Copy link

kylelk commented Jun 26, 2014

How do i compile this

@bababoss
Copy link

please upload
opencv2/nonfree/nonfree.hpp also

@sagartesla
Copy link

During First Run it gave me access vialation error. After going through code, I found bugs.... here
In euclidDistance function , It wasn't able to access both vectors i.e.(1 D Matrix ) vec1 and vec2 :-

So I made change here as follow:
for (int i = 0; i < 1; i++)
for( int j=0; j< dim ; j++)
{
uchar * a = vec1.ptr(i);
uchar * b = vec2.ptr(i);
sum += (a[j]- b[j]) *(a[j]- b[j]) ;
}

And it working well :-) 👍

@gary2020
Copy link

gary2020 commented Jul 8, 2016

hi guys
i want change this code that replace input images from hard rather than camera
can you help me ????

@YensyGomez
Copy link

Hello, How to compile sift code???

@mohbattharani
Copy link

install nonfree on ubuntu

sudo add-apt-repository --yes ppa:xqms/opencv-nonfree
sudo apt-get update
sudo apt-get install libopencv-nonfree-dev

@shabrinarin
Copy link

i can't run this code, can you help me?

@jrojas9206
Copy link

jrojas9206 commented Jul 5, 2017

@shabrinarin, if you are working with opencv3.x, you have to remove from line 78 to 88 and add in the same interval the following

cv::Ptrcv::xfeatures2d::SIFT sift;
sift = cv::xfeatures2d::SIFT::create(0,4,0.04,10,1.6);

and change
detector->detect(originalGrayImage, keypoints2); to sift->detect(originalGrayImage, keypoints2);
extractor->compute(grayFrame, keypoints1, descriptors1); to sift->compute(grayFrame, keypoints1, descriptors1);

And, if you are in ubuntu, you can compile the code with the following (If opencv is installed in the default path)
g++ -I/usr/local/include/opencv -I/usr/local/include matching_sift.cpp -o matching_sift.cpp -L/usr/local/lib -lopencv_xfeatures2d -lopencv_highgui -lopencv_core -lopencv_video -lopencv_imgproc -lopencv_features2d -lopencv_imgcodecs

to run the code ./matching_sift img.jpg

@alikakar
Copy link

can some one send the complete code of SIFT for videos .in open cv c++

@alikakar
Copy link

if is this is my id [email protected]

@Kaushik2017
Copy link

can anyone upload the correct code for opencv3.2.0

@Kaushik2017
Copy link

also what flags do we have to set in project properties after installing the extra modules so that sift features are enabled.
i am getting errors like "identifier is expected " in above code.

@Kaushik2017
Copy link

@jrojas9206
cv::Ptrcv::xfeatures2d::SIFT sift;
sift = cv::xfeatures2d::SIFT::create(0,4,0.04,10,1.6);
There might be some changes in these lines . i m getting some errors.

@PaoloGz
Copy link

PaoloGz commented Jan 15, 2018

For OpenCv 3.2 and above.

Change:

 FeatureDetector* detector;
 detector = new SiftFeatureDetector(0,4,0.04,10,1.6);

in:

 cv::Ptr<cv::xfeatures2d::SIFT> sift;
 sift = cv::xfeatures2d::SIFT::create (0,4,0.04,10,1.6);

Delete:

 DescriptorExtractor* extractor;
 extractor = new SiftDescriptorExtractor();

Change:

 detector->detect(originalGrayImage, keypoints2);
 extractor->compute(originalGrayImage, keypoints2, descriptors2);

in:

 sift->detect (originalGrayImage,keypoints2);
 sift->compute (originalGrayImage, keypoints2, descriptors2);

Change:

 detector->detect(grayFrame, keypoints1);
 extractor->compute(grayFrame, keypoints1, descriptors1);

in:

 sift->detect (grayFrame, keypoints1);
 sift->compute (grayFrame, keypoints1, descriptors1);

Tested.

@kaliadi
Copy link

kaliadi commented Sep 17, 2018

error

please hel me

In file included from /usr/local/include/opencv2/nonfree/nonfree.hpp:46:0,
from main.cpp:2:
/usr/local/include/opencv2/nonfree/features2d.hpp:73:21: error: ‘vector’ has not been declared
vector& keypoints) const;
^
/usr/local/include/opencv2/nonfree/features2d.hpp:73:27: error: expected ‘,’ or ‘...’ before ‘<’ token
vector& keypoints) const;
^
/usr/local/include/opencv2/nonfree/features2d.hpp:77:21: error: ‘vector’ has not been declared
vector& keypoints,
^
/usr/local/include/opencv2/nonfree/features2d.hpp:77:27: error: expected ‘,’ or ‘...’ before ‘<’ token
vector& keypoints,
^
/usr/local/include/opencv2/nonfree/features2d.hpp:76:10: error: ‘void cv::SIFT::operator()(cv::InputArray, cv::InputArray, int) const’ cannot be overloaded
void operator()(InputArray img, InputArray mask,
^
/usr/local/include/opencv2/nonfree/features2d.hpp:72:10: error: with ‘void cv::SIFT::operator()(cv::InputArray, cv::InputArray, int) const’
void operator()(InputArray img, InputArray mask,
^
/usr/local/include/opencv2/nonfree/features2d.hpp:81:5: error: ‘AlgorithmInfo’ does not name a type
AlgorithmInfo* info() const;
^
/usr/local/include/opencv2/nonfree/features2d.hpp:83:49: error: ‘vector’ has not been declared
void buildGaussianPyramid( const Mat& base, vector& pyr, int nOctaves ) const;
^
/usr/local/include/opencv2/nonfree/features2d.hpp:83:55: error: expected ‘,’ or ‘...’ before ‘<’ token
void buildGaussianPyramid( const Mat& base, vector& pyr, int nOctaves ) const;
^
/usr/local/include/opencv2/nonfree/features2d.hpp:84:33: error: ‘vector’ does not name a type
void buildDoGPyramid( const vector& pyr, vector& dogpyr ) const;
^
/usr/local/include/opencv2/nonfree/features2d.hpp:84:39: error: expected ‘,’ or ‘...’ before ‘<’ token
void buildDoGPyramid( const vector& pyr, vector& dogpyr ) const;
^
/usr/local/include/opencv2/nonfree/features2d.hpp:85:39: error: ‘vector’ does not name a type
void findScaleSpaceExtrema( const vector& gauss_pyr, const vector& dog_pyr,
^
/usr/local/include/opencv2/nonfree/features2d.hpp:85:45: error: expected ‘,’ or ‘...’ before ‘<’ token
void findScaleSpaceExtrema( const vector& gauss_pyr, const vector& dog_pyr,
^
/usr/local/include/opencv2/nonfree/features2d.hpp:89:40: error: ‘vector’ has not been declared
void detectImpl( const Mat& image, vector& keypoints, const Mat& mask=Mat() ) const;
^
/usr/local/include/opencv2/nonfree/features2d.hpp:89:46: error: expected ‘,’ or ‘...’ before ‘<’ token
void detectImpl( const Mat& image, vector& keypoints, const Mat& mask=Mat() ) const;
^
/usr/local/include/opencv2/nonfree/features2d.hpp:90:41: error: ‘vector’ has not been declared
void computeImpl( const Mat& image, vector& keypoints, Mat& descriptors ) const;
^
/usr/local/include/opencv2/nonfree/features2d.hpp:90:47: error: expected ‘,’ or ‘...’ before ‘<’ token
void computeImpl( const Mat& image, vector& keypoints, Mat& descriptors ) const;
^
/usr/local/include/opencv2/nonfree/features2d.hpp:125:28: error: ‘vector’ has not been declared
CV_OUT vector& keypoints) const;
^
/usr/local/include/opencv2/nonfree/features2d.hpp:125:34: error: expected ‘,’ or ‘...’ before ‘<’ token
CV_OUT vector& keypoints) const;
^
In file included from /usr/local/include/opencv2/nonfree/nonfree.hpp:46:0,
from main.cpp:2:
/usr/local/include/opencv2/nonfree/features2d.hpp:128:28: error: ‘vector’ has not been declared
CV_OUT vector& keypoints,
^
/usr/local/include/opencv2/nonfree/features2d.hpp:128:34: error: expected ‘,’ or ‘...’ before ‘<’ token
CV_OUT vector& keypoints,
^
/usr/local/include/opencv2/nonfree/features2d.hpp:127:10: error: ‘void cv::SURF::operator()(cv::InputArray, cv::InputArray, int) const’ cannot be overloaded
void operator()(InputArray img, InputArray mask,
^
In file included from /usr/local/include/opencv2/nonfree/nonfree.hpp:46:0,
from main.cpp:2:
/usr/local/include/opencv2/nonfree/features2d.hpp:124:10: error: with ‘void cv::SURF::operator()(cv::InputArray, cv::InputArray, int) const’
void operator()(InputArray img, InputArray mask,
^
In file included from /usr/local/include/opencv2/nonfree/nonfree.hpp:46:0,
from main.cpp:2:
/usr/local/include/opencv2/nonfree/features2d.hpp:132:5: error: ‘AlgorithmInfo’ does not name a type
AlgorithmInfo* info() const;
^
/usr/local/include/opencv2/nonfree/features2d.hpp:142:40: error: ‘vector’ has not been declared
void detectImpl( const Mat& image, vector& keypoints, const Mat& mask=Mat() ) const;
^
/usr/local/include/opencv2/nonfree/features2d.hpp:142:46: error: expected ‘,’ or ‘...’ before ‘<’ token
void detectImpl( const Mat& image, vector& keypoints, const Mat& mask=Mat() ) const;
^
/usr/local/include/opencv2/nonfree/features2d.hpp:143:41: error: ‘vector’ has not been declared
void computeImpl( const Mat& image, vector& keypoints, Mat& descriptors ) const;
^
/usr/local/include/opencv2/nonfree/features2d.hpp:143:47: error: expected ‘,’ or ‘...’ before ‘<’ token
void computeImpl( const Mat& image, vector& keypoints, Mat& descriptors ) const;
^
main.cpp: In function ‘int main(int, char**)’:
main.cpp:78:11: error: ‘xfeatures2d’ is not a member of ‘cv’
cv::Ptrcv::xfeatures2d::SIFT sift;
^
main.cpp:78:11: error: ‘xfeatures2d’ is not a member of ‘cv’
main.cpp:78:32: error: template argument 1 is invalid
cv::Ptrcv::xfeatures2d::SIFT sift;
^
main.cpp:79:14: error: ‘cv::xfeatures2d’ has not been declared
sift = cv::xfeatures2d::SIFT::create(
^
main.cpp:105:47: error: ‘detect’ was not declared in this scope
sift = detect (originalGrayImage, keypoints2);
^
main.cpp:106:62: error: ‘compute’ was not declared in this scope
sift = compute (originalGrayImage, keypoints2, descriptors2);
^
main.cpp:143:11: error: base operand of ‘->’ is not a pointer
sift -> detect (grayFrame, keypoints1);
^
main.cpp:144:11: error: base operand of ‘->’ is not a pointer
sift -> compute (grayFrame, keypoints1, descriptors1);
^
nbproject/Makefile-Debug.mk:72: recipe for target 'build/Debug/GNU-Linux/main.o' failed
make[2]: *** [build/Debug/GNU-Linux/main.o] Error 1
make[2]: Leaving directory '/home/ak/Documents/Data/Panorama Drone SIFT/SIFT-master/Helloword'
nbproject/Makefile-Debug.mk:60: recipe for target '.build-conf' failed
make[1]: *** [.build-conf] Error 2
make[1]: Leaving directory '/home/ak/Documents/Data/Panorama Drone SIFT/SIFT-master/Helloword'
nbproject/Makefile-impl.mk:39: recipe for target '.build-impl' failed
make: *** [.build-impl] Error 2

BUILD FAILED (exit value 2, total time: 1s)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment