/**************************************************************************
 * File: routines.c            ROUTINES.C
 * Programmer: Justin Miller Cornell id# 356452
 * 
 * Purpose: Repository for useful image manipulation routines that have no
 *   other place to go, many may be duplicated by other procedures, be
 *   sure to read the NOTES.
 * 
 * Last Sanity Check: 940808
 *
 * See Also: routines.h
 *
 * Copyright (c) 1995 Cornell University.  All Rights Reserved.
 **************************************************************************/
/* THIS FILE:
 * 
 * void min_max(FloatImage image, float *outmin, float*outmax)
 *   returns minimum and maximum values from a floating point image.
 *
 * GrayImage pfm_to_pgm(FloatImage image, float min, float max)
 *   converts pfm to pgm by renormalizing values, identical to 
 *   William's imcFtoG()
 *
 * 
*/
static char rcsid[] = "@(#)$Header: /usr/u/jmiller/prog/ImDiss/src/RCS/thresher.c,v 1.1 1995/07/01 17:01:34 jmiller Exp jmiller $";
#include <stdio.h>
#include "math.h"
#include "image.h"
#include "misc.h"
#include "dbug.h"
#include "solaris.h"
#include "routines.h"

/* void box_spiral(int *x, int *y)
 *  
 *  given an x and y coordinate, it modifies x and y to be the next 
 *  location on the rectangular counter-clockwise spiral beginning at 
 *  (0,0),(1,0),(1,1), and continuing.  To spiral out through an nxn
 *  box one should stop when x > n, since the x always increments 
 *  before the y diameter.
 * 
 *  How it works: (four sides, four cases)
 *  x > 0 and x > abs(y), y++
 *  x < 0 and -x > abs(y) or -x = y, y--
 *  y > 0 and y > -x, x--
 *  y < 0 and -y >= x, x++, or x = y = 0 x++, note that order of 
 *  evaluation is important.
 */
void box_spiral(int *x, int *y){
  BOX_SPIRAL(*x,*y);
  return;
}



/* counts number of ON pixels in a PBM.*/
float pbm_percentOn(BinaryImage inim){
  unsigned int total = 0;
  int x,y, maxX, maxY;

  maxX = (unsigned int)imGetWidth(inim);
  maxY = (unsigned int)imGetHeight(inim);

  for(y = 0; y < maxY; y++){
    for(x = 0; x < maxX; x++){
      total += imRef(inim, x, y);
    }
  }
  return(((float)total) /((float)(maxX * maxY)));
}


/* counts number of ON pixels in a PBM.*/
void laplacian_calc(FloatImage inim, FloatImage outim){
  int x,y, maxX, maxY;

  maxX = (unsigned int)imGetWidth(inim);
  maxY = (unsigned int)imGetHeight(inim);
  
  for(y = 1; y < maxY-1; y++){
    for(x = 1; x < maxX-1; x++){
      imRef(outim, x,y) = imRef(inim,x-1,y-1) + imRef(inim,x+1,y-1) + 
	  imRef(inim,x-1,y+1) + imRef(inim, x+1,y+1) + 
	      4.0*(imRef(inim,x,y-1) + imRef(inim,x,y+1) + imRef(inim,x-1,y)
		   + imRef(inim,x+1,y)) - 20.0 * imRef(inim,x,y);
    }
  }
}

#define SC_MIN(a)({t=(a); if(t<mt) mt = t;})

void laplacian_sign_change(FloatImage inim){
  int x,y, maxX, maxY;
  float t,mt,s;

  maxX = (unsigned int)imGetWidth(inim);
  maxY = (unsigned int)imGetHeight(inim);
  
  for(y = 2; y < maxY-2; y++){
    for(x = 2; x < maxX-2; x++){
      s = imRef(inim,x,y);
      if(s >= 0){
	mt = 256.0;
	SC_MIN(imRef(inim,x-1,y-1));
	SC_MIN(imRef(inim,x,y-1));
	SC_MIN(imRef(inim,x+1,y-1));
	SC_MIN(imRef(inim,x-1,y));
	SC_MIN(imRef(inim,x+1,y));
	SC_MIN(imRef(inim,x-1,y+1));
	SC_MIN(imRef(inim,x,y+1));
	SC_MIN(imRef(inim,x+1,y+1));
	if(mt < 0)
	    imRef(inim,x,y) = s - mt;
	else
	    imRef(inim,x,y) = 0.0;
      }
      else{
	imRef(inim,x,y) = 0.0;
      }
    }
  }
  
  for(y = 0; y < 2; y++){
    for(x = 0; x < maxX; x++){
      imRef(inim,x,y) = 0;
    }
  }
  for(y = maxY-2; y < maxY; y++){
    for(x = 0; x < maxX; x++){
      imRef(inim,x,y) = 0;
    }
  }
  for(y = 2; y < maxY-2; y++){
    imRef(inim,0,y) = 0;
    imRef(inim,1,y) = 0;
    imRef(inim,maxX-1,y) = 0;
    imRef(inim,maxX-2,y) = 0;
  }
  return;
}


void laplacian_sign_change_2step(FloatImage inim){
  int x,y, maxX, maxY;
  float t,mt,s;

  maxX = (unsigned int)imGetWidth(inim);
  maxY = (unsigned int)imGetHeight(inim);
  
  for(y = 2; y < maxY-1; y++){
    for(x = 2; x < maxX-1; x++){
      s = imRef(inim,x,y);
      if(s >= 0){
	mt = 256.0;
	SC_MIN(imRef(inim,x+1,y));
	SC_MIN(imRef(inim,x,y+1));
	SC_MIN(imRef(inim,x+1,y+1));
	if(mt < 0)
	    imRef(inim,x,y) = s - mt;
	else
	    imRef(inim,x,y) = 0.0;
      }
      else{
	imRef(inim,x,y) = 0.0;
      }
    }
  }
  
  for(y = 0; y < 2; y++){
    for(x = 0; x < maxX; x++){
      imRef(inim,x,y) = 0;
    }
  }
  for(x = 0; x < maxX; x++){
    imRef(inim,x,maxY-1) = 0;
  }

  for(y = 2; y < maxY-1; y++){
    imRef(inim,0,y) = 0;
    imRef(inim,1,y) = 0;
    imRef(inim,maxX-1,y) = 0;
  }
  return;
}


void laplacian_create_pbm(FloatImage inim, BinaryImage outim){
  int x,y, maxX, maxY;

  maxX = (unsigned int)imGetWidth(inim);
  maxY = (unsigned int)imGetHeight(inim);

  for(y = 0; y < maxY; y++){
    for(x = 0; x < maxX; x++){
      if(imRef(inim,x,y) > 0.0){
	imRef(outim,x,y) = 1;
      }
    }
  }
  return;
}

void laplacian_create_thresh_pbm(FloatImage inim, BinaryImage outim, float thresh){
  int x,y, maxX, maxY;

  maxX = (unsigned int)imGetWidth(inim);
  maxY = (unsigned int)imGetHeight(inim);

  for(y = 0; y < maxY; y++){
    for(x = 0; x < maxX; x++){
      if(imRef(inim,x,y) > thresh){
	imRef(outim,x,y) = 1;
      }
    }
  }
  return;
}



void laplacian_square_mag(FloatImage inim){
  int x,y, maxX, maxY;
  float t;
  
  maxX = (unsigned int)imGetWidth(inim);
  maxY = (unsigned int)imGetHeight(inim);

  for(y = 0; y < maxY; y++){
    for(x = 0; x < maxX; x++){
      t = imRef(inim,x,y);
      imRef(inim,x,y) = t*t;
    }
  }
  return;
}


Quad laplacianEdge(FloatImage inimage){
  Quad q;

  q = createQuad((int)imGetWidth(inimage), (int)imGetHeight(inimage));
  laplacian_calc(inimage,q->sgMagnitude);
  laplacian_sign_change_2step(q->sgMagnitude);
  laplacian_create_pbm(q->sgMagnitude,q->peaks);
  return(q);
}
  


void sumsqr_uchar(unsigned char *i, unsigned int *o, 
		  int w, int h){
  unsigned char *a,*z;
  unsigned int y,*b,*c;
  for(a=i,b=o+w,z=i+w*h-1;a<z;*(b++)=*(a++)+*(a+w));
  for(b=o+1,c=o+w*h-1,w--;b<c;a++,b++)for(y=w;(y--)!=0;*(b++)+=*(b-1));
  return;
}

void pbm_areahist(BinaryImage inim, int xdivs, int ydivs, int *arr){
  int x,y, maxX, maxY;
  int xstart, ystart, xstop, ystop;
  int xout,yout;
  int temp;

  maxX = (unsigned int)imGetWidth(inim);
  maxY = (unsigned int)imGetHeight(inim);
  
  for(yout = 0, ystart = 0; yout < ydivs; yout++, ystart = ystop){
    ystop = ystart + 1 + (maxY-1)/ydivs;
    ystop = MIN(ystop,maxY);
      for(xout = 0, temp = 0, xstart = 0; 
	  xout < xdivs; xout++, xstart = xstop){
	xstop = xstart + 1 + (maxX-1)/xdivs;
	xstop = MIN(xstop,maxX);
	for(y = ystart; y < ystop; y++){
	  for(x = xstart; x < xstop; x++){
	    temp += imRef(inim,x,y);
	  }
	}
	arr[xout + yout*xdivs] = temp;
      }
  }
  return;
}
