#ifndef MYCV_H
#define MYCV_H

#include <QImage>

#include "opencv2/core/core.hpp"
#include "opencv2/highgui/highgui.hpp"
#include "opencv2/imgproc/imgproc.hpp"
#include "opencv2/features2d/features2d.hpp"

#include "mycvdigitpreproc.h"
#include "mycvdigitprocgeometric.h"
#include "mycvdigitprocfeatures.h"
#include "mycvdigitprocann.h"

#include "mycvframelochaar.h"
#include "mycvframelocvert.h"

#include "mycvdigitssegm.h"

#define ROW_FRES_MIN_ONES 10

#define GLOBAL_WIDTH 500

// processImage modes
#define M_ALL_IMAGE_PROC    0
#define M_FRAME_PROC        1

// VerHor direction
#define PROJ_VERTICAL       0
#define PROJ_HRIZONTAL      1

using namespace std;
using namespace cv;

struct sPoints4
{
//  Rectangle points
//    cornerLU____
//           |    |
//            ----cornerPD
    Point cornerLU;
    Point cornerPD;
};

class mycv
{
private:
        vector<Mat> mResFrames; // founded counters frames
        vector<vector<Mat>> mResDigits; // Segmented and processed chars
        QString mStrDir;        // source image directory
        QString mStrFile;       // source image name

        // digit preproc class
        mycvDigitProproc mcDigitPreproc;

        /// Haar cascade
        mycvFrameLocHaar mcFrameHaar;
        Mat mImgNoFrame; // for negative samples creation

        /// Matching by shape
        vector<vector<Point>> mPatternsContours;  // contours of ideal numbers 0-9
        mycvDigitProcGeometric mcDigitGeometric;
        mycvDigitProcFeatures mcDigitFeatures;

        /// ANN
        mycvDigitProcANN mcANN;


public:
    mycv();

    void processImage(QString aStrDir, QString aStrFile, QImage &aImg, int aMode);
    void saveFrames();
    void saveDigits();
    void mycvSaveNoFrameImg();
    void processImageSimple(QString aStrDir, QString aStrFile, int aMode);

    int mycvLoadPatternNumbers(QString aStrFile, int aMode);
    int mycvLoadPatternNumbers2(QString aStrFile, int aMode);
    void LoadXMLFrameHaar(QString aStrFile);

    void mycvRemoveHighLowObjects(const Mat &aSrc, Mat &aDst, uint aMaxVol, uint maxX, uint maxY, uint minX = 0, uint minY = 0, uint aMinVol = 0);
    void mycvRemoveHighLowObjects2(const Mat &aSrc, Mat &aDst, uint aMaxVol, uint maxX, uint maxY, uint minX = 0, uint minY = 0, uint aMinVol = 0);
    void mycvSharpening(const Mat &aSrc, Mat &aDst);
    int mycvVerHorProjection(const Mat &aSrc, Mat &aDst, const int aDir, vector<Point> &aSepar);

    // ANN interface
    void clearTrainingDataANN();
    void addTrainingDataANN(QString aStrFile, int aLabel);
    void trainANN();
    void predictANN(QString aStrFile);
    void saveXMLANN(QString aStrFile);
    void loadXMLANN(QString aStrFile);

    /**
     * @brief Locates electrometer counter
     * @param aScr - source image
     * @param aDst - destination image
     */
    void detectText(const Mat &aScr, Mat &aDst);
    void detectText2(const Mat &aScr, Mat &aDst);
    void detectText3(const Mat &aScr, Mat &aDst);

    /**
     * @brief Segmentation of numbers from image of counter
     * @return  0 - error
     *          1 - one counter found
     *          2 - two counters found
     */
    int numbersSeg();   // Vertical projection
    int numbersSeg2();  // Contours
    int numbersSeg3();  // MSER features

    QImage putImage(const Mat& mat);
    void maskBlackSpots(const Mat &aScr, Mat &aDst);
    void mycvFindRed(const Mat &aSrc, Mat &aDst);
    void mycvRemoveFalseFrames(vector<sPoints4> &aTextBlocks, Mat &aImgBlackMask, const Mat &aImgRedMask);
    void mycvEqualizeIntensity(const Mat& aSrc, Mat &aDst);
    void mycvHoughLines(Mat &aImage, vector<Vec2f> &aLines);
    Mat mycvRotateAcDominantLines(const Mat &aSrc1Gray, float &aAngle);
    void mycvRowFreks(const Mat &aImage, vector<int> &avFreks);
    void mycvRowClusters(const Mat &aImgThresh, Mat &aDst, vector<sPoints4> &aTxtBlocks);
    void mycvReduseLines(vector<Vec2f> &aLinesCartesian);
    void mycvReduseLines(vector<Vec4i> &aLinesCartesian, vector<Vec4i> &aLinesCartesianRed, float &aAngle);
    int maxVectInt(const vector<int> &aV);
    int blockSize(int aNum, int aDiv);
    void mycvAdjustFrame(sPoints4 &aTextBlock, const Mat &aImgBlackMask);

    void mycvRemoveHorizontal(const Mat &aSrc, Mat &aDst);
    void mycvRemoveBorderSmalls(const Mat &aSrc, Mat &aDst, int aMaxBorder);
    Point mycvCheckHorizBorders(const Mat &aSrc, vector<Point> &aHorProj);
    void mycvFloodFill(Mat &aDst, Point aP, uint &aVol, sPoints4 &aSize, uchar aActVal, uchar aNewVal);

    void mycvPreprocCount(const Mat &aSrc, Mat &aDst, bool abTime = true);
    void mycvDrawMSERsPoints(Mat &aImgMSER, Mat &aImgEllipse, const vector<vector<Point> > aP);
    void mycvDrawMSERMask(Mat &aImgMSER, const vector<vector<Point>> aP);

    void mycvCheckDigit(const Mat &aSrc, vector<Rect> &aRects);

};

#endif // MYCV_H
