Opencv里面,特征提取可以分为两步进行:detection + computation,具体为detection后,得要一些keypoints,然后在这些keypoints上应用相应的描述符。
SIFT是一个比较常用的特征,下面就以SIFT特征为例,在Opencv进行SIFT提取(SIFT detection + SIFT description)。具体代码如下:
static inline void unpackOctave(const KeyPoint& kpt, int& octave, int& layer, float& scale) { octave = kpt.octave & 255; layer = (kpt.octave >> 8) & 255; octave = octave < 128 ? octave : (-128 | octave); scale = octave >= 0 ? 1.f / (1 << octave) : (float)(1 << -octave); } string strfixedLength(const int i, const int length) { ostringstream oss; if (i < 0) { oss << '-1'; } oss << setfill('0') << setw(length) << (i < 0 ? -i : i); return oss.str(); } int main() { initModule_nonfree(); int nImages = 1; string image_path = "D:\\Datasets\\ukbench\\ukbench_test\\ukbench"; //string image_path = "D:\\Datasets\\ukbench\\ukbench_imgs\\full\\ukbench"; Mat img; vector<KeyPoint> keypoints; vector<KeyPoint>::iterator itr_keypoints; Ptr<FeatureDetector> detector = FeatureDetector::create("SIFT"); Ptr<DescriptorExtractor> extractor = DescriptorExtractor::create("SIFT"); Mat sift_tmp; ofstream img_sift_info("sift_info.txt", ofstream::out); ofstream img_sift("sift.txt", ofstream::out); string img_name = "ukbench"; for (int i = 0; i < nImages; ++i) { img_name = "ukbench"; img_name = img_name + strfixedLength(i, 5) + ".jpg"; cout << img_name << endl; img = imread(image_path + strfixedLength(i, 5) + ".jpg", CV_LOAD_IMAGE_GRAYSCALE); // SIFT detection detector->detect(img, keypoints); // SIFT description extractor->compute(img, keypoints, sift_tmp); if (keypoints.size() != sift_tmp.rows) { cout << "Error: number of keypoints should matched the number of descriptor matrix rows!" << endl; return -1; } // sift file format: "x y:octave:angle:sift descriptor" int octave; int layer; float scale; for (int i = 0; i < sift_tmp.rows; ++i) { unpackOctave(keypoints[i], octave, layer, scale); img_sift << keypoints[i].pt.x << " " << keypoints[i].pt.y << ":" << octave << ":" << keypoints[i].angle << ":"; for (int j = 0; j < sift_tmp.cols - 1; ++j) { img_sift << *(float *)(sift_tmp.data + sift_tmp.step[0] * i + sift_tmp.step[1] * j) << " "; } img_sift << *(float *)(sift_tmp.data + sift_tmp.step[0] * i + sift_tmp.step[1] * (sift_tmp.cols - 1)) << endl; } // sift info file format: "image_name:num. of sift" img_sift_info << img_name << ":" << keypoints.size() << endl; keypoints.clear(); } img_sift.close(); img_sift_info.close(); system("pause"); return 0; }
Opencv里面把octave,scale,layer等都编码到keypoint的octave中,具体可以看https://stackoverflow.com/questions/17015995/opencv-sift-descriptor-keypoint-radius
上面特征提取代码里面的unpackOctave(const KeyPoint& kpt, int& octave, int& layer, float& scale)函数就是用来将keypoint octave解码成对应的参数的(copy from sift.cpp)。
此外,还需注意的是,不同的detection方法(SIFT、SURF、MSER等),keypoint不同成员变量(octave、size等)的具体含义是不尽相同的,使用时需要小心。