/****************************************************************************/
/* Kontur Tracking nach Zamperoni					*/
/*									*/
/* Written by Uli Mezger						*/
/* Adapted by Thomas Bräunl, 2001                                       */
/* Look for contours and save then in a contour list                    */
/****************************************************************************/ 

#include "../FW/labImage.h"
#include "../FW/labImgDraw.h"

#include "contourtrack.h"

void konturtracking(Picture *p_image,int grauwerte[],int anzahl_schwellen,int E[])
{
  
  int DX[8] = {1, 1, 0, -1, -1, -1, 0, 1};
  int DY[8] = {0, -1, -1, -1, 0, 1, 1, 1};
  
  int ANF, EZP, ZUR;	
  int x, y;
  int x1,y1;
  int X, Y;					
  int XK, YK;				/*= E(2),= E(3) */
  int RL = 0;
  int anz=0;			
  
  short akt_pixel, vorgaenger;
  int temp,t,flag;
  int ebene,ebene1,ebenetmp;
  unsigned z;
  int wirk,W;
  
  int MAX_GRAY;
  
  /* kleinste Nicht - Farbe festlegen*/
  MAX_GRAY=grauwerte[anzahl_schwellen-1]+1;
  
  /* schwarzes Rechteck als Begrenzung einzeichnen-> sorgt dafür das x,y Werte */
  /* nicht den Bildbereich verlassen */
  setDrawGValImage(0);
  drawRectInImage(p_image,0,0,p_image->width-1,p_image->height-1,1);
  
  E[0]=0;
  /* Durch das ganze Bild laufen*/
  for (y1 = 0;y1 < (signed) p_image->height-1; y1++)
    {
      
      for (x1 = 0; x1 < (signed) p_image->width-1; x1++)
	{
	  
	  if(x1>0)
	    vorgaenger = GETPIXELVALUE(p_image,x1-1,y1);		/* alten Pixelwert erhalten*/ 
	  else
	    vorgaenger = GETPIXELVALUE(p_image,x1,y1) ;
	  
	  /* aktueller Pixelwert */
	  akt_pixel=GETPIXELVALUE(p_image,x1,y1);			
	  
	  
	  /* BEDINGUNG FÜR DEN EINTRITT IN EIN KONTURTRACKING */
	  if(	(akt_pixel >= grauwerte[0] ) && (vorgaenger < akt_pixel) && 
		(akt_pixel<MAX_GRAY)
		)
	    
	    { 
	      
				/* Grauwertebenenbestimmung */
	      for(ebene=1;ebene<=anzahl_schwellen;ebene++)
		{
		  if(akt_pixel==grauwerte[ebene-1])
		    break;
		}
	      
	      x=x1;y=y1;
	      
	      E[0]++;			/* Die Gesamtanzahl der gefundenen Konturen erhöhen */
	      ANF = 1;		/* =1 falls aktueller Konturpukt = Anfangspunkt */
	      
	      XK = x;			/* Koordinaten des Anfangspunktes */
	      YK = y;
	      
	      EZP = 0;		/* =1 falls Einzelpunkt */
	      ZUR = 0;		/* =1 falls Konturpunkt==Anfangspunkt */ 
	      
	      E[1 + anz] = 0;	/* E(1) Gesamtzahl Konturschritte */
	      E[2 + anz] = x;	/* x - Anfangspunkt */
	      E[3 + anz] = y;	/* y - Anfangspunkt */
	      E[4 + anz] =0;
	      z = 5;			/* Index des nächsten freien Speicherplatzes */
	      
	      for (;;)			/* for(;;) durch break verlassen */
		{
		  
		  if (ANF == 1)
		    {
		      ANF = 0;
		      RL = 4;		/* RL = Richtung des letzten Konturschrittes */
		    }
		  else
		    RL = (RL + 4) % 8; 
		  
		  /* Koordinaten des aktuell, zu untersuchenden Konturpunktes */
		  X = x;		
		  Y = y;
		  
		  flag = 0;	/* =1 Kontur beendet! */	
		  t = 0;		
		  
		  /* Nachbarschaft des aktuellen Pixels prüfen */
		  do
		    {
		      
		      RL = (RL + 1) % 8;
		      
		      /* x,y - Koordinaten des Nachbarn */
		      x = X + DX[RL];	
		      y = Y + DY[RL];
		      
		      if (ZUR == 1)	/* Kontur zu Ende */
			{
			  if ( GETPIXELVALUE(p_image,x,y) >= MAX_GRAY  )
			    {
			      flag = 1;	/* Kontour Ende */
			      break;
			    }
			}
		      
		      t++;	/* Zähler, der angibt wieviel Nachbarn schon geprüft worden sind*/
		      
		      temp=GETPIXELVALUE(p_image,x,y);
		      wirk=temp;			
		      
		      /*Nicht-Farbe dekodieren (welche Farbe lag darunter)*/
		      if(temp !=(MAX_GRAY + ebene))
			{	
			  /* Farbe rekonstruieren */
			  if(temp >= MAX_GRAY )
			    {		
			      ebene1=temp-MAX_GRAY;
			      temp=grauwerte[ebene1-1];
			    }
			  
			  /* aktuelle Farbe; Rest ist Schwarz */
			  if(temp >= akt_pixel)
			    temp=akt_pixel;
			  else
			    temp=0;
			}
		    }
		  while (	(t < 8 ) && 
				(temp != akt_pixel) && 
				(temp != (MAX_GRAY + ebene)) );
		  
		  /* Dunkle Einzelpunkte ignorieren*/
		  if((flag) && (E[1 + anz]<5) && E[5+anz]==5 && E[6+anz]==3 &&E[7+anz]==1)
		    {
		      EZP=1;			
		      E[0]--;			/* Konturzähler zurücksetzen */
		      /*dunklen Punkt kennzeichnen */
		      setDrawGValImage((unsigned char) (MAX_GRAY + ebene));
		      PutPixelInImage(p_image,XK,YK);
		      /* Markierung entfernen */
		      setDrawGValImage((unsigned char) akt_pixel);
		      PutPixelInImage(p_image,XK+DX[5],YK+DY[5]);
		      PutPixelInImage(p_image,XK+DX[3],YK+DY[3]);
		      PutPixelInImage(p_image,XK+DX[5]+DX[3],YK+DY[5]+DY[3]);
		      setDrawGValImage((unsigned char) (MAX_GRAY + ebene));
		      break;			/* =>Punkt nicht in Konturliste aufnehmen */
		    }
		  
		  
		  /* Helle Einzelpunkte ignorieren */
		  if (t == 8 && E[1+anz]==0 && 
		      (GETPIXELVALUE(p_image,x,y) != akt_pixel) && 
		      (GETPIXELVALUE(p_image,x,y) != (MAX_GRAY + ebene)))	/* Einzelpunkt gefunden! */
		    {													
		      EZP=1;			
		      E[0]--;			/* Konturzähler zurücksetzen */
		      break;			/* =>Punkt nicht in Konturliste aufnehmen */
		    }
		  
		  if (flag)			/* komplette Kontour gefunden */
		    break;			/* => Kontur Tracking beenden */
		  
		  
		  /* Endlosschleife verhindern */
		  if(E[1+anz]>10000)
		    {
		      EZP=1;
		      E[0]--;
		      break;
		    }
		  
		  /* bisher gefundene Kontour kennzeichnen mit der Nicht-Farbe (= (MAX_GRAY + ebene)) */
		  if(wirk!=temp)
		    {	
		      
		      if(wirk<MAX_GRAY)
			{
			  /* Schwellebenenbestimmung für wirk */
			  for(ebenetmp=1;ebenetmp<=anzahl_schwellen;ebenetmp++)
			    {
			      if(wirk==grauwerte[ebenetmp-1])
				break;
			    }	
			  setDrawGValImage((unsigned char) (MAX_GRAY + ebenetmp));
			}
		      else
			setDrawGValImage((unsigned char) wirk);
		      
		      
		    }
		  else
		    /* Nicht - Farbe setzen zur Konturmarkierung */
		    setDrawGValImage((unsigned char) (MAX_GRAY + ebene));
		  
		  PutPixelInImage(p_image,x,y);
		  
		  if(!EZP)						/* Einzelpunkte Ignorieren? */ 
		    {								/* ansonsten */
		      E[1 + anz]++;				/* Anzahl Konturpunkt erhöhen */				
		      
		      E[(z++) + anz] = RL;		/* Konturrichtung eintragen */
		      
		      if ( !(z <= 6) ) 
			{
			  W = (int) (E[(z - 1) + anz]) - (int) (E[(z - 2) + anz]);
			  if (W >= 4)			/* W bezeichnet Winkel (ganzes Vielfaches von 45 Grad) */
			    W -= 8;			/* zw. Richtung des letzten Konturschrittes und Richtung 
							   /* des zum nächsten erkannten  Konturschrittes */
			  if (W <= -4)			/* E(4) >= 0 -> Objekt; E(4)<0 -> Loch */
			    W += 8;
			  E[4 + anz] += W;
			}
		      
		      
		      if (x == XK && y == YK)
			ZUR = 1;		
		      else
			ZUR = 0;
		      
		      
		    }/* end of if(EZP!=0)*/
		}/* end of for(;;)*/
	      
	      
	      
	      if(!EZP)	/* Einzelpunkte Ignorieren */ 
		{
		  
		  
		  W = (int) (E[5 + anz]) - (int) (E[(z - 1) + anz]); 
		  if (W >= 4)
		    W -= 8;
		  if (W <= -4)
		    W += 8;
		  E[4 + anz] += W;					
		  
		  //fprintf(stdout,"%d gefundene Konturen\n ",E[0]);
		  
		  /********************************************************/
		  /* Konturschritte sequentiel in ein Array schreiben:	*/
		  /*----------------------------------------------		*/
		  /*Konturschritt Schema:									*/
		  /*	E[0] = Gesamtzahl gefundener Konturen				*/
		  /*	E[1] = Anzahl Konturschritte						*/
		  /*	E[2] = x Anfangspunkt								*/
		  /*	E[3] = y Anfangspunkt								*/
		  /*	E[4] = Loch oder Objekt								*/
		  /*	E[5] = erster Konturschritt							*/
		  /*		.												*/
		  /*		.												*/
		  /*	Schema:	E[1]	= Startfeld Kontur 1				*/
		  /*			E[ E[1]+4 ] = Startfeld Kontur 2			*/
		  /*			E[ E[E[1]+4] + 4 ]	= Startfeld Kontur 3	*/
		  /*			usw.										*/
		  /********************************************************/
		  
		  if(anz==0)
		    temp = 1;				/* initialisieren */
		  else
		    temp = anz+1;			/* alten Wert merken */
		  
		  anz +=(E[temp]+4);			/* neue Kontur in Array eintragen*/	
		  
		}
	      
	    }					/* End of Kontour Bedingung */
	  
	}				/* End x */
    }			/*End y*/
  
}/* Overall End*/


