27 #ifdef USE_STD_NAMESPACE
35 (kMaxDeslantAngle - kMinDeslantAngle) / kDeslantAngleDelta));
36 float *Bmp8::tan_table_ =
NULL;
49 void Bmp8::FreeBmpBuffer(
unsigned char **buff) {
51 if (buff[0] !=
NULL) {
58 void Bmp8::FreeBmpBuffer(
unsigned int **buff) {
60 if (buff[0] !=
NULL) {
68 unsigned char **Bmp8::CreateBmpBuffer(
unsigned char init_val) {
76 stride_ = ((
wid_ % 4) == 0) ?
wid_ : (4 * (1 + (
wid_ / 4)));
78 buff = (
unsigned char **)
new unsigned char *[
hgt_ *
sizeof(*buff)];
85 buff[0] = (
unsigned char *)
86 new unsigned char[stride_ *
hgt_ *
sizeof(*buff[0])];
91 memset(buff[0], init_val, stride_ *
hgt_ *
sizeof(*buff[0]));
93 for (
int y = 1; y <
hgt_; y++) {
94 buff[y] = buff[y -1] + stride_;
101 unsigned int ** Bmp8::CreateBmpBuffer(
int wid,
int hgt,
102 unsigned char init_val) {
106 buff = (
unsigned int **)
new unsigned int *[hgt *
sizeof(*buff)];
113 buff[0] = (
unsigned int *)
new unsigned int[wid * hgt *
sizeof(*buff[0])];
118 memset(buff[0], init_val, wid * hgt *
sizeof(*buff[0]));
120 for (
int y = 1; y < hgt; y++) {
121 buff[y] = buff[y -1] + wid;
149 if (fp->
Read(&val32,
sizeof(val32)) !=
sizeof(val32)) {
153 if (val32 != kMagicNumber) {
158 if (fp->
Read(&wid,
sizeof(wid)) !=
sizeof(wid)) {
162 if (fp->
Read(&hgt,
sizeof(hgt)) !=
sizeof(hgt)) {
167 if (fp->
Read(&buf_size,
sizeof(buf_size)) !=
sizeof(buf_size)) {
173 if (buf_size != (3 * pix_cnt)) {
178 buff =
new unsigned char[buf_size];
183 if (fp->
Read(buff, buf_size) != buf_size) {
199 for (y = 0, pix = 0; y <
hgt_; y++) {
200 for (x = 0; x <
wid_; x++, pix += 3) {
203 if (buff[pix] != buff[pix + 1] || buff[pix] != buff[pix + 2]) {
220 if (bmp_obj ==
NULL) {
244 if (fread(&val32, 1,
sizeof(val32), fp) !=
sizeof(val32)) {
248 if (val32 != kMagicNumber) {
253 if (fread(&wid, 1,
sizeof(wid), fp) !=
sizeof(wid)) {
257 if (fread(&hgt, 1,
sizeof(hgt), fp) !=
sizeof(hgt)) {
262 if (fread(&buf_size, 1,
sizeof(buf_size), fp) !=
sizeof(buf_size)) {
268 if (buf_size != (3 * pix_cnt)) {
273 buff =
new unsigned char[buf_size];
278 if (fread(buff, 1, buf_size, fp) != buf_size) {
294 for (y = 0, pix = 0; y <
hgt_; y++) {
295 for (x = 0; x <
wid_; x++, pix += 3) {
298 if (buff[pix] != buff[pix + 1] || buff[pix] != buff[pix + 2]) {
315 if (bmp_obj ==
NULL) {
328 for (
int y = 0; y <
hgt_; y++) {
338 for (
int x = 0; x <
wid_; x++) {
355 while ((*xst) < (
wid_ - 1) && (*xst) <= xend) {
363 while (xend > 0 && xend >= (*xst)) {
371 while ((*yst) < (
hgt_ - 1) && (*yst) <= yend) {
379 while (yend > 0 && yend >= (*yst)) {
387 (*wid) = xend - (*xst) + 1;
388 (*hgt) = yend - (*yst) + 1;
406 int xend_src = bmp->
wid_ - 1;
407 int yend_src = bmp->
hgt_ - 1;
412 wid_src = xend_src - xst_src + 1,
413 hgt_src = yend_src - yst_src + 1;
417 if ((
wid_ * hgt_src) > (
hgt_ * wid_src)) {
418 x_num = y_num =
hgt_;
419 x_denom = y_denom = hgt_src;
421 x_num = y_num =
wid_;
422 x_denom = y_denom = wid_src;
432 xoff = (
wid_ - ((x_num * wid_src) / x_denom)) / 2;
433 yoff = (
hgt_ - ((y_num * hgt_src) / y_denom)) / 2;
436 if (y_num > y_denom) {
437 for (ydest = yoff; ydest < (
hgt_ - yoff); ydest++) {
439 ysrc =
static_cast<int>(0.5 + (1.0 * (ydest - yoff) *
441 if (ysrc < 0 || ysrc >= hgt_src) {
445 for (xdest = xoff; xdest < (
wid_ - xoff); xdest++) {
447 xsrc =
static_cast<int>(0.5 + (1.0 * (xdest - xoff) *
449 if (xsrc < 0 || xsrc >= wid_src) {
454 bmp->
line_buff_[ysrc + yst_src][xsrc + xst_src];
461 unsigned int **dest_line_buff = CreateBmpBuffer(
wid_,
hgt_, 0),
462 **dest_pix_cnt = CreateBmpBuffer(
wid_,
hgt_, 0);
464 for (ysrc = 0; ysrc < hgt_src; ysrc++) {
466 ydest = yoff +
static_cast<int>(0.5 + (1.0 * ysrc * y_num / y_denom));
467 if (ydest < 0 || ydest >=
hgt_) {
471 for (xsrc = 0; xsrc < wid_src; xsrc++) {
473 xdest = xoff +
static_cast<int>(0.5 + (1.0 * xsrc * x_num / x_denom));
474 if (xdest < 0 || xdest >=
wid_) {
478 dest_line_buff[ydest][xdest] +=
479 bmp->
line_buff_[ysrc + yst_src][xsrc + xst_src];
480 dest_pix_cnt[ydest][xdest]++;
484 for (ydest = 0; ydest <
hgt_; ydest++) {
485 for (xdest = 0; xdest <
wid_; xdest++) {
486 if (dest_pix_cnt[ydest][xdest] > 0) {
487 unsigned int pixval =
488 dest_line_buff[ydest][xdest] / dest_pix_cnt[ydest][xdest];
491 (
unsigned char) min((
unsigned int)255, pixval);
497 FreeBmpBuffer(dest_line_buff);
498 FreeBmpBuffer(dest_pix_cnt);
505 unsigned char *pline_data = data;
508 for (
int y = 0; y <
hgt_; y++, pline_data +=
wid_) {
527 val32 = kMagicNumber;
528 if (fwrite(&val32, 1,
sizeof(val32), fp) !=
sizeof(val32)) {
534 if (fwrite(&wid, 1,
sizeof(wid), fp) !=
sizeof(wid)) {
539 if (fwrite(&hgt, 1,
sizeof(hgt), fp) !=
sizeof(hgt)) {
545 buf_size = 3 * pix_cnt;
546 if (fwrite(&buf_size, 1,
sizeof(buf_size), fp) !=
sizeof(buf_size)) {
551 buff =
new unsigned char[buf_size];
557 for (y = 0, pix = 0; y <
hgt_; y++) {
558 for (x = 0; x <
wid_; x++, pix += 3) {
565 if (fwrite(buff, 1, buf_size, fp) != buf_size) {
579 int x_end = min(x_st + wid, static_cast<int>(
wid_)),
580 y_end = min(y_st + hgt, static_cast<int>(
hgt_));
582 for (
int y = y_st; y < y_end; y++) {
583 for (
int x = x_st; x < x_end; x++) {
595 for (
int y = 0; y <
hgt_; y++) {
608 unsigned int **out_bmp_array = CreateBmpBuffer(
wid_,
hgt_, 0);
609 if (out_bmp_array ==
NULL) {
610 fprintf(stderr,
"Cube ERROR (Bmp8::FindConComps): could not allocate "
623 int alloc_concomp_cnt = 0;
626 const int nbr_cnt = 4;
629 int x_del[nbr_cnt] = {-1, 0, 1, -1},
630 y_del[nbr_cnt] = {-1, -1, -1, 0};
633 for (y = 0; y <
hgt_; y++) {
634 for (x = 0; x <
wid_; x++) {
637 int master_concomp_id = 0;
641 for (
int nbr = 0; nbr < nbr_cnt; nbr++) {
642 x_nbr = x + x_del[nbr];
643 y_nbr = y + y_del[nbr];
645 if (x_nbr < 0 || y_nbr < 0 || x_nbr >= wid_ || y_nbr >= hgt_) {
652 concomp_id = out_bmp_array[y_nbr][x_nbr];
655 if (concomp_id < 1 || concomp_id > alloc_concomp_cnt) {
656 fprintf(stderr,
"Cube ERROR (Bmp8::FindConComps): illegal "
657 "connected component id: %d\n", concomp_id);
658 FreeBmpBuffer(out_bmp_array);
659 delete []concomp_array;
665 if (master_concomp !=
NULL && concomp_id != master_concomp_id) {
668 while (pt_ptr !=
NULL) {
669 out_bmp_array[pt_ptr->
y()][pt_ptr->
x()] = master_concomp_id;
670 pt_ptr = pt_ptr->
Next();
674 if (!master_concomp->
Merge(concomp_array[concomp_id - 1])) {
675 fprintf(stderr,
"Cube ERROR (Bmp8::FindConComps): could not "
676 "merge connected component: %d\n", concomp_id);
677 FreeBmpBuffer(out_bmp_array);
678 delete []concomp_array;
683 delete concomp_array[concomp_id - 1];
684 concomp_array[concomp_id - 1] =
NULL;
687 master_concomp_id = concomp_id;
688 master_concomp = concomp_array[master_concomp_id - 1];
690 out_bmp_array[y][x] = master_concomp_id;
692 if (!master_concomp->
Add(x, y)) {
693 fprintf(stderr,
"Cube ERROR (Bmp8::FindConComps): could not "
694 "add connected component (%d,%d)\n", x, y);
695 FreeBmpBuffer(out_bmp_array);
696 delete []concomp_array;
704 if (master_concomp ==
NULL) {
705 master_concomp =
new ConComp();
706 if (master_concomp ==
NULL || master_concomp->
Add(x, y) ==
false) {
707 fprintf(stderr,
"Cube ERROR (Bmp8::FindConComps): could not "
708 "allocate or add a connected component\n");
709 FreeBmpBuffer(out_bmp_array);
710 delete []concomp_array;
718 if (temp_con_comp ==
NULL) {
719 fprintf(stderr,
"Cube ERROR (Bmp8::FindConComps): could not "
720 "extend array of connected components\n");
721 FreeBmpBuffer(out_bmp_array);
722 delete []concomp_array;
726 if (alloc_concomp_cnt > 0) {
727 memcpy(temp_con_comp, concomp_array,
728 alloc_concomp_cnt *
sizeof(*concomp_array));
730 delete []concomp_array;
733 concomp_array = temp_con_comp;
736 concomp_array[alloc_concomp_cnt++] = master_concomp;
737 out_bmp_array[y][x] = alloc_concomp_cnt;
744 FreeBmpBuffer(out_bmp_array);
746 if (alloc_concomp_cnt > 0 && concomp_array !=
NULL) {
752 for (
int concomp_idx = 0; concomp_idx < alloc_concomp_cnt; concomp_idx++) {
753 concomp = concomp_array[concomp_idx];
756 if (concomp !=
NULL) {
758 if (concomp->
PtCnt() > min_size) {
761 concomp->
SetID((*concomp_cnt));
762 concomp_array[(*concomp_cnt)++] = concomp;
770 return concomp_array;
774 bool Bmp8::ComputeTanTable() {
781 if (tan_table_ ==
NULL) {
785 for (ang_idx = 0, ang_val = kMinDeslantAngle;
787 tan_table_[ang_idx] = tan(ang_val * M_PI / 180.0f);
788 ang_val += kDeslantAngleDelta;
813 if (tan_table_ ==
NULL && !ComputeTanTable()) {
818 min_des_x =
static_cast<int>(0.5f + (
hgt_ - 1) * tan_table_[0]);
819 max_des_x = (
wid_ - 1) +
822 des_wid = max_des_x - min_des_x + 1;
827 angle_hist[ang_idx] =
new int[des_wid];
828 if (angle_hist[ang_idx] ==
NULL) {
832 memset(angle_hist[ang_idx], 0, des_wid *
sizeof(*angle_hist[ang_idx]));
836 for (y = 0; y <
hgt_; y++) {
837 for (x = 0; x <
wid_; x++) {
840 des_y = hgt_ - y - 1;
843 des_x = x +
static_cast<int>(0.5f + (des_y * tan_table_[ang_idx]));
844 if (des_x >= min_des_x && des_x <= max_des_x) {
845 angle_hist[ang_idx][des_x - min_des_x]++;
854 double best_entropy = 0.0f;
861 for (x = min_des_x; x <= max_des_x; x++) {
862 if (angle_hist[ang_idx][x - min_des_x] > 0) {
863 norm_val = (1.0f * angle_hist[ang_idx][x - min_des_x] /
hgt_);
864 entropy += (-1.0f * norm_val * log(norm_val));
868 if (best_ang == -1 || entropy < best_entropy) {
870 best_entropy = entropy;
874 delete[] angle_hist[ang_idx];
879 if (best_ang != -1) {
880 unsigned char **dest_lines;
885 dest_lines = CreateBmpBuffer();
886 if (dest_lines ==
NULL) {
890 for (y = 0; y <
hgt_; y++) {
891 for (x = 0; x < old_wid; x++) {
894 des_y = hgt_ - y - 1;
896 des_x = x +
static_cast<int>(0.5f + (des_y * tan_table_[best_ang]));
897 dest_lines[y][des_x - min_des_x] = 0;
915 unsigned char *raw_data = (*raw_data_ptr);
921 memcpy(&val32, raw_data,
sizeof(val32));
922 raw_data +=
sizeof(val32);
924 if (val32 != kMagicNumber) {
929 memcpy(&wid, raw_data,
sizeof(wid));
930 raw_data +=
sizeof(wid);
932 memcpy(&hgt, raw_data,
sizeof(hgt));
933 raw_data +=
sizeof(hgt);
936 memcpy(&buf_size, raw_data,
sizeof(buf_size));
937 raw_data +=
sizeof(buf_size);
940 if (buf_size != (3 * wid * hgt)) {
953 for (y = 0, pix = 0; y <
hgt_; y++) {
954 for (x = 0; x <
wid_; x++, pix += 3) {
957 if (raw_data[pix] != raw_data[pix + 1] ||
958 raw_data[pix] != raw_data[pix + 2]) {
966 (*raw_data_ptr) = raw_data + buf_size;
977 for (
int y = 0; y <
hgt_; y++) {
978 for (
int x = 0; x <
wid_; x++) {
979 fore_cnt += (
line_buff_[y][x] == 0xff ? 0 : 1);
983 return (1.0 * (fore_cnt / hgt_) /
wid_);
998 if (tan_table_ ==
NULL && !ComputeTanTable()) {
1003 min_des_y = min(0, static_cast<int>((
wid_ - 1) * tan_table_[0]));
1004 max_des_y = (
hgt_ - 1) +
1007 des_hgt = max_des_y - min_des_y + 1;
1012 angle_hist[ang_idx] =
new int[des_hgt];
1013 if (angle_hist[ang_idx] ==
NULL) {
1014 delete[] angle_hist;
1017 memset(angle_hist[ang_idx], 0, des_hgt *
sizeof(*angle_hist[ang_idx]));
1021 for (y = 0; y <
hgt_; y++) {
1022 for (x = 0; x <
wid_; x++) {
1027 des_y = y -
static_cast<int>(x * tan_table_[ang_idx]);
1028 if (des_y >= min_des_y && des_y <= max_des_y) {
1029 angle_hist[ang_idx][des_y - min_des_y]++;
1038 float best_entropy = 0.0f;
1045 for (y = min_des_y; y <= max_des_y; y++) {
1046 if (angle_hist[ang_idx][y - min_des_y] > 0) {
1047 norm_val = (1.0f * angle_hist[ang_idx][y - min_des_y] /
wid_);
1048 entropy += (-1.0f * norm_val * log(norm_val));
1052 if (best_ang == -1 || entropy < best_entropy) {
1054 best_entropy = entropy;
1058 delete[] angle_hist[ang_idx];
1060 delete[] angle_hist;
1062 (*deslant_angle) = 0.0;
1065 if (best_ang != -1) {
1066 unsigned char **dest_lines;
1070 min_des_y = min(0, static_cast<int>((
wid_ - 1) * -tan_table_[best_ang]));
1071 max_des_y = (hgt_ - 1) +
1072 max(0, static_cast<int>((
wid_ - 1) * -tan_table_[best_ang]));
1073 hgt_ = max_des_y - min_des_y + 1;
1074 dest_lines = CreateBmpBuffer();
1075 if (dest_lines ==
NULL) {
1079 for (y = 0; y < old_hgt; y++) {
1080 for (x = 0; x <
wid_; x++) {
1084 des_y = y -
static_cast<int>((x * tan_table_[best_ang]));
1085 dest_lines[des_y - min_des_y][x] = 0;
1094 (*deslant_angle) = kMinDeslantAngle + (best_ang * kDeslantAngleDelta);
1101 float entropy = 0.0f;
1104 for (
int y = 0; y <
hgt_; y++) {
1107 for (
int x = 0; x <
wid_; x++) {
1115 float norm_val = (1.0f * pix_cnt /
wid_);
1116 entropy += (-1.0f * norm_val * log(norm_val));
1120 return entropy /
hgt_;
1124 int *hist =
new int[
hgt_];
1130 for (
int y = 0; y <
hgt_; y++) {
1133 for (
int x = 0; x <
wid_; x++) {
bool LoadFromCharDumpFile(CachedFile *fp)
void Copy(int x, int y, int wid, int hgt, Bmp8 *bmp_dest) const
static const int kConCompAllocChunk
bool IsBlankRow(int y) const
bool LoadFromRawData(unsigned char *data)
void SetLeftMost(bool left_most)
ConComp ** FindConComps(int *concomp_cnt, int min_size) const
static Bmp8 * FromCharDumpFile(CachedFile *fp)
void Crop(int *xst_src, int *yst_src, int *wid, int *hgt)
Bmp8(unsigned short wid, unsigned short hgt)
bool SaveBmp2CharDumpFile(FILE *fp) const
static const int kDeslantAngleCount
bool IsBlankColumn(int x) const
bool Merge(ConComp *con_comp)
int * HorizontalHistogram() const
unsigned char ** line_buff_
float ForegroundRatio() const
bool ScaleFrom(Bmp8 *bmp, bool isotropic=true)
bool IsIdentical(Bmp8 *pBmp) const
float MeanHorizontalHistogramEntropy() const
void SetRightMost(bool right_most)
bool HorizontalDeslant(double *deslant_angle)
int Read(void *read_buff, int bytes)