#include "mycvframelocvert.h"


mycvFrameLocVert::mycvFrameLocVert()
{

}

mycvFrameLocVert::~mycvFrameLocVert()
{
    mResFrames.clear();
}

void mycvFrameLocVert::detectFrame(const Mat &aSrc, vector<Rect> &aFrame, int aMode)
{
    mycv mcMycv;
    /// Load image
    Mat imgBGR = aSrc.clone();
    Mat imgBGROrigSize = aSrc.clone();

    // Scale to defined width if larger
    int width = IMAGE_WIDTH;
    double scaleFactor = (double)width/imgBGR.cols;
    if(imgBGR.cols > GLOBAL_WIDTH)
        resize(imgBGR, imgBGR, Size(), scaleFactor, scaleFactor, INTER_CUBIC);

    // Convert to grayscale
    Mat imgGray;
    cvtColor(imgBGR, imgGray, CV_BGR2GRAY);

    // Gausian filter
    GaussianBlur(imgBGR, imgBGR, Size(5,5), 3, 3);
    GaussianBlur(imgGray, imgGray, Size(5,5), 3, 3);

    // Apply Histogram Equalization
    equalizeHist( imgGray, imgGray );
    // Rotate image according dominant lines (Haugh lines)
    Mat imgRot, imgBGRRot;
    float angle = 0;
    if(aMode & MODE_AUTO_ROTATE)
    {
        // Find rotation matrix
        Mat rotMat = mcMycv.mycvRotateAcDominantLines(imgGray, angle);

        // Rotate images
        warpAffine( imgGray, imgRot, rotMat, imgGray.size() );
        warpAffine( imgBGR, imgBGRRot, rotMat, imgBGR.size() );
    }
    // Create Red mask
    Mat imgRed;
    int blockSz = mcMycv.blockSize(imgRot.cols, 10);
    mcMycv.mycvFindRed(imgBGRRot, imgRed);
    // Connect near horizontal lines in red mask
    Mat elem = getStructuringElement(MORPH_RECT, Size(blockSz, blockSz*2));
    morphologyEx(imgRed, imgRed, CV_MOP_CLOSE, elem);
    // Remove too large regions in red mask
    mcMycv.mycvRemoveHighLowObjects(imgRed, imgRed, 0, imgRed.cols/2, imgRed.cols/2);

    // Create black mask
    Mat imgToThresh, imgThresh;
    double min, max;
    // Suppress rexts using morphology
    blockSz = mcMycv.blockSize(imgRot.cols, 40);
    elem = getStructuringElement(MORPH_ELLIPSE, Size(blockSz*2, blockSz));
    morphologyEx(imgRot, imgToThresh, CV_MOP_CLOSE, elem);

    // Threahold image
    cv::minMaxLoc(imgGray, &min, &max);
//    threshold(imgToThresh, imgThresh, (max - min)/3, max, THRESH_BINARY_INV | CV_THRESH_OTSU);
    blockSz = mcMycv.blockSize(imgGray.cols, 4);
    adaptiveThreshold(imgToThresh, imgThresh, max, CV_ADAPTIVE_THRESH_MEAN_C, CV_THRESH_BINARY_INV, blockSz, 1);

    // Compose Red and Black masks
//    bitwise_or(imgThresh, imgRed, imgThresh);
    // Remove small holes
    blockSz = mcMycv.blockSize(imgRot.cols, 60);
    elem = getStructuringElement(MORPH_ELLIPSE, Size(blockSz*2, blockSz));
    morphologyEx(imgThresh, imgThresh, CV_MOP_CLOSE, elem);
    // Remove too small dark objects
//    mycvRemoveHigherObjects(imgThresh, imgThresh, 0, 0, 0, imgThresh.cols/15, imgThresh.rows/30);

    // Dilatation
    blockSz = mcMycv.blockSize(imgRot.cols, 120);
    elem = getStructuringElement(MORPH_ELLIPSE, Size(blockSz*2, blockSz));
    morphologyEx(imgThresh, imgThresh, CV_MOP_DILATE, elem);

    /// Extract vertical edges
    Mat imgEdgesV;
    Sobel(imgRot, imgEdgesV, CV_8U, 1, 0, 3);
    // Mask vertical image
    bitwise_and(imgThresh,imgEdgesV, imgEdgesV);
    // Remove noise using minmax part threshold
    cv::minMaxLoc(imgEdgesV, &min, &max);
    Mat imgNoiseVMask;
    threshold(imgEdgesV, imgNoiseVMask, (max - min)/20, max, THRESH_BINARY);
    bitwise_and(imgEdgesV,imgNoiseVMask, imgEdgesV);

    // Threshold vertical edges
    Mat imgThreshV;
    blockSz = mcMycv.blockSize(2*imgEdgesV.cols, 3);
    cv::minMaxLoc(imgEdgesV, &min, &max);
    adaptiveThreshold(imgEdgesV, imgThreshV, max, CV_ADAPTIVE_THRESH_MEAN_C, CV_THRESH_BINARY, blockSz, 1);

    // Remove too large objects
    int szMaxX = imgThreshV.cols/4;
    int szMaxY = imgThreshV.cols/4;
    mcMycv.mycvRemoveHighLowObjects(imgThreshV, imgThreshV, imgThreshV.cols*4, szMaxX, szMaxY);

    // Remove small holes
    blockSz = mcMycv.blockSize(imgRot.cols, 120);
    elem = getStructuringElement(MORPH_ELLIPSE, Size(blockSz, blockSz*2));
    morphologyEx(imgThreshV, imgThreshV, CV_MOP_CLOSE, elem);

    Mat imgThreshVColor;
    cvtColor(imgThreshV, imgThreshVColor, CV_GRAY2BGR);

    /// Cluster analysis
    vector<sPoints4> textBlocks; // list of estimated text blocks
    mcMycv.mycvRowClusters(imgThreshV, imgThreshV, textBlocks);

    Mat imgThreshVColor2, imgRotColor2;
    cvtColor(imgThreshV, imgThreshVColor2, CV_GRAY2BGR);
    cvtColor(imgRot, imgRotColor2, CV_GRAY2BGR);

    // Draw before removing false rects
    for(size_t i = 0 ; i < textBlocks.size() ; i++)
    {
        rectangle(imgThreshVColor2, textBlocks[i].cornerLU, textBlocks[i].cornerPD, Scalar(255, 0, 0));
    }

    // Adjust size of rect according to red color
    mcMycv.mycvRemoveFalseFrames(textBlocks, imgThresh, imgRed);

    if(aMode & MODE_AUTO_ROTATE)
    {
        // Rotate orig. size image
        Point centerP(imgBGROrigSize.cols/2, imgBGROrigSize.rows/2);
        Mat rotMat = getRotationMatrix2D( centerP, angle, 1 );

        warpAffine( imgBGROrigSize, imgBGROrigSize, rotMat, imgBGROrigSize.size() );
    }
    Mat imgOrigBlack;
    cvtColor(imgBGROrigSize, imgOrigBlack, CV_BGR2GRAY);

    blockSz = mcMycv.blockSize(imgRot.cols, 3);
    adaptiveThreshold(imgOrigBlack, imgOrigBlack, max, CV_ADAPTIVE_THRESH_MEAN_C, CV_THRESH_BINARY, blockSz, 1);

    // Draw true rects
    for(size_t i = 0 ; i < textBlocks.size() ; i++)
    {
//      crop&show
        // Apply back scale
        double scaleBack = 1/scaleFactor;
        sPoints4 actP4 = textBlocks[i];
        actP4.cornerLU.x *= scaleBack;
        actP4.cornerLU.y *= scaleBack;
        actP4.cornerPD.x *= scaleBack;
        actP4.cornerPD.y *= scaleBack;

        mcMycv.mycvAdjustFrame(actP4, imgOrigBlack);
        if( textBlocks[i].cornerPD.y - textBlocks[i].cornerLU.y <= 0 || \
            textBlocks[i].cornerPD.x - textBlocks[i].cornerLU.x <= 0)continue;
        Rect roi(actP4.cornerLU.x, actP4.cornerLU.y, actP4.cornerPD.x - actP4.cornerLU.x \
                 , actP4.cornerPD.y - actP4.cornerLU.y);

        Mat cropped = imgBGROrigSize(roi).clone();

        std::ostringstream ostream;
        ostream << "Frame " << i;

        aFrame.push_back(roi);
        mResFrames.push_back(cropped.clone());

        rectangle(imgThreshVColor2, textBlocks[i].cornerLU, textBlocks[i].cornerPD, Scalar(0, 255, 0), 2);
        rectangle(imgBGROrigSize, actP4.cornerLU, actP4.cornerPD, Scalar(0, 255, 0), 2);
    }
}
