//piece of code for postprocessing
#include <iostream>
#include "opencv2/opencv.hpp"
#include <stdio.h>
#include "opencv2/imgproc/imgproc.hpp"
#include "opencv2/highgui/highgui.hpp"
#include <stdlib.h>

using namespace cv;
using namespace std;
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////
Mat postprocessing(cv::Mat& input, int& w, int& limitebianchi, int& limiteneri) //postprocessing method
{
	Mat image_post(input.rows-w+1,input.cols-w+1,CV_8UC1);
	Mat finestra(w,w,CV_8UC1);
	input.convertTo(input,CV_8UC1);
	for(int i=0; i<input.cols-w+1; i++)
	{
		for(int j=0; j<input.rows-w+1; j++)
		{
			finestra = input(cv::Rect(i,j,w,w));
			int countbianchi = 0, countneri = 0;
			for(int z=0; z<finestra.cols; z++)
			{
				for(int k=0; k<finestra.rows; k++)
				{
					if(finestra.at<unsigned char>(z,k)==255) countbianchi++;
					else countneri++;
				}
			}

			if(input.at<unsigned char>(j+floor(w/2),i+floor(w/2))==0)
			{
				if(countbianchi>=limitebianchi) image_post.at<unsigned char>(j,i)=255;
				else image_post.at<unsigned char>(j,i)=input.at<unsigned char>(j+floor(w/2),i+floor(w/2));
			}
			else
			{
				if(countneri>=limiteneri) image_post.at<unsigned char>(j,i)=0;
				else image_post.at<unsigned char>(j,i)=input.at<unsigned char>(j+floor(w/2),i+floor(w/2));
			}
		}
	}
	return image_post;
}
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////
Mat difference(cv::Mat& reference, cv::Mat& test) //produce colours enlighted output postprocessed image
{
	reference.convertTo(reference,CV_8UC1);
	test.convertTo(test,CV_8UC1);

	Mat r(reference.rows,reference.cols,CV_8UC1),g(reference.rows,reference.cols,CV_8UC1),b(reference.rows,reference.cols,CV_8UC1);
	Mat channel[3];
	Mat output(reference.rows,reference.cols,CV_8UC1);

	for(int i=0; i<reference.rows; i++)
	{
		for(int j=0; j<reference.cols; j++)
		{
			if(reference.at<uchar>(i,j)==test.at<uchar>(i,j))    //equal
			{
				r.at<uchar>(i,j) = reference.at<uchar>(i,j);
				g.at<uchar>(i,j) = reference.at<uchar>(i,j);
				b.at<uchar>(i,j) = reference.at<uchar>(i,j);
			}else if(reference.at<uchar>(i,j)==255) 			//different && reference == bianco
			{
				r.at<uchar>(i,j) = 0;
				g.at<uchar>(i,j) = 200;
				b.at<uchar>(i,j) = 255;  //yellow for false negative
									    //classified vessels
			}else  												//different && reference == nero
			{
				r.at<uchar>(i,j) = 36;
				g.at<uchar>(i,j) = 28;
				b.at<uchar>(i,j) = 237; //red for false positive classified vessels
			}
		}
	}

	channel[0]=r; channel[1]=g; channel[2]=b;
	merge(channel, 3, output);
	return output;
}
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////
Mat countData(cv::Mat& reference, cv::Mat& mat, cv::Mat destination)
//reference and destination must have same dimensions
//method to compute performance measures
{
	float tp=0, fp=0, tn=0, fn=0;
	reference.convertTo(reference,CV_32F);
	mat.convertTo(mat,CV_32F);

	for(int i=0; i<reference.cols; i++)
	{
		for(int j=0; j<reference.rows; j++)
		{
			if(reference.at<float>(i,j)==255)
			{
				tp++; if(mat.at<float>(i,j)!=reference.at<float>(i,j)) fn++;
			}
			else
			{
				tn++; if(mat.at<float>(i,j)!=reference.at<float>(i,j)) fp++;
			}
		}
	}

	float se,sp,ppv,npv,acc;

	se = tp / (tp + fn); 	sp = tn / (tn + fp);
	ppv = tp / (tp + fp); 	npv = tn / (tn + fn);
	acc = (tp + tn) / (tp + fn + tn + fp);

	Mat data(1,5,CV_32FC1);
	data.at<float>(0,0)=se; data.at<float>(0,1)=sp; data.at<float>(0,2)=ppv; data.at<float>(0,3)=npv; data.at<float>(0,4)=acc;
	destination = data;
	cout<<data<<endl;

	return destination;
}
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

int main( int argc, char** argv )
{
	//parameters
	int  w = 3, vicinibianchi=6, vicinineri=8;

	//list of strings for recursive postprocessing over DRIVE database

	string listref[] = {"01_manual_cut.tif","02_manual_cut.tif","03_manual_cut.tif","04_manual_cut.tif","05_manual_cut.tif","06_manual_cut.tif","07_manual_cut.tif","08_manual_cut.tif","09_manual_cut.tif","10_manual_cut.tif",
						"11_manual_cut.tif","12_manual_cut.tif","13_manual_cut.tif","14_manual_cut.tif","15_manual_cut.tif","16_manual_cut.tif","17_manual_cut.tif","18_manual_cut.tif","19_manual_cut.tif","20_manual_cut.tif",
                        "21_manual_cut.tif","22_manual_cut.tif","23_manual_cut.tif","24_manual_cut.tif","25_manual_cut.tif","26_manual_cut.tif","27_manual_cut.tif","28_manual_cut.tif","29_manual_cut.tif","30_manual_cut.tif",
						"31_manual_cut.tif","32_manual_cut.tif","33_manual_cut.tif","34_manual_cut.tif","35_manual_cut.tif","36_manual_cut.tif","37_manual_cut.tif","38_manual_cut.tif","39_manual_cut.tif","40_manual_cut.tif"};

	string listref2[] = {"01_manual_cut2.tif","02_manual_cut2.tif","03_manual_cut2.tif","04_manual_cut2.tif","05_manual_cut2.tif","06_manual_cut2.tif","07_manual_cut2.tif","08_manual_cut2.tif","09_manual_cut2.tif","10_manual_cut2.tif",
			             "11_manual_cut2.tif","12_manual_cut2.tif","13_manual_cut2.tif","14_manual_cut2.tif","15_manual_cut2.tif","16_manual_cut2.tif","17_manual_cut2.tif","18_manual_cut2.tif","19_manual_cut2.tif","20_manual_cut2.tif",
                         "21_manual_cut2.tif","22_manual_cut2.tif","23_manual_cut2.tif","24_manual_cut2.tif","25_manual_cut2.tif","26_manual_cut2.tif","27_manual_cut2.tif","28_manual_cut2.tif","29_manual_cut2.tif","30_manual_cut2.tif",
						 "31_manual_cut2.tif","32_manual_cut2.tif","33_manual_cut2.tif","34_manual_cut2.tif","35_manual_cut2.tif","36_manual_cut2.tif","37_manual_cut2.tif","38_manual_cut2.tif","39_manual_cut2.tif","40_manual_cut2.tif"};

	string listin[] = {"01p.tif","02p.tif","03p.tif","04p.tif","05p.tif","06p.tif","07p.tif","08p.tif","09p.tif","10p.tif",
			   	   	   "11p.tif","12p.tif","13p.tif","14p.tif","15p.tif","16p.tif","17p.tif","18p.tif","19p.tif","20p.tif",
			           "21p.tif","22p.tif","23p.tif","24p.tif","25p.tif","26p.tif","27p.tif","28p.tif","29p.tif","30p.tif",
					   "31p.tif","32p.tif","33p.tif","34p.tif","35p.tif","36p.tif","37p.tif","38p.tif","39p.tif","40p.tif",};

	string listouttif[] = {"01processed.tif","02processed.tif","03processed.tif","04processed.tif","05processed.tif","06processed.tif","07processed.tif","08processed.tif","09processed.tif","10processed.tif",
						   "11processed.tif","12processed.tif","13processed.tif","14processed.tif","15processed.tif","16processed.tif","17processed.tif","18processed.tif","19processed.tif","20processed.tif",
					       "21processed.tif","22processed.tif","23processed.tif","24processed.tif","25processed.tif","26processed.tif","27processed.tif","28processed.tif","29processed.tif","30processed.tif",
						   "31processed.tif","32processed.tif","33processed.tif","34processed.tif","35processed.tif","36processed.tif","37processed.tif","38processed.tif","39processed.tif","40processed.tif"};

	string listouttifdifference[] = {"01processed_difference.tif","02processed_difference.tif","03processed_difference.tif","04processed_difference.tif","05processed_difference.tif","06processed_difference.tif","07processed_difference.tif","08processed_difference.tif","09processed_difference.tif","10processed_difference.tif",
						             "11processed_difference.tif","12processed_difference.tif","13processed_difference.tif","14processed_difference.tif","15processed_difference.tif","16processed_difference.tif","17processed_difference.tif","18processed_difference.tif","19processed_difference.tif","20processed_difference.tif",
						             "21processed_difference.tif","22processed_difference.tif","23processed_difference.tif","24processed_difference.tif","25processed_difference.tif","26processed_difference.tif","27processed_difference.tif","28processed_difference.tif","29processed_difference.tif","30processed_difference.tif",
						             "31processed_difference.tif","32processed_difference.tif","33processed_difference.tif","34processed_difference.tif","35processed_difference.tif","36processed_difference.tif","37processed_difference.tif","38processed_difference.tif","39processed_difference.tif","40processed_difference.tif"};

	//recursive postprocessing

	for(int i=0; i<sizeof(listin)/4; i++)
	{
		string input = listin[i];                   //354x354 dimension used
		string nameref = listref[i];			   //354x354 dimension used
		string nameref2 = listref2[i];			  //352x352 dimension used
		string outputtif = listouttif[i];
		string outputtifdifference = listouttifdifference[i];

		Mat image = imread(input,0);          image.convertTo(image, CV_32F);
		Mat reference = imread(nameref,0); 	  reference.convertTo(reference, CV_32F);
		Mat reference2 = imread(nameref2,0);  reference2.convertTo(reference2, CV_32F);

		Mat image_post = postprocessing(image,w,vicinibianchi,vicinineri); //352x352 dimension used
		Mat image_difference = difference(reference2,image_post);
		imwrite(outputtif,image_post);
		imwrite(outputtifdifference,image_difference);

		Mat datapre,datapost;
		countData(reference,image,datapre);
		countData(reference2,image_post,datapost);
	}

	waitKey(0);
	return 0;
}
