#ifndef CLIPHEADER_
#define CLIPHEADER_
//===================================================================================
//
//  clip.h
//
// CLassic Image Processing (CLIP) Library ( 101 functions )
//
// All functions are independent from each other
//
// developer: Henry Guennadi Levkin
//
// frame - grey scale image or color component
// image - 3 frames with color information
//
// B at the end of function name means that pixel has byte size
// S at the end of function name means that pixel has short (2 bytes) size
//
// v - intensity of pixel
//
//===================================================================================


typedef unsigned char  byte;

//-----------------------------------------------------------------------------------
typedef struct
{
  int xL; // x-left
  int yT; // y-top
  int nW; // width
  int nH; // height
} SRect;

//-----------------------------------------------------------------------------------
// can be used to make shorter signatures of library functions
// and use 2 dim arrays for image processing
typedef struct
{
  int nW;
  int nH;
  unsigned char* pF;
  unsigned char** m; // pointers to frame rows
} SFrameB;

//-----------------------------------------------------------------------------------
// allocate memory and fill by zeros
void FrameConstructB(byte**  ppFrm, int nW, int nH); //
void FrameConstructS(short** ppFrm, int nW, int nH); //

//-----------------------------------------------------------------------------------
void FrameFreeB(byte*  pFrm); //
void FrameFreeS(short* pFrm); //

//-----------------------------------------------------------------------------------
// fill pixel values by nConst
void FrameFillConstB(byte*  pFrm, int nW, int nH, int nConst); //

//-----------------------------------------------------------------------------------
// fill pixel values by uniform noise from [nLow, nHigh]
void FrameFillNoiseB(byte*  pFrm, int nW, int nH, int nLow, int nHigh); //
void FrameFillNoiseS(short* pFrm, int nW, int nH, int nLow, int nHigh); //

//-----------------------------------------------------------------------------------
void FrameFillTextureB(byte* pFrm, int nW, int nH, byte* pTexture, int nWT, int nHT); //

//-----------------------------------------------------------------------------------
// frame copy
void FrameCopyB2B(byte* pSrc, byte* pDest, int nW, int nH); //

//-----------------------------------------------------------------------------------
// copy byte frame to short frame
void FrameB2S(byte* pSrc, short* pDst, int nW, int nH); //

//-----------------------------------------------------------------------------------
// transform with cut of shorts to (0,255)
void FrameS2B(short* pSrc, byte* pDst, int nW, int nH); //

//-----------------------------------------------------------------------------------
// transform from short (min,max) to byte (0,255)
void FrameS2BSqueeze(short* pSrc, byte* pDst, int nW, int nH); //

//-----------------------------------------------------------------------------------
// pHist - histogram vector with dimension 256
void FrameHistB(byte* pFrm, int nW, int nH, int* pHist);  //
void FrameHistS(short* pFrm, int nW, int nH, int* pHist, short nMin, short nMax); // pHist has dim=nMax-nMin+1

//-----------------------------------------------------------------------------------
// *pnMin - minimal intensity of pixels
// *pnMax - maximal intensity of pixels
void FrameMinMaxB(byte*  pFrm, int nW, int nH, int* pnMin, int* pnMax); //
void FrameMinMaxS(short* pFrm, int nW, int nH, int* pnMin, int* pnMax); //

//-----------------------------------------------------------------------------------
void FrameMeanStdDevB(byte* pFrm, int nW, int nH, double* pfMean, double* pfStdDev); //
void FrameMeanStdDevS(short* pFrm, int nW, int nH, double* pfMean, double* pfStdDev); //

//-----------------------------------------------------------------------------------
// destination image size = (nW+2*nDelta) * (nH+2*nDelta)
// new pixels fills by closest border pixel values
void FrameAddBordersB(byte* pSr, byte* pDs, int nW, int nH, int nDelta); //

//-----------------------------------------------------------------------------------
void FrameGetBlockB(byte* pFr, int nW, int nH, byte* pBlk, SRect rect); //
void FrameGetBlockS(short* pFr, int nW, int nH, short* pBlk, SRect rect); //

//-----------------------------------------------------------------------------------
void FramePutBlockB(byte* pFr, int nW, int nH, byte* pBlk, SRect rect); //
void FramePutBlockS(short* pFr, int nW, int nH, short* pBlk, SRect rect); //

//-----------------------------------------------------------------------------------
// zeros fill free pixels
void FrameShiftB(byte* pSrc, byte* pDst, int nW, int nH, int nX, int nY);
void FrameShiftS(short* pSrc, short* pDst, int nW, int nH, int nX, int nY);

//-----------------------------------------------------------------------------------
// separate R,G,B frames
void FrameRGB2YUV(byte* pR, byte* pG, byte* pB, byte* pYUV, int nW, int nH);

//-----------------------------------------------------------------------------------
// separate R,G,B frames
void FrameYUV2RGB(byte* pYOV, byte* pR, byte* pG, byte* pB, int nW, int nH);

//-----------------------------------------------------------------------------------
// frame magnification (upsampling) 2x2 times
void FrameMagnifyB(byte* pSrc,  byte* pDst,  int nW, int nH); //
void FrameMagnifyS(short* pSrc, short* pDst, int nW, int nH); //

//-----------------------------------------------------------------------------------
// frame downsampling 2x2 times
void FrameDownsampleB(byte* pSrc,  byte* pDst,  int nW, int nH); //
void FrameDownsampleS(short* pSrc, short* pDst, int nW, int nH); //

//-----------------------------------------------------------------------------------
// v=v+nConst
void FrameAddConstB(byte* pSrc, short* pDst, int nW, int nH, int nConst); //
void FrameAddConstS(short* pSrc, short* pDst, int nW, int nH, short nConst); //

//-----------------------------------------------------------------------------------
// v=(short)(v*fConst + 0.5)
void FrameMultConstB(byte* pSrc, short* pDst, int nW, int nH, double fConst); //
void FrameMultConstS(short* pSrc, short* pDst, int nW, int nH, double fConst); //

//-----------------------------------------------------------------------------------
// v= v & nConst
void FrameBinaryAndConstB(byte* pSrc, byte* pDst, int nW, int nH, byte nConst); //
void FrameBinaryAndConstS(short* pSrc, short* pDst, int nW, int nH, short nConst); //

//-----------------------------------------------------------------------------------
// v= v | nConst
void FrameBinaryOrConstB(byte* pSrc, byte* pDst, int nW, int nH, byte nConst); //
void FrameBinaryOrConstS(short* pSrc, short* pDst, int nW, int nH, short nConst); //

//-----------------------------------------------------------------------------------
void FrameBinaryShiftRightConstB(byte* pSrc, byte* pDst, int nW, int nH, int nConst); //

//-----------------------------------------------------------------------------------
void FrameBinaryShiftLeftConstB(byte* pSrc, byte* pDst, int nW, int nH, int nConst); //

//-----------------------------------------------------------------------------------
// v = v1 & v2
void FrameBinaryAndB(byte* pFrm1, byte* pFrm2, byte* pDst, int nW, int nH); //
void FrameBinaryAndS(short* pFrm1, short* pFrm2, short* pDst, int nW, int nH); //

//-----------------------------------------------------------------------------------
// v = v1 | v2
void FrameBinaryOrB(byte* pFrm1, byte* pFrm2, byte* pDst, int nW, int nH); //
void FrameBinaryOrS(short* pFrm1, short* pFrm2, short* pDst, int nW, int nH); //

//-----------------------------------------------------------------------------------
// v = v1 ^ v2
void FrameBinaryXorB(byte* pFrm1, byte* pFrm2, byte* pDst, int nW, int nH); // 
void FrameBinaryXorS(short* pFrm1, short* pFrm2, short* pDst, int nW, int nH); //

//-----------------------------------------------------------------------------------
// v = v1 + v2
void FrameAddB(byte* pSrc1, byte* pSrc2, short* pDst, int nW, int nH); //
void FrameAddS(short* pSrc1, short* pSrc2, short* pDst, int nW, int nH); //

//-----------------------------------------------------------------------------------
// Dst = Src1 - Src2
void FrameSubtractB(byte* pSrc1, byte* pSrc2, short* pDst, int nW, int nH); //
void FrameSubtractS(short* pSrc1, short* pSrc2, short* pDst, int nW, int nH); //

//-----------------------------------------------------------------------------------
// -1 0 1
// -1 0 1
// -1 0 1
void FrameGradX3B(byte* pSrc,  short* pDst, int nW, int nH); //
void FrameGradX3S(short* pSrc, short* pDst, int nW, int nH); //

//-----------------------------------------------------------------------------------
// -1 -1 -1
//  0  0  0
//  1  1  1
void FrameGradY3B(byte* pSrc,  short* pDst, int nW, int nH); //
void FrameGradY3S(short* pSrc, short* pDst, int nW, int nH); //

//-----------------------------------------------------------------------------------
// -1 0 1
// -2 0 2
// -1 0 1
void FrameSobelX3B(byte* pSrc,  short* pDst, int nW, int nH); //
void FrameSobelX3S(short* pSrc, short* pDst, int nW, int nH); //

//-----------------------------------------------------------------------------------
// -1 -2 -1
//  0  0  0
//  1  2  1
void FrameSobelY3B(byte* pSrc,  short* pDst, int nW, int nH); //
void FrameSobelY3S(short* pSrc, short* pDst, int nW, int nH); //

//-----------------------------------------------------------------------------------
// -2 -1 0 1  2
// -2 -1 0 1  2
// -2 -1 0 1  2
// -2 -1 0 1  2
// -2 -1 0 1  2
void FrameGradX5B(byte* pSrc,  short* pDst, int nW, int nH); //
void FrameGradX5S(short* pSrc, short* pDst, int nW, int nH); //

//-----------------------------------------------------------------------------------
// -2 -2 -2 -2 -2
// -1 -1 -1 -1 -1
//  0  0  0  0  0
//  1  1  1  1  1
//  2  2  2  2  2
void FrameGradY5B(byte* pSrc,  short* pDst, int nW, int nH); //
void FrameGradY5S(short* pSrc, short* pDst, int nW, int nH); //

//-----------------------------------------------------------------------------------
// abs = |Gx| + |Gy|
void FrameGradAbs3B(byte* pSrc, short* pDst, int nW, int nH); //
void FrameGradAbs5B(byte* pSrc, short* pDst, int nW, int nH); //

//-----------------------------------------------------------------------------------
//  0 -1  0
// -1  4 -1
//  0 -1  0
void FrameLaplace3CrossB(byte* pSrc, short* pDst, int nW, int nH); //

//-----------------------------------------------------------------------------------
// -1 -1 -1
// -1  8 -1
// -1 -1 -1
void FrameLaplace3B(byte* pSrc, short* pDst, int nW, int nH); //
 
//-----------------------------------------------------------------------------------
// -1 -1 -1 -1 -1
// -1 -1 -1 -1 -1
// -1 -1 24 -1 -1
// -1 -1 -1 -1 -1
// -1 -1 -1 -1 -1
void FrameLaplace5B(byte* pSrc, short* pDst, int nW, int nH);

//-----------------------------------------------------------------------------------
// 0 1 0
// 1 1 1
// 0 1 0
void FrameSmooth3CrossB(byte* pSrc, byte* pDst, int nW, int nH); //
void FrameSmooth3CrossThresholdB(byte* pSrc, byte* pDst, int nW, int nH, int nThreshold); //

//-----------------------------------------------------------------------------------
// 1 1 1
// 1 1 1
// 1 1 1
void FrameSmooth3B(byte* pSrc, byte* pDst, int nW, int nH); //
void FrameSmooth3ThresholdB(byte* pSrc, byte* pDst, int nW, int nH, int nThreshold); //

//-----------------------------------------------------------------------------------
// 1 2 1
// 2 4 2
// 1 2 1
void FrameSmooth3GaussB(byte* pSrc, byte* pDst, int nW, int nH); //
void FrameSmooth3GaussThresholdB(byte* pSrc, byte* pDst, int nW, int nH, int nThreshold); //

//-----------------------------------------------------------------------------------
// 1 1 1 1 1
// 1 1 1 1 1
// 1 1 1 1 1
// 1 1 1 1 1
// 1 1 1 1 1
void FrameSmooth5B(byte* pSrc, byte* pDst, int nW, int nH); //
void FrameSmooth5ThresholdB(byte* pSrc, byte* pDst, int nW, int nH, int nThreshold); //

//-----------------------------------------------------------------------------------
//  2  7  12  7  2
//  7 31  52 31  7
// 12 52 127 52 12
//  7 31  52 31  7
//  2  7  12  7  2
void FrameSmooth5GaussB(byte* pSrc, byte* pDst, int nW, int nH);
void FrameSmooth5GaussThresholdB(byte* pSrc, byte* pDst, int nW, int nH, int nThreshold);

//-----------------------------------------------------------------------------------
// pCon array (convolution coefficients) has dimension = 9 (row after row)
void FrameConvolution3B(byte* pSrc,  short* pDst, int nW, int nH, int* pCon);
void FrameConvolution3S(short* pSrc, short* pDst, int nW, int nH, int* pCon);

//-----------------------------------------------------------------------------------
// pCon array (convolution coefficients) has dimension = 25 (row after row)
void FrameConvolution5B(byte* pSrc,  short* pDst, int nW, int nH, int* pCon);
void FrameConvolution5S(short* pSrc, short* pDst, int nW, int nH, int* pCon);

//-----------------------------------------------------------------------------------
// return Sum of Absolute Differences
int FrameSADB(byte* pFrm1,  byte* pFrm2,  int nW, int nH);
double FrameSADS(short* pFrm1, short* pFrm2, int nW, int nH);

//-----------------------------------------------------------------------------------
// v= 255 - v
void FrameNegativeB(byte* pSrc, byte* pDst, int nW, int nH);

//-----------------------------------------------------------------------------------
// if (v<nLow)  v=0
// if (v>nHigh) v=0
void FrameCutsB(byte* pSrc, byte* pDst,  int nW, int nH, int nLow, int nHigh);

//-----------------------------------------------------------------------------------
// (nLow,nHigh) to (0,255)
void FrameRenormB(byte* pSrc, byte* pDst, int nW, int nH, int nLow, int nHigh);

//-----------------------------------------------------------------------------------
void FrameMedianFilter3B(byte* pSrc, byte* pDst,  int nW, int nH);

//-----------------------------------------------------------------------------------
void FrameMedianFilter5B(byte* pSrc, byte* pDst,  int nW, int nH);

//-----------------------------------------------------------------------------------
// -1 -1 -1
// -1 16 -1
// -1 -1 -1
void FrameSharpenFilter3B(byte* pSrc, short* pDst,  int nW, int nH);

//-----------------------------------------------------------------------------------
// -1 -1 -1 -1 -1
// -1 -2 -2 -2 -1
// -1 -2 64 -2 -1
// -1 -2 -2 -2 -1
// -1 -1 -1 -1 -1
void FrameSharpenFilter5B(byte* pSrc, short* pDst,  int nW, int nH);

//-----------------------------------------------------------------------------------
// v=min from window 3x3
void FrameMinFilter3B(byte* pSrc, byte* pDst,  int nW, int nH);

//-----------------------------------------------------------------------------------
// v=max from window 3x3
void FrameMaxFilter3B(byte* pSrc, byte* pDst,  int nW, int nH);

//-----------------------------------------------------------------------------------
// v=(min+max)/2 from window 3x3
void FrameMinMaxFilter3B(byte* pSrc, byte* pDst,  int nW, int nH);

//-----------------------------------------------------------------------------------
// v=min from window 5x5
void FrameMinFilter5B(byte* pSrc, byte* pDst,  int nW, int nH);

//-----------------------------------------------------------------------------------
// v=max from window 5x5
void FrameMaxFilter5B(byte* pSrc, byte* pDst,  int nW, int nH);

//-----------------------------------------------------------------------------------
// v=(min+max)/2 from window 5x5
void FrameMinMaxFilter5B(byte* pSrc, byte* pDst,  int nW, int nH);

//-----------------------------------------------------------------------------------
void FrameMirrorXB(byte* pSrc, byte* pDst,  int nW, int nH);
void FrameMirrorYB(byte* pSrc, byte* pDst,  int nW, int nH);

//-----------------------------------------------------------------------------------
void FrameMirrorRotate90LeftB (byte* pSrc, byte* pDst,  int nW, int nH);
void FrameMirrorRotate90RightB(byte* pSrc, byte* pDst,  int nW, int nH);

//-----------------------------------------------------------------------------------
int  ReadPGM(char* file_name, byte** ppImg, int* pnWidth, int* pnHeight);
void WritePGM(char* file_name, byte* pImg, int nWidth, int nHeight);

//-----------------------------------------------------------------------------------
int PpmImageFileRead(char* filename, byte** ppPic, int* pnW, int* pnH);
int PpmImageFileWrite(char* filename, byte* pPic, int nWidth, int nHeight);

//-----------------------------------------------------------------------------------
int BmpWidthHeight(byte* pBmpFile, int* pnWidth, int* pnHeight);
int ReadBmpFile(char* pFileName, byte* pBmpFile);
int GetColorComponentFromBmp(byte* pBmp, byte* pRed, byte* pGreen, byte* pBlue);

//-----------------------------------------------------------------------------------
void YCC420ToRGB(byte* pLu, byte* pCb, byte* pCr, int nW, int nH,
                 byte* pR, byte* pG, byte* pB);

void YUV420ToRGB(byte* pY, byte* pU, byte* pV, int nW, int nH,
                 byte* pR, byte* pG, byte* pB);

//-----------------------------------------------------------------------------------
// 4:4:4
void TransformRGBtoLuCbCr(byte* pRed,  byte* pGreen,   byte* pBlue,
                          byte* pLuma, byte* pChromaB, byte* pChromaR,
                          int nWidth, int nHeight);

void TransformLuCbCrToRGB(byte* pLuma, byte* pChromaB, byte* pChromaR,
                          byte* pRed,  byte* pGreen,   byte* pBlue,
                          int nWidth, int nHeight);

//-----------------------------------------------------------------------------------
void MakeRGBfromComponents(byte* pRGB, byte* pRed, byte* pGreen, byte* pBlue,
                           int nWidth, int nHeight);

void GetComponentsFromRGB(byte* pRGB, byte* pRed, byte* pGreen, byte* pBlue,
                          int nWidth, int nHeight);

//-----------------------------------------------------------------------------------
double FrameSnrCalcB(byte* pFrm1, byte* pFrm2, int nWidth, int nHeight);

#endif
