////////////////////////////////////////////////////////////////////////////
// Fast Track library header file
///////////////////////////////////////////////////////////////////////////
// Copyright to Joao P. Hespanha, 2004
///////////////////////////////////////////////////////////////////////////

#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <string.h>
#include <assert.h>
#include <errno.h>
#include <math.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <sys/timeb.h> 
#include <fcntl.h>

#include <gtk/gtk.h>

#ifdef GDK12
#include <gdk-pixbuf/gdk-pixbuf.h>
#endif

#ifndef NOV4L2
// neede by V4L2
#include <sys/ioctl.h>
#include <sys/stat.h>
#include <sys/mman.h>
#include <asm/types.h>          /* for videodev2.h */
#include <linux/videodev2.h>
#endif

//#define MIN(a,b) ((a)>(b)?(b):(a))
//#define MAX(a,b) ((a)<(b)?(b):(a))

///////////////////////////////////////////////////////////
// Image defines & types
///////////////////////////////////////////////////////////

#define FT_MAX_IMAGEWIDTH  640
#define FT_MAX_IMAGEHEIGHT 480
#define FT_MAX_RLELENGHT   64000*4

#define FT_IMAGESIZE(image) (sizeof(FT_8GrayImage_T)-FT_MAX_IMAGEWIDTH*FT_MAX_IMAGEHEIGHT+(image)->pixelslength)

#define FT_4BITGREY  1
#define FT_8BITGREY  2
#define FT_16BITGREY 3

#define FT_8BITRLEGREY 4  // Run Length Encoding

// 4bit gray-level image data with maximum size
typedef struct {
  unsigned short width;
  unsigned short height;
  unsigned short type;
  int            pixelslength;
  unsigned char pixels[FT_MAX_IMAGEWIDTH*FT_MAX_IMAGEHEIGHT/2];
} FT_4GrayImage_T;

// 8bit gray-level image data with maximum size
typedef struct {
  unsigned short width;
  unsigned short height;
  unsigned short type;
  int            pixelslength;
  unsigned char pixels[FT_MAX_IMAGEWIDTH*FT_MAX_IMAGEHEIGHT];
} FT_8GrayImage_T;

// 16bit gray-level image data with maximum size
typedef struct {
  unsigned short width;
  unsigned short height;
  unsigned short type;
  int            pixelslength;
  signed short pixels[FT_MAX_IMAGEWIDTH*FT_MAX_IMAGEHEIGHT];
} FT_16GrayImage_T;

// 8bit RLE gray-level image data with maximum size
typedef struct {
  unsigned short width;
  unsigned short height;
  unsigned short type;
  int            pixelslength;
  unsigned char pixels[FT_MAX_RLELENGHT];
} FT_8RLEGrayImage_T;

////////////////////////////////////////////////////////////////////
// prototypes from FastTrack.c
////////////////////////////////////////////////////////////////////

/*************************************************************************/
// X windows functions
/*************************************************************************/

void ProcessXEvents();
GtkWidget *DisplayNewImage(FT_8GrayImage_T *Gray8Image,char *windowname);
void UpdateImageDisplay(GtkWidget *drawarea);

/*************************************************************************/
// Load and Save image functions
/*************************************************************************/

void LoadImage(char *filename,FT_16GrayImage_T *GrayImage);
void SavePGM8(char *filename, FT_8GrayImage_T *Image);

/*************************************************************************/
// Image convertion functions
/*************************************************************************/

void ConvertAnyto8(FT_16GrayImage_T *Input,FT_8GrayImage_T *Output);
void Convert16to8(FT_16GrayImage_T *Input,FT_8GrayImage_T *Output);
void Convert16to4(FT_16GrayImage_T *Input,FT_4GrayImage_T *Output);
void Convert4to8(FT_4GrayImage_T *Input,FT_8GrayImage_T *Output);
void Convert8RLEto8(FT_8RLEGrayImage_T *Input,FT_8GrayImage_T *Output);
void Convert16to8RLE(FT_16GrayImage_T *Input,FT_8RLEGrayImage_T *Output,int threshold);


#ifndef NOV4L2

/*************************************************************************/
// Video4Linux2 functions
/*************************************************************************/
struct streamCaptureBuffer_S {
        void * start;
        size_t length; };

int v4l2Init(
  char* deviceName,           // device name, typically "/dev/video0" (input)
  int videoSource,            // index of the video source (0)        (input)
  v4l2_std_id videoStandard,  // video standard (V4L2_STD_NTSC_M)     (input)
  int pixelFormat,            // desired pixel format                 (input)
             // http://v4l2spec.bytesex.org/spec-single/v4l2.html#RGB-FORMATS
  enum v4l2_field fieldOrder, // desired field order                  (input)
              // http://v4l2spec.bytesex.org/spec-single/v4l2.html#V4L2-FIELD
  int width,                  // window capture width                 (input)
  int height,                 // window capture height                (input)
  int nBuffers);              // desired # of buffers for stream capture (input)

void v4l2SetParameters(
     int fd,          // device file handle for ioctl
     int brightness,  // desired brightness, i.e., the black level
     int contrast,    // desired brightness, i.e., luma gain
     int saturation,  // desired color saturation, i.e., chroma gain
     int hue);        // desired hue or color balance
                      // all parameters from 0..65535

int v4l2GetImage(
  int fd,                   // device file handle for ioctl            (input)
  FT_16GrayImage_T *Output, // Image buffer to be filled               (output)
  struct timeval *tstamp,   // time stamp with start-of-capture time   (output)
  int *sequence,            // frame sequence number                   (output)
  struct timeval *timeout,  // timeout for waiting for new frame (input/output)
                            // outputs time left before timeout
  int *mnptr,               // minimum grey level (0..255)             (output)
                            // not computed if NULL (saves time)
  int *mxptr,               // maximum grey level (0..255)             (output)
                            // not computed if NULL (which saves time)
  int lastPicFlag);         // when nonzero, gets the most recent      (input) 
                            //               image available
                            // when zero, gets the oldest image not yet read

int v4l2GetSubImage(
  int fd,                   // device file handle for ioctl            (input)
  FT_16GrayImage_T *Output, // Image buffer to be filled               (output)
  struct timeval *tstamp,   // time stamp with start-of-capture time   (output)
  int *sequence,            // frame sequence number                   (output)
  struct timeval *timeout,  // timeout for waiting for new frame (input/output)
                            // outputs time left before timeout
  int FirstColumn,          // region of interest                      (input)
  int FirstRow,
  int LastColumn,
  int LastRow,
  int *mnptr,               // minimum grey level (0..255)             (output)
                            // not computed if NULL (saves time)
  int *mxptr,               // maximum grey level (0..255)             (output)
                            // not computed if NULL (which saves time)
  int lastPicFlag);         // when nonzero, gets the most recent      (input) 
                            //               image available
                            // when zero, gets the oldest image not yet read

void v4l2End(int fd);       // device file handle for ioctl

#endif

/*************************************************************************/
// Image processing function
/*************************************************************************/

// Convolution
void HorizConv(
   FT_16GrayImage_T *Input,   // original image                         (input)
   FT_16GrayImage_T *Output,  // output image                           (output)
   int hlength,               // horizontal length of (half) template   (input)
   int vlength,               // vertical length of template            (input)
   int FirstColumn,           // region of interest                     (input)
   int FirstRow,
   int LastColumn,
   int LastRow);

void VertConv(
   FT_16GrayImage_T *Input,   // original image                         (input)
   FT_16GrayImage_T *Output,  // output image                           (output)
   int vlength,               // vertical length of (half) template     (input)
   int hlength,               // horizontal length of template          (input)
   int FirstColumn,           // region of interest                     (input)
   int FirstRow,
   int LastColumn,
   int LastRow);

// Edge detection
int HEdgeCross(
   FT_16GrayImage_T *Grad,     // horizontal gradient                   (input)
   FT_16GrayImage_T *Grad2,    // horizontal "2nd" gradient             (input)
   FT_16GrayImage_T *Output,   // output image                          (output)
   int FirstColumn,            // region of interest                    (input)
   int FirstRow,
   int LastColumn,
   int LastRow,
   int EdgeThreshold,          // edge detection threhold               (input)
   float HCross,               // horizontal cross-ratio                (input)
   float HCrossThreshold,      // horizontal cross-ratio threshold      (input)
   int   *bestrow,             // row of vertical edges                 (output)
   float *bestedges            // vertical edges (array of 4)           (output)
   );

int VEdgeCross(
   FT_16GrayImage_T *Grad,     // vertical gradient                     (input)
   FT_16GrayImage_T *Grad2,    // vertical "2nd" gradient               (input)
   FT_16GrayImage_T *Output,   // output image                          (output)
   int FirstColumn,            // region of interest
   int FirstRow,
   int LastColumn,
   int LastRow,
   int EdgeThreshold,          // edge detection threhold               (input)
   float VCross,               // vertical cross-ratio                  (input)
   float VCrossThreshold,      // vertical cross-ratio threshold        (input)
   int   *bestcolumn,          // column of vertical edges              (output)
   float *bestedges            // horizontal edges (array of 4)         (output)
   );

void EdgeVExtend(
   FT_16GrayImage_T *Grad,     // horizontal gradient                   (input)
   FT_16GrayImage_T *Grad2,    // horizontal "2nd" gradient             (input)
   FT_16GrayImage_T *Output,   // output image                          (output)
   int FirstColumn,            // region of interest                    (input)
   int FirstRow,
   int LastColumn,
   int LastRow,
   int EdgeThreshold,          // edge detection threhold               (input)
   int   row,                  // row of vertical edge to extend        (input)
   float edge,                 // vertical edge (column) to extend      (input)
   float *m,                   // slope of vertical edge                (output)
   float *b,                   // origin of vertical edge               (output)
   int *minrow,                // row where edge starts                 (output)
   int *maxrow,                // row where edge ends                   (output)
   int *mincolumn,             // column where edge starts              (output)
   int *maxcolumn              // column where edge ends                (output)
   );

void EdgeHExtend(
   FT_16GrayImage_T *Grad,     // vertical gradient                     (input)
   FT_16GrayImage_T *Grad2,    // vertical "2nd" gradient               (input)
   FT_16GrayImage_T *Output,   // output image                          (output)
   int FirstColumn,            // region of interest                    (input)
   int FirstRow,
   int LastColumn,
   int LastRow,
   int EdgeThreshold,          // edge detection threhold               (input)
   int   column,               // column of horizontal edge to extend   (input)
   float edge,                 // horizontal edge (row) to extend       (input)
   float *m,                   // slope of horizontal edge              (output)
   float *b,                   // origin of horizontal edge             (output)
   int *minrow,                // row where edge starts                 (output)
   int *maxrow,                // row where edge ends                   (output)
   int *mincolumn,             // column where edge starts              (output)
   int *maxcolumn              // column where edge ends                (output)
   );

int HVEdgeCross(
   FT_16GrayImage_T *Image,    // original image                        (input)
   FT_16GrayImage_T *Output,   // output image                          (output)
   int FirstColumn,            // region of interest                    (input)
   int FirstRow,
   int LastColumn,
   int LastRow,
   int LengthGradDir,          // length of (half) template in grad dir (input)
   int LengthAveDir,           // length of template in averaging dir   (input)
   int EdgeThreshold,          // edge detection threhold               (input)
   float HCross,               // horizontal cross-ratio                (input)
   float HCrossThreshold,      // horizontal cross-ratio threshold      (input)
   float VCross,               // vertical cross-ratio                  (input)
   float VCrossThreshold,      // vertical cross-ratio threshold        (input)
   float *bestvm,              // slopes of vertical edges (array of 4) (output)
   float *bestvb,              // origin of vertical edges (array of 4) (output)
   float *besthm,              // slopes of horiz. edges (array of 4)   (output)
   float *besthb               // origin of horiz. edges (array of 4)   (output)
   );

int VHEdgeCross(
   FT_16GrayImage_T *Image,    // original image                        (input)
   FT_16GrayImage_T *Output,   // output image                          (output)
   int FirstColumn,            // region of interest                    (input)
   int FirstRow,
   int LastColumn,
   int LastRow,
   int LengthGradDir,          // length of (half) template in grad dir (input)
   int LengthAveDir,           // length of template in averaging dir   (input)
   int EdgeThreshold,          // edge detection threhold               (input)
   float HCross,               // horizontal cross-ratio                (input)
   float HCrossThreshold,      // horizontal cross-ratio threshold      (input)
   float VCross,               // vertical cross-ratio                  (input)
   float VCrossThreshold,      // vertical cross-ratio threshold        (input)
   float *bestvm,              // slopes of vertical edges (array of 4) (output)
   float *bestvb,              // origin of vertical edges (array of 4) (output)
   float *besthm,              // slopes of horiz. edges (array of 4)   (output)
   float *besthb               // origin of horiz. edges (array of 4)   (output)
   );

void Lines2Points(
   float *vm,  // slopes of vertical edges       (array of 4) (input)
   float *vb,  // origin of vertical edges       (array of 4) (input)
   float *hm,  // slopes of horiz. edges         (array of 4) (input)
   float *hb,  // origin of horiz. edges         (array of 4) (input)
   float *px,  // x coordinates of intersections (array of 8) (output)
               // big square clock-wise from top-left, 
               // followed by small square
   float *py   // y coordinates of intersections (array of 8) (output)
   );          // same order as px
