Tesseract  3.02
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
bmp_8.cpp
Go to the documentation of this file.
1 /**********************************************************************
2  * File: bmp_8.cpp
3  * Description: Implementation of an 8-bit Bitmap class
4  * Author: Ahmad Abdulkader
5  * Created: 2007
6  *
7  * (C) Copyright 2008, Google Inc.
8  ** Licensed under the Apache License, Version 2.0 (the "License");
9  ** you may not use this file except in compliance with the License.
10  ** You may obtain a copy of the License at
11  ** http://www.apache.org/licenses/LICENSE-2.0
12  ** Unless required by applicable law or agreed to in writing, software
13  ** distributed under the License is distributed on an "AS IS" BASIS,
14  ** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15  ** See the License for the specific language governing permissions and
16  ** limitations under the License.
17  *
18  **********************************************************************/
19 
20 #include <stdlib.h>
21 #include <math.h>
22 #include <cstring>
23 #include <algorithm>
24 #include "bmp_8.h"
25 #include "con_comp.h"
26 #ifdef USE_STD_NAMESPACE
27 using std::min;
28 using std::max;
29 #endif
30 
31 #ifdef _WIN32
32 #ifndef M_PI
33 #define M_PI 3.14159265358979323846
34 #endif
35 #endif
36 
37 namespace tesseract {
38 
39 const int Bmp8::kDeslantAngleCount = (1 + static_cast<int>(0.5f +
40  (kMaxDeslantAngle - kMinDeslantAngle) / kDeslantAngleDelta));
41 float *Bmp8::tan_table_ = NULL;
42 
43 Bmp8::Bmp8(unsigned short wid, unsigned short hgt)
44  : wid_(wid)
45  , hgt_(hgt) {
46  line_buff_ = CreateBmpBuffer();
47 }
48 
50  FreeBmpBuffer(line_buff_);
51 }
52 
53 // free buffer
54 void Bmp8::FreeBmpBuffer(unsigned char **buff) {
55  if (buff != NULL) {
56  if (buff[0] != NULL) {
57  delete []buff[0];
58  }
59  delete []buff;
60  }
61 }
62 
63 void Bmp8::FreeBmpBuffer(unsigned int **buff) {
64  if (buff != NULL) {
65  if (buff[0] != NULL) {
66  delete []buff[0];
67  }
68  delete []buff;
69  }
70 }
71 
72 // init bmp buffers
73 unsigned char **Bmp8::CreateBmpBuffer(unsigned char init_val) {
74  unsigned char **buff;
75 
76  // Check valid sizes
77  if (!hgt_ || !wid_)
78  return NULL;
79 
80  // compute stride (align on 4 byte boundries)
81  stride_ = ((wid_ % 4) == 0) ? wid_ : (4 * (1 + (wid_ / 4)));
82 
83  buff = (unsigned char **) new unsigned char *[hgt_ * sizeof(*buff)];
84  if (!buff) {
85  delete []buff;
86  return NULL;
87  }
88 
89  // alloc and init memory for buffer and line buffer
90  buff[0] = (unsigned char *)
91  new unsigned char[stride_ * hgt_ * sizeof(*buff[0])];
92  if (!buff[0]) {
93  return NULL;
94  }
95 
96  memset(buff[0], init_val, stride_ * hgt_ * sizeof(*buff[0]));
97 
98  for (int y = 1; y < hgt_; y++) {
99  buff[y] = buff[y -1] + stride_;
100  }
101 
102  return buff;
103 }
104 
105 // init bmp buffers
106 unsigned int ** Bmp8::CreateBmpBuffer(int wid, int hgt,
107  unsigned char init_val) {
108  unsigned int **buff;
109 
110  // compute stride (align on 4 byte boundries)
111  buff = (unsigned int **) new unsigned int *[hgt * sizeof(*buff)];
112  if (!buff) {
113  delete []buff;
114  return NULL;
115  }
116 
117  // alloc and init memory for buffer and line buffer
118  buff[0] = (unsigned int *) new unsigned int[wid * hgt * sizeof(*buff[0])];
119  if (!buff[0]) {
120  return NULL;
121  }
122 
123  memset(buff[0], init_val, wid * hgt * sizeof(*buff[0]));
124 
125  for (int y = 1; y < hgt; y++) {
126  buff[y] = buff[y -1] + wid;
127  }
128 
129  return buff;
130 }
131 
132 // clears the contents of the bmp
133 bool Bmp8::Clear() {
134  if (line_buff_ == NULL) {
135  return false;
136  }
137 
138  memset(line_buff_[0], 0xff, stride_ * hgt_ * sizeof(*line_buff_[0]));
139  return true;
140 }
141 
143  unsigned short wid;
144  unsigned short hgt;
145  unsigned short x;
146  unsigned short y;
147  int buf_size;
148  int pix;
149  int pix_cnt;
150  unsigned int val32;
151  unsigned char *buff;
152 
153  // read and check 32 bit marker
154  if (fp->Read(&val32, sizeof(val32)) != sizeof(val32)) {
155  return false;
156  }
157 
158  if (val32 != kMagicNumber) {
159  return false;
160  }
161 
162  // read wid and hgt
163  if (fp->Read(&wid, sizeof(wid)) != sizeof(wid)) {
164  return false;
165  }
166 
167  if (fp->Read(&hgt, sizeof(hgt)) != sizeof(hgt)) {
168  return false;
169  }
170 
171  // read buf size
172  if (fp->Read(&buf_size, sizeof(buf_size)) != sizeof(buf_size)) {
173  return false;
174  }
175 
176  // validate buf size: for now, only 3 channel (RBG) is supported
177  pix_cnt = wid * hgt;
178  if (buf_size != (3 * pix_cnt)) {
179  return false;
180  }
181 
182  // alloc memory & read the 3 channel buffer
183  buff = new unsigned char[buf_size];
184  if (buff == NULL) {
185  return false;
186  }
187 
188  if (fp->Read(buff, buf_size) != buf_size) {
189  delete []buff;
190  return false;
191  }
192 
193  // create internal buffers
194  wid_ = wid;
195  hgt_ = hgt;
196 
197  line_buff_ = CreateBmpBuffer();
198  if (line_buff_ == NULL) {
199  delete []buff;
200  return false;
201  }
202 
203  // copy the data
204  for (y = 0, pix = 0; y < hgt_; y++) {
205  for (x = 0; x < wid_; x++, pix += 3) {
206  // for now we only support gray scale,
207  // so we expect R = G = B, it this is not the case, bail out
208  if (buff[pix] != buff[pix + 1] || buff[pix] != buff[pix + 2]) {
209  delete []buff;
210  return false;
211  }
212  line_buff_[y][x] = buff[pix];
213  }
214  }
215 
216  // delete temp buffer
217  delete[]buff;
218 
219  return true;
220 }
221 
223  // create a Bmp8 object
224  Bmp8 *bmp_obj = new Bmp8(0, 0);
225  if (bmp_obj == NULL) {
226  return NULL;
227  }
228 
229  if (bmp_obj->LoadFromCharDumpFile(fp) == false) {
230  delete bmp_obj;
231  }
232 
233  return bmp_obj;
234 }
235 
237  unsigned short wid;
238  unsigned short hgt;
239  unsigned short x;
240  unsigned short y;
241  int buf_size;
242  int pix;
243  int pix_cnt;
244  unsigned int val32;
245  unsigned char *buff;
246 
247  // read and check 32 bit marker
248  if (fread(&val32, 1, sizeof(val32), fp) != sizeof(val32)) {
249  return false;
250  }
251 
252  if (val32 != kMagicNumber) {
253  return false;
254  }
255 
256  // read wid and hgt
257  if (fread(&wid, 1, sizeof(wid), fp) != sizeof(wid)) {
258  return false;
259  }
260 
261  if (fread(&hgt, 1, sizeof(hgt), fp) != sizeof(hgt)) {
262  return false;
263  }
264 
265  // read buf size
266  if (fread(&buf_size, 1, sizeof(buf_size), fp) != sizeof(buf_size)) {
267  return false;
268  }
269 
270  // validate buf size: for now, only 3 channel (RBG) is supported
271  pix_cnt = wid * hgt;
272  if (buf_size != (3 * pix_cnt)) {
273  return false;
274  }
275 
276  // alloc memory & read the 3 channel buffer
277  buff = new unsigned char[buf_size];
278  if (buff == NULL) {
279  return false;
280  }
281 
282  if (fread(buff, 1, buf_size, fp) != buf_size) {
283  delete []buff;
284  return false;
285  }
286 
287  // create internal buffers
288  wid_ = wid;
289  hgt_ = hgt;
290 
291  line_buff_ = CreateBmpBuffer();
292  if (line_buff_ == NULL) {
293  delete []buff;
294  return false;
295  }
296 
297  // copy the data
298  for (y = 0, pix = 0; y < hgt_; y++) {
299  for (x = 0; x < wid_; x++, pix += 3) {
300  // for now we only support gray scale,
301  // so we expect R = G = B, it this is not the case, bail out
302  if ( buff[pix] != buff[pix + 1] ||
303  buff[pix] != buff[pix + 2]
304  ) {
305  delete []buff;
306  return false;
307  }
308 
309  line_buff_[y][x] = buff[pix];
310  }
311  }
312 
313  // delete temp buffer
314  delete[]buff;
315 
316  return true;
317 }
318 
320  // create a Bmp8 object
321  Bmp8 *bmp_obj = new Bmp8(0, 0);
322  if (bmp_obj == NULL) {
323  return NULL;
324  }
325 
326  if (bmp_obj->LoadFromCharDumpFile(fp) == false) {
327  delete bmp_obj;
328  }
329 
330  return bmp_obj;
331 }
332 
333 bool Bmp8::IsBlankColumn(int x) const {
334  for (int y = 0; y < hgt_; y++) {
335  if (line_buff_[y][x] != 0xff) {
336  return false;
337  }
338  }
339 
340  return true;
341 }
342 
343 bool Bmp8::IsBlankRow(int y) const {
344  for (int x = 0; x < wid_; x++) {
345  if (line_buff_[y][x] != 0xff) {
346  return false;
347  }
348  }
349 
350  return true;
351 }
352 
353 // crop the bitmap returning new dimensions
354 void Bmp8::Crop(int *xst, int *yst, int *wid, int *hgt) {
355  (*xst) = 0;
356  (*yst) = 0;
357 
358  int xend = wid_ - 1;
359  int yend = hgt_ - 1;
360 
361  while ((*xst) < (wid_ - 1) && (*xst) <= xend) {
362  // column is not empty
363  if (!IsBlankColumn((*xst))) {
364  break;
365  }
366  (*xst)++;
367  }
368 
369  while (xend > 0 && xend >= (*xst)) {
370  // column is not empty
371  if (!IsBlankColumn(xend)) {
372  break;
373  }
374  xend--;
375  }
376 
377  while ((*yst) < (hgt_ - 1) && (*yst) <= yend) {
378  // column is not empty
379  if (!IsBlankRow((*yst))) {
380  break;
381  }
382  (*yst)++;
383  }
384 
385  while (yend > 0 && yend >= (*yst)) {
386  // column is not empty
387  if (!IsBlankRow(yend)) {
388  break;
389  }
390  yend--;
391  }
392 
393  (*wid) = xend - (*xst) + 1;
394  (*hgt) = yend - (*yst) + 1;
395 }
396 
397 // generates a scaled bitmap with dimensions the new bmp will have the
398 // same aspect ratio and will be centered in the box
399 bool Bmp8::ScaleFrom(Bmp8 *bmp, bool isotropic) {
400  int x_num;
401  int x_denom;
402  int y_num;
403  int y_denom;
404  int xoff;
405  int yoff;
406  int xsrc;
407  int ysrc;
408  int xdest;
409  int ydest;
410  int xst_src = 0;
411  int yst_src = 0;
412  int xend_src = bmp->wid_ - 1;
413  int yend_src = bmp->hgt_ - 1;
414  int wid_src;
415  int hgt_src;
416 
417  // src dimensions
418  wid_src = xend_src - xst_src + 1,
419  hgt_src = yend_src - yst_src + 1;
420 
421  // scale to maintain aspect ratio if required
422  if (isotropic) {
423  if ((wid_ * hgt_src) > (hgt_ * wid_src)) {
424  x_num = y_num = hgt_;
425  x_denom = y_denom = hgt_src;
426  } else {
427  x_num = y_num = wid_;
428  x_denom = y_denom = wid_src;
429  }
430  } else {
431  x_num = wid_;
432  y_num = hgt_;
433  x_denom = wid_src;
434  y_denom = hgt_src;
435  }
436 
437  // compute offsets needed to center new bmp
438  xoff = (wid_ - ((x_num * wid_src) / x_denom)) / 2;
439  yoff = (hgt_ - ((y_num * hgt_src) / y_denom)) / 2;
440 
441  // scale up
442  if (y_num > y_denom) {
443  for (ydest = yoff; ydest < (hgt_ - yoff); ydest++) {
444  // compute un-scaled y
445  ysrc = static_cast<int>(0.5 + (1.0 * (ydest - yoff) *
446  y_denom / y_num));
447  if (ysrc < 0 || ysrc >= hgt_src) {
448  continue;
449  }
450 
451  for (xdest = xoff; xdest < (wid_ - xoff); xdest++) {
452  // compute un-scaled y
453  xsrc = static_cast<int>(0.5 + (1.0 * (xdest - xoff) *
454  x_denom / x_num));
455  if (xsrc < 0 || xsrc >= wid_src) {
456  continue;
457  }
458 
459  line_buff_[ydest][xdest] =
460  bmp->line_buff_[ysrc + yst_src][xsrc + xst_src];
461  }
462  }
463  } else {
464  // or scale down
465  // scaling down is a bit tricky: we'll accumulate pixels
466  // and then compute the means
467  unsigned int **dest_line_buff = CreateBmpBuffer(wid_, hgt_, 0),
468  **dest_pix_cnt = CreateBmpBuffer(wid_, hgt_, 0);
469 
470  for (ysrc = 0; ysrc < hgt_src; ysrc++) {
471  // compute scaled y
472  ydest = yoff + static_cast<int>(0.5 + (1.0 * ysrc * y_num / y_denom));
473  if (ydest < 0 || ydest >= hgt_) {
474  continue;
475  }
476 
477  for (xsrc = 0; xsrc < wid_src; xsrc++) {
478  // compute scaled y
479  xdest = xoff + static_cast<int>(0.5 + (1.0 * xsrc * x_num / x_denom));
480  if (xdest < 0 || xdest >= wid_) {
481  continue;
482  }
483 
484  dest_line_buff[ydest][xdest] +=
485  bmp->line_buff_[ysrc + yst_src][xsrc + xst_src];
486  dest_pix_cnt[ydest][xdest]++;
487  }
488  }
489 
490  for (ydest = 0; ydest < hgt_; ydest++) {
491  for (xdest = 0; xdest < wid_; xdest++) {
492  if (dest_pix_cnt[ydest][xdest] > 0) {
493  unsigned int pixval =
494  dest_line_buff[ydest][xdest] / dest_pix_cnt[ydest][xdest];
495 
496  line_buff_[ydest][xdest] =
497  (unsigned char) min((unsigned int)255, pixval);
498  }
499  }
500  }
501 
502  // we no longer need these temp buffers
503  FreeBmpBuffer(dest_line_buff);
504  FreeBmpBuffer(dest_pix_cnt);
505  }
506 
507  return true;
508 }
509 
510 bool Bmp8::LoadFromRawData(unsigned char *data) {
511  unsigned char *pline_data = data;
512 
513  // copy the data
514  for (int y = 0; y < hgt_; y++, pline_data += wid_) {
515  memcpy(line_buff_[y], pline_data, wid_ * sizeof(*pline_data));
516  }
517 
518  return true;
519 }
520 
521 bool Bmp8::SaveBmp2CharDumpFile(FILE *fp) const {
522  unsigned short wid;
523  unsigned short hgt;
524  unsigned short x;
525  unsigned short y;
526  int buf_size;
527  int pix;
528  int pix_cnt;
529  unsigned int val32;
530  unsigned char *buff;
531 
532  // write and check 32 bit marker
533  val32 = kMagicNumber;
534  if (fwrite(&val32, 1, sizeof(val32), fp) != sizeof(val32)) {
535  return false;
536  }
537 
538  // write wid and hgt
539  wid = wid_;
540  if (fwrite(&wid, 1, sizeof(wid), fp) != sizeof(wid)) {
541  return false;
542  }
543 
544  hgt = hgt_;
545  if (fwrite(&hgt, 1, sizeof(hgt), fp) != sizeof(hgt)) {
546  return false;
547  }
548 
549  // write buf size
550  pix_cnt = wid * hgt;
551  buf_size = 3 * pix_cnt;
552  if (fwrite(&buf_size, 1, sizeof(buf_size), fp) != sizeof(buf_size)) {
553  return false;
554  }
555 
556  // alloc memory & write the 3 channel buffer
557  buff = new unsigned char[buf_size];
558  if (buff == NULL) {
559  return false;
560  }
561 
562  // copy the data
563  for (y = 0, pix = 0; y < hgt_; y++) {
564  for (x = 0; x < wid_; x++, pix += 3) {
565  buff[pix] =
566  buff[pix + 1] =
567  buff[pix + 2] = line_buff_[y][x];
568  }
569  }
570 
571  if (fwrite(buff, 1, buf_size, fp) != buf_size) {
572  delete []buff;
573  return false;
574  }
575 
576  // delete temp buffer
577  delete[]buff;
578 
579  return true;
580 }
581 
582 // copy part of the specified bitmap to the top of the bitmap
583 // does any necessary clipping
584 void Bmp8::Copy(int x_st, int y_st, int wid, int hgt, Bmp8 *bmp_dest) const {
585  int x_end = min(x_st + wid, static_cast<int>(wid_)),
586  y_end = min(y_st + hgt, static_cast<int>(hgt_));
587 
588  for (int y = y_st; y < y_end; y++) {
589  for (int x = x_st; x < x_end; x++) {
590  bmp_dest->line_buff_[y - y_st][x - x_st] =
591  line_buff_[y][x];
592  }
593  }
594 }
595 
596 bool Bmp8::IsIdentical(Bmp8 *pBmp) const {
597  if (wid_ != pBmp->wid_ || hgt_ != pBmp->hgt_) {
598  return false;
599  }
600 
601  for (int y = 0; y < hgt_; y++) {
602  if (memcmp(line_buff_[y], pBmp->line_buff_[y], wid_) != 0) {
603  return false;
604  }
605  }
606 
607  return true;
608 }
609 
610 // Detect connected components in the bitmap
611 ConComp ** Bmp8::FindConComps(int *concomp_cnt, int min_size) const {
612  (*concomp_cnt) = 0;
613 
614  unsigned int **out_bmp_array = CreateBmpBuffer(wid_, hgt_, 0);
615  if (out_bmp_array == NULL) {
616  fprintf(stderr, "Cube ERROR (Bmp8::FindConComps): could not allocate "
617  "bitmap array\n");
618  return NULL;
619  }
620 
621  // listed of connected components
622  ConComp **concomp_array = NULL;
623 
624  int x;
625  int y;
626  int x_nbr;
627  int y_nbr;
628  int concomp_id;
629  int alloc_concomp_cnt = 0;
630 
631  // neighbors to check
632  const int nbr_cnt = 4;
633 
634  // relative coordinates of nbrs
635  int x_del[nbr_cnt] = {-1, 0, 1, -1},
636  y_del[nbr_cnt] = {-1, -1, -1, 0};
637 
638 
639  for (y = 0; y < hgt_; y++) {
640  for (x = 0; x < wid_; x++) {
641  // is this a foreground pix
642  if (line_buff_[y][x] != 0xff) {
643  int master_concomp_id = 0;
644  ConComp *master_concomp = NULL;
645 
646  // checkout the nbrs
647  for (int nbr = 0; nbr < nbr_cnt; nbr++) {
648  x_nbr = x + x_del[nbr];
649  y_nbr = y + y_del[nbr];
650 
651  if (x_nbr < 0 || y_nbr < 0 || x_nbr >= wid_ || y_nbr >= hgt_) {
652  continue;
653  }
654 
655  // is this nbr a foreground pix
656  if (line_buff_[y_nbr][x_nbr] != 0xff) {
657  // get its concomp ID
658  concomp_id = out_bmp_array[y_nbr][x_nbr];
659 
660  // this should not happen
661  if (concomp_id < 1 || concomp_id > alloc_concomp_cnt) {
662  fprintf(stderr, "Cube ERROR (Bmp8::FindConComps): illegal "
663  "connected component id: %d\n", concomp_id);
664  FreeBmpBuffer(out_bmp_array);
665  delete []concomp_array;
666  return NULL;
667  }
668 
669  // if we has previously found a component then merge the two
670  // and delete the latest one
671  if (master_concomp != NULL && concomp_id != master_concomp_id) {
672  // relabel all the pts
673  ConCompPt *pt_ptr = concomp_array[concomp_id - 1]->Head();
674  while (pt_ptr != NULL) {
675  out_bmp_array[pt_ptr->y()][pt_ptr->x()] = master_concomp_id;
676  pt_ptr = pt_ptr->Next();
677  }
678 
679  // merge the two concomp
680  if (!master_concomp->Merge(concomp_array[concomp_id - 1])) {
681  fprintf(stderr, "Cube ERROR (Bmp8::FindConComps): could not "
682  "merge connected component: %d\n", concomp_id);
683  FreeBmpBuffer(out_bmp_array);
684  delete []concomp_array;
685  return NULL;
686  }
687 
688  // delete the merged concomp
689  delete concomp_array[concomp_id - 1];
690  concomp_array[concomp_id - 1] = NULL;
691  } else {
692  // this is the first concomp we encounter
693  master_concomp_id = concomp_id;
694  master_concomp = concomp_array[master_concomp_id - 1];
695 
696  out_bmp_array[y][x] = master_concomp_id;
697 
698  if (!master_concomp->Add(x, y)) {
699  fprintf(stderr, "Cube ERROR (Bmp8::FindConComps): could not "
700  "add connected component (%d,%d)\n", x, y);
701  FreeBmpBuffer(out_bmp_array);
702  delete []concomp_array;
703  return NULL;
704  }
705  }
706  } // foreground nbr
707  } // nbrs
708 
709  // if there was no foreground pix, then create a new concomp
710  if (master_concomp == NULL) {
711  master_concomp = new ConComp();
712  if (master_concomp == NULL || master_concomp->Add(x, y) == false) {
713  fprintf(stderr, "Cube ERROR (Bmp8::FindConComps): could not "
714  "allocate or add a connected component\n");
715  FreeBmpBuffer(out_bmp_array);
716  delete []concomp_array;
717  return NULL;
718  }
719 
720  // extend the list of concomps if needed
721  if ((alloc_concomp_cnt % kConCompAllocChunk) == 0) {
722  ConComp **temp_con_comp =
723  new ConComp *[alloc_concomp_cnt + kConCompAllocChunk];
724  if (temp_con_comp == NULL) {
725  fprintf(stderr, "Cube ERROR (Bmp8::FindConComps): could not "
726  "extend array of connected components\n");
727  FreeBmpBuffer(out_bmp_array);
728  delete []concomp_array;
729  return NULL;
730  }
731 
732  if (alloc_concomp_cnt > 0) {
733  memcpy(temp_con_comp, concomp_array,
734  alloc_concomp_cnt * sizeof(*concomp_array));
735 
736  delete []concomp_array;
737  }
738 
739  concomp_array = temp_con_comp;
740  }
741 
742  concomp_array[alloc_concomp_cnt++] = master_concomp;
743  out_bmp_array[y][x] = alloc_concomp_cnt;
744  }
745  } // foreground pix
746  } // x
747  } // y
748 
749  // free the concomp bmp
750  FreeBmpBuffer(out_bmp_array);
751 
752  if (alloc_concomp_cnt > 0 && concomp_array != NULL) {
753  // scan the array of connected components and color
754  // the o/p buffer with the corresponding concomps
755  (*concomp_cnt) = 0;
756  ConComp *concomp = NULL;
757 
758  for (int concomp_idx = 0; concomp_idx < alloc_concomp_cnt; concomp_idx++) {
759  concomp = concomp_array[concomp_idx];
760 
761  // found a concomp
762  if (concomp != NULL) {
763  // add the connected component if big enough
764  if (concomp->PtCnt() > min_size) {
765  concomp->SetLeftMost(true);
766  concomp->SetRightMost(true);
767  concomp->SetID((*concomp_cnt));
768  concomp_array[(*concomp_cnt)++] = concomp;
769  } else {
770  delete concomp;
771  }
772  }
773  }
774  }
775 
776  return concomp_array;
777 }
778 
779 // precompute the tan table to speedup deslanting
780 bool Bmp8::ComputeTanTable() {
781  int ang_idx;
782  float ang_val;
783 
784  // alloc memory for tan table
785  delete []tan_table_;
786  tan_table_ = new float[kDeslantAngleCount];
787  if (tan_table_ == NULL) {
788  return false;
789  }
790 
791  for (ang_idx = 0, ang_val = kMinDeslantAngle;
792  ang_idx < kDeslantAngleCount; ang_idx++) {
793  tan_table_[ang_idx] = tan(ang_val * M_PI / 180.0f);
794  ang_val += kDeslantAngleDelta;
795  }
796 
797  return true;
798 }
799 
800 // generates a deslanted bitmap from the passed bitmap.
802  int x;
803  int y;
804  int des_x;
805  int des_y;
806  int ang_idx;
807  int best_ang;
808  int min_des_x;
809  int max_des_x;
810  int des_wid;
811 
812  // only do deslanting if bitmap is wide enough
813  // otherwise it slant estimate might not be reliable
814  if (wid_ < (hgt_ * 2)) {
815  return true;
816  }
817 
818  // compute tan table if needed
819  if (tan_table_ == NULL && !ComputeTanTable()) {
820  return false;
821  }
822 
823  // compute min and max values for x after deslant
824  min_des_x = static_cast<int>(0.5f + (hgt_ - 1) * tan_table_[0]);
825  max_des_x = (wid_ - 1) +
826  static_cast<int>(0.5f + (hgt_ - 1) * tan_table_[kDeslantAngleCount - 1]);
827 
828  des_wid = max_des_x - min_des_x + 1;
829 
830  // alloc memory for histograms
831  int **angle_hist = new int*[kDeslantAngleCount];
832  for (ang_idx = 0; ang_idx < kDeslantAngleCount; ang_idx++) {
833  angle_hist[ang_idx] = new int[des_wid];
834  if (angle_hist[ang_idx] == NULL) {
835  delete[] angle_hist;
836  return false;
837  }
838  memset(angle_hist[ang_idx], 0, des_wid * sizeof(*angle_hist[ang_idx]));
839  }
840 
841  // compute histograms
842  for (y = 0; y < hgt_; y++) {
843  for (x = 0; x < wid_; x++) {
844  // find a non-bkgrnd pixel
845  if (line_buff_[y][x] != 0xff) {
846  des_y = hgt_ - y - 1;
847  // stamp all histograms
848  for (ang_idx = 0; ang_idx < kDeslantAngleCount; ang_idx++) {
849  des_x = x + static_cast<int>(0.5f + (des_y * tan_table_[ang_idx]));
850  if (des_x >= min_des_x && des_x <= max_des_x) {
851  angle_hist[ang_idx][des_x - min_des_x]++;
852  }
853  }
854  }
855  }
856  }
857 
858  // find the histogram with the lowest entropy
859  float entropy;
860  double best_entropy = 0.0f;
861  double norm_val;
862 
863  best_ang = -1;
864  for (ang_idx = 0; ang_idx < kDeslantAngleCount; ang_idx++) {
865  entropy = 0.0f;
866 
867  for (x = min_des_x; x <= max_des_x; x++) {
868  if (angle_hist[ang_idx][x - min_des_x] > 0) {
869  norm_val = (1.0f * angle_hist[ang_idx][x - min_des_x] / hgt_);
870  entropy += (-1.0f * norm_val * log(norm_val));
871  }
872  }
873 
874  if (best_ang == -1 || entropy < best_entropy) {
875  best_ang = ang_idx;
876  best_entropy = entropy;
877  }
878 
879  // free the histogram
880  delete[] angle_hist[ang_idx];
881  }
882  delete[] angle_hist;
883 
884  // deslant
885  if (best_ang != -1) {
886  unsigned char **dest_lines;
887  int old_wid = wid_;
888 
889  // create a new buffer
890  wid_ = des_wid;
891  dest_lines = CreateBmpBuffer();
892  if (dest_lines == NULL) {
893  return false;
894  }
895 
896  for (y = 0; y < hgt_; y++) {
897  for (x = 0; x < old_wid; x++) {
898  // find a non-bkgrnd pixel
899  if (line_buff_[y][x] != 0xff) {
900  des_y = hgt_ - y - 1;
901  // compute new pos
902  des_x = x + static_cast<int>(0.5f + (des_y * tan_table_[best_ang]));
903  dest_lines[y][des_x - min_des_x] = 0;
904  }
905  }
906  }
907 
908  // free old buffer
909  FreeBmpBuffer(line_buff_);
910  line_buff_ = dest_lines;
911  }
912  return true;
913 }
914 
915 // Load dimensions & contents of bitmap from raw data
916 bool Bmp8::LoadFromCharDumpFile(unsigned char **raw_data_ptr) {
917  unsigned short wid;
918  unsigned short hgt;
919  unsigned short x;
920  unsigned short y;
921  unsigned char *raw_data = (*raw_data_ptr);
922  int buf_size;
923  int pix;
924  unsigned int val32;
925 
926  // read and check 32 bit marker
927  memcpy(&val32, raw_data, sizeof(val32));
928  raw_data += sizeof(val32);
929 
930  if (val32 != kMagicNumber) {
931  return false;
932  }
933 
934  // read wid and hgt
935  memcpy(&wid, raw_data, sizeof(wid));
936  raw_data += sizeof(wid);
937 
938  memcpy(&hgt, raw_data, sizeof(hgt));
939  raw_data += sizeof(hgt);
940 
941  // read buf size
942  memcpy(&buf_size, raw_data, sizeof(buf_size));
943  raw_data += sizeof(buf_size);
944 
945  // validate buf size: for now, only 3 channel (RBG) is supported
946  if (buf_size != (3 * wid * hgt)) {
947  return false;
948  }
949 
950  wid_ = wid;
951  hgt_ = hgt;
952 
953  line_buff_ = CreateBmpBuffer();
954  if (line_buff_ == NULL) {
955  return false;
956  }
957 
958  // copy the data
959  for (y = 0, pix = 0; y < hgt_; y++) {
960  for (x = 0; x < wid_; x++, pix += 3) {
961  // for now we only support gray scale,
962  // so we expect R = G = B, it this is not the case, bail out
963  if (raw_data[pix] != raw_data[pix + 1] ||
964  raw_data[pix] != raw_data[pix + 2]) {
965  return false;
966  }
967 
968  line_buff_[y][x] = raw_data[pix];
969  }
970  }
971 
972  (*raw_data_ptr) = raw_data + buf_size;
973  return true;
974 }
975 
976 float Bmp8::ForegroundRatio() const {
977  int fore_cnt = 0;
978 
979  if (wid_ <= 0 || hgt_ <= 0) {
980  return 1.0;
981  }
982 
983  for (int y = 0; y < hgt_; y++) {
984  for (int x = 0; x < wid_; x++) {
985  fore_cnt += (line_buff_[y][x] == 0xff ? 0 : 1);
986  }
987  }
988 
989  return (1.0 * (fore_cnt / hgt_) / wid_);
990 }
991 
992 // generates a deslanted bitmap from the passed bitmap
993 bool Bmp8::HorizontalDeslant(double *deslant_angle) {
994  int x;
995  int y;
996  int des_y;
997  int ang_idx;
998  int best_ang;
999  int min_des_y;
1000  int max_des_y;
1001  int des_hgt;
1002 
1003  // compute tan table if necess.
1004  if (tan_table_ == NULL && !ComputeTanTable()) {
1005  return false;
1006  }
1007 
1008  // compute min and max values for x after deslant
1009  min_des_y = min(0, static_cast<int>((wid_ - 1) * tan_table_[0]));
1010  max_des_y = (hgt_ - 1) +
1011  max(0, static_cast<int>((wid_ - 1) * tan_table_[kDeslantAngleCount - 1]));
1012 
1013  des_hgt = max_des_y - min_des_y + 1;
1014 
1015  // alloc memory for histograms
1016  int **angle_hist = new int*[kDeslantAngleCount];
1017  for (ang_idx = 0; ang_idx < kDeslantAngleCount; ang_idx++) {
1018  angle_hist[ang_idx] = new int[des_hgt];
1019  if (angle_hist[ang_idx] == NULL) {
1020  delete[] angle_hist;
1021  return false;
1022  }
1023  memset(angle_hist[ang_idx], 0, des_hgt * sizeof(*angle_hist[ang_idx]));
1024  }
1025 
1026  // compute histograms
1027  for (y = 0; y < hgt_; y++) {
1028  for (x = 0; x < wid_; x++) {
1029  // find a non-bkgrnd pixel
1030  if (line_buff_[y][x] != 0xff) {
1031  // stamp all histograms
1032  for (ang_idx = 0; ang_idx < kDeslantAngleCount; ang_idx++) {
1033  des_y = y - static_cast<int>(x * tan_table_[ang_idx]);
1034  if (des_y >= min_des_y && des_y <= max_des_y) {
1035  angle_hist[ang_idx][des_y - min_des_y]++;
1036  }
1037  }
1038  }
1039  }
1040  }
1041 
1042  // find the histogram with the lowest entropy
1043  float entropy;
1044  float best_entropy = 0.0f;
1045  float norm_val;
1046 
1047  best_ang = -1;
1048  for (ang_idx = 0; ang_idx < kDeslantAngleCount; ang_idx++) {
1049  entropy = 0.0f;
1050 
1051  for (y = min_des_y; y <= max_des_y; y++) {
1052  if (angle_hist[ang_idx][y - min_des_y] > 0) {
1053  norm_val = (1.0f * angle_hist[ang_idx][y - min_des_y] / wid_);
1054  entropy += (-1.0f * norm_val * log(norm_val));
1055  }
1056  }
1057 
1058  if (best_ang == -1 || entropy < best_entropy) {
1059  best_ang = ang_idx;
1060  best_entropy = entropy;
1061  }
1062 
1063  // free the histogram
1064  delete[] angle_hist[ang_idx];
1065  }
1066  delete[] angle_hist;
1067 
1068  (*deslant_angle) = 0.0;
1069 
1070  // deslant
1071  if (best_ang != -1) {
1072  unsigned char **dest_lines;
1073  int old_hgt = hgt_;
1074 
1075  // create a new buffer
1076  min_des_y = min(0, static_cast<int>((wid_ - 1) * -tan_table_[best_ang]));
1077  max_des_y = (hgt_ - 1) +
1078  max(0, static_cast<int>((wid_ - 1) * -tan_table_[best_ang]));
1079  hgt_ = max_des_y - min_des_y + 1;
1080  dest_lines = CreateBmpBuffer();
1081  if (dest_lines == NULL) {
1082  return false;
1083  }
1084 
1085  for (y = 0; y < old_hgt; y++) {
1086  for (x = 0; x < wid_; x++) {
1087  // find a non-bkgrnd pixel
1088  if (line_buff_[y][x] != 0xff) {
1089  // compute new pos
1090  des_y = y - static_cast<int>((x * tan_table_[best_ang]));
1091  dest_lines[des_y - min_des_y][x] = 0;
1092  }
1093  }
1094  }
1095 
1096  // free old buffer
1097  FreeBmpBuffer(line_buff_);
1098  line_buff_ = dest_lines;
1099 
1100  (*deslant_angle) = kMinDeslantAngle + (best_ang * kDeslantAngleDelta);
1101  }
1102 
1103  return true;
1104 }
1105 
1107  float entropy = 0.0f;
1108 
1109  // compute histograms
1110  for (int y = 0; y < hgt_; y++) {
1111  int pix_cnt = 0;
1112 
1113  for (int x = 0; x < wid_; x++) {
1114  // find a non-bkgrnd pixel
1115  if (line_buff_[y][x] != 0xff) {
1116  pix_cnt++;
1117  }
1118  }
1119 
1120  if (pix_cnt > 0) {
1121  float norm_val = (1.0f * pix_cnt / wid_);
1122  entropy += (-1.0f * norm_val * log(norm_val));
1123  }
1124  }
1125 
1126  return entropy / hgt_;
1127 }
1128 
1130  int *hist = new int[hgt_];
1131  if (hist == NULL) {
1132  return NULL;
1133  }
1134 
1135  // compute histograms
1136  for (int y = 0; y < hgt_; y++) {
1137  hist[y] = 0;
1138 
1139  for (int x = 0; x < wid_; x++) {
1140  // find a non-bkgrnd pixel
1141  if (line_buff_[y][x] != 0xff) {
1142  hist[y]++;
1143  }
1144  }
1145  }
1146 
1147  return hist;
1148 }
1149 
1150 } // namespace tesseract