reference/ocr-simple/RLEMap.cc
changeset 0 6b8091ca909a
equal deleted inserted replaced
-1:000000000000 0:6b8091ca909a
       
     1 #include "system.h"
       
     2 #include "RLEMap.h"
       
     3 #include "RLEPair.h"
       
     4 #include "tcl_interface.h"
       
     5 #include "status_message.h"
       
     6 
       
     7  /* *****************************************************************
       
     8   * RLEMap.cc - Member functions for an RLEMap                      *
       
     9   *         
       
    10   *	RLEMap() - Constructor
       
    11   *     ~RLEMap() - Destructor
       
    12   *
       
    13   *	int imageLength();
       
    14   *	int imageWidth();
       
    15   *	MapStatus & status;
       
    16   *  
       
    17   * Below is an index of the other functions and the files where they 
       
    18   * appear.  
       
    19   *
       
    20   *   	MapStatus readMap(char * filename) - RLEMap_readMap.cc
       
    21   *	MapStatus WriteMap(char * filename);
       
    22   *
       
    23   *	// Data Access and low level manipulation functions  
       
    24   *     RLEPairs * row(int i) - Returns a pointer to the list of RLEPairs
       
    25   *     for row i.                       
       
    26   *     MapStatus setBit(Point point, Color clr);
       
    27   *	Color readBit(Point point);
       
    28   *
       
    29   *
       
    30    ***************************************************************/
       
    31 
       
    32 RLEMap::RLEMap()
       
    33 : fMapData(NULL), fImageLength(0), fImageWidth(0), fStatus(EMPTY)
       
    34 /*--------------------------------------------------------------
       
    35 Primary Function: Constructor
       
    36 Return Value: pointer to new RLEMap
       
    37 Effects: Initialize status to empty other values to zero
       
    38 Rev: 10/6/95  KM
       
    39 ---------------------------------------------------------------*/
       
    40 { }
       
    41 
       
    42 
       
    43 
       
    44  RLEMap::~RLEMap()
       
    45 /*--------------------------------------------------------------
       
    46 Primary Purpose: destructor
       
    47 Effects: Deletes each row of RLEPairs then the array of rows
       
    48 Rev: 10/6/95   KM
       
    49 ---------------------------------------------------------------*/
       
    50 {
       
    51   if (fMapData != NULL)
       
    52     {
       
    53       int i;
       
    54 
       
    55 
       
    56       // delete each row
       
    57       for (i=0; i< fImageLength; i++)
       
    58 	  {
       
    59 	    delete fMapData[i];
       
    60 	  }
       
    61       // delete array of rows
       
    62         delete fMapData;   
       
    63     }
       
    64 };
       
    65 
       
    66 int & RLEMap::imageLength()
       
    67 /*--------------------------------------------------------------
       
    68 Return Value: vertical length of image in pixels
       
    69 Constraints: readMap() must have been run and fStatus be VALID
       
    70 Rev: 10/6 KM
       
    71 ---------------------------------------------------------------*/
       
    72   {
       
    73   return fImageLength;
       
    74 
       
    75 };
       
    76 
       
    77 
       
    78 int & RLEMap::imageWidth()
       
    79 /*--------------------------------------------------------------
       
    80 Return Value: horizontal width of image in pixels
       
    81 Constraints: readMap() must have been run and fStatus be valid
       
    82 Rev: 10/20 KM
       
    83 ---------------------------------------------------------------*/
       
    84 {
       
    85   return fImageWidth;
       
    86 
       
    87 }
       
    88 
       
    89 
       
    90 MapStatus & RLEMap::status()
       
    91 /*--------------------------------------------------------------
       
    92 Return Value: return reference to current status EMPTY, VALID etc..
       
    93 Rev: 10/6/95 KM
       
    94 ---------------------------------------------------------------*/
       
    95 {
       
    96   return fStatus;
       
    97 
       
    98 }
       
    99 
       
   100 
       
   101 
       
   102 RLEPairs *  RLEMap::operator [](int i)
       
   103 /*--------------------------------------------------------------
       
   104 Arguments: i is the row # of the RLEPair list to be returned
       
   105 Return Value: A pointer to the list of RLEPairs in row i
       
   106 Rev:  10/20/95 KM
       
   107 ---------------------------------------------------------------*/
       
   108 {
       
   109 
       
   110   return fMapData[i];
       
   111 }
       
   112 
       
   113 
       
   114 RLEPairs * RLEMap::row(int i)
       
   115 // Same as overloaded [] function above
       
   116 {
       
   117   return fMapData[i];
       
   118 }
       
   119 
       
   120 
       
   121 
       
   122 MapStatus RLEMap::readMap(char * filename)
       
   123 /*--------------------------------------------------------------
       
   124 Primary Purpose: Read an RLEMap from a TIFF file
       
   125 Arguments: filename of TIFF file
       
   126 Return Value: A MapStatus, either VALID or READERROR
       
   127 Effects:
       
   128   *  RLEMap::readMap(filename) will read a two level TIFF file
       
   129   *  and place it in an RLEMap.  The private fields of the RLEMap
       
   130   *  set are:
       
   131          fImageWidth - the pixel width of the image
       
   132 	 fImageLength - the vertical pixel length of the image
       
   133 	 fstat - the status of the image VALID or READERROR
       
   134          fMapData - an array of pointers to lists of RLEPairs
       
   135 Constraints: filename must be a two level TIFF file
       
   136 Rev: 10/20/95  Portions Borrowed from Assignment 1
       
   137 ---------------------------------------------------------------*/
       
   138 {
       
   139   TIFF *tif;
       
   140   unsigned char * buf;
       
   141   short photometric;
       
   142 
       
   143   // Open File - Read length and width
       
   144 
       
   145   tif = TIFFOpen (filename, "r");
       
   146   if(tif == NULL)
       
   147     return READERROR;
       
   148 
       
   149   TIFFGetField (tif, TIFFTAG_IMAGELENGTH, &fImageLength);
       
   150   TIFFGetField (tif, TIFFTAG_IMAGEWIDTH, &fImageWidth);
       
   151   TIFFGetField (tif, TIFFTAG_PHOTOMETRIC, &photometric);
       
   152   
       
   153   printf("open succeeded on file %s.  length = %d. width = %d ",
       
   154 	 filename, fImageLength, fImageWidth);
       
   155   if(photometric == PHOTOMETRIC_MINISWHITE)
       
   156     printf("min-is-white format\n");
       
   157   else if(photometric == PHOTOMETRIC_MINISBLACK )
       
   158     printf("min-is-black format\n");
       
   159   else
       
   160     printf("with an unknown photometric: %d\n", photometric);
       
   161 
       
   162   // allocate buffer and array for data
       
   163   int numCharsInBuf = fImageWidth / 8  +1 ;
       
   164   buf = new unsigned char[numCharsInBuf];
       
   165   fMapData = new (RLEPairs*)[fImageLength]; 
       
   166  
       
   167  for (int row = 0; row < fImageLength; ++row)
       
   168     {
       
   169       TIFFReadScanline(tif,buf,row,0);
       
   170       if(photometric != PHOTOMETRIC_MINISWHITE)  /* invert anything except white */
       
   171 	invertBitsInBuffer(buf, numCharsInBuf);
       
   172 
       
   173       // Create a list of RLEPairs for this row and fill with buffer data
       
   174       fMapData[row] = new RLEPairs(row);  
       
   175       fMapData[row]->fill(buf, numCharsInBuf, row);
       
   176     }
       
   177   TIFFClose(tif);
       
   178    
       
   179   return VALID;
       
   180 }
       
   181 
       
   182 short int RLEMap::grayScale(Point ul, Point lr)
       
   183 // Dummy function for now
       
   184 {
       
   185    int numPixels = pixelsInRegion( ul, lr);
       
   186    int area = (lr.x() - ul.x()+1) * (lr.y() - ul.y()+1);
       
   187    if (area < numPixels) {
       
   188      printf("Uh oh! Area = %d and pixels = %d\n", area, numPixels);
       
   189      assert(area >= numPixels);
       
   190    }
       
   191    short int gscale =(short int)(((float)numPixels/area) * 255);
       
   192    
       
   193    return gscale;
       
   194  }
       
   195 
       
   196 int RLEMap::pixelsInRegion(Point ul, Point lr)
       
   197 {
       
   198   assert (ul >= Point(0,0));
       
   199   assert (ul <= lr);
       
   200   assert (lr <= Point(fImageWidth, fImageLength));
       
   201 
       
   202   int ulx = ul.x(); int uly = ul.y();
       
   203   int lrx = lr.x(); int lry = lr.y();
       
   204   int numPixels = 0;
       
   205   RLEPairs * curRow;
       
   206 
       
   207   for (int r = uly; r <= lry; r++)
       
   208     {
       
   209       curRow = row(r);
       
   210       numPixels += curRow->pixelsBetween(ulx, lrx);
       
   211 //      cout << curRow->pixelsBetween(ulx,lrx) <<" ";
       
   212  //     cout << numPixels << endl;
       
   213     }
       
   214   
       
   215   return numPixels;
       
   216 
       
   217 }
       
   218 
       
   219 ListElement*
       
   220 RLEMap::FindNearVertDot(int startCol, int endCol, int startRow, int endRow) 
       
   221 /*--------------------------------------------------------------
       
   222 Primary Purpose: Return closest interval to startRow within bounds of
       
   223                  startCol and endRow in the direction of endRow. Finds
       
   224                  closest dot vertically from startRow.
       
   225 Arguments: startRow is row to start from, startCol and endCol are
       
   226            left and right boundaries of search. Search in the direction
       
   227 	   of endRow.
       
   228 Return Value: An RLE interval - pointer to a list element in RLEPairs 
       
   229 Effects:
       
   230 Constraints: startRow < endRow
       
   231 ---------------------------------------------------------------*/
       
   232 {
       
   233   ListElement* current;
       
   234   if (startRow < endRow) {
       
   235     for (int i = startRow+2; i <= endRow; i++) {
       
   236       current = fMapData[i]->first;
       
   237       while (current != NULL) {
       
   238 	if ((((RLEPair *) current->item)->start <= endCol)
       
   239 	    && (((RLEPair *) current->item)->end >= startCol))
       
   240 	  return current;
       
   241 	current = current->next;
       
   242       }
       
   243     }
       
   244   } else {
       
   245     for (int i = startRow-2; i >= endRow; i--) {
       
   246       current = fMapData[i]->first;
       
   247       while (current != NULL) {
       
   248 	if ((((RLEPair *) current->item)->start <= endCol)
       
   249 	    && (((RLEPair *) current->item)->end >= startCol))
       
   250 	  return current;
       
   251 	current = current->next;
       
   252       }
       
   253     }
       
   254   }
       
   255   return NULL;
       
   256 }
       
   257 
       
   258 
       
   259 
       
   260 
       
   261 
       
   262 ListElement*
       
   263 RLEMap::FindNearHorizDot(int startCol, int startRow, int endRow) 
       
   264 /*--------------------------------------------------------------
       
   265 Primary Purpose: Return closest interval to startCol within bounds of
       
   266                  startRow and endRow (startRow is lower). Finds
       
   267                  closest dot horizontally from startCol.
       
   268 Arguments: startCol is column to start from, startRow and endRow are
       
   269            upper and lower boundaries of search
       
   270 Return Value: An RLE interval - pointer to a list element in RLEPairs 
       
   271 Effects:
       
   272 Constraints: startRow < endRow
       
   273 ---------------------------------------------------------------*/
       
   274 {
       
   275   ListElement* answer = NULL;
       
   276   ListElement* current;
       
   277   int closest = fImageWidth;
       
   278 
       
   279   for (int i = startRow; i <= endRow; i++) {
       
   280     current = fMapData[i]->first;
       
   281     while ((current != NULL) && (((RLEPair *) current->item)->end 
       
   282 				 < startCol)) {
       
   283       current = current->next;
       
   284     }
       
   285     if ((current != NULL) && (((RLEPair *) current->item)->start < closest)) {
       
   286       answer = current;
       
   287       closest = ((RLEPair *) answer->item)->start;
       
   288     }
       
   289   }
       
   290   return answer;
       
   291 }
       
   292 
       
   293 
       
   294 
       
   295 
       
   296 void testRLEMap(char * filename)
       
   297 /*--------------------------------------------------------------
       
   298 Primary Purpose: Test the reading of tiff files into RLE format
       
   299 Effects:  Reads filename,  puts it into RLE format then prints
       
   300 Rev:  10/7/95 KM
       
   301 ---------------------------------------------------------------*/
       
   302 {
       
   303   RLEMap m;
       
   304 
       
   305   m.readMap(filename);
       
   306   if (m.imageLength() < 100)  printMap(&m);
       
   307   testpixelsBetween(&m);   // In RLEPairs.cc - tests pixelsBetween function
       
   308 }
       
   309 
       
   310 
       
   311 void printMap(RLEMap * map)
       
   312 {
       
   313   int startX = 0;
       
   314   int endX = 0;
       
   315   int pos;    
       
   316   RLEPair * item;
       
   317   RLEPairs * rowdata;
       
   318 
       
   319   RLEMap & m = *map;
       
   320 
       
   321   for (int r = 0; r < m.imageLength(); r++)
       
   322     {
       
   323       startX = 0;
       
   324       endX = -1;
       
   325       rowdata = m[r];
       
   326 
       
   327       for (ListElement* ptr = rowdata->first; ptr != NULL; ptr = ptr->next) 
       
   328 	{
       
   329 	  item = (RLEPair *)(ptr->item);
       
   330 	  startX = item->start;	  
       
   331 	  for ( pos = endX+1; pos< startX; pos++)
       
   332 	  cout << " ";
       
   333           endX = item->end;	  
       
   334 	  for ( pos = startX; pos <= endX; pos++)
       
   335 	    cout << "X";
       
   336 	}
       
   337       cout << "" << endl;
       
   338     }
       
   339 
       
   340 }
       
   341 
       
   342 void RLEMap::printPairs(int startRow, int endRow)
       
   343 /*--------------------------------------------------------------
       
   344 Primary Purpose: Prints RLE Pairs for this map from startRow to endRow  
       
   345 Rev:11/2 KM
       
   346 ---------------------------------------------------------------*/
       
   347 {
       
   348   int startX, endX;
       
   349   RLEPair * item;
       
   350   RLEPairs * rowdata;
       
   351 
       
   352   RLEMap & m = *this;
       
   353   cout << "printing rows " << startRow << " to " << endRow << endl;
       
   354   for (int r = startRow; r <= endRow; r++)
       
   355     {
       
   356       rowdata = m[r];
       
   357 
       
   358       cout << "row " << r << " ";
       
   359 
       
   360       for (ListElement *ptr = rowdata->first; ptr != NULL; ptr = ptr->next) 
       
   361 	{
       
   362 	  item = (RLEPair *)(ptr->item);
       
   363 	  startX = item->start;	  
       
   364 	  endX = item->end;
       
   365 	  cout << "(" << startX << "," << endX <<")";
       
   366 	}
       
   367       cout << endl;
       
   368     }
       
   369 }
       
   370 
       
   371 void testpixelsBetween(RLEMap * map)
       
   372 // tests out a row by making sure that pixels between 
       
   373 // 0 and ImageWidth - 1 == pixels in sub ranges of 29 pixels
       
   374 // Test performed on center row.
       
   375 {
       
   376   int start = 0;
       
   377   int end = 28;
       
   378 
       
   379   int pcount;
       
   380   int sum = 0;
       
   381   RLEPairs * pairs;
       
   382   int row;
       
   383 
       
   384   for (row = 0; row < map->imageLength(); row++)
       
   385     {
       
   386       pairs = (*map)[row];  
       
   387       while (start <= map->imageWidth())
       
   388 	{
       
   389 	  pcount = pairs->pixelsBetween(start, end);
       
   390 //	  printf("row %d col %d to %d - %d pixels\n",row, start,end,pcount);
       
   391 	  sum += pcount;
       
   392 	  start +=29;
       
   393 	  end +=29;
       
   394 	}
       
   395       if (sum !=0)
       
   396 	printf("row %d sum was %d , should be %d\n", row, sum, pairs->numPixels);
       
   397       assert(sum == pairs->numPixels);
       
   398       start = 0;
       
   399       end = 28;
       
   400       sum = 0;
       
   401     }
       
   402 
       
   403   delete pairs;
       
   404 }
       
   405 
       
   406 int RLEMap::deskew()
       
   407 /* going to be a (near-blind) steal from fateman */
       
   408 /*--------------------------------------------------------------
       
   409 Primary Purpose: deskewing an RLEMap
       
   410 Arguments: none 
       
   411 Return Value: 1 if the page is altered, 0 if not
       
   412 Effects: RLEMap is straightened out
       
   413 Constraints: RLE shouldn't be tilted too much (< 10deg)
       
   414 Rev: AR 11/1/95
       
   415 ---------------------------------------------------------------*/
       
   416 {
       
   417   double skew = -get_skew(this);  /* skew in rad */
       
   418   if((skew >= MINIMUM_SKEW_ANGLE)||(skew <= - MINIMUM_SKEW_ANGLE))
       
   419     {
       
   420       double h = tan(skew / (180 / M_PI));  
       
   421       if(h > 0)
       
   422 	  {
       
   423 	    tilt_and_slant(1/h, 1); /* clockwise */
       
   424 	    return 1;
       
   425 	  }
       
   426       else if (h < 0)
       
   427 	  {
       
   428 	    tilt_and_slant(-(1/h), -1); /* counter clockwise */
       
   429 	    return 1;
       
   430 	  }
       
   431       else
       
   432 	return 0;
       
   433     }
       
   434   else 
       
   435     return 0;
       
   436 }
       
   437 
       
   438 #define DEBUG_TILT_AND_SLANT 1
       
   439 void RLEMap::tilt_and_slant(double step, int direction)
       
   440 /*--------------------------------------------------------------
       
   441 Primary Purpose: do the work of shifting the RLEMap
       
   442 Arguments: step--something about how many rows to go before shifting,
       
   443            direction--counterclockwise or clockwise
       
   444 Return Value: none
       
   445 Effects: rotates the RLEMap some ammount by tilting the map slightly,
       
   446         then slanting it. (duh). Not an exact rotation
       
   447 Constraints:
       
   448 Rev: AR 11/1/95
       
   449 ---------------------------------------------------------------*/
       
   450 {
       
   451   if(DEBUG_TILT_AND_SLANT)
       
   452     printf("Call to tilt_and_slant: step = %lf, direction = %d\n ", step, direction);
       
   453   if(direction > 0)
       
   454     {
       
   455       tilt(step, direction);  
       
   456       slant(step, direction);
       
   457     }
       
   458   else
       
   459     {
       
   460       slant(step, -direction);
       
   461       tilt(step, direction); 
       
   462     }
       
   463 }     
       
   464 
       
   465 #define DEBUG_SLANT 1
       
   466 /*  "slant a picture by shifting lines horizontally 1 bit every step rows"
       
   467   ;; dir 1 means shift to right as row number increases
       
   468   ;; dir -1 means shift by left
       
   469   ;; this does not rotate the picture, since rows are each unchanged.
       
   470   ;; the effect of a positive direction, say (slantpic pic 3 3 1)
       
   471   ;; is to "italicize".
       
   472 */  
       
   473 void RLEMap::slant(double step, int direction)
       
   474 {
       
   475   if(DEBUG_SLANT)
       
   476     printf("Slant called, step = %lf, dir = %d\n", step, direction);
       
   477   fImageWidth += (int)((double)fImageLength / (double)step);
       
   478   int shift_amount = direction;
       
   479   int num_steps = 1;
       
   480   for(int i = 0; i < fImageLength; i++)
       
   481       {
       
   482 	if(i > (num_steps*(int)step))  
       
   483 /* if we have gone through step rows, increment the shift */
       
   484 	    {
       
   485 	      shift_amount += direction;
       
   486 	      num_steps++;
       
   487 	    }
       
   488 /*	printf("Shifting row %d by %d\n", i, shift_amount);  */
       
   489 	fMapData[i]->shift(shift_amount);
       
   490       }
       
   491 }
       
   492 
       
   493 
       
   494 
       
   495 void RLEMap::display_intervals(char* color)
       
   496 {
       
   497   if(!DISPLAY_IMAGE)
       
   498     return;
       
   499   double skip;
       
   500   last_status = 0.0;
       
   501   printf("SCALE_FACTOR = %lf  ", SCALE_FACTOR);
       
   502   skip = 1.0 / SCALE_FACTOR;
       
   503   printf("Skip = %lf\n", skip);
       
   504 
       
   505   /* delete any garbage hanging around */
       
   506   docommand(".main_window.display.work_space delete all");
       
   507 
       
   508   set_status("Displaying Image: 0%...");
       
   509   for(int i= 0; (int)(i*skip) < ((double)fImageLength); i++)
       
   510     {
       
   511       set_display_status((int)(i*skip), fImageLength);
       
   512       fMapData[(int)(i*skip)]->draw_pairs(i, color, 1.0/skip);
       
   513     }
       
   514   last_status = 0.0;
       
   515   update();
       
   516   set_status("Displaying Image: Done");
       
   517 }
       
   518 
       
   519 void RLEMap::tilt(double step, int direction)
       
   520 {
       
   521 /*    printf("tilt called, step = %lf, dir = %d\n", step, direction); */
       
   522   int old_height = fImageLength;
       
   523   int new_height = /* ceiling */ (int)(((double)fImageWidth) / step) + old_height;
       
   524   int delta = old_height - new_height;
       
   525   RLEPairs ** new_data = new RLEPairs*[new_height];
       
   526   for(int i = 0; i < new_height; i++)
       
   527       {
       
   528 	new_data[i] = new RLEPairs(i);
       
   529       }
       
   530   for(int j = 0; j < old_height; j++)
       
   531       {
       
   532 	tilt_row(j, delta, new_data, step, direction);
       
   533       }
       
   534   fMapData = new_data;  /* probably want to delete old data */
       
   535   fImageLength = new_height;
       
   536   display_intervals("black");
       
   537 }  
       
   538 
       
   539 
       
   540 void RLEMap::tilt_row(int old_row_index, int old_new_row_diff, RLEPairs** new_data, double step, int direction)
       
   541 {
       
   542 /*    printf("Tilt row called: old row = %d, row diff = %d, step = %lf, dir = %d\n", old_row_index, old_new_row_diff, step, direction); */
       
   543 
       
   544   double cur_x = 0;  /* I don't know what will happen with negative rows */
       
   545   double new_x;
       
   546   int cur_y = old_row_index + (old_new_row_diff * direction);
       
   547   
       
   548   while(((new_x = cur_x + step) < fImageWidth) &&
       
   549 	(cur_y >= 0) && (cur_y < fImageLength))
       
   550     {
       
   551       RLEPairs* new_pairs;
       
   552       new_pairs = (fMapData[old_row_index])->extract((int) cur_x, (int)new_x);
       
   553       new_data[cur_y]->merge(new_pairs);
       
   554       cur_x = new_x + 1;
       
   555       cur_y += direction;
       
   556     }
       
   557 }
       
   558 
       
   559 
       
   560 
       
   561 
       
   562 
       
   563 
       
   564