#include "mycvdigitpreproc.h"
#include "mycv.h"

mycvDigitProproc::mycvDigitProproc()
{
    // Default size of normalized image
    mNormSize.width = 30;
    mNormSize.height = 30;
}

mycvDigitProproc::~mycvDigitProproc()
{

}

void mycvDigitProproc::loadFrame(const Mat &aFrame)
{
    mImgActFrame = aFrame.clone();
    // To grayscale
//    int blockSz = mImgActFrame.rows/14;
//    blockSz += (blockSz + 1) % 2;
//    cvtColor(mImgActFrame, mImgActFrame, CV_BGR2GRAY);
//    bilateralFilter(mImgActFrame.clone(), mImgActFrame, blockSz, 150, blockSz);
//    imshow("Preproc frame bilateralFilter", mImgActFrame);
//    // Threshold
//    adaptiveThreshold(mImgActFrame, mImgActFrame, 255, CV_ADAPTIVE_THRESH_MEAN_C, CV_THRESH_BINARY, blockSz, 0);
//    medianBlur(mImgActFrame, mImgActFrame, 3);
//    imshow("Preproc frame", mImgActFrame);
}

int mycvDigitProproc::preproc(Mat &aDst, Rect &aDigit, int aMode)
{
    mActDigit = aDigit;
    if(mImgActFrame.empty())return 0;
    checkRect();
    switch(aMode)
    {
    case PROC_MODE_GENERAL:
            return procGeneral(aDst);
    case PROC_MODE_NORMALIZE:
            procGeneral(aDst);
            return procNormalize(aDst, aDst);
        break;
    }
    return 0;
}

int mycvDigitProproc::procNormalize(const Mat &aSrc, Mat &aDst)
{
    Mat imgPreproc;

    if(aSrc.dims > 2)
        cvtColor(aSrc, imgPreproc, CV_BGR2GRAY);
    else imgPreproc = aSrc.clone();
    imgPreproc.clone().convertTo(imgPreproc, CV_8UC1);

    Mat imgThresh;
    threshold(imgPreproc, imgThresh, 150, 255, CV_THRESH_BINARY);
//    imshow("thresh", imgThresh);

    // get boundaries
    vector<vector<Point> > contours;
    findContours(imgThresh.clone(), contours, CV_RETR_EXTERNAL, CV_CHAIN_APPROX_SIMPLE);

    if(contours.size() == 0)return 0;

    Rect rectBound;
    rectBound.x = imgPreproc.cols;
    rectBound.y = imgPreproc.rows;
    // Get x and y
    for(int i = 0 ; i < contours.size() ; i++)
    {
        Rect actRect = boundingRect(contours[i]);
        if(rectBound.x > actRect.x)rectBound.x = actRect.x;
        if(rectBound.y > actRect.y)rectBound.y = actRect.y;
    }
    // Get width and height
    for(int i = 0 ; i < contours.size() ; i++)
    {
        Rect actRect = boundingRect(contours[i]);
        if(rectBound.x + rectBound.width < actRect.x + actRect.width)
            rectBound.width = actRect.x + actRect.width - rectBound.x;
        if(rectBound.y + rectBound.height < actRect.y + actRect.height)
            rectBound.height = actRect.y + actRect.height - rectBound.y;
    }

    // Cut image boundaries
    Mat imgCut;
    imgCut = imgPreproc(rectBound).clone();

    // Normalize image
    resize(imgCut, aDst, mNormSize, 0, 0, INTER_CUBIC);


//    resize(aDst, aDst, Size(), 10, 10);

    return 1;
}

int mycvDigitProproc::procGeneral(Mat &aDst)
{
    Mat imgDigit;
    imgDigit = mImgActFrame(mActDigit).clone();

    // filter
    int blockSz = imgDigit.rows/10;
    blockSz += (blockSz + 1) % 2;
    if(blockSz == 1)blockSz = 3;
    cvtColor(imgDigit, imgDigit, CV_BGR2GRAY);
    bilateralFilter(imgDigit.clone(), imgDigit, blockSz, 150, blockSz);

    // Threshold
    adaptiveThreshold(imgDigit, imgDigit, 255, CV_ADAPTIVE_THRESH_MEAN_C, CV_THRESH_BINARY, blockSz, 0);
    mycv cMycv;
    cMycv.mycvRemoveHighLowObjects(imgDigit, imgDigit, 0, 0, 0, imgDigit.cols/5, imgDigit.rows/4, 9);
    medianBlur(imgDigit, imgDigit, 3);

    // Find largest contours
    vector<vector<Point> > contours;
    findContours(imgDigit.clone(), contours, CV_RETR_EXTERNAL, CV_CHAIN_APPROX_SIMPLE);

    // find max area contour
    double maxArea = 0;
    for(int i = 0 ; i < (int)contours.size() ; i++)
    {
        double area = contourArea(contours[i]);
        if(maxArea < area)maxArea = area;
    }
    vector<vector<Point> > contours2;
    for(int i = 0 ; i < (int)contours.size() ; i++)
    {
        double area = contourArea(contours[i]);
        if(area >= (/*maxArea - */maxArea/8))contours2.push_back(contours[i]);
    }

    Mat imgNoSmalls = Mat::zeros(imgDigit.size(), CV_8UC1);
    for(int i = 0 ; i < (int)contours2.size() ; i++)
    {
        drawContours(imgNoSmalls, contours2, i, Scalar(255), CV_FILLED, 8);
    }

    bitwise_and(imgNoSmalls, imgDigit, imgDigit);
    copyMakeBorder(imgDigit, imgDigit, 5, 5, 40, 40, BORDER_CONSTANT, Scalar(0));
    aDst = imgDigit.clone();
/// --------------------------------------------
//    Mat imgBGR;
//    imgBGR = mImgActFrame(mActDigit).clone();

//    // To grayscale
//    Mat imgGray;
//    cvtColor(imgBGR, imgGray, CV_BGR2GRAY);

//    // Filtering
//    mycv cMycv;
//    cMycv.mycvSharpening(imgGray, imgGray);
////    equalizeHist( imgGray, imgGray );
//    int blockSz = imgGray.cols/12;
//    blockSz += (blockSz + 1) % 2;
//    bilateralFilter(imgGray.clone(), imgGray, blockSz, 50, blockSz);

//    // Threshold
//    Mat imgThresh;
////    threshold(imgGray, imgThresh, 100, 255, CV_THRESH_BINARY | CV_THRESH_OTSU);
//    blockSz = imgGray.cols/5;
//    blockSz += (blockSz + 1) % 2;
//    adaptiveThreshold(imgGray, imgThresh, 255, CV_ADAPTIVE_THRESH_MEAN_C, CV_THRESH_BINARY, blockSz, 0);

////    // Morphology
////    blockSz = imgThresh.cols/10;
////    blockSz += (blockSz + 1) % 2;
////    Mat element = getStructuringElement(MORPH_ELLIPSE, Size(blockSz, blockSz));
////    morphologyEx(imgThresh, imgThresh, CV_MOP_OPEN, element);

//    // if there more then 3/4 onec -> remove digit
//    float nonZero = (float)countNonZero(imgThresh);
//    float black = (float)(imgThresh.rows*imgThresh.cols);
//    if(nonZero/black > 2.0f/3.0f)return 0;

//    // Find largest contours
//    vector<vector<Point> > contours;
//    findContours(imgThresh.clone(), contours, CV_RETR_EXTERNAL, CV_CHAIN_APPROX_TC89_L1);

//    // find max area contour
//    double maxArea = 0;
//    for(int i = 0 ; i < (int)contours.size() ; i++)
//    {
//        double area = contourArea(contours[i]);
//        if(maxArea < area)maxArea = area;
//    }
//    vector<vector<Point> > contours2;
//    for(int i = 0 ; i < (int)contours.size() ; i++)
//    {
//        double area = contourArea(contours[i]);
//        if(area >= (maxArea - maxArea/5))contours2.push_back(contours[i]);
//    }

//    Mat imgNoSmalls = Mat::zeros(imgThresh.size(), CV_8UC1);
//    for(int i = 0 ; i < (int)contours2.size() ; i++)
//    {
//        drawContours(imgNoSmalls, contours2, i, Scalar(255), CV_FILLED, 8);
//    }

//    bitwise_and(imgNoSmalls, imgThresh, imgNoSmalls);
//    copyMakeBorder(imgNoSmalls, imgNoSmalls, 5, 5, 40, 40, BORDER_CONSTANT, Scalar(0));
//    aDst = imgNoSmalls.clone();
    return 1;
}

void mycvDigitProproc::checkRect()
{
    if(mImgActFrame.empty())return;
    if(mActDigit.x < 0)mActDigit.x = 0;
    if(mActDigit.y < 0)mActDigit.y = 0;

    if(mActDigit.x >= mImgActFrame.cols)mActDigit.x = mImgActFrame.cols-1;
    if(mActDigit.y >= mImgActFrame.rows)mActDigit.y = mImgActFrame.rows-1;

    if(mActDigit.width + mActDigit.x >= mImgActFrame.cols)mActDigit.width = mImgActFrame.cols-mActDigit.x-1;
    if(mActDigit.height + mActDigit.y >= mImgActFrame.rows)mActDigit.height = mImgActFrame.rows-mActDigit.y-1;
}
