reference/ocr-new/Component.cc
changeset 0 6b8091ca909a
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/reference/ocr-new/Component.cc	Thu May 18 23:12:51 2006 +0200
@@ -0,0 +1,607 @@
+
+#include "system.h"
+#include "Component.h"
+#include "BitMap.h"
+#include <assert.h>
+#include "list.h"
+#include "tcl_interface.h"
+
+/*** Component.cc
+  Member functions for Components 
+  Component functions defined in Component.h
+  rev 12/9/95 KM
+***/
+
+extern Page * global_page;
+extern Page * active_page;
+
+
+Components::Components()
+:List()
+{
+}
+
+
+Components::~Components()
+{
+
+  for (ListElement *ptr = first; ptr != NULL && ptr->item!=NULL; 
+       ptr = ptr->next) {
+    if (ptr->item != NULL)
+      delete (Component *) (ptr->item);
+     }
+  while(!IsEmpty())
+    Remove();
+}
+
+Component * Components::compAt(Point p)
+/*--------------------------------------------------------------
+Primary Purpose:  Return smallest component that contains this point
+Arguments:  Point of request
+Return Value: Component pointer or NULL if there is no component here
+Rev 4/22/96
+---------------------------------------------------------------*/
+{
+  double size;
+  Component * returnComp = NULL;
+
+  int rowwidth = (((Component *) last->item)->ul().x()) -
+    (((Component *) first->item)->ul().x()) ;
+
+  int rowheight = (((Component *) last->item)->ul().x()) -
+    (((Component *) first->item)->ul().x());
+ 
+
+    size = rowwidth*rowheight; // this is now as big as the whole line.
+ 
+   for (ListElement *ptr = first; ptr != NULL && ptr->item!=NULL; 
+       ptr = ptr->next) 
+     {
+       Component * item = (Component *) ptr->item;
+       if ( p > item->ul() && p < item->lr())
+	 {
+	   double area = item->area();
+	   if(area < size) size = area;
+	   returnComp = item;
+	 }
+       }
+   return returnComp;
+
+}
+
+
+
+Component * Component::copy()
+{
+  Component * newcomp = new Component(ful, flr);
+  newcomp->numBits() = fnumBits;
+  newcomp->fasciiId = new char[strlen(fasciiId)];
+  strcpy(newcomp->fasciiId, fasciiId);
+  newcomp->fconfid = confid();
+  newcomp->charGroup = charGroup;
+  newcomp->ffontId = fontId();
+  for (int i = 0; i < numProperties; i++)
+	         newcomp->property(i) = fproperty[i];
+  return newcomp;
+}
+
+
+
+int Component::AddToComponent(ListElement* intrvl, RLEMap* rlemap, 
+			      int horizMerge)
+{
+  assert(intrvl != NULL);
+  List* list = new List();           //make a new queue
+  ListElement* current;
+  ListElement* nextelt;
+  int counter = 0;
+  int currentRow;
+
+  if (intrvl->previous != NULL)
+    intrvl->previous->next = intrvl->next;
+  else rlemap->fMapData[((RLEPair *) intrvl->item)->row]->first = intrvl->next;
+  if (intrvl->next != NULL)
+    intrvl->next->previous = intrvl->previous;
+  list->first = intrvl;              //put starting interval on queue
+  list->last = intrvl;
+  list->length = 1;
+  intrvl->next = NULL;
+  intrvl->previous = NULL;
+  currentRow = 0;
+  while ((intrvl = list->first) != NULL && 
+	 currentRow < rlemap->imageLength()-1) //Take an interval off queue
+    {
+      currentRow = ((RLEPair *) intrvl->item)->row;
+
+      for (int i=-1; i < 2; i+=2) { 
+	current = rlemap->fMapData[currentRow+i]->first;
+	while ((current != NULL) 
+	       && (((RLEPair *) current->item)->start <= 
+		   ((RLEPair *) intrvl->item)->end+horizMerge)) {
+
+//	  printf("Looking at an interval on row %d that goes from %d to %d\n",
+//		 currentRow, ((RLEPair *) intrvl->item)->start,
+//		  ((RLEPair *) intrvl->item)->end);
+
+	  if ((((RLEPair *) current->item)->end 
+	       >= ((RLEPair *) intrvl->item)->start-1) 
+	      && (((RLEPair *) current->item)->start <= 
+		  ((RLEPair *) intrvl->item)->end+horizMerge)) {
+//	  printf("Adding connection for interval on row %d that goes from %d to %d\n", currentRow+i,
+//		 ((RLEPair *) current->item)->start,
+//		  ((RLEPair *) current->item)->end);
+	
+	    if (current->previous != NULL)
+	      current->previous->next = current->next;   //take off RLEMap
+	    else
+	      rlemap->fMapData[currentRow+i]->first = current->next;
+	    if (current->next != NULL)
+	      current->next->previous = current->previous;
+	    nextelt = current->next;
+	    list->last->next = current;                //add to queue
+	    current->previous = list->last;
+	    list->last = current;
+	    current->next = NULL;
+	    current = nextelt;
+	    list->length++;
+	  } else
+	    current = current->next;
+	}
+      }
+      
+      if ((((RLEPair *) intrvl->item)->start < ful.x()) || (ful.x()==-1)) {
+	ful.x() = ((RLEPair *) intrvl->item)->start;
+//	printf("Changed ful.x to %d\n", ful.x());
+      }
+      if ((((RLEPair *) intrvl->item)->end > flr.x()) || (flr.x()==-1)) {
+	flr.x() = ((RLEPair *) intrvl->item)->end;
+//	printf("Changed flr.x to %d\n", flr.x());
+      }
+      if ((((RLEPair *) intrvl->item)->row < ful.y()) || (ful.y()==-1)) {
+	ful.y() = ((RLEPair *) intrvl->item)->row;
+//	printf("Changed ful.y to %d\n", ful.y());
+      }
+      if ((((RLEPair *) intrvl->item)->row > flr.y()) || (flr.y()==-1)) {
+	flr.y() = ((RLEPair *) intrvl->item)->row;
+//	printf("Changed flr.y to %d\n", flr.y());
+      }      
+      list->first = intrvl->next;
+      if (intrvl->next != NULL)
+	intrvl->next->previous = NULL;
+      delete ((RLEPair *) (intrvl->item));
+      delete intrvl;               //so the letter O won't go forever
+      counter++;
+      list->length--;
+    }
+
+  delete list;
+  return counter;
+
+}
+
+void Component::setProperties(BitMap * map)  // was BitMap
+/*--------------------------------------------------------------
+Primary Purpose: Set the property vector for this component
+Arguments:  The BitMap to which this component belongs
+Return Value:
+Effects: The component is divided into a 5 by 5 grid.  A gray
+    scale (0 - 255) for each section is determined.  The gray scale
+    is 0 for all white, 255 for all black but normally will e somewhere
+    between the two.  The gray scales are represented in properties
+    0-24. 
+    Property 25 is the grayscale accross the top.
+    Property 26 is the grayscale accross the bottom.
+    Property 27 is the width/height ratio again scaled to (0-255)
+    Actually the formula for property 27 is
+        width/ height * 255  if height > width
+        1- height/width * 255 if width > height
+    This way near 0 is very tall and thin
+             near 128 height near width
+	     near 255 very wide
+    Property 28 is  Indicator of a vertically disjoint character
+     like i and j.
+    Also the total number of black pixels is set in fnumBits.
+    // This is not used at this time.    
+Constraints: The data fields ful and flr must already be set 
+   before calling this function. These fields specify a bounding
+   box for the character within the BitMap.
+Rev: 12/9 KM
+---------------------------------------------------------------*/
+{
+  if (ful > flr) 
+    printf("Problem\n");
+  assert (ful <= flr);
+  short int hflag[NumHorizDiv + 1];  // flags horizontal section dividers
+  short int vflag[NumVertDiv + 1];   // flags vertical section dividers
+  float height, width;
+  int propNum;
+  float darkest = 0;
+  float lightest; 
+  int darkrow = 0;
+  int lightrow = 0;
+
+  Point sectionLr, sectionUl;
+  // Set Number of bits
+  fnumBits = map->pixelsInRegion(ful, flr);
+
+  setSectionFlags(hflag, vflag);
+  for (int r = 0; r < NumVertDiv; r++)
+    for (int c = 0; c < NumHorizDiv; c++)
+      {
+	propNum = (r * NumHorizDiv) + c;
+	sectionUl = Point(hflag[c], vflag[r]);
+	sectionLr = Point(hflag[c+1]-1, vflag[r+1]-1);
+	if (sectionUl <= sectionLr)
+	  fproperty[propNum] = map->grayScale(sectionUl, sectionLr); 
+	assert(fproperty[propNum] >= 0 && fproperty[propNum] < 256);
+      }
+
+  // set the height/width ratio
+  // 0 is very thin 128 is even 256 is very wide.
+  width = flr.x() - ful.x() + 1;
+  height = flr.y() - ful.y() + 1;
+ 
+  // Grayscale across the top - Indicator of top bar
+  sectionUl = Point(ful.x(), ful.y());
+  sectionLr = Point(flr.x(), ful.y() + (int)(height/(NumVertDiv*2)));
+  fproperty[25] = map->grayScale(sectionUl, sectionLr);
+
+   // Grayscale across bottom - Indicator of a foot for l opposed to 1
+  sectionUl = Point(ful.x(),  flr.y() -  (int)(height/(NumVertDiv*2)));
+  sectionLr = Point(flr.x(),  flr.y());
+  fproperty[26] = map->grayScale(sectionUl, sectionLr);
+
+  float hdivw = (float)height/width;
+  float wdivh = (float) width/height;
+  if (width > height)
+       fproperty[27]= (short int) ((1- hdivw/2)*255);
+  else
+    fproperty[27] = (short int)((wdivh/2)* 255);
+
+  // is this a disjoint character like i or j  255 = yes 0 = no
+  fproperty[28]=0;
+  lightest = width;
+  for(int row = ful.y(); row < flr.y(); row++)
+      {
+	int pixelsThisRow = pixelsBetween(map->row(row), ful.x(), flr.x());
+	if(!(pixelsThisRow))
+	      fproperty[28]=255;
+      }
+
+  fproperty[29]= 0;
+    for(int p = 0; p < numProperties; p++)	
+      assert(fproperty[p] >= 0 && fproperty[p] < 256);
+
+
+}
+
+void Component::setSectionFlags(short int hflag[], short int vflag[])
+/*--------------------------------------------------------------
+Primary Purpose: Breaks this component into a grid NumHorizDiv X NumVertDiv
+    for determining grayscale property vectors.
+Arguments:  hflag[] is an empty array to be filled by this procedure with
+    the starting columns of each horizontal subdivision.  vflag[] will
+    be filled with the vertical subdivisions.
+Effects:  fills hflag[] with the starting column for each subdivision.
+     The last element of the array is actually the pixel immediately 
+     following the last  subdivision.  The last subdivision contains any 
+     remaining pixels that did not divide evenly amongst the divisions.
+     vflag[NumHorizDiv] is comparable for vertical supdivisions.
+     Example ful = (0,25) flr = (52,46) NumHorizDiv = NumVertDiv = 5
+         hflag[6] = { 0,10,20,30,40,53 }
+	 vflag[6] = {25.29.33.37.41.47 } 
+Constraints: ful and flr must be set to mark the bounding box before
+   calling this procedure.
+Rev:  10/27 KM
+---------------------------------------------------------------*/
+{
+  int ulx = ful.x();  int uly = ful.y();
+  int lrx = flr.x();  int lry = flr.y();
+
+  int width =  lrx - ulx+1;
+  int height = lry - uly+1;
+
+  int horizDiv = width/NumHorizDiv;
+  int vertDiv = height/NumVertDiv;
+
+  int horizExtra = width - horizDiv*NumHorizDiv;
+  int vertExtra = height - vertDiv*NumVertDiv;
+
+  int i, add;
+  for (i = 0; i < NumHorizDiv; i++)
+    {
+    if(horizExtra - i > 0) add = i; else add = horizExtra;
+    hflag[i] = ulx + (i*horizDiv)+ add;
+  }
+  hflag[i] = lrx + 1;              // Closes off last division
+
+  int j;
+  for(j = 0; j < NumVertDiv; j ++)
+      {
+    if(vertExtra - j > 0) add = j; else add = vertExtra;
+    vflag[j] = uly + (j*vertDiv)+ add;
+  }
+  vflag[j] = lry + 1;
+
+    
+
+
+}
+
+
+Distance Component::distance(Component * comp) 
+/*--------------------------------------------------------------
+Primary Purpose: Determines heuristic distance between two components
+Arguments:  Another component to compare
+Return Value: integer value which represents the distance between two 
+   components. Distance = sum over i of
+                       weight *square (this->fproperty[i] - comp->fproperty[i])
+		       weight for i == 26, 27 is 3 weight is 1 for all other 
+		       properties
+Constraints: setProperties must have been run on both components
+
+Rev: 11/1 KM
+---------------------------------------------------------------*/
+{
+  Property * a = fproperty;
+  Property * b = comp->properties();
+  Distance dist=0;
+  int dif=0;
+  int worst = 0;
+  int weight = 1;
+
+  for(int i= 0; i < numProperties; i++)
+    { 
+
+      if(i == 27) weight = 50;
+     if (i == 28) weight = 3;
+     else if(i != 27 && i != 28)
+       weight = 1;
+     
+       dif = (a[i] - b[i]);      
+      dist += weight*dif*dif;
+    }
+
+  return dist;
+}
+
+
+
+
+
+
+
+
+
+void printVector(short int vector[], int size)
+{
+  for (int i = 0; i < size; i++)
+    cout << vector[i] << " " ;
+  cout << endl;
+
+}
+
+
+void testProperties(Component* c, BitMap * map)
+{
+  short int hflag[NumHorizDiv + 1];  // flags horizontal section dividers
+  short int vflag[NumVertDiv + 1];   // flags vertical section dividers
+
+  cout << "First test subDivisions  " << endl;
+  c->setSectionFlags(hflag, vflag);
+  cout << "Horizontal flags" <<endl;
+  printVector(hflag, NumHorizDiv + 1);
+  cout << "Vertical flags" <<endl;
+  printVector(vflag, NumHorizDiv + 1);
+
+  cout << "Now lets look at the properties " << endl;
+  // setSectionFlags will actually get called again within setProperties
+  c->setProperties(map);
+  printVector(c->properties(), NumHorizDiv*NumVertDiv + 1);
+  cout << endl << " The distance of this component from itself: " << " ";
+  cout << c->distance(c) << endl;
+
+}
+
+void Component::display_bounding_box()
+{
+  display_bounding_box("blue");
+}
+
+void Component::display_bounding_box(char * color)
+{
+  if(global_page == active_page)
+    {
+      display_bounding_box(color, SCALE_FACTOR, 
+		       ".main_window.display.work_space");
+    }
+}
+
+void Component::display_bounding_box(char * color, double scaleFactor, 
+				     char * window)
+{
+  int ulx = (ul()).x();
+  int uly = (ul()).y();
+  int lrx = (lr()).x();
+  int lry = (lr()).y();
+  scale(ulx,scaleFactor); scale(uly,scaleFactor); scale(lrx,scaleFactor); 
+  scale(lry,scaleFactor);
+  
+  if(ENABLE_USER_INTERFACE)
+    docommand("%s create rectangle %d %d %d %d -outline %s -tags IMAGE_TAG ",  window, ulx, uly, lrx, lry, color);
+}  
+
+
+Distance Component::recognize(Component * learnedchars)
+// This is out of date. Current recognize is below
+{
+  Distance d, nextd;
+  char id;
+
+
+//  printf("Another call to recognize\n");
+  d = (256*256)*numProperties;  // this is the biggest distance
+                        
+
+	       
+    for (int i = 0; i < 256; i++)
+	{
+	  if(learnedchars[i].confid() != 0)
+	      {
+		nextd = distance(&learnedchars[i]);
+//		printf("Distance = %d, character = %c\n", nextd, i);
+		if (nextd < d)
+		    {
+		      d = nextd;
+		      id = (char) i;
+		    }
+	      }
+	  
+	}
+  
+  fasciiId = &id;
+  /*  printf("Recognized a Component: %c\n", id); */
+  return d;
+}
+
+
+Distance Component::recognize(Components * learnedgroups, bool allGroups)
+{
+  Distance d, worstDistance,nextd;
+  char * id;
+  short int fontid;
+  float tempd;
+  worstDistance = 150000;
+
+//  printf("Another call to new recognize\n");
+  d = (65536)*numProperties;  // this is the biggest distance
+  
+                        
+    fconfid = 0;
+
+    for(int g = 0; g < NumCharGroups &&
+ 	((fconfid < ConfidenceThreshold) || allGroups); g++)
+    {
+      int offset = (charGroup+g) % NumCharGroups;
+      //      if (offset == 4 && charGroup != 4) continue;
+      for (ListElement* ptr = learnedgroups[offset].first; ptr != NULL;
+	 ptr = ptr->next)
+	{
+	  Component * item = (Component *) ptr->item;
+	  nextd = distance(item);
+//	  printf("Distance = %d, character = %c\n", nextd, i);
+	  if (nextd < d)
+	      {
+		d = nextd;
+		id = item->fasciiId;
+		fontid = item->ffontId;
+	      }
+
+	}
+
+      if (d >= worstDistance) 
+	  tempd = worstDistance - 1;
+      else tempd = d;
+	
+	fconfid = (unsigned short int)
+	  (255 - (tempd/worstDistance)*256);
+      if(charGroup == 4) break;  // dont check other groups for floaters
+    }
+  
+
+  fasciiId = new char[strlen(id)+1];
+  strcpy(fasciiId,id);
+
+
+  ffontId = fontid;
+  //printf("Recognized a Component: %s confid-%d dist-%u h/wratio %u\n", 
+  //	 id,  fconfid, d, property(27));
+
+
+
+  return d;
+}
+
+
+
+int Component::vertShrink(BitMap * bitmap)
+{
+  int r;
+  int shrunk = 0;
+	for(r = ful.y(); r < flr.y(); r++)
+	      if (pixelsBetween(bitmap->row(r), ful.x(), flr.x()))
+		  {
+		    ful.y() = r;
+		    shrunk = 1;
+		    break;
+		  }
+	for(r = flr.y(); r > ful.y(); r--)
+	      if (pixelsBetween(bitmap->row(r), ful.x(), flr.x()))
+		  {
+		    flr.y() = r;
+		    shrunk = 1;
+		    break;		    
+		  }
+		
+  return shrunk;
+}
+
+
+int Component::horizontalShrink(BitMap * bitmap)
+{
+  int c;
+  int shrunk = 0;
+	for(c = ful.x(); c < flr.x(); c++)
+	      if (bitmap->pixelsInRegion( Point(c, ful.y()), 
+					  Point(c, flr.y())))
+		  {
+		    if (ful.x() != c)
+		      shrunk = 1;
+		    ful.x() = c;
+		    break;
+		  }
+
+	// now start from the other side
+	for(c = flr.x(); c > ful.x(); c--)
+	      if (bitmap->pixelsInRegion( Point(c, ful.y()), 
+					  Point(c, flr.y())))
+		  {
+		    if (flr.x() != c)
+		      shrunk = 1;
+		    flr.x() = c;
+		    break;
+		  }
+
+		
+  return shrunk;
+}
+
+
+
+
+
+
+void Component::join(Component * comp)
+{
+
+  display_bounding_box("white");
+  comp->display_bounding_box("white");
+
+  ful.x() = ((ful.x() < comp->ul().x()) ? ful.x() : comp->ul().x());
+  ful.y() = ((ful.y() < comp->ul().y()) ? ful.y() : comp->ul().y());
+
+  flr.x() = ((flr.x() > comp->lr().x()) ? flr.x() : comp->lr().x());
+  flr.y() = ((flr.y() > comp->lr().y()) ? flr.y() : comp->lr().y());
+  display_bounding_box("blue");
+
+}
+
+
+
+
+
+
+
+
+
+