/*=========================================================================
    CMVision.h
  -------------------------------------------------------------------------
    API definition for the CMVision real time Color Machine Vision library
  -------------------------------------------------------------------------
    Copyright 1999, 2000         #### ### ### ## ## ## #### ##  ###  ##  ##
    James R. Bruce              ##    ####### ## ## ## ##   ## ## ## ######
    School of Computer Science  ##    ## # ## ## ## ##  ### ## ## ## ## ###
    Carnegie Mellon University   #### ##   ##  ###  ## #### ##  ###  ##  ##
  -------------------------------------------------------------------------
    This program is free software; you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation; either version 2 of the License, or
    (at your option) any later version.

    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with this program; if not, write to the Free Software
    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
  =========================================================================*/

#ifndef __CMVISION_H__
#define __CMVISION_H__

#include <string.h>
#include <stdio.h>

/*
Ultra-fast intro to processing steps:
 - Color segmentation
   - load / save
   - set new values
   - process frame
 - Connected Regions
   - RLE
   - merge
   - extract blobs
   - separate blobs
   - sort blobs
   - merge blobs
 - Blob merging (not currently in release)
   - merge by area occupied

Options File Format: (RGB merge name)
[Colors]
(00,00,00) 0.95 'Orange'
(00,00,00) 0.00 'Pink'
(00,00,00) 0.00 'Red'
(00,00,00) 0.00 'DarkBlue'
(00,00,00) 0.00 'Blue'

[Thresholds]
(<lo>:<hi>,<lo>:<hi>,<lo>:<hi>)
(<lo>:<hi>,<lo>:<hi>,<lo>:<hi>)
(<lo>:<hi>,<lo>:<hi>,<lo>:<hi>)
*/

#define CMV_COLOR_LEVELS  256
#define CMV_MAX_COLORS     32

// sets tweaked optimal values for image size
#define CMV_DEFAULT_WIDTH  160
#define CMV_DEFAULT_HEIGHT 120

// values may need tweaked, although these seem to work usually
#define CMV_MAX_RUNS     (CMV_DEFAULT_WIDTH * CMV_DEFAULT_HEIGHT) / 4
#define CMV_MAX_REGIONS  CMV_MAX_RUNS / 4
#define CMV_MIN_AREA        4

#define CMV_NONE ((unsigned)(-1))

#ifndef NULL
#define NULL (0)
#endif

struct yuv422{
  unsigned char y1,u,y2,v;
};

struct rgb{
  unsigned char red,green,blue;
};

class CMVision{
public:
  struct region{
    int color;          // id of the color
    int area;           // occupied area in pixels
    int x1,y1,x2,y2;    // bounding box (x1,y1) - (x2,y2)
    float cen_x,cen_y;  // centroid
    int sum_x,sum_y;    // temporaries for centroid calculation
    region *next;       // next region in list
  };

  struct rle{
    unsigned color;     // which color(s) this run represents
    int length;         // the length of the run (in pixels)
    int parent;         // run's parent in the connected components tree
  };

  struct color_info{
    rgb color;          // example color (such as used in test output)
    char *name;         // color's meaninful name (e.g. ball, goal)
    double merge;       // merge factor (currently unused)
    int y_low,y_high;   // Y,U,V component thresholds
    int u_low,u_high;
    int v_low,v_high;
  };

protected:
  unsigned yclass[CMV_COLOR_LEVELS];
  unsigned uclass[CMV_COLOR_LEVELS];
  unsigned vclass[CMV_COLOR_LEVELS];

  region region_table[CMV_MAX_REGIONS];
  region *region_list[CMV_MAX_COLORS];
  int region_count[CMV_MAX_COLORS];

  rle rmap[CMV_MAX_RUNS];

  color_info colors[CMV_MAX_COLORS];
  int width,height;
  unsigned *map;

protected:
// Private functions
  void classifyFrame(yuv422 *img,unsigned *map);
  int  encodeRuns(rle *out,unsigned *map);
  void connectComponents(rle *map,int num);
  int  extractRegions(region *reg,rle *rmap,int num);
  int  separateRegions(region *reg,int num);
  region *sortRegionListByArea(region *list,int passes);
  void sortRegions(int max_area);

  void clear();

public:
  CMVision()  {clear();}
  ~CMVision() {close();}

  bool initialize(int nwidth,int nheight);
  bool loadOptions(char *filename);
  bool saveOptions(char *filename);
  void close();

  bool testClassify(rgb *out,yuv422 *image);
  bool getThreshold(int color,
         int &y_low,int &y_high,
	 int &u_low,int &u_high,
         int &v_low,int &v_high);
  bool setThreshold(int color,
         int y_low,int y_high,
	 int u_low,int u_high,
         int v_low,int v_high);

  char *getColorName(int color)
    {return(colors[color].name);}

  color_info *getColorInfo(int color)
    {return(&colors[color]);}
  void getColorInfo(int color,color_info &info)
    {info = colors[color];}
  void setColorInfo(int color,color_info &info)
    {colors[color] = info;}

  bool processFrame(yuv422 *image);
  int numRegions(int color_id);
  region *getRegions(int color_id);
};

#endif