// ćwiczenia z końca rozdziału 11
// 1、2、5、6 i 7
#include <opencv2/opencv.hpp>
#include <iostream>

using namespace cv;
using namespace std;

void help(const char **argv) {
	cout << "\n\n"
		<< "Ten program rozwiązuje ćwiczenia z końca rozdziału 11 (oprócz 3、4 i 8)\n"
		<< "Wywołanie:\n"
		<< argv[0] << " <path/image_name>\n\n"
		<< "Na przykład: " << argv[0] << " /AverageMaleFace.jpg\n"
		<< endl;
}

// pobranie współrzędnych punktów po rotacji
Point2f getPointAffinedPos(const Point2f src, const Point2f center, double angle)  
{  
	Point dst;  
	int x = src.x - center.x;  
	int y = src.y - center.y;  

	dst.x = x * cos(angle) + y * sin(angle) + center.x;  
	dst.y = -x * sin(angle) + y * cos(angle) + center.y;  
	return dst;  
}  

int main( int argc, const char** argv )
{
	help(argv);
	if(argc < 2) {
		cout << "\nERROR: You had too few parameters.\n" << endl;
		return -1;
	}
	/************************************************************************/
	/* 1. Znajdź i załaduj obraz twarzy zwróconej przodem, z otwartymi oczami i zajmującej większość powierzchni obrazu. Napisz program znajdujący źrenice oczu.                                                                     */
	/************************************************************************/
	Mat matFrontFace = imread(argv[1]);
	Mat gray;Mat temp;
	double minPixelValue, maxPixelValue;
	Point minPixelPoint,maxPixelPoint;
	cvtColor(matFrontFace,gray,COLOR_BGR2GRAY);
	// Laplacian pyramid
	pyrDown(gray,temp);
	pyrUp(temp,temp);
	temp = gray - temp;
	// znajduje i zakreśla wynik
	minMaxLoc(temp,&minPixelValue,&maxPixelValue,&minPixelPoint,&maxPixelPoint);
	circle(matFrontFace,maxPixelPoint,10,Scalar(255,255,255),2);
	/************************************************************************/
	/* 2.	Spójrz na wykresy przedstawiające, jak funkcja konwersji na współrzędne logarytmiczno-biegunowe zamienia kwadrat w falowaną linię.
a.	Narysuj wyniki konwersji na współrzędne logarytmiczno-biegunowe dla przypadku, gdy punkt środkowy znajduje się w jednym z rogów kwadratu.
b.	Jak wyglądałoby koło po przekształceniu na współrzędne logarytmiczno-biegunowe, gdyby punkt centralny znajdował się wewnątrz tego koła i blisko jego krawędzi?
c.	Narysuj wynik transformacji dla przypadku, gdy punkt centralny znajduje się tuż za krawędzią koła.                                                                     */
	/************************************************************************/
	// rysuje koło, białe na czarnym
	Mat matLogPolar = Mat(512,512,CV_8U,Scalar(0));
	circle(matLogPolar,Point(256,256),100,Scalar(255),3);
	//a
	logPolar(matLogPolar,temp,Point(0,0),40,INTER_CUBIC);
	//b
	logPolar(matLogPolar,temp,Point(256-101,256),40,INTER_CUBIC);
	//c wynik wygląda jak dwa pierścienie
	logPolar(matLogPolar,temp,Point(256-101-3,256),40,INTER_CUBIC);
	/************************************************************************/
	/* 5.	Załaduj obraz i poddaj go przekształceniu perspektywicznemu, a następnie rotacji. Czy można te dwa przekształcenia wykonać za jednym razem?                                            */
	/************************************************************************/
	Mat matE5_1 = imread(argv[1]);
	Mat matE5_2 = imread(argv[1]);
	double angle = 45;
	// macierz perspektywy
	Point2f src_vertices[4];
	src_vertices[0] = Point(0, 0);
	src_vertices[1] = Point(matE5_1.cols, 0);
	src_vertices[2] = Point(matE5_1.cols, matE5_1.rows);
	src_vertices[3] = Point(0, matE5_1.rows);
	Point2f dst_vertices[4];
	dst_vertices[0] = Point(100, 0);
	dst_vertices[1] = Point(matE5_1.cols - 100, 0);
	dst_vertices[2] = Point(matE5_1.cols, matE5_1.rows);
	dst_vertices[3] = Point(0, matE5_1.rows);
	Mat perspectiveMatrix = getPerspectiveTransform(src_vertices, dst_vertices);
	// macierz obrotu
	Mat affineMatrix = getRotationMatrix2D(Point(matE5_1.cols/2,matE5_1.rows/2), angle, 1.0 );
	// perspektywa -> rotacja
	warpPerspective(
		matE5_1, 
		matE5_1, 
		perspectiveMatrix,
		matE5_1.size(), 
		INTER_LINEAR, 
		BORDER_CONSTANT,
		Scalar());
	warpAffine(
		matE5_1,
		matE5_1,
		affineMatrix,
		matE5_1.size(),
		INTER_LINEAR,
		BORDER_CONSTANT,
		Scalar()
		);
	// jeden krok
	Point center = Point(matE5_2.cols/2,matE5_2.rows/2);
	dst_vertices[0] = getPointAffinedPos(dst_vertices[0],center,angle);
	dst_vertices[1] = getPointAffinedPos(dst_vertices[1],center,angle);
	dst_vertices[2] = getPointAffinedPos(dst_vertices[2],center,angle);
	dst_vertices[3] = getPointAffinedPos(dst_vertices[3],center,angle);
	perspectiveMatrix = getPerspectiveTransform(src_vertices, dst_vertices);
	warpPerspective(
		matE5_2, 
		matE5_2, 
		perspectiveMatrix,
		matE5_2.size(), 
		INTER_LINEAR, 
		BORDER_CONSTANT,
		Scalar());
	// wynik jest prawie taki sam
	/************************************************************************/
	/* 6.  6.	Inpainting sprawdza się bardzo dobrze w przypadku usuwania napisów z wzorzystych obszarów. Co by się stało, gdyby napis zasłaniał prawdziwą krawędź obiektu na obrazie? Sprawdź to.                                                                     */
	/************************************************************************/
	Mat matInpaint = imread(argv[1]);
	Mat matInpaintMask = Mat(matInpaint.size(),CV_8UC1,Scalar(0));//the same size,all in black(oh yeah!)
	// rysuje to samo koło na matInpaint i matInpaintMask
	circle(matInpaint,Point(255,255),100,Scalar(255),10);
	circle(matInpaintMask,Point(255,255),100,Scalar(255),10);
	imshow("befor inpaint",matInpaint);
	inpaint(matInpaint,matInpaintMask,matInpaint,10,CV_INPAINT_TELEA);
	imshow("po inpaintingu",matInpaint);
	// wynik: jeśli „napis zasłania prawdziwą krawędź obiektu na obrazie”, wynik jest zły
	/************************************************************************/
	/* 7.	Wypróbuj działanie techniki wyrównywania histogramu na kilku własnych obrazach i opisz wyniki.                                                                     */
	/************************************************************************/
	Mat matSrc = imread(argv[1]);
	vector<Mat> planes;
	split(matSrc,planes);
	imshow("b",planes[0]);
	imshow("g",planes[1]);
	imshow("r",planes[2]);
	cv::equalizeHist(planes[0],planes[0]);
	cv::equalizeHist(planes[1],planes[1]);
	cv::equalizeHist(planes[2],planes[2]);
	imshow("bh",planes[0]);
	imshow("gh",planes[1]);
	imshow("rh",planes[2]);
	waitKey();
	return 0;

}
