/*
 * detector.hpp
 *
 *  Created on: 16.04.2012
 *      Author: isvoboda
 */

#ifndef DETECTOR_HPP_
#define DETECTOR_HPP_

#include <vector>
#include "opencv2/opencv.hpp"
#include "ppd.hpp"

namespace ppd
{

	/**
	 * Response of the classifier contains the value of response and the position in the image.
	 */
	class Response
	{
	public:
		Response();
		Response(const Response& response);
		Response(cv::Rect_<int>& position, float response);

		float getResponse() const;
		void setResponse(const float response);
		void getPosition(cv::Rect_<int>& pos) const;
		void setPosition(const cv::Rect_<int>& pos);

	public:
		cv::Rect_<int> position;
		float response;
	};

	/**
	 * Detector. Class for scanning the image for some specified object (according to trained classifier).
	 */
	class Detector
	{
	public:

		/**
		 * NonParametric constructor sets as the default scan step 1 px in horizontal and 1px in vertical direction. Min neighbours for declare the detection is 36.
		 */
		Detector();

		/**
		 * Parametric constructor
		 * @param scan_row_step - the step in the vertical direction
		 * @param scan_col_step - the step in the horizontal direction
		 */
		Detector(unsigned int scan_row_step, unsigned int scan_col_step);
//		~Detector();
	public:

		/**
		 * Detects the object in the input image.
		 * @param image - source image
		 * @param descriptor_extractor
		 * @param bow_extractor
		 * @param classifier
		 * @param positions - detected position of specified object
		 * @param responses - vector of responses of the specified objects, it its positions and value of responses
		 * @param min_neigbours - set the minimum of neighbors to declare the detection
		 */
		void detect(const cv::Mat& image,\
				const ppd::Extractor& descriptor_extractor,\
				const ppd::BOW& bow_extractor,\
				const ppd::SVM& classifier,\
				const ppd::Scaler& scaler,\
				std::vector<Response>& positions,\
				std::vector<Response>& responses,\
				unsigned int min_neigbours = 25);

		void tmp(const cv::Mat& image, const ppd::Extractor& descriptor_extractor, const ppd::BOW& bow_extractor, cv::Mat& bow_features) const;

	private:
		void extract_window(const cv::Rect_<int>& sc_window, const std::vector<std::vector<std::vector<int> > > iArray, cv::Mat& bow_feature);

		void scan_image(const cv::Rect_<int>& sc_window,\
				const std::vector<std::vector<std::vector<int> > > iArray,\
				const ppd::SVM& classifier,\
				const ppd::Scaler& scaler,\
				std::vector<Response>& responses);

		void merge(const std::vector<ppd::Response>& responses, std::vector<ppd::Response>& positions, const int min_neighbours = 3);

	private:
		unsigned int scan_row_step;
		unsigned int scan_col_step;
		unsigned int voc_size;
		std::vector<cv::Rect_<int> > sc_windows;
		float scale_factor;
		float _threshold;

	public:
		/**
		 * Sets the scanning step
		 * @param scan_row_step step in the vertical direction
		 * @param scan_col_step step in the horizontal direction
		 */
		void set_scan_steps(const unsigned int scan_row_step, const unsigned int scan_col_step);

		/**
		 * Set the size of scanning windows. If the maximum scanning window is not defined, the maximum scanning window is then adjusted to the size of the scanned image.
		 * @param window_min - minimum size of scanning window
		 * @param scale_factor - the scale factor
		 * @param window_max - the maximum size of scanning window
		 */
		void set_scan_windows(const cv::Size_<int> window_min, const float scale_factor = 0.f, const cv::Size_<int> window_max = cv::Size_<int>(0,0));

		/**
		 * Returns all responses and not only the merged (defined by min neighbor) one.
		 * @param responses
		 */
//		void get_All_Responses(std::vector<ppd::Response>& responses);
	};

	class Scanner
		{
		public:

			/**
			 * NonParametric constructor sets as the default scan step 1 px in horizontal and 1px in vertical direction. Min neighbours for declare the detection is 36.
			 */
			Scanner();

			/**
			 * Parametric constructor
			 * @param scan_row_step - the step in the vertical direction
			 * @param scan_col_step - the step in the horizontal direction
			 */
			Scanner(unsigned int scan_row_step, unsigned int scan_col_step);
	//		~Detector();
		public:

			/**
			 * Detects the object in the input image.
			 * @param image - source image
			 * @param descriptor_extractor
			 * @param bow_extractor
			 * @param feature
			 */
			void scan(const cv::Mat& image,\
					const ppd::Extractor& descriptor_extractor,\
					const ppd::BOW& bow_extractor,\
					cv::Mat& features);


		private:
			void extract_window(const std::vector<std::vector<std::vector<int> > > iArray, const cv::Rect_<int>& sc_window, cv::Mat& feature, bool& extracted);

			void scan_image(const std::vector<std::vector<std::vector<int> > > iArray,\
					const cv::Rect_<int>& sc_window,\
					cv::Mat& features);

		private:
			unsigned int scan_row_step;
			unsigned int scan_col_step;
			unsigned int voc_size;
			std::vector<cv::Rect_<int> > sc_windows;
			float scale_factor;

		public:
			/**
			 * Sets the scanning step
			 * @param scan_row_step step in the vertical direction
			 * @param scan_col_step step in the horizontal direction
			 */
			void set_scan_steps(const unsigned int scan_row_step, const unsigned int scan_col_step);

			/**
			 * Set the size of scanning windows. If the maximum scanning window is not defined, the maximum scanning window is then adjusted to the size of the scanned image.
			 * @param window_min - minimum size of scanning window
			 * @param scale_factor - the scale factor
			 * @param window_max - the maximum size of scanning window
			 */
			void set_scan_windows(const cv::Size_<int> window_min, const float scale_factor = 0.f, const cv::Size_<int> window_max = cv::Size_<int>(0,0));

			/**
			 * Returns all responses and not only the merged (defined by min neighbor) one.
			 * @param responses
			 */
	//		void get_All_Responses(std::vector<ppd::Response>& responses);
		};

}

#endif /* DETECTOR_HPP_ */
