#include "funkce.h"

void show_image(my_image * img,int time){
    IplImage * img_s=img->get_cv_image();
    cvShowImage("mainWin", img_s);
    if(time>=0)cvSetMouseCallback( "mainWin", my_mouse_callback_write_pixel, (void*) img_s);
    if(time>=0)cvWaitKey(time);
    if(time>=0)cvDestroyWindow("mainWin");
    cvReleaseImage(&img_s);
}



void save_image(my_image * img,char * name){
    IplImage * img_s=img->get_cv_image();
    cvSaveImage(name,img_s);
    cvReleaseImage(&img_s);
}

void show_point_on_image(my_image * img,std::vector<BOD> body,int size){
    IplImage * img_ss=img->get_cv_image();
    IplImage * img_s=cvCreateImage(cvSize(img_ss->width,img_ss->height),img_ss->depth,3);
    cvCvtColor(img_ss,img_s,CV_GRAY2BGR);
    CvPoint pt1, pt2;
    int half=size/2;
    CvScalar color=cvScalar(0,0,255);

    std::vector<BOD>::iterator it;
    for(it=body.begin();it!=body.end();it++)
    {
        pt1.x = it->x-half;
        pt1.y = it->y-half;

        pt2.x = it->x+half;
        pt2.y = it->y+half;
        if(it==body.begin()+3){
            color.val[0]=0;
            color.val[1]=255;
            color.val[2]=0;
        }
        if(it==body.begin()+6){
            color.val[0]=255;
            color.val[1]=0;
            color.val[2]=0;
        }


        cvRectangle( img_s, pt1, pt2, color, 1, 8, 0 );
        std::cout<<"bod x "<<it->x<<" y "<<it->y<<" value "<<it->val<<"\n";

    }

    cvNamedWindow( "body" );

    cvSetMouseCallback( "body", my_mouse_callback_write_pixel, (void*) img_s);

    cvShowImage("body", img_s);
    std::cout<<std::endl;
    cvWaitKey(0);
    cvDestroyWindow("body");
    cvReleaseImage(&img_s);
    cvReleaseImage(&img_ss);
}


bool BOD::operator<(const BOD &druhy) const
{
   return this->val<druhy.val;
}

my_image * gauss_smooth(my_image *img, int size_kernel){
    IplImage *src=img->get_cv_image();
    IplImage * dest =cvCreateImage( cvSize(src->width,src->height), src->depth, src->nChannels );


    cvSmooth( src, dest, CV_GAUSSIAN, size_kernel, size_kernel );

    my_image* result=new my_image(dest);

    cvReleaseImage(&src);
    cvReleaseImage(&dest);
return result;
}



my_image * edge(my_image * img,double t1,double t2,int size){
    IplImage *src=img->get_cv_image();
    IplImage * dest =cvCreateImage( cvSize(src->width,src->height), src->depth, src->nChannels );


    cvCanny(src,dest,t1,t2,size);
    invert(dest);

    my_image* result=new my_image(dest);

    cvReleaseImage(&src);
    cvReleaseImage(&dest);
return result;
}

void invert(IplImage * dest){
    if(dest==NULL){
        std::cout<<"vstupni obraz je nulovy!!!";
        return;
    }

 uchar * data      = (uchar *)dest->imageData;
    // invert the image
    for(int i=0;i<dest->height;i++) for(int j=0;j<dest->width;j++) for(int k=0;k<dest->nChannels;k++)
       data[i*dest->widthStep+j*dest->nChannels+k]=255-data[i*dest->widthStep+j*dest->nChannels+k];
return ;
}


void my_mouse_callback_write_pixel( int event, int x, int y, int flags, void* param ){
    IplImage* image = (IplImage*) param;

    switch( event ){
            case CV_EVENT_MOUSEMOVE:

                    break;

            case CV_EVENT_LBUTTONDOWN:
                    CvScalar s;
                    s=cvGet2D(image,y,x);
                    std::cout<<"bod "<<x<< "x" <<y<< " hodnota "<<s.val[0]<<std::endl;//<< <<std::endl;
                    //std::cout<<"bod"<<std::endl;
                    break;

            case CV_EVENT_LBUTTONUP:

                    break;
    }

}


my_image * load_image(const char * path){
        IplImage *img_cv = cvLoadImage(path,0);
        if(img_cv==NULL )
        {
           std::cout<<"obraz nenacten"<<"\n";
           return NULL;
        }


        my_image *my_img_ref=new my_image(img_cv);
        cvReleaseImage(&img_cv);
        return my_img_ref;
}




my_image_T<int> * harris(my_image *img,int okenko){
    int w=img->Width();
    int h=img->Height();


    // Masky Prewittova hranového detektoru
    //int ** maska =new int [3][3];//{{1,1,1}, {1,1,1},{1,1,1}};
    int maskaX[3][3] ={{1,1,1}, {0,0,0},{-1,-1,-1}};
    int maskaY[3][3] ={{1,0,-1}, {1,0,-1},{1,0,-1}};


    //tvorim derivace:
    my_image_T<int> * Ix= convolution(img,(int *)maskaX,3,6);
    my_image_T<int> * Iy= convolution(img,(int *)maskaY,3,6);
    my_image_T<int> * Ixy= new my_image_T<int>(Ix);
    my_image_T<int> * out= new my_image_T<int>(w,h);

    Ix->nasob(Ix);
    Iy->nasob(Iy);
    Ixy->nasob(Iy);

    int A,B,C;
    unsigned int H;
    double k=0.05;
    int r=okenko;//cistici okno
    int akt;

    for(int j=r;j<h-r;j++){//jedu od r do h-r protoze tam nedosahne cistici okno a chci to mit cerny
        for(int i=r;i<w-r;i++){
            A=Ix->get(i,j);
            B=Iy->get(i,j);
            C=Ixy->get(i,j);
            H=(unsigned int) ((double)(A*B-C*C))-(double(k*(double)((A+B)*(A+B))));
            out->set(i,j,H);
        }
    }


//cistici okno
    for(int j=r;j<h-r;j++){
        for(int i=r;i<w-r;i++){
            if(out->get(i,j)==0)
                continue;
            akt=out->get(i,j);
            for(int a=-r;a<r;a++){
                for(int b=-r;b<r;b++){
                    if(out->get(i+a,j+b)>akt){
                        akt=0;
                        break;
                    }
                    //odstraneni tesnych sousedu
                    if(out->get(i+a,j+b)==akt && akt!=0){
                        out->set(i+a,j+b,out->get(i+a,j+b)-1);
                    }//*/

                }
            }
            out->set(i,j,akt);
        }
    }

    delete Ix;
    delete Iy;
    delete Ixy;

return out;
}


my_image_T<int>  * harris_cv(my_image *img,int blockSize,int aperture,double k){
    double scale, shift;
    double min=0,max=255,maxVal,minVal;
    IplImage * img_cv=img->get_cv_image();
    //IplImage * img_cv2=cvCreateImage( cvSize(img_cv->width*10,img_cv->height), img_cv->depth, img_cv->nChannels );
    IplImage * img_cv_32=cvCreateImage(cvGetSize(img_cv),IPL_DEPTH_32F ,img_cv->nChannels );


    cvCornerHarris(img_cv,img_cv_32,blockSize,aperture,k);

    cvMinMaxLoc( img_cv_32, &minVal, &maxVal, NULL, NULL, 0);
    scale = (max - min)/(maxVal-minVal);
    shift = -minVal * scale + min;
    cvConvertScale( img_cv_32, img_cv, scale, shift );

    /*cvNamedWindow( "precorner", 1);
    cvShowImage( "precorner", img_cv_32);
    cvWaitKey(0);//*/

    my_image * pom=new my_image(img_cv);
    my_image_T<int>  *ret=new my_image_T<int>(pom);

    delete pom;
    cvReleaseImage(&img_cv_32);
    cvReleaseImage(&img_cv);
    return ret;
}


my_image_T<int>* convolution(my_image *img, int * maska, int sirka,int delitel)
{
    int w=img->Width();
    int h=img->Height();

my_image_T<int>* out=new my_image_T<int>(w,h);
int sum;

for(int j=0;j<h-sirka;j++){
    for(int i=0;i<w-sirka;i++){
        sum=0;
        for(int a=0;a<sirka;a++){
            for(int b=0;b<sirka;b++){
                int m=maska[(sirka*a)+b];
                int bod=img->get(i+a,j+b);
                int cit=m*bod;
                sum+=cit;
            }
        }
        out->set(i+(sirka/2),j+(sirka/2),sum/delitel);
    }
}


return out;
}


