/*****************************************************************************/
/*                       Image processing functions                          */
/*  Source file : image color corrections                                    */
/*  Designed by Igor Potucek (potucek@fit.vutbr.cz)                          */
/*  created 2006                                                             */
/*****************************************************************************/
#include <mem>
#include <math>

void rgb_to_hsv(int r, int g, int b, int *h, int *s, int *v)
{   // new values are 0 - 255
    int min, max, delta;
    int i, w;

    w = 0;
    min = max = r;
    if (g<min) min=g;
    if (b<min) min=b;
    if (g>max) { max=g; w=1; }
    if (b>max) { max=b; w=2; }

    /* calculate V */
    *v = max;
    /* calculate S */
    *s = (255.0*(float)(max-min))/max+0.5;

    /* calculate H */
    delta = max-min;
    if (delta==0)
    {
      *h=0; *s=0;
      return ;
    }
    float fh=0;
    switch(w) {
    case 0: fh = 60.0*(0.0 + (g-b)/(float)delta); break;
    case 1: fh = 60.0*(2.0 + (b-r)/(float)delta); break;
    case 2: fh = 60.0*(4.0 + (r-g)/(float)delta); break;
    }
    while (fh < 0.0) fh += 360.0;
    *h=(fh*256.0/360+0.5);
}

void hsv_to_rgb(int h, int s, int v, int *r, int *g, int *b)
{
        float f,p,q,t;
        int i;

        float fh=h*6.0/256.0;           // result is sector 0 to 5( h is 0-360 and h/6
        i = floor(fh);
        f = fh-(float)i;                // relative position in the sector
        p = v*(1-s/255.0)+0.5;
        q = v*(1-s*f/255.0)+0.5;
        t = v*(1-s*(1-f)/255.0)+0.5;

        switch(i) {
        case 0: *r = v; *g = t; *b = p; break;
        case 1: *r = q; *g = v; *b = p; break;
        case 2: *r = p; *g = v; *b = t; break;
        case 3: *r = p; *g = q; *b = v; break;
        case 4: *r = t; *g = p; *b = v; break;
        case 5: *r = v; *g = p; *b = q; break;
        }
}

void AreaHistogramColorEqual(unsigned char *InputImage, unsigned char *OutputImage, unsigned char *Mask, int Width, int Height, int Color)
{  // RGB, R, G, B, HSV - 0, 1, 2, 3, 4
   int r,g,b, h,s,v;
   long Histogram[256];
   long PixelCount = 0;
   unsigned char LookUpTable[256];
   memset(Histogram, 0, sizeof(Histogram));
   unsigned char *data = InputImage;
   unsigned char *Maskdata = Mask;
   // compute histograms
   for (int j=0; j<Height; j++)
     for (int i=0; i<Width; i++)
     if (*Maskdata>0)
     {
        r = *data; data++;
        g = *data; data++;
        b = *data; data++;
        if (Color == 0)
        {
          int value = (0.299*r+0.587*g+0.114*b);
          if ((value>=0) && (value<256))
            Histogram[value]++;
        }
        else
        if ((Color == 1) && (r<255))
          Histogram[r]++;
        else
        if ((Color == 2) && (g<255))
          Histogram[g]++;
        else
        if ((Color == 3) && (b<255))
          Histogram[b]++;
        else
        if (Color == 4)
        {
          rgb_to_hsv(r,g,b, &h, &s, &v);
          if ((v>=0) && (v<256))
            Histogram[v]++;
        }

        Maskdata++;
        PixelCount++;
     }
     else
     {
        Maskdata++;
        data+=3;
     }
   // compute integral histogram
   for (int k=1; k<256; k++)
      Histogram[k]+=Histogram[k-1];
   // compute new color distributions
   for (int k=0; k<256; k++)
     LookUpTable[k] = 255*Histogram[k]/PixelCount;
   // create new image
   data = InputImage;
   Maskdata = Mask;
   for (int j=0; j<Height; j++)
     for (int i=0; i<Width; i++)
      {
        r = *data; data++;
        g = *data; data++;
        b = *data; data++;
        if (*Maskdata>0)
        {
          ////////////////////////////////////////////////////////////////////////
        if (Color == 0)
        {
          v = (0.299*r+0.587*g+0.114*b);
        }
        else

          if ((Color == 1) && (r<255))
            v = r;
          else
          if ((Color == 2) && (g<255))
            v = g;
          else
          if ((Color == 3) && (b<255))
            v = b;
          else
          if (Color == 4)
          {
            rgb_to_hsv(r,g,b, &h, &s, &v);
            if ((v<0) && (v>255))
              v = 0;
          }
          unsigned char newv = LookUpTable[v];
          if (Color == 4)
          {
            hsv_to_rgb(h,s,newv, &r, &g, &b);
          }
          else
          {
            r = newv;
            g = newv;
            b = newv;
          }
          ////////////////////////////////////////////////////////////////////////
        }
        *OutputImage = r;
         OutputImage++;
        *OutputImage = g;
         OutputImage++;
        *OutputImage = b;
         OutputImage++;
         Maskdata++;
      }
}

void ContrastSetting(unsigned char *InputImage, unsigned char *OutputImage, int Width, int Height, int Min, int Max, int Color)
// Value - presents the number of the change(0 - ..) - multiplikative parameter
{  // RGB, R, G, B, HSV - 0, 1, 2, 3, 4
   int r,g,b, h,s,v;
   float Value = 255.0/(Max-Min);
   unsigned char *data = InputImage;
   for (int j=0; j<Height; j++)
     for (int i=0; i<Width; i++)
      {
        if (Color == 4)
        {
          r = *data; data++;
          g = *data; data++;
          b = *data; data++;
          rgb_to_hsv(r,g,b, &h, &s, &v);
          v = (v - Min)*Value;
          hsv_to_rgb(h,s,v, &r, &g, &b);
        }
        else
        if (Color == 0)
        {
          r = *data; data++;
          g = *data; data++;
          b = *data; data++;
          int value = ((0.299*r+0.587*g+0.114*b)-Min)*Value;
            if (value<0)
              r = 0;
            else
            if (value>255)
              r = 255;
            else
              r = value;
        }
        else
        {
          r = (*data-Min)*Value; data++;
          g = (*data-Min)*Value; data++;
          b = (*data-Min)*Value; data++;
        }
        if (r<0) r=0; if (r>255) r=255;
        if (g<0) g=0; if (g>255) g=255;
        if (b<0) b=0; if (b>255) b=255;

        switch (Color) {
          case 0: *OutputImage = (unsigned char)r; break;
          case 1: *OutputImage = (unsigned char)r; break;
          case 2: *OutputImage = (unsigned char)g; break;
          case 3: *OutputImage = (unsigned char)b; break;
          case 4: *OutputImage = (unsigned char)r; break;
        }
         OutputImage++;
        switch (Color) {
          case 0: *OutputImage = (unsigned char)r; break;
          case 1: *OutputImage = (unsigned char)r; break;
          case 2: *OutputImage = (unsigned char)g; break;
          case 3: *OutputImage = (unsigned char)b; break;
          case 4: *OutputImage = (unsigned char)g; break;
        }
         OutputImage++;
        switch (Color) {
          case 0: *OutputImage = (unsigned char)r; break;
          case 1: *OutputImage = (unsigned char)r; break;
          case 2: *OutputImage = (unsigned char)g; break;
          case 3: *OutputImage = (unsigned char)b; break;
          case 4: *OutputImage = (unsigned char)b; break;
        }
         OutputImage++;
      }
}