VLFeat中SIFT特征点检测
本代码使用VLFeat库中的函数对一幅图像进行了SIFT检测
需要事先配置好VLFeat和OpenCV,VLFeat的配置参考前一篇博文,OpenCV的配置网上一大堆,自己去百度
#include "stdafx.h" #include <stdio.h> #include <tchar.h> #include <opencv2/opencv.hpp> #include <stdio.h> using namespace cv; using namespace std; extern "C"{ #include <vl/generic.h> #include <vl/stringop.h> #include <vl/sift.h> #include <vl/getopt_long.h> }; int _tmain(int argc, _TCHAR* argv[]) { // 注意此处一定是0,不能不填,因为是单通道,灰度空间 IplImage* img = cvLoadImage("1.jpg", 0); // 此处这三个变量的定义看下面vl_sift_new函数中的解释 int noctaves = 4, nlevels = 2, o_min = 0; // vl_sift_pix 就是float型数据 vl_sift_pix *imgdata = new vl_sift_pix[img->height * img->width]; // 将原图像复制到float型的vl_sift_pix数组中 unsigned char *Pixel; for (int i=0;i<img->height;i++) { for (int j=0;j<img->width;j++) { Pixel=(unsigned char*)(img->imageData+i*img->width+j); imgdata[i*img->width+j]=*(Pixel); } } // VlSiftFilt: This filter implements the SIFT detector and descriptor. // 这个过滤器实现了SIFT检测器和描述符 VlSiftFilt *siftfilt = NULL; // vl_sift_new(int width, int height, int noctaves, int nlevels, int o_min) // noctaves: numbers of octaves 组数 // nlevels: numbers of levels per octave 每组的层数 // o_min: first octave index 第一组的索引号 siftfilt = vl_sift_new(img->width, img->height, noctaves, nlevels, o_min); float Descri[1000][128]; //记录每个特征点的描述符,一个特征点有可能有多个描述符,最多有4个 int area[1000][4]; //0~3分别记录每个特征点的坐标x,y,圆的半径大小r,该特征点的方向个数,或者说描述符个数 int keypoint = 0; int idx_point = 0; //特征点的个数 int idx_descri = 0; //特征点描述符的个数 >= idx_point // vl_sift_process_first_octave: // The function starts processing a new image by computing its Gaussian scale space at the lower octave. // It also empties the internal keypoint buffer. // 这个函数开始处理一幅新图像,通过计算它在低层的高斯尺度空间 // 它还清空内部记录关键点的缓冲区 if (vl_sift_process_first_octave(siftfilt, imgdata) != VL_ERR_EOF) { while (1) { // 计算每组中的关键点 vl_sift_detect(siftfilt); // 遍历每个特征点 keypoint += siftfilt->nkeys; VlSiftKeypoint *pkeypoint = siftfilt->keys; for (int i = 0; i < siftfilt->nkeys; i ++) { VlSiftKeypoint tempkeypoint = *pkeypoint; pkeypoint++; area[idx_point][0] = tempkeypoint.x; area[idx_point][1] = tempkeypoint.y; area[idx_point][2] = tempkeypoint.sigma/2; // 计算并遍历每个点的方向 double angles[4]; // The function computes the orientation(s) of the keypoint k. // The function returns the number of orientations found (up to four). // The orientations themselves are written to the vector angles. // 计算每个极值点的方向,包括主方向和辅方向,最多4个方向 int angleCount = vl_sift_calc_keypoint_orientations(siftfilt, angles, &tempkeypoint); area[idx_point][3] = angleCount; idx_point ++; for (int j = 0; j < angleCount; ++ j) { printf("%d: %f\n", j, angles[j]); // 计算每个方向的描述符 float *descriptors = new float[128]; vl_sift_calc_keypoint_descriptor(siftfilt, descriptors, &tempkeypoint, angles[j]); memcpy(Descri[idx_descri], descriptors, 128 * sizeof(float)); idx_descri ++; delete []descriptors; descriptors = NULL; } } // vl_sift_process_next_octave: // The function computes the next octave of the Gaussian scale space. // Notice that this clears the record of any feature detected in the previous octave. // 这个函数计算高斯尺度空间中的下一组尺度空间图像 // 这个函数会清除在前一层空间中检测到的特征点 if (vl_sift_process_next_octave(siftfilt) == VL_ERR_EOF) { break; } keypoint = 0; } } vl_sift_delete(siftfilt); delete []imgdata; imgdata = NULL; for (int i = 0; i < idx_point; ++ i) { cvDrawCircle(img, cvPoint(area[i][0], area[i][1]), area[i][3], CV_RGB(255,0,0)); } cvNamedWindow("Source Image", 1); cvShowImage("Source Image", img); cvWaitKey(0); cvReleaseImage(&img); cvDestroyAllWindows(); return 0; }