//Exercises_12_1.cpp ćwiczenia z końca rozdziału 12

#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 1, 2 i 11 z rozdziału 12 \n"
		<< "Wywołanie:\n"
		<< argv[0] << " <path/image_name1>" << " <path/image_name2>\n\n"
		<< "Na przykład: ./" << argv[0] << " ../left.jpg "<< " ../left.jpg\n"
		<< endl;
}

int main( int argc, const char** argv )
{
  help(argv);
	if(argc < 3) {
		cout << "\nBłąd: za mało parametrów.\n" << endl;
		return -1;
	}

	/************************************************************************/
	/* 1. Celem tego ćwiczenia jest nauczenie się znajdowania odpowiednich wartości dla parametrów lowThresh i highThresh funkcji cv::Canny(). Załaduj obraz przedstawiający ciekawą strukturę liniową. Zastosujemy trzy różne proporcje ustawień górnej i dolnej wartości progowej: 1,5:1, 2,75:1 oraz 4:1.
a.	Co widzisz, gdy górny próg ma wartość mniejszą od 50?
b.	Co widzisz, gdy górny próg ma wartość w przedziale od 50 do 100?
c.	Co widzisz, gdy górny próg ma wartość w przedziale od 100 do 150?
d.	Co widzisz, gdy górny próg ma wartość w przedziale od 150 do 200?
e.	Co widzisz, gdy górny próg ma wartość w przedziale od 200 do 250?
f.	Podsumuj otrzymane wyniki i wyjaśnij je najlepiej jak potrafisz.                                                                     */
	/************************************************************************/
  Mat src = imread(argv[1],IMREAD_GRAYSCALE);
	Mat dst;
	
	int iHighThresh = 50;
	Canny(src,dst,static_cast<int>(iHighThresh/1.5),iHighThresh);
	imshow("iHighThresh wynosi 50 a high:low wynosi 1.5:1",dst);
	Canny(src,dst,static_cast<int>(iHighThresh/2.75),iHighThresh);
	imshow("iHighThresh wynosi 50 a high:low wynosi 2.75:1",dst);
	Canny(src,dst,static_cast<int>(iHighThresh/4),iHighThresh);
	imshow("iHighThresh wynosi 50 a high:low wynosi 4:1",dst);

	iHighThresh = (50+100)/2;
	Canny(src,dst,static_cast<int>(iHighThresh/1.5),iHighThresh);
	imshow("iHighThresh wynosi (50+100)/2 a high:low wynosi 1.5:1",dst);
	Canny(src,dst,static_cast<int>(iHighThresh/2.75),iHighThresh);
	imshow("iHighThresh wynosi (50+100)/2 a  high:low wynosi 2.75:1",dst);
	Canny(src,dst,static_cast<int>(iHighThresh/4),iHighThresh);
	imshow("iHighThresh wynosi (50+100)/2 a  high:low wynosi 4:1",dst);

	iHighThresh = (100+150)/2;
	Canny(src,dst,static_cast<int>(iHighThresh/1.5),iHighThresh);
	imshow("iHighThresh wynosi (100+150)/2 a  high:low wynosi 1.5:1",dst);
	Canny(src,dst,static_cast<int>(iHighThresh/2.75),iHighThresh);
	imshow("iHighThresh wynosi (100+150)/2 a  high:low wynosi 2.75:1",dst);
	Canny(src,dst,static_cast<int>(iHighThresh/4),iHighThresh);
	imshow("iHighThresh wynosi (100+150)/2 a  high:low wynosi 4:1",dst);

	iHighThresh = (150+200)/2;
	Canny(src,dst,static_cast<int>(iHighThresh/1.5),iHighThresh);
	imshow("iHighThresh wynosi (150+200)/2 a  high:low wynosi 1.5:1",dst);
	Canny(src,dst,static_cast<int>(iHighThresh/2.75),iHighThresh);
	imshow("iHighThresh wynosi (150+200)/2 a high:low wynosi 2.75:1",dst);
	Canny(src,dst,static_cast<int>(iHighThresh/4),iHighThresh);
	imshow("iHighThresh wynosi (150+200)/2 a  high:low wynosi 4:1",dst);

	iHighThresh = (200+250)/2;
	Canny(src,dst,static_cast<int>(iHighThresh/1.5),iHighThresh);
	imshow("iHighThresh wynosi (200+250)/2 a  high:low wynosi 1.5:1",dst);
	Canny(src,dst,static_cast<int>(iHighThresh/2.75),iHighThresh);
	imshow("iHighThresh wynosi (200+250)/2 a  high:low wynosi 2.75:1",dst);
	Canny(src,dst,static_cast<int>(iHighThresh/4),iHighThresh);
	imshow("iHighThresh wynosi (200+250)/2 a  high:low wynosi 4:1",dst);

	/************************************************************************/
	/* 2.	Załaduj obraz przedstawiający wyraźne linie i koła, np. zdjęcie roweru. Poddaj je transformacji liniowej i kołowej Hougha i sprawdź wyniki.                                                                     */
	/************************************************************************/
	Mat src = imread(argv[1],IMREAD_GRAYSCALE);//a bike in gray
	GaussianBlur( src, src, Size(9, 9), 2, 2 );
	Mat temp;
	vector<Vec4i> linesP;
	vector<Vec3f> circles;
	// najpierw znajduje krawędź canny'ego
	Canny(src,temp,50,200);
	// znajduje linie
	HoughLinesP(temp,linesP,1,CV_PI/180,80,50,10);
	// znajduje koła
	HoughCircles( src, circles, CV_HOUGH_GRADIENT, 1, src.rows/8, 200, 100, 0, 0 );
	// rysuje linie i koła na obrazie źródłowym
	for (int i = 0;i<linesP.size();i++)
	{
		Vec4i l = linesP[i];
		line(src,Point(l[0],l[1]),Point(l[2],l[3]),Scalar(255));
	}

	for( size_t i = 0; i < circles.size(); i++ )
	{
		Point center(cvRound(circles[i][0]), cvRound(circles[i][1]));
		int radius = cvRound(circles[i][2]);
		// środek koła
		circle( src, center, 3, Scalar(255,255,255), -1, 8, 0 );
		// obrys koła
		circle( src, center, radius, Scalar(255,255,255), 1, 8, 0 );
	}
	
	/*11. Utwórz obraz zawierający kwadrat o wymiarach 20×20. Obróć go o dowolny kąt. Wykonaj transformację odległościową tego obrazu. Utwórz kwadrat o wymiarach 20×20. Przy użyciu obrazu wynikowego transformacji odległościowej algorytmicznie nałóż ten kształt na obrócony kwadrat znajdujący się na utworzonym przez siebie obrazie.*/
	// tworzy kwadrat o boku 20 × 20
	Mat matBoard = Mat(500,500,CV_8UC3,Scalar(0));
	rectangle(matBoard,Rect(250,250,20,20),Scalar(255,255,255),-1);
	// tworzy arbitralny kąt
	cv::RNG rng = cv::theRNG();
	float fDegree = rng.uniform(0,360);
	Mat rotMatS = getRotationMatrix2D(Point(250,250), fDegree, 1.0);
	warpAffine(matBoard, matBoard, rotMatS, matBoard.size(), 1, 0, Scalar(0,0,0));
	// rozwiązuje problem
	Mat matDistance;
	cvtColor(matBoard,gray,COLOR_BGR2GRAY);
	threshold(gray,gray,100,255,CV_THRESH_BINARY); 
	distanceTransform(gray,matDistance,CV_DIST_L2,3);  
       // znajduje środkowe rogi
	double minVal; 
	double maxVal2; 
	Point minLoc,maxLoc;
	minMaxLoc( matDistance, &minVal, &maxVal2, &minLoc, &maxLoc, matDistance>0); 
	// rysuje wynik
	circle(matBoard,maxLoc,1,Scalar(0),1);
	circle(matBoard,minLoc,2,Scalar(255),2);
	rectangle(matBoard,Rect(maxLoc.x - 10,maxLoc.y - 10,20,20),Scalar(0,0,255),-1);
	return 0;
}
 
