#ifndef BOF_H
#define BOF_H

#include <opencv2/opencv.hpp>
#include <opencv2/nonfree/features2d.hpp>

class BoF {
public:
	BoF();
	~BoF();

	enum featureType {SIFT, SURF};

	// 特徴検出
	void detectFeature(const std::string pathToFolder, const int start, const int end, const int featureType);
	// 特徴量記述子の計算
	void computeDescriptors(const int featureType);
	// コードブックの生成
	void createCodebook(const int size, const cv::TermCriteria tc, const int retries, const int flags);
	// 画像記述子の生成
	void createImageDescriptorsForImages(const int featureType);
	// 類似度が最も高い画像を求める
	void computeMostSimilarImage(const cv::Mat img, cv::Mat& similarImg, int& mostSimilarImageIndex, double& dist, const int featureType);


	// コードブックの保存
	void saveCodebook(const std::string pathToXML);
	// コードブックの読み込み
	void loadCodebook(const std::string pathToXML);


private:
	static const int DEFAULT_DESCRIPTOR_DIMENSION;
	static const int DEFAULT_GRID;

	int codebookSize;
	int descriptorDimension;
	int grid; // グリッドサンプリングにおけるグリッドの幅(pixel)
	std::vector<int> gridScale; // グリッドサンプリングにおけるサンプルのスケール

	std::vector<cv::Mat> images;
	std::vector<cv::Mat> imageDescriptors;
	std::vector<std::vector<cv::KeyPoint>> keyPoints;
	std::vector<cv::Mat> descriptors; // grid samplingの数 * 次元数 のMatが画像数だけ格納されている

	cv::Mat codebook;

	cv::BOWKMeansTrainer *BoWTrainer;

	cv::BOWImgDescriptorExtractor *bowDE;
	cv::Ptr<cv::DescriptorMatcher> matcher;
	cv::Ptr<cv::DescriptorExtractor> extractor;

	// 特徴検出(画像1枚分)
	void detectFeatureOfImage(const cv::Mat img, std::vector<cv::KeyPoint>& imgKeyPoints, const int featureType);
	// 画像記述子の生成(画像1枚分)
	void createImageDescriptor(const cv::Mat img, cv::Mat& imgDescriptor, const int featureType);
	// 類似度の計算
	void computeSimilarityToImageDescriptors(const cv::Mat imgDescriptor, int& mostSimilarImageNum, double& dist);

};

#endif