Tesseract 3.02

- Main Page
- Related Pages
- Modules
- Namespaces
- Classes
- Files

- File List
- File Members

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
49 Bmp8::~Bmp8() {
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
142 bool Bmp8::LoadFromCharDumpFile(CachedFile *fp) {
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
222 Bmp8 * Bmp8::FromCharDumpFile(CachedFile *fp) {
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
236 bool Bmp8::LoadFromCharDumpFile(FILE *fp) {
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
319 Bmp8 * Bmp8::FromCharDumpFile(FILE *fp) {
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.
801 bool Bmp8::Deslant() {
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
1106 float Bmp8::MeanHorizontalHistogramEntropy() const {
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
1129 int *Bmp8::HorizontalHistogram() const {
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