packages feed

CV-0.3.7: cbits/cvWrapLEO.c

//@+leo-ver=4-thin
//@+node:aleator.20050908100314:@thin cvWrapLEO.c
//@@language c

//@+all
//@+node:aleator.20050908100314.1:Includes
#include "cvWrapLEO.h"
#include <stdio.h>
#include <opencv2/core/types_c.h>
#include <complex.h>
#include <stdint.h>

//@-node:aleator.20050908100314.1:Includes
//@+node:aleator.20050908100314.2:Wrappers

#define FGET(img,x,y) (((float *)((img)->imageData + (y)*(img)->widthStep))[(x)])
#define UGETC(img,color,x,y) (((uint8_t *)((img)->imageData + (y)*(img)->widthStep))[(x)*3+(color)])

size_t images;

inline double eucNorm(CvPoint2D64f p) {return (p.x*p.x+p.y*p.y);}
inline CvPoint2D64f toNormalizedCoords(CvSize area, CvPoint from)
{
    CvPoint2D64f res;
    res.x = (from.x-area.width/2.0)/area.width;
    res.y = (from.y-area.height/2.0)/area.height;
    return res;
}

inline CvPoint fromNormalizedCoords(CvSize area, CvPoint2D64f from)
{
    CvPoint res;
    res.x = (from.x+0.5)*area.width;
    res.y = (from.y+0.5)*area.height;
    return res;
}

inline CvPoint2D64f fromNormalizedCoords64f(CvSize area, CvPoint2D64f from)
{
    CvPoint2D64f res;
    res.x = (from.x+0.5)*area.width;
    res.y = (from.y+0.5)*area.height;
    return res;
}

void incrImageC(void)
{
 images++;
}

void wrapReleaseImage(IplImage *t)
{
 // printf("%d ",images);
 cvReleaseImage(&t);
 images--;
}

void wrapReleaseCapture(CvCapture *t)
{
 cvReleaseCapture(&t);
}

void wrapReleaseVideoWriter(CvCapture *t)
{
 cvReleaseCapture(&t);
}

void wrapReleaseStructuringElement(IplConvKernel *t)
{
 cvReleaseStructuringElement(&t);
}

IplImage* wrapLaplace(IplImage *src,int size)
{
IplImage *res;
IplImage *tmp;
tmp = cvCreateImage(cvGetSize(src),IPL_DEPTH_16S,1);
res = cvCreateImage(cvGetSize(src),IPL_DEPTH_8U,1);
cvLaplace(src,tmp,size);
cvConvertScale(tmp,res,1,0);
return res;
}

IplImage* wrapSobel(IplImage *src,int dx
                   ,int dy,int size)
{
IplImage *res;
IplImage *tmp;
tmp = cvCreateImage(cvGetSize(src),IPL_DEPTH_16S,1);
res = cvCreateImage(cvGetSize(src),IPL_DEPTH_8U,1);
cvSobel(src,tmp,dx,dy,size);
cvConvertScale(tmp,res,1,0);
cvReleaseImage(&tmp);
return res;
}

IplImage* wrapCreateImage32F(const int width
                         ,const int height
                         ,const int channels)
{
 CvSize s;
 IplImage *r;
 s.width = width; s.height = height;
 r = cvCreateImage(s,IPL_DEPTH_32F,channels);
 cvSetZero(r);
 return r;
}

IplImage* wrapCreateImage64F(const int width
                         ,const int height
                         ,const int channels)
{
 CvSize s;
 IplImage *r;
 s.width = width; s.height = height;
 r = cvCreateImage(s,IPL_DEPTH_64F,channels);
 cvSetZero(r);
 return r;
}


IplImage* wrapCreateImage8U(const int width
                         ,const int height
                         ,const int channels)
{
 CvSize s;
 IplImage *r;
 s.width = width; s.height = height;
 r = cvCreateImage(s,IPL_DEPTH_8U,channels);
 cvSetZero(r);
 return r;
}

IplImage *wrapCopyMakeBorder(IplImage* src
                            ,const int top
                            ,const int bottom
                            ,const int left
                            ,const int right
                            ,const int borderType
                            ,const float value)
{
 CvSize s = cvGetSize(src);
 s.width += left + right;
 s.height += top + bottom;
 IplImage *r;
 CvPoint p;
 p.x = left;
 p.y = top;
 r = cvCreateImage(s, src->depth, src->nChannels);
 cvCopyMakeBorder(src,r,p,borderType,cvScalarAll((double)value));
 return r;
}

IplImage* composeMultiChannel(IplImage* img0
                             ,IplImage* img1
                             ,IplImage* img2
                             ,IplImage* img3
                             ,const int channels)
{
 CvSize s;
 IplImage *r;
 s = cvGetSize(img0);
 r = cvCreateImage(s,img0->depth,channels);
 cvSetZero(r);
 cvMerge(img0,img1,img2,img3,r);
 return r;
}
void wrapSubRS(const CvArr *src, double s, CvArr *dst)
{
 cvSubRS(src,cvRealScalar(s),dst,0);
}

void wrapSubS(const CvArr *src, double s, CvArr *dst)
{
 cvSubS(src,cvRealScalar(s),dst,0);
}

void wrapAddS(const CvArr *src, double s, CvArr *dst)
{
 cvAddS(src,cvRealScalar(s),dst,0);
}

void wrapAbsDiffS(const CvArr *src, double s, CvArr *dst)
{
 cvAbsDiffS(src,dst,cvScalarAll(s));
}

double wrapAvg(const CvArr *src, const CvArr *mask)
{
 CvScalar avg = cvAvg(src,mask);
 return avg.val[0];
}

double wrapStdDev(const CvArr *src)
{
 CvScalar dev;
 cvAvgSdv(src,0,&dev,0);
 return dev.val[0];
}

double wrapStdDevMask(const CvArr *src,const CvArr *mask)
{
 CvScalar dev;
 IplImage *mask8 = ensure8U(mask);
 cvAvgSdv(src,0,&dev,mask8);
 cvReleaseImage(&mask8);
 return dev.val[0];
}
double wrapMeanMask(const CvArr *src,const CvArr *mask)
{
 CvScalar mean;
 IplImage *mask8 = ensure8U(mask);
 cvAvgSdv(src,&mean,0,mask8);
 cvReleaseImage(&mask8);
 return mean.val[0];
}

double wrapSum(const CvArr *src)
{
 CvScalar sum = cvSum(src);
 return sum.val[0];
}

void wrapMinMax(const CvArr *src,const CvArr *mask
               ,double *minVal, double *maxVal)
{
 //cvMinMaxLoc(src,minVal,maxVal,NULL,NULL,NULL);
 int i,j;
 int minx,miny,maxx,maxy;
 double pixel;
 double maskP;
 int t;
 double min=100000,max=-100000; // Some problem with DBL_MIN.

 CvSize s = cvGetSize(src);
 for(i=0; i<s.width; i++)
  for(j=0; j<s.height; j++)
   {
   pixel = cvGetReal2D(src,j,i);
   maskP = mask != 0 ? cvGetReal2D(mask,j,i) : 1;
   // TODO: Fix below..
   min   = (maskP >0.5 ) && (pixel < min) ? pixel : min;
   max   = (maskP >0.5 ) && (pixel > max) ? pixel : max;
   }
 (*minVal) = min; (*maxVal) = max;
}

void wrapSetImageROI(IplImage *i,int x, int y, int w, int h)
{
 CvRect r = cvRect(x,y,w,h);
 cvSetImageROI(i,r);
}


// Return image that is IPL_DEPTH_8U version of
// given src
IplImage* ensure8U(const IplImage *src)
{
 CvSize size;
 IplImage *result;
 int channels = src->nChannels;
 int dstDepth = IPL_DEPTH_8U;
 size = cvGetSize(src);
 result = cvCreateImage(size,dstDepth,channels);

 switch(src->depth) {
  case IPL_DEPTH_32F:
  case IPL_DEPTH_64F:
   cvConvertScale(src,result,255.0,0); // Scale the values to [0,255]
   return result;
  case IPL_DEPTH_8U:
   cvConvertScale(src,result,1,0);
   return result;
  default:
   printf("Cannot convert to floating image");
   abort();

 }
}

// Return image that is IPL_DEPTH_32F version of
// given src
IplImage* ensure64F(const IplImage *src)
{
 CvSize size;
 IplImage *result;
 int channels = src->nChannels;
 int dstDepth = IPL_DEPTH_64F;
 size = cvGetSize(src);
 result = cvCreateImage(size,dstDepth,channels);

 switch(src->depth) {
  case IPL_DEPTH_32F:
  case IPL_DEPTH_64F:
   cvConvertScale(src,result,1,0); // Scale the values to [0,255]
   return result;
  case IPL_DEPTH_8U:
  case IPL_DEPTH_8S:
   cvConvertScale(src,result,1.0/255.0,0);
   return result;
  case IPL_DEPTH_16S:
   cvConvertScale(src,result,1.0/65535.0,0);
   return result;
  case IPL_DEPTH_32S:
   cvConvertScale(src,result,1.0/4294967295.0,0);
   return result;
  default:
   printf("Cannot convert to floating image");
   abort();
 }
}

IplImage* ensure32F(const IplImage *src)
{
 CvSize size;
 IplImage *result;
 int channels = src->nChannels;
 int dstDepth = IPL_DEPTH_32F;
 size = cvGetSize(src);
 result = cvCreateImage(size,dstDepth,channels);

 switch(src->depth) {
  case IPL_DEPTH_32F:
  case IPL_DEPTH_64F:
   cvConvertScale(src,result,1,0); // Scale the values to [0,255]
   return result;
  case IPL_DEPTH_8U:
  case IPL_DEPTH_8S:
   cvConvertScale(src,result,1.0/255.0,0);
   return result;
  case IPL_DEPTH_16S:
   cvConvertScale(src,result,1.0/65535.0,0);
   return result;
  case IPL_DEPTH_32S:
   cvConvertScale(src,result,1.0/4294967295.0,0);
   return result;
  default:
   printf("Cannot convert to floating image");
   abort();
 }
}

void wrapSet32F2D(CvArr *arr, int x, int y, double value)
{
 cvSet2D(arr,x,y,cvRealScalar(value));
}


double wrapGet32F2D(CvArr *arr, int x, int y)
{
 CvScalar r;
 r = cvGet2D(arr,x,y);
 return r.val[0];
}

double wrapGet32F2DC(CvArr *arr, int x, int y,int c)
{
 CvScalar r;
 r = cvGet2D(arr,x,y);
 return r.val[c];
}

uint8_t wrapGet8U2DC(IplImage *arr, int x, int y,int c)
{
 return UGETC(arr,c,y,x);
}


void wrapDrawCircle(CvArr *img, int x, int y, int radius, float r,float g,float b, int thickness)
{
 cvCircle(img,cvPoint(x,y),radius,CV_RGB(r,g,b),thickness,8,0);
}

void wrapDrawText(CvArr *img, char *text, float s, int x, int y,float r,float g,float b)
{
CvFont font; //?
cvInitFont(&font, CV_FONT_HERSHEY_PLAIN, s, s, 0, 2, 8);
cvPutText(img, text, cvPoint(x,y), &font, CV_RGB(r,g,b));
}

void wrapDrawRectangle(CvArr *img, int x1, int y1,
                       int x2, int y2, float r, float g, float b,
                       int thickness)
{
 cvRectangle(img,cvPoint(x1,y1),cvPoint(x2,y2),CV_RGB(r,g,b),thickness,8,0);
}


void wrapDrawLine(CvArr *img, int x, int y, int x1, int y1, double r, double g, double b, int thickness)
{
 cvLine(img,cvPoint(x,y),cvPoint(x1,y1),CV_RGB(r,g,b),thickness,4,0);
}

void wrapFillPolygon(IplImage *img, int pc, int *xs, int *ys, float r, float g, float b)
{
 int i=0;
 int pSizes[] = {pc};
 CvPoint *pts = (CvPoint*)malloc(pc*sizeof(CvPoint));
 for (i=0; i<pc; ++i)
    {pts[i].x = xs[i];
     pts[i].y = ys[i];
     }
 cvFillPoly(img, &pts, pSizes, 1, CV_RGB(r,g,b), 8, 0 );
 free(pts);
}

void wrapDrawEllipse(IplImage *img, int x, int y, int r1, int r2, float a, float a1, float a2, float r, float g, float b, int thickness)
{
  cvEllipse(img, cvPoint(x,y),cvSize(r1,r2),a,a1,a2,CV_RGB(r,g,b),thickness,8,0);
}

int getImageWidth(IplImage *img)
{
 return cvGetSize(img).width;
}
int getImageHeight(IplImage *img)
{
 return cvGetSize(img).height;
}

IplImage* getSubImage(IplImage *img, int sx,int sy,int w,int h)
{
 CvRect r;
 CvSize s;
 IplImage *newImage;

 r.x = sx; r.y = sy;
 r.width = w; r.height = h;
 s.width = w; s.height = h;

 cvSetImageROI(img,r);
 newImage = cvCreateImage(s,img->depth,img->nChannels);
 cvCopy(img, newImage,0);
 cvResetImageROI(img);
 return newImage;
}

IplImage* simpleMergeImages(IplImage *a, IplImage *b,int offset_x, int offset_y)
{
 CvSize aSize = cvGetSize(a);
 CvSize bSize = cvGetSize(b);
 int startx = 0 < offset_x ? 0 : offset_x;
 int endx = aSize.width > bSize.width+offset_x ? aSize.width : bSize.width+offset_x ;

 int starty = 0 < offset_y ? 0 : offset_y;
 int endy = aSize.height > bSize.height+offset_y ? aSize.height : bSize.height+offset_y ;

 CvSize size;
 size.width  = endx-startx;
 size.height = endy-starty;

 CvRect aPos = cvRect(offset_x<0?-offset_x:0
                     ,offset_y<0?-offset_y:0
                     ,aSize.width
                     ,aSize.height);

 CvRect bPos = cvRect(offset_x<0?0:offset_x
                     ,offset_y<0?0:offset_y
                     ,bSize.width
                     ,bSize.height);

 IplImage *resultImage = cvCreateImage(size,a->depth,a->nChannels);

 // Blit the images into bigger result image using cvCopy
 cvSetImageROI(resultImage,aPos);
 cvCopy(a,resultImage,NULL);
 cvSetImageROI(resultImage,bPos);
 cvCopy(b,resultImage,NULL);
 cvResetImageROI(resultImage);
 return resultImage;
}

void blitImg(IplImage *a, IplImage *b,int offset_x, int offset_y)
{
 CvSize bSize = cvGetSize(b);
 CvRect pos = cvRect(offset_x
                    ,offset_y
                    ,bSize.width
                    ,bSize.height);

 // Blit the images b into a using cvCopy
// printf("Doing a blit\n"); fflush(stdout);
 cvSetImageROI(a,pos);
 cvCopy(b,a,NULL);
 cvResetImageROI(a);
// printf("Done!\n"); fflush(stdout);
}

// Assuming a is the bigger image
void blitShadow(IplImage *a, IplImage *b)
{
 CvSize sa = cvGetSize(a);
 CvSize sb = cvGetSize(b);

 for ( int i=0; i<sb.width; i++ )
  for ( int j=0; j<sb.height; j++ )
   FGET(a,i,j) = FGET(b,i,j);

 for ( int i=sb.width; i<sa.width; i++ )
  for ( int j=0; j<sb.height; j++ )
   FGET(a,i,j) = FGET(b,sb.width-1,j);

 for ( int i=0; i<sb.width; i++ )
  for ( int j=sb.height; j<sa.height; j++ )
   FGET(a,i,j) = FGET(b,i,sb.height-1);

 for ( int i=sb.width; i<sa.width; i++ )
  for ( int j=sb.height; j<sa.height; j++ )
   FGET(a,i,j) = FGET(b,sb.width-1,sb.height-1);

}

IplImage* makeEvenDown(IplImage *src)
{
 CvSize size = cvGetSize(src);
 int w = size.width-(size.width % 2);
 int h = size.height-(size.height % 2);
 IplImage *result = wrapCreateImage32F(w,h,1);
 CvRect pos = cvRect(0
                    ,0
                    ,size.width
                    ,size.height);
 // Blit the images b into a using cvCopy
 cvSetImageROI(src,pos);
 cvCopy(src,result,NULL);
 cvResetImageROI(result);
 return result;
}

IplImage* makeEvenUp(IplImage *src)
{
 CvSize size = cvGetSize(src);
 int w = size.width+(size.width % 2);
 int h = size.height+(size.height % 2);
 int j;
 IplImage *result = wrapCreateImage32F(w,h,1);
 CvRect pos = cvRect(0
                    ,0
                    ,size.width
                    ,size.height);
 // Blit the images b into a using cvCopy
 cvSetImageROI(result,pos);
 cvCopy(src,result,NULL);
 cvResetImageROI(result);
 if (size.width % 2 == 1)
      {for (j=0; j<=size.height; j++) {
          FGET(result,size.width,j) = FGET(result,size.width-1,j); } }
 if (size.width % 2 == 1)
      {for (j=0; j<=size.width; j++) {
          FGET(result,j,(size.height)) = FGET(result,j,(size.height-1)); } }
 return result;
}

IplImage* padUp(IplImage *src,int right, int bottom)
{
 CvSize size = cvGetSize(src);
 int w = size.width + (right  ? 1 : 0);
 int h = size.height+ (bottom ? 1 : 0);
 int j;
 IplImage *result = wrapCreateImage32F(w,h,1);
 CvRect pos = cvRect(0
                    ,0
                    ,size.width
                    ,size.height);
 // Blit the images b into a using cvCopy
 cvSetImageROI(result,pos);
 cvCopy(src,result,NULL);
 cvResetImageROI(result);
 if (right)
      {for (j=0; j<=size.height; j++) {
          FGET(result,size.width,j) = 2*FGET(result,size.width-1,j)
                                       -FGET(result,size.width-2,j); } }
 if (bottom)
      {for (j=0; j<=size.width; j++) {

          FGET(result,j,(size.height)) = 2*FGET(result,j,(size.height-1))
                                          -FGET(result,j,(size.height-2));
                                          } }
 return result;
}

void masked_merge(IplImage *src1, IplImage *mask, IplImage *src2, IplImage *dst)
{
 int i,j;
 CvSize size = cvGetSize(dst);
 for (i=0; i<size.width; i++)
    for (j=0; j<size.height; j++) {
       FGET(dst,i,j) =  FGET(src1,i,j)*FGET(mask,i,j)
                        +FGET(src2,i,j)*(1-FGET(mask,i,j));
     }
}

void vertical_average(IplImage *src, IplImage *dst)
{
 int i,j;
 double avg;
 CvSize size = cvGetSize(dst);
 for (i=0; i<size.width; i++) {
    avg = 0;
    for (j=0; j<size.height; j++) { avg += FGET(src,i,j); }
    avg = avg / size.height;
    for (j=0; j<size.height; j++) { FGET(dst,i,j) = avg; }
    }
}


IplImage* fadedEdges(int w, int h, int edgeW) {
    IplImage *result;
    int i,j;
    result = wrapCreateImage32F(w,h,1);
    for (i=0; i<h; i++)
       for (j=0; j<w; j++) {
           float dx = i < (h/2.0) ? i : h-i ;
           float dy = j < (w/2.0) ? j : w-j ;
           float x = dx > edgeW ? 1 : dx/edgeW;
           float y = dy > edgeW ? 1 : dy/edgeW;
           FGET(result,j,i) = x*y;
           }
    return result;
}

IplImage* rectangularDistance(int w, int h) {
    IplImage *result;
    int i,j;
    result = wrapCreateImage32F(w,h,1);
    for (i=0; i<h; i++)
       for (j=0; j<w; j++) {
           float dx = i < (h/2.0) ? i/(h*1.0) : (h-i)/(h*1.0) ;
           float dy = j < (w/2.0) ? j/(w*1.0) : (w-j)/(w*1.0) ;
           FGET(result,j,i) = dx<dy?dx:dy;
           }
    return result;
}
IplImage* vignettingModelCos4(int w, int h) {
    IplImage *result;
    int i,j;
    double nx,ny;
    double r;
    const double x0 = w/2.0;
    const double y0 = h/2.0;
    result = wrapCreateImage32F(w,h,1);
    for (i=0; i<h; i++)
       for (j=0; j<w; j++) {
            nx = (y0-i)/h;
            ny = (x0-j)/w;
            r = sqrt(nx*nx+ny*ny);
            FGET(result,j,i) = pow(cos (r),4);
           }
    return result;
}

IplImage* vignettingModelCos4XCyl(int w, int h) {
    IplImage *result;
    int i,j;
    double r;
    const double x0 = w/2.0;
    const double y0 = h/2.0;
    result = wrapCreateImage32F(w,h,1);
    for (i=0; i<h; i++)
       for (j=0; j<w; j++) {
            r = fabs((i-y0)/y0) ;
            FGET(result,j,i) = pow(cos (r),4);
           }
    return result;
}

IplImage* vignettingModelX2Cyl(int w, int h,double m, double s, double c) {
    IplImage *result;
    int i,j;
    double r;
    result = wrapCreateImage32F(w,h,1);
    for (i=0; i<h; i++)
       for (j=0; j<w; j++) {
            FGET(result,j,i) = -((i-c)*s)*((i-c)*s)-m;
           }
    return result;
}

IplImage* vignettingModelB3(int w, int h,double b1, double b2, double b3) {
    IplImage *result;
    int i,j;
    double r;
    result = wrapCreateImage32F(w,h,1);
    for (i=0; i<h; i++)
       for (j=0; j<w; j++) {
            CvPoint2D64f nor = toNormalizedCoords(cvSize(w,h),cvPoint(j,i));
            r = eucNorm(nor);
            FGET(result,j,i) = b3*pow(r,6)+b2*pow(r,4)+b3*pow(r,2)+1;
           }
    return result;
}
IplImage* vignettingModelP(int w, int h,double scalex, double scaley, double max) {
    IplImage *result;
    int i,j;
    double r;
    double mx = w/2.0;
    double my = w/2.0;
    result = wrapCreateImage32F(w,h,1);
    for (i=0; i<h; i++)
       for (j=0; j<w; j++) {
            FGET(result,j,i) =-((i-my)*scaley)*((i-my)*scaley)*((j-mx)*scalex)*((j-mx)*scalex)-max ;
           }
    return result;
}

IplImage* simplePerspective(double k,IplImage *src) {
    IplImage *result;
    int i,j;
    double r;
    result = cvCloneImage(src);
    int h = cvGetSize(src).height;
    int w = cvGetSize(src).width;
    CvPoint2D32f srcPts[4] = {{0,0},{w-1,0},{w-1,h-1},{0,h-1}};
    CvPoint2D32f dstPts[4] = {{-k,0},{w-1+k,0},{w-1,h-1},{0,h-1}};
    CvMat* M = cvCreateMat(3,3,CV_32FC1);
    cvGetPerspectiveTransform(srcPts, dstPts, M);
    cvWarpPerspective(src, result, M, CV_INTER_LINEAR+CV_WARP_FILL_OUTLIERS, cvScalarAll(0));
    cvReleaseMat(&M);
    return result;
}

IplImage* wrapPerspective(IplImage* src, double a1, double a2, double a3
                                       , double a4, double a5, double a6
                                       , double a7, double a8, double a9)
{
    IplImage *res = cvCloneImage(src);
    double a[] = { a1,a2,a3,
                   a4,a5,a6,
                   a7,a8,a9};

    CvMat M = cvMat(3,3,CV_64FC1,a);
    cvWarpPerspective(src, res, &M, CV_INTER_LINEAR+CV_WARP_FILL_OUTLIERS, cvScalarAll(0));
    return res;
}

void findHomography(double* srcPts, double *dstPts, int noPts, double *homography)
{
CvMat src = cvMat(noPts, 2, CV_64FC1, srcPts);
CvMat dst = cvMat(noPts, 2, CV_64FC1, dstPts);
CvMat *hmg = cvCreateMat(3,3,CV_32FC1);
int i;
cvFindHomography(&src, &dst, hmg, 0, 0, 0);
for (i=0;i<3*3;++i)
        homography[i] = cvmGet(hmg,i/3,i%3);
cvReleaseMat(&hmg);
}


void alphaBlit(IplImage *a, IplImage *aAlpha, IplImage *b, IplImage *bAlpha, int offset_y, int offset_x)
{
    // TODO: Add checks for image type and size
 int i,j;
 CvSize bSize = cvGetSize(b);
 CvSize aSize = cvGetSize(a);
 CvRect pos = cvRect(offset_x
                    ,offset_y
                    ,bSize.width
                    ,bSize.height);
 for (i=0; i<bSize.height; i++)
    for (j=0; j<bSize.width; j++) {
       float aA, bA,fV;
       if (j+offset_x>=aSize.width || i+offset_y>=aSize.height || i+offset_y < 0 || j+offset_x<0) continue;

       aA = FGET(aAlpha,j+offset_x,i+offset_y);
       bA = FGET(bAlpha,j,i);
       fV = aA+bA > 0 ? (FGET(b,j,i)*bA+FGET(a,j+offset_x,i+offset_y)*aA)/(aA+bA) : FGET(b,j,i) ;
       FGET(a,j+offset_x,i+offset_y) =fV;
       FGET(aAlpha,j+offset_x,i+offset_y) =aA+bA;
    }
}


void plainBlit(IplImage *a, IplImage *b, int offset_y, int offset_x)
{
    // TODO: Add checks for image type and size
 int i,j;
 CvSize aSize = cvGetSize(a);
 CvSize bSize = cvGetSize(b);
 for (i=0; i<bSize.height; i++) {
    for (j=0; j<bSize.width; j++) {
       if (j+offset_x<0 || j+offset_x>=aSize.width || i+offset_y<0 || i+offset_y>=aSize.height ) continue;
       if (a->nChannels == 1)
            {FGET(a,j+offset_x,i+offset_y) =FGET(b,j,i);}
        else if (a->nChannels ==3)
            {
             int dx = j+offset_x; int dy = i+offset_y;
             ((float *)(a->imageData + dy*a->widthStep))[dx*a->nChannels + 0] =
              ((float *)(b->imageData + i*b->widthStep))[j*b->nChannels + 0] ; // B
             ((float *)(a->imageData + dy*a->widthStep))[dx*a->nChannels + 1] =
              ((float *)(b->imageData + i*b->widthStep))[j*b->nChannels + 1] ; // G
             ((float *)(a->imageData + dy*a->widthStep))[dx*a->nChannels + 2] =
              ((float *)(b->imageData + i*b->widthStep))[j*b->nChannels + 2] ; // R
            }
             else {printf("Can't blit this - pic weird number of channels\n"); abort();}

    }}
}

void subpixel_blit(IplImage *a, IplImage *b, double offset_y, double offset_x)
{
    // TODO: Add checks for image type and size
 int i,j;
 CvSize aSize = cvGetSize(a);
 CvSize bSize = cvGetSize(b);
 for (i=0; i<aSize.height; i++)
    for (j=0; j<aSize.width; j++) {
       double x_at_b=j-offset_x;
       double y_at_b=i-offset_y;
       if (x_at_b <0 || x_at_b >= bSize.width
           || y_at_b <0 || y_at_b >= bSize.height) continue;
       FGET(a,j,i) =bilinearInterp(b,x_at_b,y_at_b);
        // TODO: Check boundaries! #SAFETY

    }
}


// Histograms.
void wrapReleaseHist(CvHistogram *hist)
{
 cvReleaseHist(&hist);
}

CvHistogram* calculateHistogram(IplImage *img,int bins)
{
 float st_range[] = {-1,1};
 float *ranges[]  = {st_range};
 int hist_size[] = {bins};
 CvHistogram *result = cvCreateHist(1,hist_size,CV_HIST_ARRAY,ranges,1);
 cvCalcHist(&img,result,0,0);
 return result;
}

void get_histogram(IplImage *img,IplImage *mask
                 ,float a, float b,int isCumulative
                 ,int binCount
                 ,double *values)
{
 int i=0;
 float st_range[] = {a,b};
 float *ranges[]  = {st_range};
 int hist_size[] = {binCount};
 CvHistogram *result = cvCreateHist(1,hist_size,CV_HIST_ARRAY
                                   ,ranges,1);
 cvCalcHist(&img,result,isCumulative,mask);
 for (i=0;i<binCount;++i)
    {
     *values = cvQueryHistValue_1D(result,i); values++;
    }
 cvReleaseHist(&result);
 return;
}


double getHistValue(CvHistogram *h,int bin)
{
 return *cvGetHistValue_1D(h,bin);
}

// Convolutions
IplImage* wrapFilter2D(IplImage *src, int ax,int ay,
                    int w, int h, double *kernel){
int i,j;
IplImage *target = cvCloneImage(src);
CvMat *kernelMat = cvCreateMat(w,h,CV_32FC1);
for(i=0;i<w*h;i++)
  cvSetReal2D(kernelMat,i%w,i/w,kernel[i]);
cvFilter2D(src,target,kernelMat,cvPoint(ay,ax));
cvReleaseMat(&kernelMat);
return target;
}

IplImage* wrapFilter2DImg(IplImage *src
                         ,IplImage *mask
                         ,int ax,int ay)
{
int i,j;
IplImage *target = cvCloneImage(src);
CvSize size = cvGetSize(mask);
CvMat *kernelMat = cvCreateMat(size.width,size.height,CV_32FC1);
for(i=0;i<size.width;i++)
 for(j=0;j<size.height;j++)
  cvSetReal2D(kernelMat,i,j,cvGetReal2D(mask,j,i));
cvFilter2D(src,target,kernelMat,cvPoint(ay,ax));
cvReleaseMat(&kernelMat);
return target;
}

// Connected components

void wrapFloodFill(IplImage *i, int x, int y, double c
                  ,double low, double high,int fixed)
{
 int flag = 8 | (fixed ? CV_FLOODFILL_FIXED_RANGE : 0);
 cvFloodFill(i,cvPoint(x,y),cvRealScalar(c),cvRealScalar(low)
            ,cvRealScalar(high),NULL,flag,NULL);
}

// hough-lines

void wrapProbHoughLines(IplImage *img, double rho, double theta
                       , int threshold, double minLength
                       , double gapLength
                       , int *maxLines
                       , int *xs, int *ys
                       , int *xs1, int *ys1)
{
 IplImage *tmp;
 CvSeq *lines = 0;
 int i;
 CvMemStorage *storage = cvCreateMemStorage(0);

 tmp = ensure8U(img);

 lines = cvHoughLines2(tmp,storage,CV_HOUGH_PROBABILISTIC
                     ,rho,theta,threshold,minLength,gapLength);
 for( i = 0; i < MIN(lines->total,*maxLines); i++ )
        {
            CvPoint* line = (CvPoint*)cvGetSeqElem(lines,i);
            xs[i] = line[0].x; xs1[i] = line[1].x;
            ys[i] = line[0].y; ys1[i] = line[1].y;
        }
 *maxLines = MIN(lines->total,*maxLines);

 cvReleaseImage(&tmp);
 cvReleaseMemStorage(&storage);

}



//@-node:aleator.20050908100314.2:Wrappers
//@+node:aleator.20050908100314.3:Utilities
/* These are utilities that operate on opencv primitives but
  are not really wrappers.. Due to the fact that I seem to
  be incapable to link multiple objects including openCV
  headers this seems to be the next best solution.

  Watch out for name collisions!

*/
//@+node:aleator.20070906153003:Trigonometric operations

void calculateAtan(IplImage *src, IplImage *dst)
{
  CvSize imageSize = cvGetSize(dst);
  double r=0; int i; int j;
  for(j=0; j<imageSize.width; ++j)
    for(i=0; i<imageSize.height; ++i) {
          r = FGET(src,j,i); //// cvGetReal2D(src,j,i);
          FGET(dst,j,i) = atan(r);
          //cvSet2D(dst,j,i,cvScalarAll(atan(r)));
    }
}

void calculateAtan2(IplImage *src1,IplImage *src2, IplImage *dst)
{
  CvSize imageSize = cvGetSize(dst);
  for(int j=0; j<imageSize.width; ++j)
    for(int i=0; i<imageSize.height; ++i) {
          double a = FGET(src1,j,i);
          double b = FGET(src2,j,i);
          FGET(dst,j,i) = atan2(a,b);
    }
}

//@nonl
//@-node:aleator.20070906153003:Trigonometric operations
//@+node:aleator.20051109111547:Pixel accessors
// All these will work only on grayscale.
inline int imax(int x, int y) {return (x>y) ? x:y;}
inline int imin(int x, int y) {return (x<y) ? x:y;}
inline double blurGet2D(IplImage *img,int x, int y)
{
 CvSize size = cvGetSize(img);
 x = imax(0,imin(x,size.width-1));
 y = imax(0,imin(y,size.height-1));

 return cvGetReal2D(img,y,x);
}

//@-node:aleator.20051109111547:Pixel accessors
//@+node:aleator.20070827150608:Haar Filters

// Simple routines for calculating pixelwise
// haar responses

void haarFilter(IplImage *intImg,
                int x1, int y1, int x2, int y2,
                IplImage *target)
{
  int i,j;
  double s = 0;
  double ratio = 1;
  double desArea = (x2-x1)*(y1-y2);
  double area = 0;
  int rx1,rx2,ry1,ry2;
  CvSize imageSize = cvGetSize(target);
  for(i=0; i<imageSize.width; ++i)
    for(j=0; j<imageSize.height; ++j) {
         rx1 = imax(0,imin(i+x1,imageSize.width-1));
         ry1 = imax(0,imin(j+y1,imageSize.height-1));
         rx2 = imax(0,imin(i+x2,imageSize.width-1));
         ry2 = imax(0,imin(j+y2,imageSize.height-1));
         area = (float)((rx2-rx1)*(ry2-ry1));
        // if (area > 0) ratio = fabs(desArea/area);
        // else ratio=1;
         //printf("Ratio(%d,%d) is %lf\n",rx1,ry1,ratio);
         s = blurGet2D(intImg,rx1,ry1)
             -blurGet2D(intImg,rx1,ry2)
             -blurGet2D(intImg,rx2,ry1)
             +blurGet2D(intImg,rx2,ry2);
          cvSet2D(target,j,i,cvScalarAll(s/area));
    }
}

double haar_at(IplImage *intImg,
                int x1, int y1, int w, int h)
{
  int i,j;
  double s = 0;
  s = blurGet2D(intImg,x1,y1)
     -blurGet2D(intImg,x1,y1+h)
     -blurGet2D(intImg,x1+w,y1)
     +blurGet2D(intImg,x1+w,y1+h);
  return s;
}

//@nonl
//@-node:aleator.20070827150608:Haar Filters
//@+node:aleator.20070130144337:Statistics along a line
#define SWAP(a,b) { \
        int c = (a);    \
        (a) = (b);      \
        (b) = c;        \
    }


double average_of_line(int x0, int y0
                     ,int x1, int y1
                     ,IplImage *src) {
     int steep = abs(y1 - y0) > abs(x1 - x0);
     int deltax=0; int deltay=0;
     int error=0;
     int ystep=0;
     int x=0; int y=0;
     float sum=0; int len=0;

     if (steep)   { SWAP(x0, y0); SWAP(x1, y1); }
     if (x0 > x1) { SWAP(x0, x1); SWAP(y0, y1); }
     deltax = x1 - x0;
     deltay = abs(y1 - y0);
     error  = 0;
     y = y0;
     if (y0 < y1) {ystep = 1;} else {ystep = -1;}
     for (x=x0; x<x1; ++x) {
         if (steep) {sum+=blurGet2D(src,y,x);
                     ++len;}
                    // _plot(y,x);}
         else       {sum+=blurGet2D(src,x,y);
                     ++len; }
                    //_plot(x,y);}
         error = error + deltay;
         if (2*error >= deltax) {
             y = y + ystep;
             error = error - deltax; }
         }
         return (sum/len);
}

//@-node:aleator.20070130144337:Statistics along a line
//@+node:aleator.20051130130836:Taking square roots of images

void sqrtImage(IplImage *src,IplImage *dst)
{
int i;int j;
double result;
CvSize size = cvGetSize(src);

for(i=0;i<size.width;++i)
 for(j=0;j<size.height;++j)
    {
     result = cvSqrt(cvGetReal2D(src,j,i));
     cvSetReal2D(dst,j,i,result);
    }
}
//@-node:aleator.20051130130836:Taking square roots of images
//@+node:aleator.20050930104348:Histogram Features
#define HISTOGRAMSIZE 10

double calculateMoment(int i,double arr[], int l)
{
int j=0;
double result = 0;
for(j=0; j<l; j++)
  {  result += pow((j*1.0)/HISTOGRAMSIZE,i)*arr[j]; }
return result;
}

double calculateAbsCentralMoment(int i,double arr[], int l)
{
int j=0;
double m1 = calculateMoment(1,arr,l);
double result = 0;
for(j=0; j<l; j++)
 {
  result += pow(fabs(((j*1.0)/HISTOGRAMSIZE)-m1),i)*arr[j];}
return result;
}

double calculateCentralMoment(int i,double arr[], int l)
{
int j=0;
double m1 = calculateMoment(1,arr, l);
double result = 0;
for(j=0; j<l; j++)
 {
    result += pow(((j*1.0)/HISTOGRAMSIZE)-m1,i)*arr[j];

 }
return result;
}
//@+node:aleator.20050930104348.1:Central Moments

IplImage* getNthCentralMoment(IplImage *src,int n, int w, int h)
{

CvSize size = cvGetSize(src);
int iw = size.width-w;
int ih = size.height-h;
IplImage *target = wrapCreateImage32F(iw,ih,1);
int x = 0;
int y = 0;
int i = 0;
int j = 0;
double histogram[HISTOGRAMSIZE];
for (x=0; x<ih; x++)
 for (y=0; y<iw; y++)
 {
memset(histogram,0,HISTOGRAMSIZE*sizeof(double));
double result = 0;

// Calculate the local histogram
for (i=0; i<w; i++)
 for (j=0; j<h; j++)
    {
     int slot = HISTOGRAMSIZE*cvGet2D(src,x+i,y+j).val[0];
     histogram[slot] += 1.0/(w*h*1.0);
    }


result = calculateCentralMoment(n,histogram,HISTOGRAMSIZE);
cvSet2D(target,x,y,cvScalarAll(result));
 }

return target;
}

IplImage* getNthAbsCentralMoment(IplImage *src,int n, int w, int h)
{

CvSize size = cvGetSize(src);
int iw = size.width-w;
int ih = size.height-h;
IplImage *target = wrapCreateImage32F(iw,ih,1);
int x = 0;
int y = 0;
int i = 0;
int j = 0;
double histogram[HISTOGRAMSIZE];
for (x=0; x<ih; x++)
 for (y=0; y<iw; y++)
 {
memset(histogram,0,HISTOGRAMSIZE*sizeof(double));
double result = 0;

// Calculate the local histogram
for (i=0; i<w; i++)
 for (j=0; j<h; j++)
    {
     int slot = HISTOGRAMSIZE*cvGet2D(src,x+i,y+j).val[0];
     histogram[slot] += 1.0/(w*h*1.0);
    }


result = calculateAbsCentralMoment(n,histogram,HISTOGRAMSIZE);
cvSet2D(target,x,y,cvScalarAll(result));
 }

return target;
}

IplImage* getNthMoment(IplImage *src,int n, int w, int h)
{

CvSize size = cvGetSize(src);
int iw = size.width-w;
int ih = size.height-h;
IplImage *target = wrapCreateImage32F(iw,ih,1);
int x = 0;
int y = 0;
int i = 0;
int j = 0;
double histogram[HISTOGRAMSIZE];
for (x=0; x<ih; x++)
 for (y=0; y<iw; y++)
 {
memset(histogram,0,HISTOGRAMSIZE*sizeof(double));
double result = 0;

// Calculate the local histogram
for (i=0; i<w; i++)
 for (j=0; j<h; j++)
    {
     int slot = HISTOGRAMSIZE*cvGet2D(src,x+i,y+j).val[0];
     histogram[slot] += 1.0/(w*h*1.0);
    }

result = calculateMoment(n,histogram,HISTOGRAMSIZE);
cvSet2D(target,x,y,cvScalarAll(result));
 }

return target;
}

//@-node:aleator.20050930104348.1:Central Moments
//@+node:aleator.20051103110155:SMAB

// Perform second moment adaptive binarization for a single pixel `x`
// using given histogram.
double max(double x,double y) {if (x<y) return y; else return x;}
double min(double x,double y) {if (x>y) return y; else return x;}
int SMABx(double x, CvHistogram *h,int binCount,double t)
{
 int binnedX;  double leftSM=0;
 double rightSM=0;
 int i=0;
 binnedX = round(min(1,max(x,0))*(binCount-1));

 // Calculate left second moment:
 for(i=0; i<binnedX; i++)
  { leftSM += pow(x - ((1.0*i)/(1.0*binCount)),2) * getHistValue(h,i); }
 for(i=binnedX; i<binCount; i++)
  { rightSM += pow(x - ((1.0*i)/(1.0*binCount)),2) * getHistValue(h,i); }
 return (leftSM - (rightSM * t));
}

// Perform SMAB for image
void smb(IplImage *image,double t)
{
int i;int j;
double result;
CvSize size = cvGetSize(image);
CvHistogram *h = calculateHistogram(image,255);
for(i=0;i<size.width;++i)
 for(j=0;j<size.height;++j)
 {
     result = SMABx(cvGet2D(image,j,i).val[0],h,255,t);
     cvSet2D(image,j,i,cvScalarAll(result));
 }
}

void smab(IplImage *image,int w, int h,double t)
{
int i;int j;
int wi;int wj;
double result;
CvHistogram *histogram;
CvRect roi;
CvSize size = cvGetSize(image);
roi.width = w;
roi.height = h;

for(i=0;i<size.width;++i)
 for(j=0;j<size.height;++j)
 {
     roi.x = i-(w/2);
     roi.y = j-(h/2);
     cvSetImageROI(image,roi);
     histogram = calculateHistogram(image,50);
     cvResetImageROI(image);
     result = SMABx(cvGetReal2D(image,j,i),histogram,50,t);
     cvReleaseHist(&histogram);
     cvSet2D(image,j,i,cvScalarAll(result));
 }
}
//@-node:aleator.20051103110155:SMAB
//@+node:aleator.20051108093248:Skewness

//@-node:aleator.20051108093248:Skewness
//@-node:aleator.20050930104348:Histogram Features
//@+node:aleator.20050926095227:Susan
/*
 Susan (Smallest Univalue Segmenting Nucleus) is
 family of image processing methods, including
 edge preserving noise reduction.
*/
//@+node:aleator.20050926095227.1:Susan Smoothing Function

/*
 Calculate susan smoothing for `src` around `x`,`y` coordinates.
 `t` determines brightness treshold and sigma controls scale of
 spatial smoothing. `w` and `h` determine window size.
*/

double calcSusanSmooth(IplImage* src, int x, int y
                      ,double t,double sigma,int w, int h)
{

int i = 0;
int j = 0;

long double numerator = 0;
long double denominator = 0;
for (i = 0; i<w; i++)
 for (j = 0; j<h; j++)
    {
    if (i==w/2 && j==h/2) continue;
    double r2 = i*i+j*j;
    double expFrac = (cvGet2D(src,x+i,y+j).val[0]
                     - cvGet2D(src,x,y).val[0]);
    expFrac *= expFrac;

    double exponential = exp(  (-r2/(2*sigma*sigma)) - (expFrac/(t*t))  );

    numerator   += cvGet2D(src,x+i,y+j).val[0] * exponential;
    denominator += exponential;
    }
return numerator/denominator;
}
//@-node:aleator.20050926095227.1:Susan Smoothing Function
//@+node:aleator.20050926100856:Susan Smoothing

IplImage* susanSmooth(IplImage *src, int w, int h
                     ,double t, double sigma)

{

CvSize size = cvGetSize(src);
int iw = size.width-w;
int ih = size.height-h;
IplImage *target = wrapCreateImage32F(iw,ih,1);
int x = 0;
int y = 0;
double result = 0;


for (x=0; x<iw; x++)
 for (y=0; y<ih; y++)
 {
  result = calcSusanSmooth(src,y,x,t,sigma,h,w);
  cvSet2D(target,y,x,cvScalarAll(result));
 }
return target;
}
//@-node:aleator.20050926100856:Susan Smoothing
//@+node:aleator.20050927083244:Susan Edge
/*
 Susan Edge Detector.
*/

// susan threshold function
inline double susanC(double r, double r0,double t)
{
 return exp(-((r-r0)/t));
}

inline double susanValue(IplImage *src,int x, int y
                        ,int w, int h, double t)
{
int i; int j;
double geometricTreshold = (3*(w*h)) / 4;
double sum = 0;

for (i = 0; i<w; i++)
 for (j = 0; j<h; j++)
    {
     sum += susanC(cvGet2D(src,x+i,y+j).val[0]
                  ,cvGet2D(src,x,y).val[0]
                  ,t);
    }
if (sum < geometricTreshold)
    return geometricTreshold - sum;
else return 0;
}

IplImage* susanEdge(IplImage *src,int w,int h,double t)
{
CvSize size = cvGetSize(src);
int iw = size.width-w;
int ih = size.height-h;
IplImage *target = wrapCreateImage32F(iw,ih,1);
int x = 0;
int y = 0;
double result = 0;


for (x=0; x<iw; x++)
 for (y=0; y<ih; y++)
 {
  result = susanValue(src,y,x,h,w,t);
  cvSet2D(target,y,x,cvScalarAll(result));
 }
return target;

}
//@-node:aleator.20050927083244:Susan Edge
//@-node:aleator.20050926095227:Susan
//@+node:aleator.20050908112008:Gabors
/*
 Gabor functions are modulated gaussians which bear some resemblance
 to human visual cortex neurons. */
//@+node:aleator.20050908104238:gabor function in C
/* This function calculates value of simple gabor function
  at given x,y coordinates. Parameters for the gabor are:

  stdX  - standard deviation in oscillation direction
  stdY  - standard deviation tangential to stdX
  theta - angle (in radians) of the gabor
  phase - phase of the gabor


*/
double calcGabor(double x, double y
                ,double stdX, double stdY
                ,double theta, double phase
                ,double cycles)
{
 double xth = x*cos(theta)  - y*sin(theta);
 double yth = x*sin(theta)  + y*cos(theta);
 double oscillationPart = cos(2*M_PI*xth/cycles+phase);
 double gaussianPart    = exp((-0.5*xth*xth)/(stdX*stdX))
                         *exp((-0.5*yth*yth)/(stdY*stdY));

 return gaussianPart * oscillationPart;
}

double calc1DGabor(double x
                ,double sigma
                ,double phase, double center
                ,double cycles)
{
 double oscillationPart = cos(2*M_PI*(x-center)/cycles+phase);
 double gaussianPart    = exp((-0.5*(x-center)*(x-center))
                              /(sigma*sigma));

 return gaussianPart * oscillationPart;
}


//@-node:aleator.20050908104238:gabor function in C
//@+node:aleator.20050908112116:rendering gabors to arrays
void renderGabor(CvArr *dst,int width, int height
                ,double dx, double dy
                ,double stdX, double stdY
                ,double theta, double phase
                ,double cycles)

{
 int i,j;
 int mx = width/2;
 int my = height/2;
 for (i=0; i<width; i++)
  for (j=0; j<height; j++) // TODO: This might be a bug
   cvSet2D(dst,i,j,cvScalarAll(calcGabor(i-dx,j-dy,stdX,stdY
                                        ,theta,phase,cycles)));
}

void render_gaussian(IplImage *dst
                   ,double stdX, double stdY)

{
 int i,j;
 double distX;
 double distY;
 CvSize size = cvGetSize(dst);
 double centerX = size.width/2.0;
 double centerY = size.height/2.0;
 for (i=0; i<size.width-1; i++)
  for (j=0; j<size.height-1; j++)
   { distX = ((centerX-i*1.0)*(centerX-i*1.0)) / (2*stdX*stdX);
     distY = ((centerY-j*1.0)*(centerY-j*1.0)) / (2*stdY*stdY);
  //   printf("w: %d, h: %d, i: %d, j:%d,dx: %e,dy: %e,exp:%e\n",size.width,size.height,i,j,distX,distY,exp(-distX-distY));
     fflush(stdout);
     cvSet2D(dst,j,i,cvScalarAll( exp(-distX-distY) ));
  }
}


void renderRadialGabor(CvArr *dst,int width, int height
                ,double sigma
                ,double phase, double center
                ,double cycles)

{
 int i,j;
 int mx = width/2;
 int my = height/2;
 double rad = 0;
 for (i=0; i<width; i++)
  for (j=0; j<width; j++)
   {
   rad = sqrt((i-mx)*(i-mx)+(j-my)*(j-my));
   cvSet2D(dst,i,j,cvScalarAll(calc1DGabor(rad,sigma
                                          ,phase,center,cycles)));
   }
}

void wrapMinMaxLoc(const IplImage* target, int* minx, int* miny, int* maxx, int* maxy, double *minval, double *maxval)
{
	CvPoint maxPoint;
	CvPoint minPoint;
	cvMinMaxLoc(target,minval,maxval,&minPoint, &maxPoint, NULL);
    *maxx = maxPoint.x ;
    *maxy = maxPoint.y ;
    *minx = minPoint.x ;
    *miny = minPoint.y ;
}

void simpleMatchTemplate(const IplImage* target, const IplImage* template, int* x, int* y, double *val,int type)
{
	int rw = cvGetSize(target).width-cvGetSize(template).width+1;
	int rh = cvGetSize(target).height-cvGetSize(template).height+1;
	IplImage* result = wrapCreateImage32F(rw,rh,1);
	cvMatchTemplate(target,template,result,type);
	double min,max;
	CvPoint maxPoint;
	maxPoint.x=-1;
	maxPoint.y=-1;
	min =0;
	max =0;
	cvMinMaxLoc(result,&min,&max,NULL, &maxPoint, NULL);
	*x = maxPoint.x;+rw/2;
	*y = maxPoint.y;+rh/2;
	*val = max;
	cvReleaseImage(&result);
	}

IplImage* templateImage(const IplImage* target, const IplImage* template)
{
	int rw = cvGetSize(target).width-cvGetSize(template).width+1;
	int rh = cvGetSize(target).height-cvGetSize(template).height+1;
	IplImage* result = wrapCreateImage32F(rw,rh,1);
	cvMatchTemplate(target,template,result,CV_TM_CCORR);
	return result;
	}


//@-node:aleator.20050908112116:rendering gabors to arrays
//@+node:aleator.20050908101148:gabor filter using cvFilter2D
void gaborFilter(const CvArr *src, CvArr *dst
                ,int maskWidth, int maskHeight
                ,double stdX, double stdY
                ,double theta,double phase
                ,double cycles)

{
 int mx = maskWidth/2;
 int my = maskHeight/2;
 CvMat *kernel = cvCreateMat(maskWidth,maskHeight,CV_32F);
 renderGabor(kernel,maskWidth,maskHeight,mx,my,stdX,stdY
             ,theta,phase,cycles);
 cvFilter2D(src,dst,kernel,cvPoint(-1,-1));
}

void radialGaborFilter(const CvArr *src, CvArr *dst
                ,int maskWidth, int maskHeight
                ,double sigma
                ,double phase,double center
                ,double cycles)

{
 CvMat *kernel = cvCreateMat(maskWidth,maskHeight,CV_32F);
 renderRadialGabor(kernel,maskWidth,maskHeight,sigma
               ,phase,center,cycles);
 cvFilter2D(src,dst,kernel,cvPoint(-1,-1));
}


//@-node:aleator.20050908101148:gabor filter using cvFilter2D
//@-node:aleator.20050908112008:Gabors
//@+node:aleator.20070511142414:Adaboost Learning
// This doesn't really work properly yet.. No
// time to do anything about it really.
//@nonl
//@+node:aleator.20070511142414.1:Fitness
// In the following the class is encoded bit
// differently. 0 is one class and +1 is another.
// if target is gray it is considered null area.

double adaFitness1(IplImage *target
                 ,IplImage *weigths
                 ,IplImage *test)
{
CvSize size = cvGetSize(target);
int i,j;
int width  = size.width;
int height = size.height;
double result=0;
double tij=0,wij=0,testij=0,rij=0;
for (i=0; i<width; i++)
 for (j=0; j<height; j++)
 {
   tij = cvGetReal2D(target,j,i);
   wij = cvGetReal2D(weigths,j,i);
   testij = cvGetReal2D(test,j,i);
   rij=wij;
   if (((tij < 0.2) && (testij < 0.2)) || ((tij > 0.8) && (testij > 0.8)))
    {rij=0;}
   result += rij;
 }

return result;
}
//@-node:aleator.20070511142414.1:Fitness
//@+node:aleator.20070511145251:Updating distributions

// This function is used to update distribution.
// Notice that alpha_t must be calculated separately
// and normalization is not applied.
IplImage* adaUpdateDistrImage(IplImage *target
                          ,IplImage *weigths
                          ,IplImage *test
                          ,double at)
{
CvSize size = cvGetSize(target);
int i,j;
int width  = size.width;
int height = size.height;
double tij=0,wij=0,testij=0,rij=0;
IplImage *result = wrapCreateImage32F(width,height,1);
for (i=0; i<width; i++)
 for (j=0; j<height; j++)
 {
   tij = cvGetReal2D(target,j,i);
   wij = cvGetReal2D(weigths,j,i);
   testij = cvGetReal2D(test,j,i);
   if ( (tij>0.2) && (tij<0.8) ) continue;
   if (((tij < 0.2) && (testij < 0.2))
      || ((tij > 0.8) && (testij > 0.8)))
    {rij = wij*exp(-at);
     cvSetReal2D(result,j,i,rij); }
   else
    {rij = wij*exp(at);
     cvSetReal2D(result,j,i,rij); }
 }

return result;
}

//@-node:aleator.20070511145251:Updating distributions
//@-node:aleator.20070511142414:Adaboost Learning
//@+node:aleator.20051207074905:LBP

void get_weighted_histogram(IplImage *src, IplImage *weights,
                       double start, double end,
                       int bins, double *histo)
{
  int i,j,index;
  double value,weight;
  CvSize imageSize = cvGetSize(src);
  for(i=0;i<bins;++i) histo[i]=0;
  for(i=0; i<imageSize.width-1; ++i)
    for(j=0; j<imageSize.height-1; ++j)
        {
         value = cvGetReal2D(src,j,i);
         weight = cvGetReal2D(weights,j,i);
         index = floor(bins*((value - start)/(end - start)));
         //printf("Adding weight %e to index %d\n",weight,index);
         if (index<0 || index>=bins) continue;
         histo[index] += weight;
        }

}

// Calculate local binary pattern for image.
// LBP is outgoing array
// of (preallocated) 256 bytes that are assumed to be 0.
void localBinaryPattern(IplImage *src, int *LBP)
{
  int i,j;
  int pattern = 0;
  double center = 0;
  CvSize imageSize = cvGetSize(src);
  for(i=1; i<imageSize.width-1; ++i)
    for(j=1; j<imageSize.height-1; ++j)
        {
         center = cvGetReal2D(src,j,i);

         pattern += (blurGet2D(src,i-1,j-1) > center) *1;
         pattern += (blurGet2D(src,i,j-1)   > center) *2;
         pattern += (blurGet2D(src,i+1,j-1) > center) *4;

         pattern += (blurGet2D(src,i-1,j)   > center) *8;
         pattern += (blurGet2D(src,i+1,j)   > center) *16;

         pattern += (blurGet2D(src,i-1,j+1) > center) *32;
         pattern += (blurGet2D(src,i,j+1)   > center) *64;
         pattern += (blurGet2D(src,i+1,j+1) > center) *128;
         LBP[pattern]++;
         pattern = 0;
        }
}


void localBinaryPattern3(IplImage *src, int *LBP)
{
  int i,j;
  int pattern = 0;
  double center = 0;
  CvSize imageSize = cvGetSize(src);
  for(i=1; i<imageSize.width-1; ++i)
    for(j=1; j<imageSize.height-1; ++j)
        {
         center = cvGetReal2D(src,j,i);

         pattern += (blurGet2D(src,i-2,j-2) > center) *1;
         pattern += (blurGet2D(src,i,j-3)   > center) *2;
         pattern += (blurGet2D(src,i+2,j-2) > center) *4;

         pattern += (blurGet2D(src,i-3,j)   > center) *8;
         pattern += (blurGet2D(src,i+3,j)   > center) *16;

         pattern += (blurGet2D(src,i-2,j+2) > center) *32;
         pattern += (blurGet2D(src,i,j+3)   > center) *64;
         pattern += (blurGet2D(src,i+2,j+2) > center) *128;
         LBP[pattern]++;
         pattern = 0;
        }
}
void localBinaryPattern5(IplImage *src, int *LBP)
{
  int i,j;
  int pattern = 0;
  double center = 0;
  CvSize imageSize = cvGetSize(src);
  for(i=1; i<imageSize.width-1; ++i)
    for(j=1; j<imageSize.height-1; ++j)
        {
         center = cvGetReal2D(src,j,i);

         pattern += (blurGet2D(src,i-4,j-4) > center) *1;
         pattern += (blurGet2D(src,i,j-5)   > center) *2;
         pattern += (blurGet2D(src,i+4,j-4) > center) *4;

         pattern += (blurGet2D(src,i-5,j)   > center) *8;
         pattern += (blurGet2D(src,i+5,j)   > center) *16;

         pattern += (blurGet2D(src,i-4,j+4) > center) *32;
         pattern += (blurGet2D(src,i,j+5)   > center) *64;
         pattern += (blurGet2D(src,i+4,j+4) > center) *128;
         LBP[pattern]++;
         pattern = 0;
        }
}

void weighted_localBinaryPattern(IplImage *src,int offsetX,int offsetXY
                                , IplImage* weights, double *LBP)
{
  int i,j;
  int pattern = 0;
  double center = 0;
  double weight = 0;
  CvSize imageSize = cvGetSize(src);
  for(i=1; i<imageSize.width-1; ++i)
    for(j=1; j<imageSize.height-1; ++j)
        {
         center = cvGetReal2D(src,j,i);
         weight = cvGetReal2D(weights,j,i);

         pattern += (blurGet2D(src,i-offsetXY,j-offsetXY) > center) *1;
         pattern += (blurGet2D(src,i,j-offsetX)   > center) *2;
         pattern += (blurGet2D(src,i+offsetXY,j-offsetXY) > center) *4;

         pattern += (blurGet2D(src,i-offsetX,j)   > center) *8;
         pattern += (blurGet2D(src,i+offsetX,j)   > center) *16;

         pattern += (blurGet2D(src,i-offsetXY,j+offsetXY) > center) *32;
         pattern += (blurGet2D(src,i,j+offsetX)   > center) *64;
         pattern += (blurGet2D(src,i+offsetXY,j+offsetXY) > center) *128;
         LBP[pattern] += weight;
         pattern = 0;
        }
}


void localHorizontalBinaryPattern(IplImage *src, int *LBP)
{
  int i,j;
  int pattern = 0;
  double center = 0;
  CvSize imageSize = cvGetSize(src);
  for(i=0; i<imageSize.width-1; ++i)
    for(j=0; j<imageSize.height-1; ++j)
        {
         center = cvGetReal2D(src,j,i);

         pattern += (blurGet2D(src,i-4,j) > center) *1;
         pattern += (blurGet2D(src,i-3,j) > center) *2;
         pattern += (blurGet2D(src,i-2,j) > center) *4;
         pattern += (blurGet2D(src,i-1,j) > center) *8;
         pattern += (blurGet2D(src,i+1,j) > center) *16;
         pattern += (blurGet2D(src,i+2,j) > center) *32;
         pattern += (blurGet2D(src,i+3,j) > center) *64;
         pattern += (blurGet2D(src,i+4,j) > center) *128;
         LBP[pattern]++;
         pattern = 0;
        }
}

void localVerticalBinaryPattern(IplImage *src, int *LBP)
{
  int i,j;
  int pattern = 0;
  double center = 0;
  CvSize imageSize = cvGetSize(src);
  for(i=0; i<imageSize.width-1; ++i)
    for(j=0; j<imageSize.height-1; ++j)
        {
         center = cvGetReal2D(src,j,i);

         pattern += (blurGet2D(src,i,j-4) > center) *1;
         pattern += (blurGet2D(src,i,j-3) > center) *2;
         pattern += (blurGet2D(src,i,j-2) > center) *4;
         pattern += (blurGet2D(src,i,j-1) > center) *8;
         pattern += (blurGet2D(src,i,j+1) > center) *16;
         pattern += (blurGet2D(src,i,j+2) > center) *32;
         pattern += (blurGet2D(src,i,j+3) > center) *64;
         pattern += (blurGet2D(src,i,j+4) > center) *128;
         LBP[pattern]++;
         pattern = 0;
        }
}


//@-node:aleator.20051207074905:LBP
//@+node:aleator.20051109102750:Selective Average
// Assuming grayscale image calculate local selective average of point x y
inline double calcSelectiveAvg(IplImage *img,double t
                                   ,int x, int y
                                   ,int wwidth, int wheight)
{
int i,j;
double accum=0;
double count=0;
double centerValue; double processed=0;
CvSize size = cvGetSize(img);
centerValue = blurGet2D(img,x,y);

for (i=-wwidth; i<wwidth;++i)
 for (j=-wheight; j<wheight;++j)
  {
   if (  x+i<0 || x+i>=size.width
      || y+j<0 || y+j>=size.height)
      continue;

   processed = blurGet2D(img,x+i,y+j);
   if (fabs(processed-centerValue)<t)
        {accum+=processed;++count;}
  }
return accum/count;
}


IplImage* selectiveAvgFilter(IplImage *src,double t
                            ,int wwidth, int wheight)
{
CvSize size = cvGetSize(src);
int i,j;
int width  = size.width;
int height = size.height;
double result;

IplImage *target = wrapCreateImage32F(width,height,1);
for (i=0; i<width; i++)
 for (j=0; j<height; j++)
 {
  result = calcSelectiveAvg(src,t,i,j,wwidth,wheight);
  cvSetReal2D(target,j,i,result);
 }

return target;
}

//@-node:aleator.20051109102750:Selective Average
//@+node:aleator.20060104154125:AcquireImage

// Copy array into single channel iplImage
IplImage *acquireImageSlow(int w, int h, double *d)
{
 IplImage *img;
 int i,j;
 img = cvCreateImage(cvSize(w,h), IPL_DEPTH_32F,1);
 for (i=0; i<h; i++) {
   for (j=0; j<w; j++) {
         //printf("(%d,%d) => %d is %f\n",j,i,(i+j*h),d[i+j*h]);
         FGET(img,j,i) = d[j*h+i];
         }
    }
 return img;
}

IplImage *acquireImageSlowF(int w, int h, float *d)
{
 IplImage *img;
 int i,j;
 img = cvCreateImage(cvSize(w,h), IPL_DEPTH_32F,1);
 for (i=0; i<h; i++) {
   for (j=0; j<w; j++) {
         //printf("(%d,%d) => %d is %f\n",j,i,(i+j*h),d[i+j*h]);
         FGET(img,j,i) = d[j*h+i];
         }
    }
 return img;
}

#define BLUE = 0
#define GREEN = 1
#define RED = 2


IplImage *acquireImageSlow8U(int w, int h, uint8_t *d)
{
 IplImage *img;
 int i,j;
 img = cvCreateImage(cvSize(w,h), IPL_DEPTH_8U,1);
 for (i=0; i<h; i++) {
   for (j=0; j<w; j++) {
         UGETC(img,0,j,i) = *d; d++;
         }
    }
 return img;
}

IplImage *acquireImageSlow8URGB(int w, int h, uint8_t *d)
{
 IplImage *img;
 int i,j;
 img = cvCreateImage(cvSize(w,h), IPL_DEPTH_8U,3);
 for (i=0; i<h; i++) {
   for (j=0; j<w; j++) {
         UGETC(img,0,j,i) = *d; d++;
         UGETC(img,1,j,i) = *d; d++;
         UGETC(img,2,j,i) = *d; d++;
         }
    }
 return img;
}

IplImage *acquireImageSlow8UBGR(int w, int h, uint8_t *d)
{
 IplImage *img;
 int i,j;
 img = cvCreateImage(cvSize(w,h), IPL_DEPTH_8U,3);
 for (i=0; i<h; i++) {
   for (j=0; j<w; j++) {
         UGETC(img,2,j,i) = *d; d++;
         UGETC(img,1,j,i) = *d; d++;
         UGETC(img,0,j,i) = *d; d++;
         }
    }
 return img;
}

IplImage *acquireImageSlowComplex(int w, int h, complex double *d)
{
 IplImage *img;
 int i,j;
 img = cvCreateImage(cvSize(w,h), IPL_DEPTH_32F,1);
 for (i=0; i<h; i++) {
   for (j=0; j<w; j++) {
         FGET(img,j,i) = (float)(creal(d[j*h+i]));
         }
    }
 return img;
}

void exportImageSlowComplex(IplImage *img, complex double *d)
{
 int i,j;
 CvSize s= cvGetSize(img);
 for (i=0; i<s.height; i++) {
   for (j=0; j<s.width; j++) {
         d[j*s.height+i] = (complex float)(FGET(img,j,i) + 0*I);
         }
    }
}

void exportImageSlow(IplImage *img, double *d)
{
 int i,j;
 CvSize s= cvGetSize(img);
 for (i=0; i<s.height; i++) {
   for (j=0; j<s.width; j++) {
         d[j*s.height+i] = FGET(img,j,i);
         }
    }
}
void exportImageSlowF(IplImage *img, float *d)
{
 int i,j;
 CvSize s= cvGetSize(img);
 for (i=0; i<s.height; i++) {
   for (j=0; j<s.width; j++) {
         d[j*s.height+i] = FGET(img,j,i);
         }
    }
}
//@-node:aleator.20060104154125:AcquireImage
//@-node:aleator.20050908100314.3:Utilities
//@+node:aleator.20060413093124:Connected components
//@+node:aleator.20071016114634:Contours


void free_found_contours(FoundContours *f)
{
 cvReleaseMemStorage(&(f->storage));
 free(f);

}

int reset_contour(FoundContours *f)
{
 f->contour = f->start;
}

int cur_contour_size(FoundContours *f)
{
 return f->contour->total;
}

double contour_area(FoundContours *f)
{
 return cvContourArea(f->contour,CV_WHOLE_SEQ,0);
}

CvMoments* contour_moments(FoundContours *f)
{
 CvMoments* moments = (CvMoments*) malloc(sizeof(CvMoments));
 cvMoments(f->contour,moments,0);
 return moments;
}

double contour_perimeter(FoundContours *f)
{
 return cvContourPerimeter(f->contour);
}

int more_contours(FoundContours *f)
{
 if (f->contour != 0)
  {return 1;}
  {return 0;} // no more contours
}

int next_contour(FoundContours *f)
{
 if (f->contour != 0)
  {f->contour = f->contour->h_next; return 1;}
  {return 0;} // no more contours
}

void contour_points(FoundContours *f, int *xs, int *ys)
{
 if (f->contour==0) {printf("unavailable contour\n"); exit(1);}

 CvPoint *pt=0;
 int total,i=0;
 total = f->contour->total;
 for (i=0; i<total;i++)
  {
   pt = (CvPoint*)cvGetSeqElem(f->contour,i);
   if (pt==0) {printf("point out of contour\n"); exit(1);}
   xs[i] = pt->x;
   ys[i] = pt->y;
  }

}

void print_contour(FoundContours *fc)
{
  int i=0;
  CvPoint *pt=0;
   for (i=0; i<fc->contour->total;++i)
    {
     pt = (CvPoint*)cvGetSeqElem(fc->contour,i);
     printf("PT=%d,%d\n",pt->x,pt->y);
    }
}

/* void draw_contour(FoundContours *fc,double color
                 , IplImage *img, IplImage *dst)
{
 cvDrawContours( dst, fc->start, color, color, -1, 0, 8
               , cvPoint(0,0));
} */


FoundContours* get_contours(IplImage *src1)
{
 CvSize size;
 IplImage *src = ensure8U(src1);
 //int dstDepth = IPL_DEPTH_8U;
 //size = cvGetSize(src1);
 //src = cvCreateImage(size,dstDepth,1);
 //cvCopy(src1,src,NULL);


 CvPoint* pt=0;
 int i=0;

 CvMemStorage *storage=0;
 CvSeq *contour=0;
 FoundContours* result = (FoundContours*)malloc(sizeof(FoundContours));
 storage = cvCreateMemStorage(0);

 cvFindContours( src,storage
               , &contour
               , sizeof(CvContour)
               ,CV_RETR_EXTERNAL
            //,CV_RETR_CCOMP
               ,CV_CHAIN_APPROX_NONE
               ,cvPoint(0,0) );

// result->contour = cvApproxPoly( result->contour, sizeof(CvContour)
//                                , result->storage, CV_POLY_APPROX_DP
//                                , 3, 1 );
 result->start = contour;
 result->contour = contour;
 result->storage = storage;

 cvReleaseImage(&src);
 return result;

 }
//@-node:aleator.20071016114634:Contours
//@+node:aleator.20070814123008:moments
CvMoments* getMoments(IplImage *src, int isBinary)
{
 CvMoments* moments = (CvMoments*) malloc(sizeof(CvMoments));
 cvMoments( src, moments, isBinary);
 return moments;
}

void freeCvMoments(CvMoments *x)
{
 free(x);
}


void getHuMoments(CvMoments *src,double *hu)
{
 CvHuMoments* hu_moments = (CvHuMoments*) malloc(sizeof(CvHuMoments));
 cvGetHuMoments( src, hu_moments);
 *hu = hu_moments->hu1; ++hu;
 *hu = hu_moments->hu2; ++hu;
 *hu = hu_moments->hu3; ++hu;
 *hu = hu_moments->hu4; ++hu;
 *hu = hu_moments->hu5; ++hu;
 *hu = hu_moments->hu6; ++hu;
 *hu = hu_moments->hu7;
 return;
}

void freeCvHuMoments(CvHuMoments *x)
{
 free(x);
}
//@-node:aleator.20070814123008:moments
//@+node:aleator.20060727102514:blobCount
int blobCount(IplImage *src)
{
    int contourCount=0;
    CvMemStorage* storage = cvCreateMemStorage(0);
    CvSeq* contour = 0;

    contourCount = cvFindContours( src, storage, &contour, sizeof(CvContour), CV_RETR_EXTERNAL, CV_CHAIN_APPROX_SIMPLE, cvPoint(0,0) );

    cvReleaseMemStorage(&storage);
    return contourCount;
}

//@-node:aleator.20060727102514:blobCount
//@+node:aleator.20060413093124.1:sizeFilter
IplImage* sizeFilter(IplImage *src, double minSize, double maxSize)
{
    IplImage* dst = cvCreateImage( cvGetSize(src), IPL_DEPTH_8U, 1 );
    CvMemStorage* storage = cvCreateMemStorage(0);
    CvSeq* contour = 0;

    cvFindContours( src, storage, &contour, sizeof(CvContour), CV_RETR_EXTERNAL, CV_CHAIN_APPROX_SIMPLE, cvPoint(0,0) );
    cvZero( dst );

    for( ; contour != 0; contour = contour->h_next )
    {
        double area=fabs(cvContourArea(contour,CV_WHOLE_SEQ,0));
        if (area <=minSize || area >= maxSize) continue;
        CvScalar color = cvScalar(255,255,255,255);
        cvDrawContours( dst, contour, color, color, -1, CV_FILLED, 8,
            cvPoint(0,0));
    }
    cvReleaseMemStorage(&storage);
    return dst;
}
//@-node:aleator.20060413093124.1:sizeFilter
//@-node:aleator.20060413093124:Connected components
//@+node:aleator.20050908101148.1:function for rotating image
IplImage* rotateImage(IplImage* src,double scale,double angle)
{

  IplImage* dst = cvCloneImage( src );
  angle = angle * (180 / CV_PI);
  int w = src->width;
  int h = src->height;
  CvMat *M;
  M = cvCreateMat(2,3,CV_32FC1);
  CvPoint2D32f center = cvPoint2D32f(w/2.0,h/2.0);
  CvMat *N = cv2DRotationMatrix(center,angle,scale,M);
  cvWarpAffine( src, dst, N, CV_INTER_LINEAR+CV_WARP_FILL_OUTLIERS
              , cvScalarAll(0));
  return dst;
  cvReleaseMat(&M);
}


inline double cubicInterpolate(
   double y0,double y1,
   double y2,double y3,
   double mu)
{
   double a0,a1,a2,a3,mu2;

   mu2 = mu*mu;
   a0 = y3 - y2 - y0 + y1;
   a1 = y0 - y1 - a0;
   a2 = y2 - y0;
   a3 = y1;
   return(a0*mu*mu2+a1*mu2+a2*mu+a3);
}

double bilinearInterp(IplImage *tex, double u, double v) {
   CvSize s = cvGetSize(tex);
   int x = floor(u);
   int y = floor(v);
   double u_ratio = u - x;
   double v_ratio = v - y;
   double u_opposite = 1 - u_ratio;
   double v_opposite = 1 - v_ratio;
   double result = ((x+1 >= s.width) || (y+1 >= s.height)) ? FGET(tex,x,y) :
                   (FGET(tex,x,y)   * u_opposite  + FGET(tex,x+1,y)   * u_ratio) * v_opposite +
                   (FGET(tex,x,y+1) * u_opposite  + FGET(tex,x+1,y+1) * u_ratio) * v_ratio;
   return result;
 }

// TODO: Check boundaries! #SAFETY
double bicubicInterp(IplImage *tex, double u, double v) {
   CvSize s = cvGetSize(tex);
   int x = floor(u);
   int y = floor(v);
   double u_ratio = u - x;
   double v_ratio = v - y;
   double p[4][4] = {FGET(tex,x-1,y-1),  FGET(tex,x,y-1),  FGET(tex,x+1,y-1),  FGET(tex,x+2,y-1),
                     FGET(tex,x-1,y),    FGET(tex,x,y),    FGET(tex,x+1,y),    FGET(tex,x+2,y),
                     FGET(tex,x-1,y+1),  FGET(tex,x,y+1),  FGET(tex,x+1,y+1),  FGET(tex,x+2,y+1),
                     FGET(tex,x-1,y+2),  FGET(tex,x,y+2),  FGET(tex,x+1,y+2),  FGET(tex,x+2,y+2)
                     };
    double a00 = p[1][1];
	double a01 = -p[1][0] + p[1][2];
	double a02 = 2*p[1][0] - 2*p[1][1] + p[1][2] - p[1][3];
	double a03 = -p[1][0] + p[1][1] - p[1][2] + p[1][3];
	double a10 = -p[0][1] + p[2][1];
	double a11 = p[0][0] - p[0][2] - p[2][0] + p[2][2];
	double a12 = -2*p[0][0] + 2*p[0][1] - p[0][2] + p[0][3] + 2*p[2][0] - 2*p[2][1]
                 + p[2][2] - p[2][3];
	double a13 = p[0][0] - p[0][1] + p[0][2] - p[0][3] - p[2][0] + p[2][1] - p[2][2] + p[2][3];
	double a20 = 2*p[0][1] - 2*p[1][1] + p[2][1] - p[3][1];
	double a21 = -2*p[0][0] + 2*p[0][2] + 2*p[1][0] - 2*p[1][2] - p[2][0] + p[2][2]
                 + p[3][0] - p[3][2];
	double a22 = 4*p[0][0] - 4*p[0][1] + 2*p[0][2] - 2*p[0][3] - 4*p[1][0] + 4*p[1][1]
                 - 2*p[1][2] + 2*p[1][3] + 2*p[2][0] - 2*p[2][1] + p[2][2] - p[2][3]
                 - 2*p[3][0] + 2*p[3][1] - p[3][2] + p[3][3];
	double a23 = -2*p[0][0] + 2*p[0][1] - 2*p[0][2] + 2*p[0][3] + 2*p[1][0] - 2*p[1][1]
                 + 2*p[1][2] - 2*p[1][3] - p[2][0] + p[2][1] - p[2][2] + p[2][3] + p[3][0]
                 - p[3][1] + p[3][2] - p[3][3];
	double a30 = -p[0][1] + p[1][1] - p[2][1] + p[3][1];
	double a31 = p[0][0] - p[0][2] - p[1][0] + p[1][2] + p[2][0] - p[2][2] - p[3][0] + p[3][2];
	double a32 = -2*p[0][0] + 2*p[0][1] - p[0][2] + p[0][3] + 2*p[1][0] - 2*p[1][1]
                 + p[1][2] - p[1][3] - 2*p[2][0] + 2*p[2][1] - p[2][2] + p[2][3] + 2*p[3][0]
                 - 2*p[3][1] + p[3][2] - p[3][3];
	double a33 = p[0][0] - p[0][1] + p[0][2] - p[0][3] - p[1][0] + p[1][1] - p[1][2]
                 + p[1][3] + p[2][0] - p[2][1] + p[2][2] - p[2][3] - p[3][0] + p[3][1]
                 - p[3][2] + p[3][3];

	double x2 = u_ratio * u_ratio;
	double x3 = x2 * u_ratio;
	double y2 = v_ratio * v_ratio;
	double y3 = y2 * v_ratio;

	return a00 + a01 * v_ratio + a02 * y2 + a03 * y3 +
	       a10 * u_ratio + a11 * u_ratio * v_ratio + a12 * u_ratio * y2 + a13 * u_ratio * y3 +
	       a20 * x2 + a21 * x2 * v_ratio + a22 * x2 * y2 + a23 * x2 * y3 +
	       a30 * x3 + a31 * x3 * v_ratio + a32 * x3 * y2 + a33 * x3 * y3;
 }

void radialRemap(IplImage *source, IplImage *dest, double k)
{
    int i,j;
    CvSize s = cvGetSize(dest);
    double x,y,cx,cy,nx,ny,r2;
    cx = s.width/2.0;
    cy = s.height/2.0;
    for (i=0; i<s.height; i++)
       for (j=0; j<s.width; j++) {
           nx = (j-cx)/s.width;
           ny = (i-cy)/s.height;
           r2 = nx*nx+ny*ny;
           nx = nx*(1+k*r2);
           ny = ny*(1+k*r2);
           x = (nx+0.5)*s.width;
           y = (ny+0.5)*s.height;
           if (x<0 || x>=s.width || y<0 || y>=s.height)
            { FGET(dest,j,i) = 0;
             continue;}
           FGET(dest,j,i) = bilinearInterp(source,x,y);
           }


}


//@-node:aleator.20050908101148.1:function for rotating image
//@+node:aleator.20051220091717:Matrix multiplication

void wrapMatMul(int w, int h, double *mat
               , double *vec, double *t)
{

CvMat matrix;
CvMat vector;
CvMat target;
cvInitMatHeader(&matrix,w,h,CV_64FC1,mat,CV_AUTOSTEP);
cvInitMatHeader(&vector,h,1,CV_64FC1,vec,CV_AUTOSTEP);
cvInitMatHeader(&target,w,1,CV_64FC1,t,CV_AUTOSTEP);
cvMatMul(&matrix,&vector,&target);
}

void maximal_covering_circle(int ox,int oy, double or, IplImage *distmap
                            ,int *max_x, int *max_y, double *max_r)
{
 double distance,radius;

 *max_x = ox;
 *max_y = oy;
 *max_r  = or;

 CvSize s = cvGetSize(distmap);
 for(int i=0; i<s.width; i++) // TODO: Limit with max_r
  for(int j=0; j<s.height; j++)
   {
    distance = sqrt((i-ox)*(i-ox) + (j-oy)*(j-oy));
    radius   = FGET(distmap,i,j);
    if (radius > *max_r && radius >= or+distance )
         { *max_x=i; *max_y=j; *max_r=radius;}
   }
}

double juliaF(double a, double b,double x, double y) {
     int limit = 1000;
     double complex z;
     int i=0;
     double complex c;
     double cr,ci;
     c = a + b*I;
     z = x+y*I;
     for (i=0;i<limit;i++)
        {
         cr=creal(z); ci=cimag(i);
         if (cr*cr+ci*ci>4) return (i*1.0)/limit;
         z=z*z+c;
        }
    return 0;
    }

CvVideoWriter* wrapCreateVideoWriter(char *fn, int fourcc,
                                     double fps,int w, int h,
                                     int color)
 {
   CvVideoWriter *res = cvCreateVideoWriter(fn,CV_FOURCC('M','P','G','4'),fps,cvSize(w,h), color);
   return res;
 }

int wrapFindChessBoardCorners(const void* image, int pw, int ph, CvPoint2D32f* corners, int* cornerCount, int flags)
{
 CvSize s = {pw,ph};
 //for (int i=0; i<pw*ph; i++) {corners[i].x=i; corners[i].y=i+10;}
 cvFindChessboardCorners(image,s,corners,cornerCount,flags);
}

int wrapDrawChessBoardCorners(void* image, int pw, int ph, CvPoint2D32f* corners, int cornerCount, int wasFound)
{
 CvSize s = {pw,ph};
 cvDrawChessboardCorners(image,s,corners,cornerCount,wasFound);
}

double wrapCalibrateCamera2(const CvMat* objectPoints, const CvMat* imagePoints, const CvMat* pointCounts, CvSize *imageSize, CvMat* cameraMatrix, CvMat* distCoeffs, CvMat* rvecs, CvMat* tvecs, int flags)
{
#ifdef OpenCV24
return cvCalibrateCamera2(objectPoints, imagePoints, pointCounts, *imageSize, cameraMatrix, distCoeffs, rvecs, tvecs, flags, cvTermCriteria(CV_TERMCRIT_ITER+CV_TERMCRIT_EPS,30,DBL_EPSILON));
#else
return cvCalibrateCamera2(objectPoints, imagePoints, pointCounts, *imageSize, cameraMatrix, distCoeffs, rvecs, tvecs, flags);
#endif
};

void wrapFindCornerSubPix(const CvArr* image, CvPoint2D32f* corners, int count, int winW, int winH, int zeroW, int zeroH, int tType, int maxIter, double epsilon) {
 CvTermCriteria t = {tType,maxIter,epsilon};
 CvSize searchWindow = {winW,winH};
 CvSize zero = {winW,winH};
 cvFindCornerSubPix(image, corners, count, searchWindow, zero, t);
};

void wrapFitEllipse(CvArr* pts, CvBox2D *out) {
CvBox2D box = cvFitEllipse2(pts);
out->center = box.center;
out->size = box.size;
out->angle = box.angle;
}

int wrapCamShift(const CvArr* prob_image, CvRect *window, CvTermCriteria *criteria, CvConnectedComp* comp, CvBox2D* box)
{ return cvCamShift(prob_image, *window, *criteria, comp, box); }



void extractCVSeq(const CvSeq* seq,void *dest){
CvSeqReader reader;
cvStartReadSeq( seq, &reader, 0 );
void *index=dest;
for( int i = 0; i < seq->total; i++ )
{
    memcpy(index,(void*)reader.ptr,seq->elem_size);
    index += seq->elem_size;
    CV_NEXT_SEQ_ELEM( seq->elem_size, reader );
}}


#ifndef OpenCV24
void wrapExtractMSER( CvArr* _img, CvArr* _mask, CvSeq** contours, CvMemStorage* storage, CvMSERParams *params ){
cvExtractMSER( _img, _mask, contours, storage, *params );
};
#endif
//
//@-node:aleator.20051220091717:Matrix multiplication
//@-all
//@-node:aleator.20050908100314:@thin cvWrapLEO.c
//@-leo