--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/reference/ocr-new/RLEMap.cc Thu May 18 23:12:51 2006 +0200
@@ -0,0 +1,578 @@
+#include "system.h"
+#include "RLEMap.h"
+#include "RLEPair.h"
+#include "tcl_interface.h"
+#include "status_message.h"
+
+ /* *****************************************************************
+ * RLEMap.cc - Member functions for an RLEMap *
+ *
+ * RLEMap() - Constructor
+ * ~RLEMap() - Destructor
+ *
+ * int imageLength();
+ * int imageWidth();
+ * MapStatus & status;
+ *
+ * Below is an index of the other functions and the files where they
+ * appear.
+ *
+ * MapStatus readMap(char * filename) - RLEMap_readMap.cc
+ * MapStatus WriteMap(char * filename);
+ *
+ * // Data Access and low level manipulation functions
+ * RLEPairs * row(int i) - Returns a pointer to the list of RLEPairs
+ * for row i.
+ * MapStatus setBit(Point point, Color clr);
+ * Color readBit(Point point);
+ *
+ *
+ ***************************************************************/
+
+RLEMap::RLEMap()
+: fMapData(NULL), fImageLength(0), fImageWidth(0), fStatus(EMPTY)
+/*--------------------------------------------------------------
+Primary Function: Constructor
+Return Value: pointer to new RLEMap
+Effects: Initialize status to empty other values to zero
+Rev: 10/6/95 KM
+---------------------------------------------------------------*/
+{ }
+
+
+
+ RLEMap::~RLEMap()
+/*--------------------------------------------------------------
+Primary Purpose: destructor
+Effects: Deletes each row of RLEPairs then the array of rows
+Rev: 10/6/95 KM
+---------------------------------------------------------------*/
+{
+ if (fMapData != NULL)
+ {
+ int i;
+
+
+ // delete each row
+ for (i=0; i< fImageLength; i++)
+ {
+ delete fMapData[i];
+ }
+ // delete array of rows
+ delete fMapData;
+ }
+};
+
+int & RLEMap::imageLength()
+/*--------------------------------------------------------------
+Return Value: vertical length of image in pixels
+Constraints: readMap() must have been run and fStatus be VALID
+Rev: 10/6 KM
+---------------------------------------------------------------*/
+ {
+ return fImageLength;
+
+};
+
+
+int & RLEMap::imageWidth()
+/*--------------------------------------------------------------
+Return Value: horizontal width of image in pixels
+Constraints: readMap() must have been run and fStatus be valid
+Rev: 10/20 KM
+---------------------------------------------------------------*/
+{
+ return fImageWidth;
+
+}
+
+
+MapStatus & RLEMap::status()
+/*--------------------------------------------------------------
+Return Value: return reference to current status EMPTY, VALID etc..
+Rev: 10/6/95 KM
+---------------------------------------------------------------*/
+{
+ return fStatus;
+
+}
+
+
+
+RLEPairs * RLEMap::operator [](int i)
+/*--------------------------------------------------------------
+Arguments: i is the row # of the RLEPair list to be returned
+Return Value: A pointer to the list of RLEPairs in row i
+Rev: 10/20/95 KM
+---------------------------------------------------------------*/
+{
+
+ return fMapData[i];
+}
+
+
+RLEPairs * RLEMap::row(int i)
+// Same as overloaded [] function above
+{
+ return fMapData[i];
+}
+
+
+
+MapStatus RLEMap::readMap(char * filename)
+/*--------------------------------------------------------------
+Primary Purpose: Read an RLEMap from a TIFF file
+Arguments: filename of TIFF file
+Return Value: A MapStatus, either VALID or READERROR
+Effects:
+ * RLEMap::readMap(filename) will read a two level TIFF file
+ * and place it in an RLEMap. The private fields of the RLEMap
+ * set are:
+ fImageWidth - the pixel width of the image
+ fImageLength - the vertical pixel length of the image
+ fstat - the status of the image VALID or READERROR
+ fMapData - an array of pointers to lists of RLEPairs
+Constraints: filename must be a two level TIFF file
+Rev: 10/20/95 Portions Borrowed from Assignment 1
+---------------------------------------------------------------*/
+{
+ TIFF *tif;
+ unsigned char * buf;
+ short photometric;
+
+ // Open File - Read length and width
+
+ tif = TIFFOpen (filename, "r");
+ if(tif == NULL)
+ return READERROR;
+
+ TIFFGetField (tif, TIFFTAG_IMAGELENGTH, &fImageLength);
+ TIFFGetField (tif, TIFFTAG_IMAGEWIDTH, &fImageWidth);
+ TIFFGetField (tif, TIFFTAG_PHOTOMETRIC, &photometric);
+
+ printf("open succeeded on file %s. length = %d. width = %d ",
+ filename, fImageLength, fImageWidth);
+ if(photometric == PHOTOMETRIC_MINISWHITE)
+ printf("min-is-white format\n");
+ else if(photometric == PHOTOMETRIC_MINISBLACK )
+ printf("min-is-black format\n");
+ else
+ printf("with an unknown photometric: %d\n", photometric);
+
+ // allocate buffer and array for data
+ int numCharsInBuf = fImageWidth / 8 +1 ;
+ buf = new unsigned char[numCharsInBuf];
+ fMapData = new (RLEPairs*)[fImageLength+1];
+
+ for (int row = 0; row < fImageLength; ++row)
+ {
+ TIFFReadScanline(tif,buf,row,0);
+ if(photometric != PHOTOMETRIC_MINISWHITE) /* invert anything except white */
+ invertBitsInBuffer(buf, numCharsInBuf);
+ if(row==0 || row == fImageLength -1)
+ clearBitsInBuffer(buf,numCharsInBuf);
+ // Create a list of RLEPairs for this row and fill with buffer data
+ fMapData[row] = new RLEPairs(row);
+ fMapData[row]->fill(buf, numCharsInBuf, row);
+ }
+
+ TIFFClose(tif);
+
+ return VALID;
+}
+
+short int RLEMap::grayScale(Point ul, Point lr)
+// Dummy function for now
+{
+ int numPixels = pixelsInRegion( ul, lr);
+ int area = (lr.x() - ul.x()+1) * (lr.y() - ul.y()+1);
+ if (area < numPixels) {
+ printf("Uh oh! Area = %d and pixels = %d\n", area, numPixels);
+ assert(area >= numPixels);
+ }
+ short int gscale =(short int)(((float)numPixels/area) * 255);
+
+ return gscale;
+ }
+
+int RLEMap::pixelsInRegion(Point ul, Point lr)
+{
+ assert (ul >= Point(0,0));
+ assert (ul <= lr);
+ assert (lr <= Point(fImageWidth, fImageLength));
+
+ int ulx = ul.x(); int uly = ul.y();
+ int lrx = lr.x(); int lry = lr.y();
+ int numPixels = 0;
+ RLEPairs * curRow;
+
+ for (int r = uly; r <= lry; r++)
+ {
+ curRow = row(r);
+ numPixels += curRow->pixelsBetween(ulx, lrx);
+// cout << curRow->pixelsBetween(ulx,lrx) <<" ";
+ // cout << numPixels << endl;
+ }
+
+ return numPixels;
+
+}
+
+ListElement*
+RLEMap::FindNearVertDot(int startCol, int endCol, int startRow, int endRow)
+/*--------------------------------------------------------------
+Primary Purpose: Return closest interval to startRow within bounds of
+ startCol and endRow in the direction of endRow. Finds
+ closest dot vertically from startRow.
+Arguments: startRow is row to start from, startCol and endCol are
+ left and right boundaries of search. Search in the direction
+ of endRow.
+Return Value: An RLE interval - pointer to a list element in RLEPairs
+Effects:
+Constraints: startRow < endRow
+---------------------------------------------------------------*/
+{
+ ListElement* current;
+ if (startRow < endRow) {
+ for (int i = startRow+2; i <= endRow; i++) {
+ current = fMapData[i]->first;
+ while (current != NULL) {
+ if ((((RLEPair *) current->item)->start <= endCol)
+ && (((RLEPair *) current->item)->end >= startCol))
+ return current;
+ current = current->next;
+ }
+ }
+ } else {
+ for (int i = startRow-2; i >= endRow; i--) {
+ current = fMapData[i]->first;
+ while (current != NULL) {
+ if ((((RLEPair *) current->item)->start <= endCol)
+ && (((RLEPair *) current->item)->end >= startCol))
+ return current;
+ current = current->next;
+ }
+ }
+ }
+ return NULL;
+}
+
+
+
+
+
+ListElement*
+RLEMap::FindNearHorizDot(int startCol, int startRow, int endRow)
+/*--------------------------------------------------------------
+Primary Purpose: Return closest interval to startCol within bounds of
+ startRow and endRow (startRow is lower). Finds
+ closest dot horizontally from startCol.
+Arguments: startCol is column to start from, startRow and endRow are
+ upper and lower boundaries of search
+Return Value: An RLE interval - pointer to a list element in RLEPairs
+Effects:
+Constraints: startRow < endRow
+---------------------------------------------------------------*/
+{
+ ListElement* answer = NULL;
+ ListElement* current;
+ int closest = fImageWidth;
+
+ for (int i = startRow; i <= endRow; i++) {
+ current = fMapData[i]->first;
+ while ((current != NULL) && (((RLEPair *) current->item)->end
+ < startCol)) {
+ current = current->next;
+ }
+ if ((current != NULL) && (((RLEPair *) current->item)->start < closest)) {
+ answer = current;
+ closest = ((RLEPair *) answer->item)->start;
+ }
+ }
+ return answer;
+}
+
+
+
+
+void testRLEMap(char * filename)
+/*--------------------------------------------------------------
+Primary Purpose: Test the reading of tiff files into RLE format
+Effects: Reads filename, puts it into RLE format then prints
+Rev: 10/7/95 KM
+---------------------------------------------------------------*/
+{
+ RLEMap m;
+
+ m.readMap(filename);
+ if (m.imageLength() < 100) printMap(&m);
+ testpixelsBetween(&m); // In RLEPairs.cc - tests pixelsBetween function
+}
+
+
+void printMap(RLEMap * map)
+{
+ int startX = 0;
+ int endX = 0;
+ int pos;
+ RLEPair * item;
+ RLEPairs * rowdata;
+
+ RLEMap & m = *map;
+
+ for (int r = 0; r < m.imageLength(); r++)
+ {
+ startX = 0;
+ endX = -1;
+ rowdata = m[r];
+
+ for (ListElement* ptr = rowdata->first; ptr != NULL; ptr = ptr->next)
+ {
+ item = (RLEPair *)(ptr->item);
+ startX = item->start;
+ for ( pos = endX+1; pos< startX; pos++)
+ cout << " ";
+ endX = item->end;
+ for ( pos = startX; pos <= endX; pos++)
+ cout << "X";
+ }
+ cout << "" << endl;
+ }
+
+}
+
+void RLEMap::printPairs(int startRow, int endRow)
+/*--------------------------------------------------------------
+Primary Purpose: Prints RLE Pairs for this map from startRow to endRow
+Rev:11/2 KM
+---------------------------------------------------------------*/
+{
+ int startX, endX;
+ RLEPair * item;
+ RLEPairs * rowdata;
+
+ RLEMap & m = *this;
+ cout << "printing rows " << startRow << " to " << endRow << endl;
+ for (int r = startRow; r <= endRow; r++)
+ {
+ rowdata = m[r];
+
+ cout << "row " << r << " ";
+
+ for (ListElement *ptr = rowdata->first; ptr != NULL; ptr = ptr->next)
+ {
+ item = (RLEPair *)(ptr->item);
+ startX = item->start;
+ endX = item->end;
+ cout << "(" << startX << "," << endX <<")";
+ }
+ cout << endl;
+ }
+}
+
+void testpixelsBetween(RLEMap * map)
+// tests out a row by making sure that pixels between
+// 0 and ImageWidth - 1 == pixels in sub ranges of 29 pixels
+// Test performed on center row.
+{
+ int start = 0;
+ int end = 28;
+
+ int pcount;
+ int sum = 0;
+ RLEPairs * pairs;
+ int row;
+
+ for (row = 0; row < map->imageLength(); row++)
+ {
+ pairs = (*map)[row];
+ while (start <= map->imageWidth())
+ {
+ pcount = pairs->pixelsBetween(start, end);
+// printf("row %d col %d to %d - %d pixels\n",row, start,end,pcount);
+ sum += pcount;
+ start +=29;
+ end +=29;
+ }
+ if (sum !=0)
+ printf("row %d sum was %d , should be %d\n", row, sum, pairs->numPixels);
+ assert(sum == pairs->numPixels);
+ start = 0;
+ end = 28;
+ sum = 0;
+ }
+
+ delete pairs;
+}
+
+int RLEMap::deskew()
+/* going to be a (near-blind) steal from fateman */
+/*--------------------------------------------------------------
+Primary Purpose: deskewing an RLEMap
+Arguments: none
+Return Value: 1 if the page is altered, 0 if not
+Effects: RLEMap is straightened out
+Constraints: RLE shouldn't be tilted too much (< 10deg)
+Rev: AR 11/1/95
+---------------------------------------------------------------*/
+{
+ double skew = -get_skew(this); /* skew in rad */
+ if((skew >= MINIMUM_SKEW_ANGLE)||(skew <= - MINIMUM_SKEW_ANGLE))
+ {
+ double h = tan(skew / (180 / M_PI));
+ if(h > 0)
+ {
+ tilt_and_slant(1/h, 1); /* clockwise */
+ return 1;
+ }
+ else if (h < 0)
+ {
+ tilt_and_slant(-(1/h), -1); /* counter clockwise */
+ return 1;
+ }
+ else
+ return 0;
+ }
+ else
+ return 0;
+}
+
+#define DEBUG_TILT_AND_SLANT 1
+void RLEMap::tilt_and_slant(double step, int direction)
+/*--------------------------------------------------------------
+Primary Purpose: do the work of shifting the RLEMap
+Arguments: step--something about how many rows to go before shifting,
+ direction--counterclockwise or clockwise
+Return Value: none
+Effects: rotates the RLEMap some ammount by tilting the map slightly,
+ then slanting it. (duh). Not an exact rotation
+Constraints:
+Rev: AR 11/1/95
+---------------------------------------------------------------*/
+{
+ if(DEBUG_TILT_AND_SLANT)
+ printf("Call to tilt_and_slant: step = %lf, direction = %d\n ", step, direction);
+ if(direction > 0)
+ {
+ tilt(step, direction);
+ slant(step, direction);
+ }
+ else
+ {
+ slant(step, -direction);
+ tilt(step, direction);
+ }
+}
+
+#define DEBUG_SLANT 1
+/* "slant a picture by shifting lines horizontally 1 bit every step rows"
+ ;; dir 1 means shift to right as row number increases
+ ;; dir -1 means shift by left
+ ;; this does not rotate the picture, since rows are each unchanged.
+ ;; the effect of a positive direction, say (slantpic pic 3 3 1)
+ ;; is to "italicize".
+*/
+void RLEMap::slant(double step, int direction)
+{
+ if(DEBUG_SLANT)
+ printf("Slant called, step = %lf, dir = %d\n", step, direction);
+ fImageWidth += (int)((double)fImageLength / (double)step);
+ int shift_amount = direction;
+ int num_steps = 1;
+ for(int i = 0; i < fImageLength; i++)
+ {
+ if(i > (num_steps*(int)step))
+/* if we have gone through step rows, increment the shift */
+ {
+ shift_amount += direction;
+ num_steps++;
+ }
+/* printf("Shifting row %d by %d\n", i, shift_amount); */
+ fMapData[i]->shift(shift_amount);
+ }
+}
+
+
+void RLEMap::display_intervals(char* color)
+{
+ display_intervals(".main_window.display.work_space", SCALE_FACTOR, color);
+}
+
+void RLEMap::display_intervals(char* window, double scaleFactor, char * color)
+{
+ assert(scaleFactor > 0);
+ if(!DISPLAY_IMAGE)
+ return;
+ double skip;
+ last_status = 0.0;
+ printf("scaleFactor = %lf ", scaleFactor);
+ skip = 1.0 / scaleFactor;
+ printf("Skip = %lf\n", skip);
+
+ /* delete any garbage hanging around */
+ docommand("%s delete all", window);
+
+ set_status("Displaying Image: 0%...");
+ for (int i = 0, j= 0; i < fImageLength;i= int(j * skip), j++)
+ {
+
+ set_display_status((int)(i*skip), fImageLength);
+ fMapData[i]->draw_pairs(window, scaleFactor,
+ i, color, 1.0/skip);
+
+
+ }
+
+ last_status = 0.0;
+ update();
+ set_status("Displaying Image: Done");
+}
+
+void RLEMap::tilt(double step, int direction)
+{
+/* printf("tilt called, step = %lf, dir = %d\n", step, direction); */
+ int old_height = fImageLength;
+ int new_height = /* ceiling */ (int)(((double)fImageWidth) / step) + old_height;
+ int delta = old_height - new_height;
+ RLEPairs ** new_data = new RLEPairs*[new_height];
+ for(int i = 0; i < new_height; i++)
+ {
+ new_data[i] = new RLEPairs(i);
+ }
+ for(int j = 0; j < old_height; j++)
+ {
+ tilt_row(j, delta, new_data, step, direction);
+ }
+ fMapData = new_data; /* probably want to delete old data */
+ fImageLength = new_height;
+ display_intervals("black");
+}
+
+
+void RLEMap::tilt_row(int old_row_index, int old_new_row_diff, RLEPairs** new_data, double step, int direction)
+{
+/* printf("Tilt row called: old row = %d, row diff = %d, step = %lf, dir = %d\n", old_row_index, old_new_row_diff, step, direction); */
+
+ double cur_x = 0; /* I don't know what will happen with negative rows */
+ double new_x;
+ int cur_y = old_row_index + (old_new_row_diff * direction);
+
+ while(((new_x = cur_x + step) < fImageWidth) &&
+ (cur_y >= 0) && (cur_y < fImageLength))
+ {
+ RLEPairs* new_pairs;
+ new_pairs = (fMapData[old_row_index])->extract((int) cur_x, (int)new_x);
+ new_data[cur_y]->merge(new_pairs);
+ cur_x = new_x + 1;
+ cur_y += direction;
+ }
+}
+
+
+
+
+
+
+
+
+