--- /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");
+
+}
+
+
+
+
+
+
+
+
+
+