tesseract
3.03
|
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