/**
 * author:SiZheng.Chen
 * update date:20210120
**/

#include "BlockedPore.h"

BlockedPoreData detectBlocked(Mat image){
    BlockedPoreData data;
    if(image.empty()||image.type()!=CV_8UC3){
        cout<<"image is empty or type error."<<endl;
        data.blockedImg=image;
        return data;
    }

    int THRESHOLD_MAX=25000;
    int THRESHOLD_L=550;
    int THRESHOLD_M=350;
    int THRESHOLD_S=0;
    Scalar MCOLOR_L=Scalar(99,54,255);
    Scalar MCOLOR_M=Scalar(99,54,255);

    Mat pore_gray_mat=detectGrayBlocked(image);
    Mat pore_normal_mat=detectNormalBlocked(image);
    Mat blocked = max(pore_gray_mat,pore_normal_mat);

    Mat strcutKernel=getStructuringElement(MORPH_ELLIPSE,cv::Size(7,7));
    erode(blocked,blocked,strcutKernel);
    dilate(blocked,blocked,strcutKernel);

    vector<vector<cv::Point> > contours;
    vector<Vec4i> hirearchy;
    int count_L=0;
    int count_M=0;
    double area_L=0;
    double area_M=0;

    findContours(blocked,contours,hirearchy,RETR_EXTERNAL,CHAIN_APPROX_SIMPLE);

    for(int i=0;i<contours.size();++i){
        double area = contourArea(contours[i]);

        if(area>=THRESHOLD_L&&area<THRESHOLD_MAX){
            drawContours(image,contours,i,MCOLOR_L,2);
            count_L++;
            area_L+=area;
        }else if(area>=THRESHOLD_M&&area<THRESHOLD_L){
            drawContours(image,contours,i,MCOLOR_M,2);
            count_M++;
            area_M+=area;
        }else{
            drawContours(blocked,contours,i,Scalar(0),FILLED);
        }
    }
    data.blockedImg=image;
    data.blockedCount=count_L+count_M;
    data.blockedArea=area_L+area_M;
    // imshow("win",image);
    // waitKey();

    return data;
}

Mat detectNormalBlocked(Mat image){
    Mat hsvImg,grayImg;
    cvtColor(image, hsvImg,COLOR_BGR2HSV);

    vector<Mat> hsvList;
    split(hsvImg,hsvList);

    Mat light_image = Mat(image.size(),CV_8UC1,Scalar(255));
    
    Mat colorMat;
    applyColorMap(hsvList[0],colorMat,5);
    hsvList.clear();
    split(colorMat,hsvList);

    Mat equa_image;
    cv::Ptr<CLAHE> clahe=createCLAHE();
    clahe->setClipLimit(1.9);
    clahe->setTilesGridSize(cv::Size(10,10));
    clahe->apply(hsvList[1],equa_image);
    equa_image=light_image-equa_image;

    // imshow("win",equa_image);
    // waitKey();

    Mat bin_image;
    adaptiveThreshold(equa_image,bin_image,255,ADAPTIVE_THRESH_GAUSSIAN_C,THRESH_BINARY,225,-25);
    Mat structKernel=getStructuringElement(MORPH_RECT,cv::Size(5,5));
    erode(bin_image,bin_image,structKernel);
    dilate(bin_image,bin_image,structKernel);

    Mat darkImg=Mat(image.size(),CV_8UC3,Scalar(0,0,0));
    Mat mask_image;
    add(image,darkImg,mask_image,bin_image);

    // imshow("win",mask_image);
    // waitKey();

    vector<vector<cv::Point> > contours;
    vector<Vec4i> hirearchy;
    findContours(bin_image,contours,hirearchy,RETR_EXTERNAL,CHAIN_APPROX_SIMPLE);

    vector<vector<cv::Point> > filterContours;
    for(int i=0;i<contours.size();++i){
        double area=contourArea(contours[i]);
        
        if(150<=area&&area<=29000){
            RotatedRect rrt=minAreaRect(contours[i]);
            float width=rrt.size.width>rrt.size.height?rrt.size.width:rrt.size.height;
            float height=rrt.size.width<rrt.size.height?rrt.size.width:rrt.size.height;
            float eccentricity=(width+height)!=0?(width-height)/(width+height):1.0;

            cv::Rect box=boundingRect(contours[i]);
            int x0=box.x;
            int y0=box.y;
            int x3=x0+box.width;
            int y3=y0+box.height;
            float sum_red=0;
            float sum_green=0;
            float sum_blue=0;
        
            for(int j=x0;j<x3;++j){
                for(int k=y0;k<y3;++k){
                    int gray_value=(int)bin_image.at<uchar>(k,j);
                    if(gray_value==255){
                        Vec3b pix=mask_image.at<Vec3b>(k,j);
                        sum_blue+=pix[0];
                        sum_green+=pix[1];
                        sum_red+=pix[2];
                    }
                }
            }

            double rrtArea = width*height;
            double ra = area/rrtArea;

            sum_red=sum_red!=0?sum_red:1;
            sum_green=sum_green!=0?sum_green:1;
            sum_blue=sum_blue!=0?sum_blue:1;

            float r1 = sum_blue/sum_red;
            float r2 = sum_blue/sum_green;
            float r3 = sum_red /sum_green;

            if(r3>=1.55||eccentricity>0.365||ra<0.5){   // 0.25-->0.365
                filterContours.push_back(contours[i]);
            }
        }
    }
    cout<<"filterContours size:"<<filterContours.size()<<endl;
    drawContours(bin_image,filterContours,-1,Scalar(0),FILLED);

    // imshow("win",bin_image);
    // waitKey();

    return bin_image;

}

Mat detectGrayBlocked(Mat image){
    Mat hsvImg,labImg,grayImg;
    cvtColor(image,grayImg,COLOR_BGR2GRAY);
    cvtColor(image,labImg,COLOR_BGR2Lab);
    cvtColor(image,hsvImg,COLOR_BGR2HSV);
    
    vector<Mat> labList,hsvList;
    split(labImg,labList);
    split(hsvImg,hsvList);

    Mat a=labList[1];
    Mat v = hsvList[2];
    Mat light_mat=Mat(a.size(),CV_8UC1,Scalar(255));
    Scalar avg_a = mean(a);
    GaussianBlur(v,v,cv::Size(3,3),0);
    GaussianBlur(grayImg,grayImg,cv::Size(7,7),0);

    // Mat v_mask;
    // adaptiveThreshold(v,v_mask,255,ADAPTIVE_THRESH_GAUSSIAN_C,THRESH_BINARY,235,-48);

    vector<vector<cv::Point> > contours;
    vector<Vec4i> hirearchy;
    // findContours(v_mask,contours,hirearchy,RETR_CCOMP,CHAIN_APPROX_SIMPLE);
    // drawContours(a,contours,-1,avg_a,FILLED);

    Mat equa_image;
    cv::Ptr<CLAHE> clahe=createCLAHE();
    clahe->setClipLimit(3.5);
    clahe->setTilesGridSize(cv::Size(10,10));
    clahe->apply(a,equa_image);
    equa_image = light_mat-equa_image;
    // imshow("w",equa_image);
    // waitKey();

    Mat bin_image;
    adaptiveThreshold(equa_image,bin_image,255,ADAPTIVE_THRESH_GAUSSIAN_C,THRESH_BINARY,225,-21);
    Mat erode_kernel=getStructuringElement(MORPH_RECT,cv::Size(3,3));
    erode(bin_image,bin_image,erode_kernel);
    dilate(bin_image,bin_image,erode_kernel);
    // imshow("w",bin_image);
    // waitKey();

    contours.clear();
    hirearchy.clear();
    // cout<<"contours size:"<<contours.size()<<endl;

    findContours(bin_image,contours,hirearchy,RETR_EXTERNAL,CHAIN_APPROX_SIMPLE);
    for(int i=0;i<contours.size();++i){
        double area=contourArea(contours[i]);
        RotatedRect box=minAreaRect(contours[i]);
        float width=box.size.width>box.size.height?box.size.width:box.size.height;
        float height=box.size.width<box.size.height?box.size.width:box.size.height;
        float eccentricity=(width+height)!=0?(width-height)/(width+height):1.0;

        if(area>=350&&area<=80000&&eccentricity<=0.3){
        }else{
            drawContours(bin_image,contours,i,Scalar(0),FILLED);
        }
    }
    // imshow("w",bin_image);
    // waitKey();
    return bin_image;
}
