tesseract  3.03
/usr/local/google/home/jbreiden/tesseract-ocr-read-only/cube/bmp_8.cpp
Go to the documentation of this file.
00001 /**********************************************************************
00002  * File:        bmp_8.cpp
00003  * Description: Implementation of an 8-bit Bitmap class
00004  * Author:    Ahmad Abdulkader
00005  * Created:   2007
00006  *
00007  * (C) Copyright 2008, Google Inc.
00008  ** Licensed under the Apache License, Version 2.0 (the "License");
00009  ** you may not use this file except in compliance with the License.
00010  ** You may obtain a copy of the License at
00011  ** http://www.apache.org/licenses/LICENSE-2.0
00012  ** Unless required by applicable law or agreed to in writing, software
00013  ** distributed under the License is distributed on an "AS IS" BASIS,
00014  ** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
00015  ** See the License for the specific language governing permissions and
00016  ** limitations under the License.
00017  *
00018  **********************************************************************/
00019 
00020 #include <stdlib.h>
00021 #include <math.h>
00022 #include <cstring>
00023 #include <algorithm>
00024 #include "bmp_8.h"
00025 #include "con_comp.h"
00026 #include "platform.h"
00027 #ifdef USE_STD_NAMESPACE
00028 using std::min;
00029 using std::max;
00030 #endif
00031 
00032 namespace tesseract {
00033 
00034 const int Bmp8::kDeslantAngleCount = (1 + static_cast<int>(0.5f +
00035     (kMaxDeslantAngle - kMinDeslantAngle) / kDeslantAngleDelta));
00036 float *Bmp8::tan_table_ = NULL;
00037 
00038 Bmp8::Bmp8(unsigned short wid, unsigned short hgt)
00039     : wid_(wid)
00040     , hgt_(hgt) {
00041   line_buff_ = CreateBmpBuffer();
00042 }
00043 
00044 Bmp8::~Bmp8() {
00045   FreeBmpBuffer(line_buff_);
00046 }
00047 
00048 // free buffer
00049 void Bmp8::FreeBmpBuffer(unsigned char **buff) {
00050   if (buff != NULL) {
00051     if (buff[0] != NULL) {
00052       delete []buff[0];
00053     }
00054     delete []buff;
00055   }
00056 }
00057 
00058 void Bmp8::FreeBmpBuffer(unsigned int **buff) {
00059   if (buff != NULL) {
00060     if (buff[0] != NULL) {
00061       delete []buff[0];
00062     }
00063     delete []buff;
00064   }
00065 }
00066 
00067 // init bmp buffers
00068 unsigned char **Bmp8::CreateBmpBuffer(unsigned char init_val) {
00069   unsigned char **buff;
00070 
00071   // Check valid sizes
00072   if (!hgt_ || !wid_)
00073     return NULL;
00074 
00075   // compute stride (align on 4 byte boundries)
00076   stride_ = ((wid_ % 4) == 0) ? wid_ : (4 * (1 + (wid_ / 4)));
00077 
00078   buff = (unsigned char **) new unsigned char *[hgt_ * sizeof(*buff)];
00079   if (!buff) {
00080     delete []buff;
00081     return NULL;
00082   }
00083 
00084   // alloc and init memory for buffer and line buffer
00085   buff[0] = (unsigned char *)
00086       new unsigned char[stride_ * hgt_ * sizeof(*buff[0])];
00087   if (!buff[0]) {
00088     return NULL;
00089   }
00090 
00091   memset(buff[0], init_val, stride_ * hgt_ * sizeof(*buff[0]));
00092 
00093   for (int y = 1; y < hgt_; y++) {
00094     buff[y] = buff[y -1] + stride_;
00095   }
00096 
00097   return buff;
00098 }
00099 
00100 // init bmp buffers
00101 unsigned int ** Bmp8::CreateBmpBuffer(int wid, int hgt,
00102                                       unsigned char init_val) {
00103   unsigned int **buff;
00104 
00105   // compute stride (align on 4 byte boundries)
00106   buff = (unsigned int **) new unsigned int *[hgt * sizeof(*buff)];
00107   if (!buff) {
00108     delete []buff;
00109     return NULL;
00110   }
00111 
00112   // alloc and init memory for buffer and line buffer
00113   buff[0] = (unsigned int *) new unsigned int[wid * hgt * sizeof(*buff[0])];
00114   if (!buff[0]) {
00115     return NULL;
00116   }
00117 
00118   memset(buff[0], init_val, wid * hgt * sizeof(*buff[0]));
00119 
00120   for (int y = 1; y < hgt; y++) {
00121     buff[y] = buff[y -1] + wid;
00122   }
00123 
00124   return buff;
00125 }
00126 
00127 // clears the contents of the bmp
00128 bool Bmp8::Clear() {
00129   if (line_buff_ == NULL) {
00130     return false;
00131   }
00132 
00133   memset(line_buff_[0], 0xff, stride_ * hgt_ * sizeof(*line_buff_[0]));
00134   return true;
00135 }
00136 
00137 bool Bmp8::LoadFromCharDumpFile(CachedFile *fp) {
00138   unsigned short wid;
00139   unsigned short hgt;
00140   unsigned short x;
00141   unsigned short y;
00142   int buf_size;
00143   int pix;
00144   int pix_cnt;
00145   unsigned int val32;
00146   unsigned char *buff;
00147 
00148   // read and check 32 bit marker
00149   if (fp->Read(&val32, sizeof(val32)) != sizeof(val32)) {
00150     return false;
00151   }
00152 
00153   if (val32 != kMagicNumber) {
00154     return false;
00155   }
00156 
00157   // read wid and hgt
00158   if (fp->Read(&wid, sizeof(wid)) != sizeof(wid)) {
00159     return false;
00160   }
00161 
00162   if (fp->Read(&hgt, sizeof(hgt)) != sizeof(hgt)) {
00163     return false;
00164   }
00165 
00166   // read buf size
00167   if (fp->Read(&buf_size, sizeof(buf_size)) != sizeof(buf_size)) {
00168     return false;
00169   }
00170 
00171   // validate buf size: for now, only 3 channel (RBG) is supported
00172   pix_cnt = wid * hgt;
00173   if (buf_size != (3 * pix_cnt)) {
00174     return false;
00175   }
00176 
00177   // alloc memory & read the 3 channel buffer
00178   buff = new unsigned char[buf_size];
00179   if (buff == NULL) {
00180     return false;
00181   }
00182 
00183   if (fp->Read(buff, buf_size) != buf_size) {
00184     delete []buff;
00185     return false;
00186   }
00187 
00188   // create internal buffers
00189   wid_ = wid;
00190   hgt_ = hgt;
00191 
00192   line_buff_ = CreateBmpBuffer();
00193   if (line_buff_ == NULL) {
00194     delete []buff;
00195     return false;
00196   }
00197 
00198   // copy the data
00199   for (y = 0, pix = 0; y < hgt_; y++) {
00200     for (x = 0; x < wid_; x++, pix += 3) {
00201       // for now we only support gray scale,
00202       // so we expect R = G = B, it this is not the case, bail out
00203       if  (buff[pix] != buff[pix + 1] || buff[pix] != buff[pix + 2]) {
00204         delete []buff;
00205         return false;
00206       }
00207       line_buff_[y][x] = buff[pix];
00208     }
00209   }
00210 
00211   // delete temp buffer
00212   delete[]buff;
00213 
00214   return true;
00215 }
00216 
00217 Bmp8 * Bmp8::FromCharDumpFile(CachedFile *fp) {
00218   // create a Bmp8 object
00219   Bmp8 *bmp_obj = new Bmp8(0, 0);
00220   if (bmp_obj == NULL) {
00221     return NULL;
00222   }
00223 
00224   if (bmp_obj->LoadFromCharDumpFile(fp) == false) {
00225     delete bmp_obj;
00226   }
00227 
00228   return bmp_obj;
00229 }
00230 
00231 bool Bmp8::LoadFromCharDumpFile(FILE *fp) {
00232   unsigned short wid;
00233   unsigned short hgt;
00234   unsigned short x;
00235   unsigned short y;
00236   int buf_size;
00237   int pix;
00238   int pix_cnt;
00239   unsigned int val32;
00240   unsigned char *buff;
00241 
00242   // read and check 32 bit marker
00243   if (fread(&val32, 1, sizeof(val32), fp) != sizeof(val32)) {
00244     return false;
00245   }
00246 
00247   if (val32 != kMagicNumber) {
00248     return false;
00249   }
00250 
00251   // read wid and hgt
00252   if (fread(&wid, 1, sizeof(wid), fp) != sizeof(wid)) {
00253     return false;
00254   }
00255 
00256   if (fread(&hgt, 1, sizeof(hgt), fp) != sizeof(hgt)) {
00257     return false;
00258   }
00259 
00260   // read buf size
00261   if (fread(&buf_size, 1, sizeof(buf_size), fp) != sizeof(buf_size)) {
00262     return false;
00263   }
00264 
00265   // validate buf size: for now, only 3 channel (RBG) is supported
00266   pix_cnt = wid * hgt;
00267   if (buf_size != (3 * pix_cnt)) {
00268     return false;
00269   }
00270 
00271   // alloc memory & read the 3 channel buffer
00272   buff = new unsigned char[buf_size];
00273   if (buff == NULL) {
00274     return false;
00275   }
00276 
00277   if (fread(buff, 1, buf_size, fp) != buf_size) {
00278     delete []buff;
00279     return false;
00280   }
00281 
00282   // create internal buffers
00283   wid_ = wid;
00284   hgt_ = hgt;
00285 
00286   line_buff_ = CreateBmpBuffer();
00287   if (line_buff_ == NULL) {
00288     delete []buff;
00289     return false;
00290   }
00291 
00292   // copy the data
00293   for (y = 0, pix = 0; y < hgt_; y++) {
00294     for (x = 0; x < wid_; x++, pix += 3) {
00295       // for now we only support gray scale,
00296       // so we expect R = G = B, it this is not the case, bail out
00297       if  ( buff[pix] != buff[pix + 1] ||
00298             buff[pix] != buff[pix + 2]
00299           ) {
00300         delete []buff;
00301         return false;
00302           }
00303 
00304           line_buff_[y][x] = buff[pix];
00305     }
00306   }
00307 
00308   // delete temp buffer
00309   delete[]buff;
00310 
00311   return true;
00312 }
00313 
00314 Bmp8 * Bmp8::FromCharDumpFile(FILE *fp) {
00315   // create a Bmp8 object
00316   Bmp8 *bmp_obj = new Bmp8(0, 0);
00317   if (bmp_obj == NULL) {
00318     return NULL;
00319   }
00320 
00321   if (bmp_obj->LoadFromCharDumpFile(fp) == false) {
00322     delete bmp_obj;
00323   }
00324 
00325   return bmp_obj;
00326 }
00327 
00328 bool Bmp8::IsBlankColumn(int x) const {
00329   for (int y = 0; y < hgt_; y++) {
00330     if (line_buff_[y][x] != 0xff) {
00331       return false;
00332     }
00333   }
00334 
00335   return true;
00336 }
00337 
00338 bool Bmp8::IsBlankRow(int y) const {
00339   for (int x = 0; x < wid_; x++) {
00340     if (line_buff_[y][x] != 0xff) {
00341       return false;
00342     }
00343   }
00344 
00345   return true;
00346 }
00347 
00348 // crop the bitmap returning new dimensions
00349 void Bmp8::Crop(int *xst, int *yst, int *wid, int *hgt) {
00350   (*xst) = 0;
00351   (*yst) = 0;
00352 
00353   int xend = wid_ - 1;
00354   int yend = hgt_ - 1;
00355 
00356   while ((*xst) < (wid_ - 1) && (*xst) <= xend) {
00357     // column is not empty
00358     if (!IsBlankColumn((*xst))) {
00359       break;
00360     }
00361     (*xst)++;
00362   }
00363 
00364   while (xend > 0 && xend >= (*xst)) {
00365     // column is not empty
00366     if (!IsBlankColumn(xend)) {
00367       break;
00368     }
00369     xend--;
00370   }
00371 
00372   while ((*yst) < (hgt_ - 1) && (*yst) <= yend) {
00373     // column is not empty
00374     if (!IsBlankRow((*yst))) {
00375       break;
00376     }
00377     (*yst)++;
00378   }
00379 
00380   while (yend > 0 && yend >= (*yst)) {
00381     // column is not empty
00382     if (!IsBlankRow(yend)) {
00383       break;
00384     }
00385     yend--;
00386   }
00387 
00388   (*wid) = xend - (*xst) + 1;
00389   (*hgt) = yend - (*yst) + 1;
00390 }
00391 
00392 // generates a scaled bitmap with dimensions the new bmp will have the
00393 // same aspect ratio and will be centered in the box
00394 bool Bmp8::ScaleFrom(Bmp8 *bmp, bool isotropic) {
00395   int x_num;
00396   int x_denom;
00397   int y_num;
00398   int y_denom;
00399   int xoff;
00400   int yoff;
00401   int xsrc;
00402   int ysrc;
00403   int xdest;
00404   int ydest;
00405   int xst_src = 0;
00406   int yst_src = 0;
00407   int xend_src = bmp->wid_ - 1;
00408   int yend_src = bmp->hgt_ - 1;
00409   int wid_src;
00410   int hgt_src;
00411 
00412   // src dimensions
00413   wid_src = xend_src - xst_src + 1,
00414   hgt_src = yend_src - yst_src + 1;
00415 
00416   // scale to maintain aspect ratio if required
00417   if (isotropic) {
00418     if ((wid_ * hgt_src) > (hgt_ * wid_src)) {
00419       x_num = y_num = hgt_;
00420       x_denom = y_denom = hgt_src;
00421     } else {
00422       x_num = y_num = wid_;
00423       x_denom = y_denom = wid_src;
00424     }
00425   } else {
00426     x_num = wid_;
00427     y_num = hgt_;
00428     x_denom = wid_src;
00429     y_denom = hgt_src;
00430   }
00431 
00432   // compute offsets needed to center new bmp
00433   xoff = (wid_ - ((x_num * wid_src) / x_denom)) / 2;
00434   yoff = (hgt_ - ((y_num * hgt_src) / y_denom)) / 2;
00435 
00436   // scale up
00437   if (y_num > y_denom) {
00438     for (ydest = yoff; ydest < (hgt_ - yoff); ydest++) {
00439       // compute un-scaled y
00440       ysrc = static_cast<int>(0.5 + (1.0 * (ydest - yoff) *
00441           y_denom / y_num));
00442       if (ysrc < 0 || ysrc >= hgt_src) {
00443         continue;
00444       }
00445 
00446       for (xdest = xoff; xdest < (wid_ - xoff); xdest++) {
00447         // compute un-scaled y
00448         xsrc = static_cast<int>(0.5 + (1.0 * (xdest - xoff) *
00449             x_denom / x_num));
00450         if (xsrc < 0 || xsrc >= wid_src) {
00451           continue;
00452         }
00453 
00454         line_buff_[ydest][xdest] =
00455             bmp->line_buff_[ysrc + yst_src][xsrc + xst_src];
00456       }
00457     }
00458   } else {
00459     // or scale down
00460     // scaling down is a bit tricky: we'll accumulate pixels
00461     // and then compute the means
00462     unsigned int **dest_line_buff = CreateBmpBuffer(wid_, hgt_, 0),
00463       **dest_pix_cnt =  CreateBmpBuffer(wid_, hgt_, 0);
00464 
00465     for (ysrc = 0; ysrc < hgt_src; ysrc++) {
00466       // compute scaled y
00467       ydest = yoff + static_cast<int>(0.5 + (1.0 * ysrc * y_num / y_denom));
00468       if (ydest < 0 || ydest >= hgt_) {
00469         continue;
00470       }
00471 
00472       for (xsrc = 0; xsrc < wid_src; xsrc++) {
00473         // compute scaled y
00474         xdest = xoff + static_cast<int>(0.5 + (1.0 * xsrc * x_num / x_denom));
00475         if (xdest < 0 || xdest >= wid_) {
00476           continue;
00477         }
00478 
00479         dest_line_buff[ydest][xdest] +=
00480             bmp->line_buff_[ysrc + yst_src][xsrc + xst_src];
00481         dest_pix_cnt[ydest][xdest]++;
00482       }
00483     }
00484 
00485     for (ydest = 0; ydest < hgt_; ydest++) {
00486       for (xdest = 0; xdest < wid_; xdest++) {
00487         if (dest_pix_cnt[ydest][xdest] > 0) {
00488           unsigned int pixval =
00489               dest_line_buff[ydest][xdest] / dest_pix_cnt[ydest][xdest];
00490 
00491           line_buff_[ydest][xdest] =
00492               (unsigned char) min((unsigned int)255, pixval);
00493         }
00494       }
00495     }
00496 
00497     // we no longer need these temp buffers
00498     FreeBmpBuffer(dest_line_buff);
00499     FreeBmpBuffer(dest_pix_cnt);
00500   }
00501 
00502   return true;
00503 }
00504 
00505 bool Bmp8::LoadFromRawData(unsigned char *data) {
00506   unsigned char *pline_data = data;
00507 
00508   // copy the data
00509   for (int y = 0; y < hgt_; y++, pline_data += wid_) {
00510     memcpy(line_buff_[y], pline_data, wid_ * sizeof(*pline_data));
00511   }
00512 
00513   return true;
00514 }
00515 
00516 bool Bmp8::SaveBmp2CharDumpFile(FILE *fp) const {
00517   unsigned short wid;
00518   unsigned short hgt;
00519   unsigned short x;
00520   unsigned short y;
00521   int buf_size;
00522   int pix;
00523   int pix_cnt;
00524   unsigned int val32;
00525   unsigned char *buff;
00526 
00527   // write and check 32 bit marker
00528   val32 = kMagicNumber;
00529   if (fwrite(&val32, 1, sizeof(val32), fp) != sizeof(val32)) {
00530     return false;
00531   }
00532 
00533   // write wid and hgt
00534   wid = wid_;
00535   if (fwrite(&wid, 1, sizeof(wid), fp) != sizeof(wid)) {
00536     return false;
00537   }
00538 
00539   hgt = hgt_;
00540   if (fwrite(&hgt, 1, sizeof(hgt), fp) != sizeof(hgt)) {
00541     return false;
00542   }
00543 
00544   // write buf size
00545   pix_cnt = wid * hgt;
00546   buf_size = 3 * pix_cnt;
00547   if (fwrite(&buf_size, 1, sizeof(buf_size), fp) != sizeof(buf_size)) {
00548     return false;
00549   }
00550 
00551   // alloc memory & write the 3 channel buffer
00552   buff = new unsigned char[buf_size];
00553   if (buff == NULL) {
00554     return false;
00555   }
00556 
00557   // copy the data
00558   for (y = 0, pix = 0; y < hgt_; y++) {
00559     for (x = 0; x < wid_; x++, pix += 3) {
00560       buff[pix] =
00561       buff[pix + 1] =
00562       buff[pix + 2] = line_buff_[y][x];
00563     }
00564   }
00565 
00566   if (fwrite(buff, 1, buf_size, fp) != buf_size) {
00567     delete []buff;
00568     return false;
00569   }
00570 
00571   // delete temp buffer
00572   delete[]buff;
00573 
00574   return true;
00575 }
00576 
00577 // copy part of the specified bitmap to the top of the bitmap
00578 // does any necessary clipping
00579 void Bmp8::Copy(int x_st, int y_st, int wid, int hgt, Bmp8 *bmp_dest) const {
00580   int x_end = min(x_st + wid, static_cast<int>(wid_)),
00581   y_end = min(y_st + hgt, static_cast<int>(hgt_));
00582 
00583   for (int y = y_st; y < y_end; y++) {
00584     for (int x = x_st; x < x_end; x++) {
00585       bmp_dest->line_buff_[y - y_st][x - x_st] =
00586           line_buff_[y][x];
00587     }
00588   }
00589 }
00590 
00591 bool Bmp8::IsIdentical(Bmp8 *pBmp) const {
00592   if (wid_ != pBmp->wid_ || hgt_ != pBmp->hgt_) {
00593     return false;
00594   }
00595 
00596   for (int y = 0; y < hgt_; y++) {
00597     if (memcmp(line_buff_[y], pBmp->line_buff_[y], wid_) != 0) {
00598       return false;
00599     }
00600   }
00601 
00602   return true;
00603 }
00604 
00605 // Detect connected components in the bitmap
00606 ConComp ** Bmp8::FindConComps(int *concomp_cnt, int min_size) const {
00607   (*concomp_cnt) = 0;
00608 
00609   unsigned int **out_bmp_array = CreateBmpBuffer(wid_, hgt_, 0);
00610   if (out_bmp_array == NULL) {
00611     fprintf(stderr, "Cube ERROR (Bmp8::FindConComps): could not allocate "
00612             "bitmap array\n");
00613     return NULL;
00614   }
00615 
00616   // listed of connected components
00617   ConComp **concomp_array = NULL;
00618 
00619   int x;
00620   int y;
00621   int x_nbr;
00622   int y_nbr;
00623   int concomp_id;
00624   int alloc_concomp_cnt = 0;
00625 
00626   // neighbors to check
00627   const int nbr_cnt = 4;
00628 
00629   // relative coordinates of nbrs
00630   int x_del[nbr_cnt] = {-1, 0, 1, -1},
00631     y_del[nbr_cnt] = {-1, -1, -1, 0};
00632 
00633 
00634   for (y = 0; y < hgt_; y++) {
00635     for (x = 0; x < wid_; x++) {
00636       // is this a foreground pix
00637       if (line_buff_[y][x] != 0xff) {
00638         int master_concomp_id = 0;
00639         ConComp *master_concomp = NULL;
00640 
00641         // checkout the nbrs
00642         for (int nbr = 0; nbr < nbr_cnt; nbr++) {
00643           x_nbr = x + x_del[nbr];
00644           y_nbr = y + y_del[nbr];
00645 
00646           if (x_nbr < 0 || y_nbr < 0 || x_nbr >= wid_ || y_nbr >= hgt_) {
00647             continue;
00648           }
00649 
00650           // is this nbr a foreground pix
00651           if (line_buff_[y_nbr][x_nbr] != 0xff) {
00652             // get its concomp ID
00653             concomp_id = out_bmp_array[y_nbr][x_nbr];
00654 
00655             // this should not happen
00656             if (concomp_id < 1 || concomp_id > alloc_concomp_cnt) {
00657               fprintf(stderr, "Cube ERROR (Bmp8::FindConComps): illegal "
00658                       "connected component id: %d\n", concomp_id);
00659               FreeBmpBuffer(out_bmp_array);
00660               delete []concomp_array;
00661               return NULL;
00662             }
00663 
00664             // if we has previously found a component then merge the two
00665             // and delete the latest one
00666             if (master_concomp != NULL && concomp_id != master_concomp_id) {
00667               // relabel all the pts
00668               ConCompPt *pt_ptr = concomp_array[concomp_id - 1]->Head();
00669               while (pt_ptr != NULL) {
00670                 out_bmp_array[pt_ptr->y()][pt_ptr->x()] = master_concomp_id;
00671                 pt_ptr = pt_ptr->Next();
00672               }
00673 
00674               // merge the two concomp
00675               if (!master_concomp->Merge(concomp_array[concomp_id - 1])) {
00676                 fprintf(stderr, "Cube ERROR (Bmp8::FindConComps): could not "
00677                         "merge connected component: %d\n", concomp_id);
00678                 FreeBmpBuffer(out_bmp_array);
00679                 delete []concomp_array;
00680                 return NULL;
00681               }
00682 
00683               // delete the merged concomp
00684               delete concomp_array[concomp_id - 1];
00685               concomp_array[concomp_id - 1] = NULL;
00686             } else {
00687               // this is the first concomp we encounter
00688               master_concomp_id = concomp_id;
00689               master_concomp = concomp_array[master_concomp_id - 1];
00690 
00691               out_bmp_array[y][x] = master_concomp_id;
00692 
00693               if (!master_concomp->Add(x, y)) {
00694                 fprintf(stderr, "Cube ERROR (Bmp8::FindConComps): could not "
00695                         "add connected component (%d,%d)\n", x, y);
00696                 FreeBmpBuffer(out_bmp_array);
00697                 delete []concomp_array;
00698                 return NULL;
00699               }
00700             }
00701           }  // foreground nbr
00702         }  // nbrs
00703 
00704         // if there was no foreground pix, then create a new concomp
00705         if (master_concomp == NULL) {
00706           master_concomp = new ConComp();
00707           if (master_concomp == NULL || master_concomp->Add(x, y) == false) {
00708             fprintf(stderr, "Cube ERROR (Bmp8::FindConComps): could not "
00709                     "allocate or add a connected component\n");
00710             FreeBmpBuffer(out_bmp_array);
00711             delete []concomp_array;
00712             return NULL;
00713           }
00714 
00715           // extend the list of concomps if needed
00716           if ((alloc_concomp_cnt % kConCompAllocChunk) == 0) {
00717             ConComp **temp_con_comp =
00718                 new ConComp *[alloc_concomp_cnt + kConCompAllocChunk];
00719             if (temp_con_comp == NULL) {
00720               fprintf(stderr, "Cube ERROR (Bmp8::FindConComps): could not "
00721                       "extend array of connected components\n");
00722               FreeBmpBuffer(out_bmp_array);
00723               delete []concomp_array;
00724               return NULL;
00725             }
00726 
00727             if (alloc_concomp_cnt > 0) {
00728               memcpy(temp_con_comp, concomp_array,
00729                      alloc_concomp_cnt * sizeof(*concomp_array));
00730 
00731               delete []concomp_array;
00732             }
00733 
00734             concomp_array = temp_con_comp;
00735           }
00736 
00737           concomp_array[alloc_concomp_cnt++] = master_concomp;
00738           out_bmp_array[y][x] = alloc_concomp_cnt;
00739         }
00740       }  // foreground pix
00741     }  // x
00742   }  // y
00743 
00744   // free the concomp bmp
00745   FreeBmpBuffer(out_bmp_array);
00746 
00747   if (alloc_concomp_cnt > 0 && concomp_array != NULL) {
00748     // scan the array of connected components and color
00749     // the o/p buffer with the corresponding concomps
00750     (*concomp_cnt) = 0;
00751     ConComp *concomp = NULL;
00752 
00753     for (int concomp_idx = 0; concomp_idx < alloc_concomp_cnt; concomp_idx++) {
00754       concomp = concomp_array[concomp_idx];
00755 
00756       // found a concomp
00757       if (concomp != NULL) {
00758         // add the connected component if big enough
00759         if (concomp->PtCnt() > min_size) {
00760           concomp->SetLeftMost(true);
00761           concomp->SetRightMost(true);
00762           concomp->SetID((*concomp_cnt));
00763           concomp_array[(*concomp_cnt)++] = concomp;
00764         } else {
00765           delete concomp;
00766         }
00767       }
00768     }
00769   }
00770 
00771   return concomp_array;
00772 }
00773 
00774 // precompute the tan table to speedup deslanting
00775 bool Bmp8::ComputeTanTable() {
00776   int ang_idx;
00777   float ang_val;
00778 
00779   // alloc memory for tan table
00780   delete []tan_table_;
00781   tan_table_ = new float[kDeslantAngleCount];
00782   if (tan_table_ == NULL) {
00783     return false;
00784   }
00785 
00786   for (ang_idx = 0, ang_val = kMinDeslantAngle;
00787        ang_idx < kDeslantAngleCount; ang_idx++) {
00788     tan_table_[ang_idx] = tan(ang_val * M_PI / 180.0f);
00789     ang_val += kDeslantAngleDelta;
00790   }
00791 
00792   return true;
00793 }
00794 
00795 // generates a deslanted bitmap from the passed bitmap.
00796 bool Bmp8::Deslant() {
00797   int x;
00798   int y;
00799   int des_x;
00800   int des_y;
00801   int ang_idx;
00802   int best_ang;
00803   int min_des_x;
00804   int max_des_x;
00805   int des_wid;
00806 
00807   // only do deslanting if bitmap is wide enough
00808   // otherwise it slant estimate might not be reliable
00809   if (wid_ < (hgt_ * 2)) {
00810     return true;
00811   }
00812 
00813   // compute tan table if needed
00814   if (tan_table_ == NULL && !ComputeTanTable()) {
00815     return false;
00816   }
00817 
00818   // compute min and max values for x after deslant
00819   min_des_x = static_cast<int>(0.5f + (hgt_ - 1) * tan_table_[0]);
00820   max_des_x = (wid_ - 1) +
00821       static_cast<int>(0.5f + (hgt_ - 1) * tan_table_[kDeslantAngleCount - 1]);
00822 
00823   des_wid = max_des_x - min_des_x + 1;
00824 
00825   // alloc memory for histograms
00826   int **angle_hist = new int*[kDeslantAngleCount];
00827   for (ang_idx = 0; ang_idx < kDeslantAngleCount; ang_idx++) {
00828     angle_hist[ang_idx] = new int[des_wid];
00829     if (angle_hist[ang_idx] == NULL) {
00830       delete[] angle_hist;
00831       return false;
00832     }
00833     memset(angle_hist[ang_idx], 0, des_wid * sizeof(*angle_hist[ang_idx]));
00834   }
00835 
00836   // compute histograms
00837   for (y = 0; y < hgt_; y++) {
00838     for (x = 0; x < wid_; x++) {
00839       // find a non-bkgrnd pixel
00840       if (line_buff_[y][x] != 0xff) {
00841         des_y = hgt_ - y - 1;
00842         // stamp all histograms
00843         for (ang_idx = 0; ang_idx < kDeslantAngleCount; ang_idx++) {
00844           des_x = x + static_cast<int>(0.5f + (des_y * tan_table_[ang_idx]));
00845           if (des_x >= min_des_x && des_x <= max_des_x) {
00846             angle_hist[ang_idx][des_x - min_des_x]++;
00847           }
00848         }
00849       }
00850     }
00851   }
00852 
00853   // find the histogram with the lowest entropy
00854   float entropy;
00855   double best_entropy = 0.0f;
00856   double norm_val;
00857 
00858   best_ang = -1;
00859   for (ang_idx = 0; ang_idx < kDeslantAngleCount; ang_idx++) {
00860     entropy = 0.0f;
00861 
00862     for (x = min_des_x; x <= max_des_x; x++) {
00863       if (angle_hist[ang_idx][x - min_des_x] > 0) {
00864         norm_val = (1.0f * angle_hist[ang_idx][x - min_des_x] / hgt_);
00865         entropy += (-1.0f * norm_val * log(norm_val));
00866       }
00867     }
00868 
00869     if (best_ang == -1 || entropy < best_entropy) {
00870       best_ang = ang_idx;
00871       best_entropy = entropy;
00872     }
00873 
00874     // free the histogram
00875     delete[] angle_hist[ang_idx];
00876   }
00877   delete[] angle_hist;
00878 
00879   // deslant
00880   if (best_ang != -1) {
00881     unsigned char **dest_lines;
00882     int old_wid = wid_;
00883 
00884     // create a new buffer
00885     wid_ = des_wid;
00886     dest_lines = CreateBmpBuffer();
00887     if (dest_lines == NULL) {
00888       return false;
00889     }
00890 
00891     for (y = 0; y < hgt_; y++) {
00892       for (x = 0; x < old_wid; x++) {
00893         // find a non-bkgrnd pixel
00894         if (line_buff_[y][x] != 0xff) {
00895           des_y = hgt_ - y - 1;
00896           // compute new pos
00897           des_x = x + static_cast<int>(0.5f + (des_y * tan_table_[best_ang]));
00898           dest_lines[y][des_x - min_des_x] = 0;
00899         }
00900       }
00901     }
00902 
00903     // free old buffer
00904     FreeBmpBuffer(line_buff_);
00905     line_buff_ = dest_lines;
00906   }
00907   return true;
00908 }
00909 
00910 // Load dimensions & contents of bitmap from raw data
00911 bool Bmp8::LoadFromCharDumpFile(unsigned char **raw_data_ptr) {
00912   unsigned short wid;
00913   unsigned short hgt;
00914   unsigned short x;
00915   unsigned short y;
00916   unsigned char *raw_data = (*raw_data_ptr);
00917   int buf_size;
00918   int pix;
00919   unsigned int val32;
00920 
00921   // read and check 32 bit marker
00922   memcpy(&val32, raw_data, sizeof(val32));
00923   raw_data += sizeof(val32);
00924 
00925   if (val32 != kMagicNumber) {
00926     return false;
00927   }
00928 
00929   // read wid and hgt
00930   memcpy(&wid, raw_data, sizeof(wid));
00931   raw_data += sizeof(wid);
00932 
00933   memcpy(&hgt, raw_data, sizeof(hgt));
00934   raw_data += sizeof(hgt);
00935 
00936   // read buf size
00937   memcpy(&buf_size, raw_data, sizeof(buf_size));
00938   raw_data += sizeof(buf_size);
00939 
00940   // validate buf size: for now, only 3 channel (RBG) is supported
00941   if (buf_size != (3 * wid * hgt)) {
00942     return false;
00943   }
00944 
00945   wid_ = wid;
00946   hgt_ = hgt;
00947 
00948   line_buff_ = CreateBmpBuffer();
00949   if (line_buff_ == NULL) {
00950     return false;
00951   }
00952 
00953   // copy the data
00954   for (y = 0, pix = 0; y < hgt_; y++) {
00955     for (x = 0; x < wid_; x++, pix += 3) {
00956       // for now we only support gray scale,
00957       // so we expect R = G = B, it this is not the case, bail out
00958       if  (raw_data[pix] != raw_data[pix + 1] ||
00959            raw_data[pix] != raw_data[pix + 2]) {
00960         return false;
00961       }
00962 
00963       line_buff_[y][x] = raw_data[pix];
00964     }
00965   }
00966 
00967   (*raw_data_ptr) = raw_data + buf_size;
00968   return true;
00969 }
00970 
00971 float Bmp8::ForegroundRatio() const {
00972   int fore_cnt = 0;
00973 
00974   if (wid_ == 0 || hgt_ == 0) {
00975     return 1.0;
00976   }
00977 
00978   for (int y = 0; y < hgt_; y++) {
00979     for (int x = 0; x < wid_; x++) {
00980       fore_cnt += (line_buff_[y][x] == 0xff ? 0 : 1);
00981     }
00982   }
00983 
00984   return (1.0 * (fore_cnt / hgt_) / wid_);
00985 }
00986 
00987 // generates a deslanted bitmap from the passed bitmap
00988 bool Bmp8::HorizontalDeslant(double *deslant_angle) {
00989   int x;
00990   int y;
00991   int des_y;
00992   int ang_idx;
00993   int best_ang;
00994   int min_des_y;
00995   int max_des_y;
00996   int des_hgt;
00997 
00998   // compute tan table if necess.
00999   if (tan_table_ == NULL && !ComputeTanTable()) {
01000     return false;
01001   }
01002 
01003   // compute min and max values for x after deslant
01004   min_des_y = min(0, static_cast<int>((wid_ - 1) * tan_table_[0]));
01005   max_des_y = (hgt_ - 1) +
01006       max(0, static_cast<int>((wid_ - 1) * tan_table_[kDeslantAngleCount - 1]));
01007 
01008   des_hgt = max_des_y - min_des_y + 1;
01009 
01010   // alloc memory for histograms
01011   int **angle_hist = new int*[kDeslantAngleCount];
01012   for (ang_idx = 0; ang_idx < kDeslantAngleCount; ang_idx++) {
01013     angle_hist[ang_idx] = new int[des_hgt];
01014     if (angle_hist[ang_idx] == NULL) {
01015       delete[] angle_hist;
01016       return false;
01017     }
01018     memset(angle_hist[ang_idx], 0, des_hgt * sizeof(*angle_hist[ang_idx]));
01019   }
01020 
01021   // compute histograms
01022   for (y = 0; y < hgt_; y++) {
01023     for (x = 0; x < wid_; x++) {
01024       // find a non-bkgrnd pixel
01025       if (line_buff_[y][x] != 0xff) {
01026         // stamp all histograms
01027         for (ang_idx = 0; ang_idx < kDeslantAngleCount; ang_idx++) {
01028           des_y = y - static_cast<int>(x * tan_table_[ang_idx]);
01029           if (des_y >= min_des_y && des_y <= max_des_y) {
01030             angle_hist[ang_idx][des_y - min_des_y]++;
01031           }
01032         }
01033       }
01034     }
01035   }
01036 
01037   // find the histogram with the lowest entropy
01038   float entropy;
01039   float best_entropy =  0.0f;
01040   float norm_val;
01041 
01042   best_ang = -1;
01043   for (ang_idx = 0; ang_idx < kDeslantAngleCount; ang_idx++) {
01044     entropy = 0.0f;
01045 
01046     for (y = min_des_y; y <= max_des_y; y++) {
01047       if (angle_hist[ang_idx][y - min_des_y] > 0) {
01048         norm_val = (1.0f * angle_hist[ang_idx][y - min_des_y] / wid_);
01049         entropy += (-1.0f * norm_val * log(norm_val));
01050       }
01051     }
01052 
01053     if (best_ang == -1 || entropy < best_entropy) {
01054       best_ang = ang_idx;
01055       best_entropy = entropy;
01056     }
01057 
01058     // free the histogram
01059     delete[] angle_hist[ang_idx];
01060   }
01061   delete[] angle_hist;
01062 
01063   (*deslant_angle) = 0.0;
01064 
01065   // deslant
01066   if (best_ang != -1) {
01067     unsigned char **dest_lines;
01068     int old_hgt = hgt_;
01069 
01070     // create a new buffer
01071     min_des_y = min(0, static_cast<int>((wid_ - 1) * -tan_table_[best_ang]));
01072     max_des_y = (hgt_ - 1) +
01073         max(0, static_cast<int>((wid_ - 1) * -tan_table_[best_ang]));
01074     hgt_ = max_des_y - min_des_y + 1;
01075     dest_lines = CreateBmpBuffer();
01076     if (dest_lines == NULL) {
01077       return false;
01078     }
01079 
01080     for (y = 0; y < old_hgt; y++) {
01081       for (x = 0; x < wid_; x++) {
01082         // find a non-bkgrnd pixel
01083         if (line_buff_[y][x] != 0xff) {
01084           // compute new pos
01085           des_y = y - static_cast<int>((x * tan_table_[best_ang]));
01086           dest_lines[des_y - min_des_y][x] = 0;
01087         }
01088       }
01089     }
01090 
01091     // free old buffer
01092     FreeBmpBuffer(line_buff_);
01093     line_buff_ = dest_lines;
01094 
01095     (*deslant_angle) = kMinDeslantAngle + (best_ang * kDeslantAngleDelta);
01096   }
01097 
01098   return true;
01099 }
01100 
01101 float Bmp8::MeanHorizontalHistogramEntropy() const {
01102   float entropy = 0.0f;
01103 
01104   // compute histograms
01105   for (int y = 0; y < hgt_; y++) {
01106     int pix_cnt = 0;
01107 
01108     for (int x = 0; x < wid_; x++) {
01109       // find a non-bkgrnd pixel
01110       if (line_buff_[y][x] != 0xff) {
01111         pix_cnt++;
01112       }
01113     }
01114 
01115     if (pix_cnt > 0) {
01116       float norm_val = (1.0f * pix_cnt / wid_);
01117       entropy += (-1.0f * norm_val * log(norm_val));
01118     }
01119   }
01120 
01121   return entropy / hgt_;
01122 }
01123 
01124 int *Bmp8::HorizontalHistogram() const {
01125   int *hist = new int[hgt_];
01126   if (hist == NULL) {
01127     return NULL;
01128   }
01129 
01130   // compute histograms
01131   for (int y = 0; y < hgt_; y++) {
01132     hist[y] = 0;
01133 
01134     for (int x = 0; x < wid_; x++) {
01135       // find a non-bkgrnd pixel
01136       if (line_buff_[y][x] != 0xff) {
01137         hist[y]++;
01138       }
01139     }
01140   }
01141 
01142   return hist;
01143 }
01144 
01145 }  // namespace tesseract
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Defines