// Listing 22.1. Wykrywanie i rysowanie twarzy

#include <vector>
#include <iostream>
#include <cstdlib>
#include <fstream>
#include <opencv2/opencv.hpp>
#include "opencv2/objdetect.hpp"
#include <opencv2/core/core.hpp>
#include <opencv2/highgui/highgui.hpp>

using std::cout;
using std::cerr;
using std::vector;
using std::string;

// wykrywanie obiektów na obrazie i oznaczanie ich za pomocą prostokątów
//
void detectAndDraw(
        cv::Mat& img,                               // obraz wejściowy
        cv::Ptr<cv::CascadeClassifier> classifier,  // załadowany klasyfikator
        double scale = 1.3) {                       // przeskalowanie obrazu
    //  definicje kolorów do rysowania prostokątów
    //
    enum { BLUE, AQUA, CYAN, GREEN };
    static cv::Scalar colors[] = {
        cv::Scalar(0, 0, 255),
        cv::Scalar(0, 128, 255),
        cv::Scalar(0, 255, 255),
        cv::Scalar(0, 255, 0)
    };
    // PRZYGOTOWYWANIE OBRAZU:
    //
    cv::Mat gray(img.size(), CV_8UC1);
    cv::Mat small_img(cvSize(cvRound(img.cols / scale),
        cvRound(img.rows / scale)), CV_8UC1);
    cv::cvtColor(img, gray, cv::COLOR_BGR2GRAY);
    cv::resize(gray, small_img, small_img.size(), 0.0, 0.0, cv::INTER_LINEAR);
    cv::equalizeHist(small_img, small_img);
    // WYKRYWANIE OBIEKTÓW
    //
    vector<cv::Rect> objects;
	classifier->detectMultiScale(
		small_img, // obraz wejściowy
		objects,   // obiekt do przechowywania wyników
		1.1,       // współczynnik skali
		2,         // minimalna liczba sąsiadów
		cv::HAAR_DO_CANNY_PRUNING, // (dotyczy tylko starych typów kaskady)
		cv::Size(30, 30)           // wykryte obszary o mniejszym rozmiarze będą odrzucane
	);

	// ITERACJA PRZEZ ZNALEZIONE OBIEKTY I RYSOWANIE WOKÓŁ NICH PROSTOKĄTNYCH RAMEK
	//
    int i = 0;
    for (vector<cv::Rect>::iterator r = objects.begin();
            r != objects.end(); r++, ++i) {
        cv::Rect r_ = (*r);
        r_.x *= scale;
        r_.y *= scale;
        r_.width *= scale;
        r_.height *= scale;
        cv::rectangle(img, r_, colors[i % 4]);
    }
}

int main(int argc, char** argv) {
    // Program oczekuje przynajmniej dwóch argumentów:
    //   - ścieżka do pliku obrazu
    //   - ścieżka do pliku .xml klasyfikatora
    //
    if (argc < 3) {
        cerr << "\nBłąd: niepoprawna liczba argumentów.\n";
        cerr    << "\nListing 22.1. Wykrywanie i rysowanie twarzy\n\n"
                << "Sposób użycia:\n" << argv[0] << " <path/image_file> <path/xml_classifier_file>\n"
                << "aby uruchomić to demo\n\n"
                << "Przykład:\n"
                << argv[0] << " ../faces.png ../haarcascade_frontalface_alt.xml\n"
                << std::endl;
        exit(1);
    }
    string image_file_name = string(argv[1]);
    cv::Mat img = cv::imread(image_file_name, CV_LOAD_IMAGE_COLOR);
    string cascade_file_name = string(argv[2]);
    cv::Ptr<cv::CascadeClassifier> cascade(new cv::CascadeClassifier(cascade_file_name));
    detectAndDraw(img, cascade);
    cv::imshow("Result", img);
    cv::waitKey(0);

    return 0;
}
