--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/reference/ocr-simple/Component.cc Thu May 18 23:12:51 2006 +0200
@@ -0,0 +1,476 @@
+#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
+***/
+
+
+Components::Components()
+:List()
+{
+}
+
+
+Components::~Components()
+{
+ for (ListElement *ptr = first; ptr != NULL; ptr = ptr->next) {
+ if (ptr->item != NULL)
+ delete (Component *) (ptr->item);
+ }
+ while(!IsEmpty())
+ Remove();
+
+}
+
+
+int Component::AddToComponent(ListElement* intrvl, RLEMap* rlemap)
+//this needs to be fixed to trap page boundaries
+//or else pad the page with a blank line at top and bottom
+{
+ 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;
+
+ while ((intrvl = list->first) != NULL) //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+MinHorizSeparation)) {
+
+// 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+MinHorizSeparation)) {
+// 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 be 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 26 is height/width ratio 255 if height > width.
+ These values are put into fProperty array in this component.
+ Property 27 is 255 if the component is vertically disjoint like i or ;
+ or 0 if it is not.
+ 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 == 27, 28 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 || i == 28) weight = 3;
+ else 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()
+{
+ int ulx = (ul()).x();
+ int uly = (ul()).y();
+ int lrx = (lr()).x();
+ int lry = (lr()).y();
+ scale(ulx); scale(uly); scale(lrx); scale(lry);
+
+ docommand(".main_window.display.work_space create rectangle %d %d %d %d -outline blue -tags IMAGE_TAG", ulx, uly, lrx, lry);
+}
+
+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 = id;
+
+
+ ffontId = fontid;
+// printf("Recognized a Component: %c in font#%d %d %u\n",
+// id, fontid, fconfid, d);
+
+
+
+ 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;
+ }
+
+
+
+