tesseract 3.04.01

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     return NULL;
00227   }
00228 
00229   return bmp_obj;
00230 }
00231 
00232 bool Bmp8::LoadFromCharDumpFile(FILE *fp) {
00233   unsigned short wid;
00234   unsigned short hgt;
00235   unsigned short x;
00236   unsigned short y;
00237   int buf_size;
00238   int pix;
00239   int pix_cnt;
00240   unsigned int val32;
00241   unsigned char *buff;
00242 
00243   // read and check 32 bit marker
00244   if (fread(&val32, 1, sizeof(val32), fp) != sizeof(val32)) {
00245     return false;
00246   }
00247 
00248   if (val32 != kMagicNumber) {
00249     return false;
00250   }
00251 
00252   // read wid and hgt
00253   if (fread(&wid, 1, sizeof(wid), fp) != sizeof(wid)) {
00254     return false;
00255   }
00256 
00257   if (fread(&hgt, 1, sizeof(hgt), fp) != sizeof(hgt)) {
00258     return false;
00259   }
00260 
00261   // read buf size
00262   if (fread(&buf_size, 1, sizeof(buf_size), fp) != sizeof(buf_size)) {
00263     return false;
00264   }
00265 
00266   // validate buf size: for now, only 3 channel (RBG) is supported
00267   pix_cnt = wid * hgt;
00268   if (buf_size != (3 * pix_cnt)) {
00269     return false;
00270   }
00271 
00272   // alloc memory & read the 3 channel buffer
00273   buff = new unsigned char[buf_size];
00274   if (buff == NULL) {
00275     return false;
00276   }
00277 
00278   if (fread(buff, 1, buf_size, fp) != buf_size) {
00279     delete []buff;
00280     return false;
00281   }
00282 
00283   // create internal buffers
00284   wid_ = wid;
00285   hgt_ = hgt;
00286 
00287   line_buff_ = CreateBmpBuffer();
00288   if (line_buff_ == NULL) {
00289     delete []buff;
00290     return false;
00291   }
00292 
00293   // copy the data
00294   for (y = 0, pix = 0; y < hgt_; y++) {
00295     for (x = 0; x < wid_; x++, pix += 3) {
00296       // for now we only support gray scale,
00297       // so we expect R = G = B, it this is not the case, bail out
00298       if  (buff[pix] != buff[pix + 1] || buff[pix] != buff[pix + 2]) {
00299         delete []buff;
00300         return false;
00301       }
00302       line_buff_[y][x] = buff[pix];
00303     }
00304   }
00305 
00306   // delete temp buffer
00307   delete[]buff;
00308 
00309   return true;
00310 }
00311 
00312 Bmp8 * Bmp8::FromCharDumpFile(FILE *fp) {
00313   // create a Bmp8 object
00314   Bmp8 *bmp_obj = new Bmp8(0, 0);
00315   if (bmp_obj == NULL) {
00316     return NULL;
00317   }
00318 
00319   if (bmp_obj->LoadFromCharDumpFile(fp) == false) {
00320     delete bmp_obj;
00321     return NULL;
00322   }
00323 
00324   return bmp_obj;
00325 }
00326 
00327 bool Bmp8::IsBlankColumn(int x) const {
00328   for (int y = 0; y < hgt_; y++) {
00329     if (line_buff_[y][x] != 0xff) {
00330       return false;
00331     }
00332   }
00333 
00334   return true;
00335 }
00336 
00337 bool Bmp8::IsBlankRow(int y) const {
00338   for (int x = 0; x < wid_; x++) {
00339     if (line_buff_[y][x] != 0xff) {
00340       return false;
00341     }
00342   }
00343 
00344   return true;
00345 }
00346 
00347 // crop the bitmap returning new dimensions
00348 void Bmp8::Crop(int *xst, int *yst, int *wid, int *hgt) {
00349   (*xst) = 0;
00350   (*yst) = 0;
00351 
00352   int xend = wid_ - 1;
00353   int yend = hgt_ - 1;
00354 
00355   while ((*xst) < (wid_ - 1) && (*xst) <= xend) {
00356     // column is not empty
00357     if (!IsBlankColumn((*xst))) {
00358       break;
00359     }
00360     (*xst)++;
00361   }
00362 
00363   while (xend > 0 && xend >= (*xst)) {
00364     // column is not empty
00365     if (!IsBlankColumn(xend)) {
00366       break;
00367     }
00368     xend--;
00369   }
00370 
00371   while ((*yst) < (hgt_ - 1) && (*yst) <= yend) {
00372     // column is not empty
00373     if (!IsBlankRow((*yst))) {
00374       break;
00375     }
00376     (*yst)++;
00377   }
00378 
00379   while (yend > 0 && yend >= (*yst)) {
00380     // column is not empty
00381     if (!IsBlankRow(yend)) {
00382       break;
00383     }
00384     yend--;
00385   }
00386 
00387   (*wid) = xend - (*xst) + 1;
00388   (*hgt) = yend - (*yst) + 1;
00389 }
00390 
00391 // generates a scaled bitmap with dimensions the new bmp will have the
00392 // same aspect ratio and will be centered in the box
00393 bool Bmp8::ScaleFrom(Bmp8 *bmp, bool isotropic) {
00394   int x_num;
00395   int x_denom;
00396   int y_num;
00397   int y_denom;
00398   int xoff;
00399   int yoff;
00400   int xsrc;
00401   int ysrc;
00402   int xdest;
00403   int ydest;
00404   int xst_src = 0;
00405   int yst_src = 0;
00406   int xend_src = bmp->wid_ - 1;
00407   int yend_src = bmp->hgt_ - 1;
00408   int wid_src;
00409   int hgt_src;
00410 
00411   // src dimensions
00412   wid_src = xend_src - xst_src + 1,
00413   hgt_src = yend_src - yst_src + 1;
00414 
00415   // scale to maintain aspect ratio if required
00416   if (isotropic) {
00417     if ((wid_ * hgt_src) > (hgt_ * wid_src)) {
00418       x_num = y_num = hgt_;
00419       x_denom = y_denom = hgt_src;
00420     } else {
00421       x_num = y_num = wid_;
00422       x_denom = y_denom = wid_src;
00423     }
00424   } else {
00425     x_num = wid_;
00426     y_num = hgt_;
00427     x_denom = wid_src;
00428     y_denom = hgt_src;
00429   }
00430 
00431   // compute offsets needed to center new bmp
00432   xoff = (wid_ - ((x_num * wid_src) / x_denom)) / 2;
00433   yoff = (hgt_ - ((y_num * hgt_src) / y_denom)) / 2;
00434 
00435   // scale up
00436   if (y_num > y_denom) {
00437     for (ydest = yoff; ydest < (hgt_ - yoff); ydest++) {
00438       // compute un-scaled y
00439       ysrc = static_cast<int>(0.5 + (1.0 * (ydest - yoff) *
00440           y_denom / y_num));
00441       if (ysrc < 0 || ysrc >= hgt_src) {
00442         continue;
00443       }
00444 
00445       for (xdest = xoff; xdest < (wid_ - xoff); xdest++) {
00446         // compute un-scaled y
00447         xsrc = static_cast<int>(0.5 + (1.0 * (xdest - xoff) *
00448             x_denom / x_num));
00449         if (xsrc < 0 || xsrc >= wid_src) {
00450           continue;
00451         }
00452 
00453         line_buff_[ydest][xdest] =
00454             bmp->line_buff_[ysrc + yst_src][xsrc + xst_src];
00455       }
00456     }
00457   } else {
00458     // or scale down
00459     // scaling down is a bit tricky: we'll accumulate pixels
00460     // and then compute the means
00461     unsigned int **dest_line_buff = CreateBmpBuffer(wid_, hgt_, 0),
00462       **dest_pix_cnt =  CreateBmpBuffer(wid_, hgt_, 0);
00463 
00464     for (ysrc = 0; ysrc < hgt_src; ysrc++) {
00465       // compute scaled y
00466       ydest = yoff + static_cast<int>(0.5 + (1.0 * ysrc * y_num / y_denom));
00467       if (ydest < 0 || ydest >= hgt_) {
00468         continue;
00469       }
00470 
00471       for (xsrc = 0; xsrc < wid_src; xsrc++) {
00472         // compute scaled y
00473         xdest = xoff + static_cast<int>(0.5 + (1.0 * xsrc * x_num / x_denom));
00474         if (xdest < 0 || xdest >= wid_) {
00475           continue;
00476         }
00477 
00478         dest_line_buff[ydest][xdest] +=
00479             bmp->line_buff_[ysrc + yst_src][xsrc + xst_src];
00480         dest_pix_cnt[ydest][xdest]++;
00481       }
00482     }
00483 
00484     for (ydest = 0; ydest < hgt_; ydest++) {
00485       for (xdest = 0; xdest < wid_; xdest++) {
00486         if (dest_pix_cnt[ydest][xdest] > 0) {
00487           unsigned int pixval =
00488               dest_line_buff[ydest][xdest] / dest_pix_cnt[ydest][xdest];
00489 
00490           line_buff_[ydest][xdest] =
00491               (unsigned char) min((unsigned int)255, pixval);
00492         }
00493       }
00494     }
00495 
00496     // we no longer need these temp buffers
00497     FreeBmpBuffer(dest_line_buff);
00498     FreeBmpBuffer(dest_pix_cnt);
00499   }
00500 
00501   return true;
00502 }
00503 
00504 bool Bmp8::LoadFromRawData(unsigned char *data) {
00505   unsigned char *pline_data = data;
00506 
00507   // copy the data
00508   for (int y = 0; y < hgt_; y++, pline_data += wid_) {
00509     memcpy(line_buff_[y], pline_data, wid_ * sizeof(*pline_data));
00510   }
00511 
00512   return true;
00513 }
00514 
00515 bool Bmp8::SaveBmp2CharDumpFile(FILE *fp) const {
00516   unsigned short wid;
00517   unsigned short hgt;
00518   unsigned short x;
00519   unsigned short y;
00520   int buf_size;
00521   int pix;
00522   int pix_cnt;
00523   unsigned int val32;
00524   unsigned char *buff;
00525 
00526   // write and check 32 bit marker
00527   val32 = kMagicNumber;
00528   if (fwrite(&val32, 1, sizeof(val32), fp) != sizeof(val32)) {
00529     return false;
00530   }
00531 
00532   // write wid and hgt
00533   wid = wid_;
00534   if (fwrite(&wid, 1, sizeof(wid), fp) != sizeof(wid)) {
00535     return false;
00536   }
00537 
00538   hgt = hgt_;
00539   if (fwrite(&hgt, 1, sizeof(hgt), fp) != sizeof(hgt)) {
00540     return false;
00541   }
00542 
00543   // write buf size
00544   pix_cnt = wid * hgt;
00545   buf_size = 3 * pix_cnt;
00546   if (fwrite(&buf_size, 1, sizeof(buf_size), fp) != sizeof(buf_size)) {
00547     return false;
00548   }
00549 
00550   // alloc memory & write the 3 channel buffer
00551   buff = new unsigned char[buf_size];
00552   if (buff == NULL) {
00553     return false;
00554   }
00555 
00556   // copy the data
00557   for (y = 0, pix = 0; y < hgt_; y++) {
00558     for (x = 0; x < wid_; x++, pix += 3) {
00559       buff[pix] =
00560       buff[pix + 1] =
00561       buff[pix + 2] = line_buff_[y][x];
00562     }
00563   }
00564 
00565   if (fwrite(buff, 1, buf_size, fp) != buf_size) {
00566     delete []buff;
00567     return false;
00568   }
00569 
00570   // delete temp buffer
00571   delete[]buff;
00572 
00573   return true;
00574 }
00575 
00576 // copy part of the specified bitmap to the top of the bitmap
00577 // does any necessary clipping
00578 void Bmp8::Copy(int x_st, int y_st, int wid, int hgt, Bmp8 *bmp_dest) const {
00579   int x_end = min(x_st + wid, static_cast<int>(wid_)),
00580   y_end = min(y_st + hgt, static_cast<int>(hgt_));
00581 
00582   for (int y = y_st; y < y_end; y++) {
00583     for (int x = x_st; x < x_end; x++) {
00584       bmp_dest->line_buff_[y - y_st][x - x_st] =
00585           line_buff_[y][x];
00586     }
00587   }
00588 }
00589 
00590 bool Bmp8::IsIdentical(Bmp8 *pBmp) const {
00591   if (wid_ != pBmp->wid_ || hgt_ != pBmp->hgt_) {
00592     return false;
00593   }
00594 
00595   for (int y = 0; y < hgt_; y++) {
00596     if (memcmp(line_buff_[y], pBmp->line_buff_[y], wid_) != 0) {
00597       return false;
00598     }
00599   }
00600 
00601   return true;
00602 }
00603 
00604 // Detect connected components in the bitmap
00605 ConComp ** Bmp8::FindConComps(int *concomp_cnt, int min_size) const {
00606   (*concomp_cnt) = 0;
00607 
00608   unsigned int **out_bmp_array = CreateBmpBuffer(wid_, hgt_, 0);
00609   if (out_bmp_array == NULL) {
00610     fprintf(stderr, "Cube ERROR (Bmp8::FindConComps): could not allocate "
00611             "bitmap array\n");
00612     return NULL;
00613   }
00614 
00615   // listed of connected components
00616   ConComp **concomp_array = NULL;
00617 
00618   int x;
00619   int y;
00620   int x_nbr;
00621   int y_nbr;
00622   int concomp_id;
00623   int alloc_concomp_cnt = 0;
00624 
00625   // neighbors to check
00626   const int nbr_cnt = 4;
00627 
00628   // relative coordinates of nbrs
00629   int x_del[nbr_cnt] = {-1, 0, 1, -1},
00630     y_del[nbr_cnt] = {-1, -1, -1, 0};
00631 
00632 
00633   for (y = 0; y < hgt_; y++) {
00634     for (x = 0; x < wid_; x++) {
00635       // is this a foreground pix
00636       if (line_buff_[y][x] != 0xff) {
00637         int master_concomp_id = 0;
00638         ConComp *master_concomp = NULL;
00639 
00640         // checkout the nbrs
00641         for (int nbr = 0; nbr < nbr_cnt; nbr++) {
00642           x_nbr = x + x_del[nbr];
00643           y_nbr = y + y_del[nbr];
00644 
00645           if (x_nbr < 0 || y_nbr < 0 || x_nbr >= wid_ || y_nbr >= hgt_) {
00646             continue;
00647           }
00648 
00649           // is this nbr a foreground pix
00650           if (line_buff_[y_nbr][x_nbr] != 0xff) {
00651             // get its concomp ID
00652             concomp_id = out_bmp_array[y_nbr][x_nbr];
00653 
00654             // this should not happen
00655             if (concomp_id < 1 || concomp_id > alloc_concomp_cnt) {
00656               fprintf(stderr, "Cube ERROR (Bmp8::FindConComps): illegal "
00657                       "connected component id: %d\n", concomp_id);
00658               FreeBmpBuffer(out_bmp_array);
00659               delete []concomp_array;
00660               return NULL;
00661             }
00662 
00663             // if we has previously found a component then merge the two
00664             // and delete the latest one
00665             if (master_concomp != NULL && concomp_id != master_concomp_id) {
00666               // relabel all the pts
00667               ConCompPt *pt_ptr = concomp_array[concomp_id - 1]->Head();
00668               while (pt_ptr != NULL) {
00669                 out_bmp_array[pt_ptr->y()][pt_ptr->x()] = master_concomp_id;
00670                 pt_ptr = pt_ptr->Next();
00671               }
00672 
00673               // merge the two concomp
00674               if (!master_concomp->Merge(concomp_array[concomp_id - 1])) {
00675                 fprintf(stderr, "Cube ERROR (Bmp8::FindConComps): could not "
00676                         "merge connected component: %d\n", concomp_id);
00677                 FreeBmpBuffer(out_bmp_array);
00678                 delete []concomp_array;
00679                 return NULL;
00680               }
00681 
00682               // delete the merged concomp
00683               delete concomp_array[concomp_id - 1];
00684               concomp_array[concomp_id - 1] = NULL;
00685             } else {
00686               // this is the first concomp we encounter
00687               master_concomp_id = concomp_id;
00688               master_concomp = concomp_array[master_concomp_id - 1];
00689 
00690               out_bmp_array[y][x] = master_concomp_id;
00691 
00692               if (!master_concomp->Add(x, y)) {
00693                 fprintf(stderr, "Cube ERROR (Bmp8::FindConComps): could not "
00694                         "add connected component (%d,%d)\n", x, y);
00695                 FreeBmpBuffer(out_bmp_array);
00696                 delete []concomp_array;
00697                 return NULL;
00698               }
00699             }
00700           }  // foreground nbr
00701         }  // nbrs
00702 
00703         // if there was no foreground pix, then create a new concomp
00704         if (master_concomp == NULL) {
00705           master_concomp = new ConComp();
00706           if (master_concomp == NULL || master_concomp->Add(x, y) == false) {
00707             fprintf(stderr, "Cube ERROR (Bmp8::FindConComps): could not "
00708                     "allocate or add a connected component\n");
00709             FreeBmpBuffer(out_bmp_array);
00710             delete []concomp_array;
00711             return NULL;
00712           }
00713 
00714           // extend the list of concomps if needed
00715           if ((alloc_concomp_cnt % kConCompAllocChunk) == 0) {
00716             ConComp **temp_con_comp =
00717                 new ConComp *[alloc_concomp_cnt + kConCompAllocChunk];
00718             if (temp_con_comp == NULL) {
00719               fprintf(stderr, "Cube ERROR (Bmp8::FindConComps): could not "
00720                       "extend array of connected components\n");
00721               FreeBmpBuffer(out_bmp_array);
00722               delete []concomp_array;
00723               return NULL;
00724             }
00725 
00726             if (alloc_concomp_cnt > 0) {
00727               memcpy(temp_con_comp, concomp_array,
00728                      alloc_concomp_cnt * sizeof(*concomp_array));
00729 
00730               delete []concomp_array;
00731             }
00732 
00733             concomp_array = temp_con_comp;
00734           }
00735 
00736           concomp_array[alloc_concomp_cnt++] = master_concomp;
00737           out_bmp_array[y][x] = alloc_concomp_cnt;
00738         }
00739       }  // foreground pix
00740     }  // x
00741   }  // y
00742 
00743   // free the concomp bmp
00744   FreeBmpBuffer(out_bmp_array);
00745 
00746   if (alloc_concomp_cnt > 0 && concomp_array != NULL) {
00747     // scan the array of connected components and color
00748     // the o/p buffer with the corresponding concomps
00749     (*concomp_cnt) = 0;
00750     ConComp *concomp = NULL;
00751 
00752     for (int concomp_idx = 0; concomp_idx < alloc_concomp_cnt; concomp_idx++) {
00753       concomp = concomp_array[concomp_idx];
00754 
00755       // found a concomp
00756       if (concomp != NULL) {
00757         // add the connected component if big enough
00758         if (concomp->PtCnt() > min_size) {
00759           concomp->SetLeftMost(true);
00760           concomp->SetRightMost(true);
00761           concomp->SetID((*concomp_cnt));
00762           concomp_array[(*concomp_cnt)++] = concomp;
00763         } else {
00764           delete concomp;
00765         }
00766       }
00767     }
00768   }
00769 
00770   return concomp_array;
00771 }
00772 
00773 // precompute the tan table to speedup deslanting
00774 bool Bmp8::ComputeTanTable() {
00775   int ang_idx;
00776   float ang_val;
00777 
00778   // alloc memory for tan table
00779   delete []tan_table_;
00780   tan_table_ = new float[kDeslantAngleCount];
00781   if (tan_table_ == NULL) {
00782     return false;
00783   }
00784 
00785   for (ang_idx = 0, ang_val = kMinDeslantAngle;
00786        ang_idx < kDeslantAngleCount; ang_idx++) {
00787     tan_table_[ang_idx] = tan(ang_val * M_PI / 180.0f);
00788     ang_val += kDeslantAngleDelta;
00789   }
00790 
00791   return true;
00792 }
00793 
00794 // generates a deslanted bitmap from the passed bitmap.
00795 bool Bmp8::Deslant() {
00796   int x;
00797   int y;
00798   int des_x;
00799   int des_y;
00800   int ang_idx;
00801   int best_ang;
00802   int min_des_x;
00803   int max_des_x;
00804   int des_wid;
00805 
00806   // only do deslanting if bitmap is wide enough
00807   // otherwise it slant estimate might not be reliable
00808   if (wid_ < (hgt_ * 2)) {
00809     return true;
00810   }
00811 
00812   // compute tan table if needed
00813   if (tan_table_ == NULL && !ComputeTanTable()) {
00814     return false;
00815   }
00816 
00817   // compute min and max values for x after deslant
00818   min_des_x = static_cast<int>(0.5f + (hgt_ - 1) * tan_table_[0]);
00819   max_des_x = (wid_ - 1) +
00820       static_cast<int>(0.5f + (hgt_ - 1) * tan_table_[kDeslantAngleCount - 1]);
00821 
00822   des_wid = max_des_x - min_des_x + 1;
00823 
00824   // alloc memory for histograms
00825   int **angle_hist = new int*[kDeslantAngleCount];
00826   for (ang_idx = 0; ang_idx < kDeslantAngleCount; ang_idx++) {
00827     angle_hist[ang_idx] = new int[des_wid];
00828     if (angle_hist[ang_idx] == NULL) {
00829       delete[] angle_hist;
00830       return false;
00831     }
00832     memset(angle_hist[ang_idx], 0, des_wid * sizeof(*angle_hist[ang_idx]));
00833   }
00834 
00835   // compute histograms
00836   for (y = 0; y < hgt_; y++) {
00837     for (x = 0; x < wid_; x++) {
00838       // find a non-bkgrnd pixel
00839       if (line_buff_[y][x] != 0xff) {
00840         des_y = hgt_ - y - 1;
00841         // stamp all histograms
00842         for (ang_idx = 0; ang_idx < kDeslantAngleCount; ang_idx++) {
00843           des_x = x + static_cast<int>(0.5f + (des_y * tan_table_[ang_idx]));
00844           if (des_x >= min_des_x && des_x <= max_des_x) {
00845             angle_hist[ang_idx][des_x - min_des_x]++;
00846           }
00847         }
00848       }
00849     }
00850   }
00851 
00852   // find the histogram with the lowest entropy
00853   float entropy;
00854   double best_entropy = 0.0f;
00855   double norm_val;
00856 
00857   best_ang = -1;
00858   for (ang_idx = 0; ang_idx < kDeslantAngleCount; ang_idx++) {
00859     entropy = 0.0f;
00860 
00861     for (x = min_des_x; x <= max_des_x; x++) {
00862       if (angle_hist[ang_idx][x - min_des_x] > 0) {
00863         norm_val = (1.0f * angle_hist[ang_idx][x - min_des_x] / hgt_);
00864         entropy += (-1.0f * norm_val * log(norm_val));
00865       }
00866     }
00867 
00868     if (best_ang == -1 || entropy < best_entropy) {
00869       best_ang = ang_idx;
00870       best_entropy = entropy;
00871     }
00872 
00873     // free the histogram
00874     delete[] angle_hist[ang_idx];
00875   }
00876   delete[] angle_hist;
00877 
00878   // deslant
00879   if (best_ang != -1) {
00880     unsigned char **dest_lines;
00881     int old_wid = wid_;
00882 
00883     // create a new buffer
00884     wid_ = des_wid;
00885     dest_lines = CreateBmpBuffer();
00886     if (dest_lines == NULL) {
00887       return false;
00888     }
00889 
00890     for (y = 0; y < hgt_; y++) {
00891       for (x = 0; x < old_wid; x++) {
00892         // find a non-bkgrnd pixel
00893         if (line_buff_[y][x] != 0xff) {
00894           des_y = hgt_ - y - 1;
00895           // compute new pos
00896           des_x = x + static_cast<int>(0.5f + (des_y * tan_table_[best_ang]));
00897           dest_lines[y][des_x - min_des_x] = 0;
00898         }
00899       }
00900     }
00901 
00902     // free old buffer
00903     FreeBmpBuffer(line_buff_);
00904     line_buff_ = dest_lines;
00905   }
00906   return true;
00907 }
00908 
00909 // Load dimensions & contents of bitmap from raw data
00910 bool Bmp8::LoadFromCharDumpFile(unsigned char **raw_data_ptr) {
00911   unsigned short wid;
00912   unsigned short hgt;
00913   unsigned short x;
00914   unsigned short y;
00915   unsigned char *raw_data = (*raw_data_ptr);
00916   int buf_size;
00917   int pix;
00918   unsigned int val32;
00919 
00920   // read and check 32 bit marker
00921   memcpy(&val32, raw_data, sizeof(val32));
00922   raw_data += sizeof(val32);
00923 
00924   if (val32 != kMagicNumber) {
00925     return false;
00926   }
00927 
00928   // read wid and hgt
00929   memcpy(&wid, raw_data, sizeof(wid));
00930   raw_data += sizeof(wid);
00931 
00932   memcpy(&hgt, raw_data, sizeof(hgt));
00933   raw_data += sizeof(hgt);
00934 
00935   // read buf size
00936   memcpy(&buf_size, raw_data, sizeof(buf_size));
00937   raw_data += sizeof(buf_size);
00938 
00939   // validate buf size: for now, only 3 channel (RBG) is supported
00940   if (buf_size != (3 * wid * hgt)) {
00941     return false;
00942   }
00943 
00944   wid_ = wid;
00945   hgt_ = hgt;
00946 
00947   line_buff_ = CreateBmpBuffer();
00948   if (line_buff_ == NULL) {
00949     return false;
00950   }
00951 
00952   // copy the data
00953   for (y = 0, pix = 0; y < hgt_; y++) {
00954     for (x = 0; x < wid_; x++, pix += 3) {
00955       // for now we only support gray scale,
00956       // so we expect R = G = B, it this is not the case, bail out
00957       if  (raw_data[pix] != raw_data[pix + 1] ||
00958            raw_data[pix] != raw_data[pix + 2]) {
00959         return false;
00960       }
00961 
00962       line_buff_[y][x] = raw_data[pix];
00963     }
00964   }
00965 
00966   (*raw_data_ptr) = raw_data + buf_size;
00967   return true;
00968 }
00969 
00970 float Bmp8::ForegroundRatio() const {
00971   int fore_cnt = 0;
00972 
00973   if (wid_ == 0 || hgt_ == 0) {
00974     return 1.0;
00975   }
00976 
00977   for (int y = 0; y < hgt_; y++) {
00978     for (int x = 0; x < wid_; x++) {
00979       fore_cnt += (line_buff_[y][x] == 0xff ? 0 : 1);
00980     }
00981   }
00982 
00983   return (1.0 * (fore_cnt / hgt_) / wid_);
00984 }
00985 
00986 // generates a deslanted bitmap from the passed bitmap
00987 bool Bmp8::HorizontalDeslant(double *deslant_angle) {
00988   int x;
00989   int y;
00990   int des_y;
00991   int ang_idx;
00992   int best_ang;
00993   int min_des_y;
00994   int max_des_y;
00995   int des_hgt;
00996 
00997   // compute tan table if necess.
00998   if (tan_table_ == NULL && !ComputeTanTable()) {
00999     return false;
01000   }
01001 
01002   // compute min and max values for x after deslant
01003   min_des_y = min(0, static_cast<int>((wid_ - 1) * tan_table_[0]));
01004   max_des_y = (hgt_ - 1) +
01005       max(0, static_cast<int>((wid_ - 1) * tan_table_[kDeslantAngleCount - 1]));
01006 
01007   des_hgt = max_des_y - min_des_y + 1;
01008 
01009   // alloc memory for histograms
01010   int **angle_hist = new int*[kDeslantAngleCount];
01011   for (ang_idx = 0; ang_idx < kDeslantAngleCount; ang_idx++) {
01012     angle_hist[ang_idx] = new int[des_hgt];
01013     if (angle_hist[ang_idx] == NULL) {
01014       delete[] angle_hist;
01015       return false;
01016     }
01017     memset(angle_hist[ang_idx], 0, des_hgt * sizeof(*angle_hist[ang_idx]));
01018   }
01019 
01020   // compute histograms
01021   for (y = 0; y < hgt_; y++) {
01022     for (x = 0; x < wid_; x++) {
01023       // find a non-bkgrnd pixel
01024       if (line_buff_[y][x] != 0xff) {
01025         // stamp all histograms
01026         for (ang_idx = 0; ang_idx < kDeslantAngleCount; ang_idx++) {
01027           des_y = y - static_cast<int>(x * tan_table_[ang_idx]);
01028           if (des_y >= min_des_y && des_y <= max_des_y) {
01029             angle_hist[ang_idx][des_y - min_des_y]++;
01030           }
01031         }
01032       }
01033     }
01034   }
01035 
01036   // find the histogram with the lowest entropy
01037   float entropy;
01038   float best_entropy =  0.0f;
01039   float norm_val;
01040 
01041   best_ang = -1;
01042   for (ang_idx = 0; ang_idx < kDeslantAngleCount; ang_idx++) {
01043     entropy = 0.0f;
01044 
01045     for (y = min_des_y; y <= max_des_y; y++) {
01046       if (angle_hist[ang_idx][y - min_des_y] > 0) {
01047         norm_val = (1.0f * angle_hist[ang_idx][y - min_des_y] / wid_);
01048         entropy += (-1.0f * norm_val * log(norm_val));
01049       }
01050     }
01051 
01052     if (best_ang == -1 || entropy < best_entropy) {
01053       best_ang = ang_idx;
01054       best_entropy = entropy;
01055     }
01056 
01057     // free the histogram
01058     delete[] angle_hist[ang_idx];
01059   }
01060   delete[] angle_hist;
01061 
01062   (*deslant_angle) = 0.0;
01063 
01064   // deslant
01065   if (best_ang != -1) {
01066     unsigned char **dest_lines;
01067     int old_hgt = hgt_;
01068 
01069     // create a new buffer
01070     min_des_y = min(0, static_cast<int>((wid_ - 1) * -tan_table_[best_ang]));
01071     max_des_y = (hgt_ - 1) +
01072         max(0, static_cast<int>((wid_ - 1) * -tan_table_[best_ang]));
01073     hgt_ = max_des_y - min_des_y + 1;
01074     dest_lines = CreateBmpBuffer();
01075     if (dest_lines == NULL) {
01076       return false;
01077     }
01078 
01079     for (y = 0; y < old_hgt; y++) {
01080       for (x = 0; x < wid_; x++) {
01081         // find a non-bkgrnd pixel
01082         if (line_buff_[y][x] != 0xff) {
01083           // compute new pos
01084           des_y = y - static_cast<int>((x * tan_table_[best_ang]));
01085           dest_lines[des_y - min_des_y][x] = 0;
01086         }
01087       }
01088     }
01089 
01090     // free old buffer
01091     FreeBmpBuffer(line_buff_);
01092     line_buff_ = dest_lines;
01093 
01094     (*deslant_angle) = kMinDeslantAngle + (best_ang * kDeslantAngleDelta);
01095   }
01096 
01097   return true;
01098 }
01099 
01100 float Bmp8::MeanHorizontalHistogramEntropy() const {
01101   float entropy = 0.0f;
01102 
01103   // compute histograms
01104   for (int y = 0; y < hgt_; y++) {
01105     int pix_cnt = 0;
01106 
01107     for (int x = 0; x < wid_; x++) {
01108       // find a non-bkgrnd pixel
01109       if (line_buff_[y][x] != 0xff) {
01110         pix_cnt++;
01111       }
01112     }
01113 
01114     if (pix_cnt > 0) {
01115       float norm_val = (1.0f * pix_cnt / wid_);
01116       entropy += (-1.0f * norm_val * log(norm_val));
01117     }
01118   }
01119 
01120   return entropy / hgt_;
01121 }
01122 
01123 int *Bmp8::HorizontalHistogram() const {
01124   int *hist = new int[hgt_];
01125   if (hist == NULL) {
01126     return NULL;
01127   }
01128 
01129   // compute histograms
01130   for (int y = 0; y < hgt_; y++) {
01131     hist[y] = 0;
01132 
01133     for (int x = 0; x < wid_; x++) {
01134       // find a non-bkgrnd pixel
01135       if (line_buff_[y][x] != 0xff) {
01136         hist[y]++;
01137       }
01138     }
01139   }
01140 
01141   return hist;
01142 }
01143 
01144 }  // namespace tesseract
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Defines