27 #ifdef USE_STD_NAMESPACE 35 (kMaxDeslantAngle - kMinDeslantAngle) / kDeslantAngleDelta));
36 float *Bmp8::tan_table_ = NULL;
49 void Bmp8::FreeBmpBuffer(
unsigned char **buff) {
56 void Bmp8::FreeBmpBuffer(
unsigned int **buff) {
64 unsigned char **Bmp8::CreateBmpBuffer(
unsigned char init_val) {
72 stride_ = ((
wid_ % 4) == 0) ?
wid_ : (4 * (1 + (
wid_ / 4)));
74 buff = (
unsigned char **)
new unsigned char *[
hgt_ *
sizeof(*buff)];
77 buff[0] = (
unsigned char *)
78 new unsigned char[stride_ *
hgt_ *
sizeof(*buff[0])];
80 memset(buff[0], init_val, stride_ *
hgt_ *
sizeof(*buff[0]));
82 for (
int y = 1; y <
hgt_; y++) {
83 buff[y] = buff[y -1] + stride_;
90 unsigned int ** Bmp8::CreateBmpBuffer(
int wid,
int hgt,
91 unsigned char init_val) {
95 buff = (
unsigned int **)
new unsigned int *[hgt *
sizeof(*buff)];
98 buff[0] = (
unsigned int *)
new unsigned int[wid * hgt *
sizeof(*buff[0])];
100 memset(buff[0], init_val, wid * hgt *
sizeof(*buff[0]));
102 for (
int y = 1; y < hgt; y++) {
103 buff[y] = buff[y -1] + wid;
131 if (fp->
Read(&val32,
sizeof(val32)) !=
sizeof(val32)) {
135 if (val32 != kMagicNumber) {
140 if (fp->
Read(&wid,
sizeof(wid)) !=
sizeof(wid)) {
144 if (fp->
Read(&hgt,
sizeof(hgt)) !=
sizeof(hgt)) {
149 if (fp->
Read(&buf_size,
sizeof(buf_size)) !=
sizeof(buf_size)) {
155 if (buf_size != (3 * pix_cnt)) {
160 buff =
new unsigned char[buf_size];
162 if (fp->
Read(buff, buf_size) != buf_size) {
178 for (y = 0, pix = 0; y <
hgt_; y++) {
179 for (x = 0; x <
wid_; x++, pix += 3) {
182 if (buff[pix] != buff[pix + 1] || buff[pix] != buff[pix + 2]) {
220 if (fread(&val32, 1,
sizeof(val32), fp) !=
sizeof(val32)) {
224 if (val32 != kMagicNumber) {
229 if (fread(&wid, 1,
sizeof(wid), fp) !=
sizeof(wid)) {
233 if (fread(&hgt, 1,
sizeof(hgt), fp) !=
sizeof(hgt)) {
238 if (fread(&buf_size, 1,
sizeof(buf_size), fp) !=
sizeof(buf_size)) {
244 if (buf_size != (3 * pix_cnt)) {
249 buff =
new unsigned char[buf_size];
251 if (fread(buff, 1, buf_size, fp) != buf_size) {
267 for (y = 0, pix = 0; y <
hgt_; y++) {
268 for (x = 0; x <
wid_; x++, pix += 3) {
271 if (buff[pix] != buff[pix + 1] || buff[pix] != buff[pix + 2]) {
298 for (
int y = 0; y <
hgt_; y++) {
308 for (
int x = 0; x <
wid_; x++) {
325 while ((*xst) < (
wid_ - 1) && (*xst) <= xend) {
333 while (xend > 0 && xend >= (*xst)) {
341 while ((*yst) < (
hgt_ - 1) && (*yst) <= yend) {
349 while (yend > 0 && yend >= (*yst)) {
357 (*wid) = xend - (*xst) + 1;
358 (*hgt) = yend - (*yst) + 1;
376 int xend_src = bmp->
wid_ - 1;
377 int yend_src = bmp->
hgt_ - 1;
382 wid_src = xend_src - xst_src + 1,
383 hgt_src = yend_src - yst_src + 1;
387 if ((
wid_ * hgt_src) > (
hgt_ * wid_src)) {
388 x_num = y_num =
hgt_;
389 x_denom = y_denom = hgt_src;
391 x_num = y_num =
wid_;
392 x_denom = y_denom = wid_src;
402 xoff = (
wid_ - ((x_num * wid_src) / x_denom)) / 2;
403 yoff = (
hgt_ - ((y_num * hgt_src) / y_denom)) / 2;
406 if (y_num > y_denom) {
407 for (ydest = yoff; ydest < (
hgt_ - yoff); ydest++) {
409 ysrc =
static_cast<int>(0.5 + (1.0 * (ydest - yoff) *
411 if (ysrc < 0 || ysrc >= hgt_src) {
415 for (xdest = xoff; xdest < (
wid_ - xoff); xdest++) {
417 xsrc =
static_cast<int>(0.5 + (1.0 * (xdest - xoff) *
419 if (xsrc < 0 || xsrc >= wid_src) {
424 bmp->
line_buff_[ysrc + yst_src][xsrc + xst_src];
431 unsigned int **dest_line_buff = CreateBmpBuffer(
wid_,
hgt_, 0),
432 **dest_pix_cnt = CreateBmpBuffer(
wid_,
hgt_, 0);
434 for (ysrc = 0; ysrc < hgt_src; ysrc++) {
436 ydest = yoff +
static_cast<int>(0.5 + (1.0 * ysrc * y_num / y_denom));
437 if (ydest < 0 || ydest >=
hgt_) {
441 for (xsrc = 0; xsrc < wid_src; xsrc++) {
443 xdest = xoff +
static_cast<int>(0.5 + (1.0 * xsrc * x_num / x_denom));
444 if (xdest < 0 || xdest >=
wid_) {
448 dest_line_buff[ydest][xdest] +=
449 bmp->
line_buff_[ysrc + yst_src][xsrc + xst_src];
450 dest_pix_cnt[ydest][xdest]++;
454 for (ydest = 0; ydest <
hgt_; ydest++) {
455 for (xdest = 0; xdest <
wid_; xdest++) {
456 if (dest_pix_cnt[ydest][xdest] > 0) {
457 unsigned int pixval =
458 dest_line_buff[ydest][xdest] / dest_pix_cnt[ydest][xdest];
461 (
unsigned char) min((
unsigned int)255, pixval);
467 FreeBmpBuffer(dest_line_buff);
468 FreeBmpBuffer(dest_pix_cnt);
475 unsigned char *pline_data = data;
478 for (
int y = 0; y <
hgt_; y++, pline_data +=
wid_) {
497 val32 = kMagicNumber;
498 if (fwrite(&val32, 1,
sizeof(val32), fp) !=
sizeof(val32)) {
504 if (fwrite(&wid, 1,
sizeof(wid), fp) !=
sizeof(wid)) {
509 if (fwrite(&hgt, 1,
sizeof(hgt), fp) !=
sizeof(hgt)) {
515 buf_size = 3 * pix_cnt;
516 if (fwrite(&buf_size, 1,
sizeof(buf_size), fp) !=
sizeof(buf_size)) {
521 buff =
new unsigned char[buf_size];
524 for (y = 0, pix = 0; y <
hgt_; y++) {
525 for (x = 0; x <
wid_; x++, pix += 3) {
532 if (fwrite(buff, 1, buf_size, fp) != buf_size) {
546 int x_end = min(x_st + wid, static_cast<int>(
wid_)),
547 y_end = min(y_st + hgt, static_cast<int>(
hgt_));
549 for (
int y = y_st; y < y_end; y++) {
550 for (
int x = x_st; x < x_end; x++) {
562 for (
int y = 0; y <
hgt_; y++) {
575 unsigned int **out_bmp_array = CreateBmpBuffer(
wid_,
hgt_, 0);
576 if (out_bmp_array == NULL) {
577 fprintf(stderr,
"Cube ERROR (Bmp8::FindConComps): could not allocate " 583 ConComp **concomp_array = NULL;
590 int alloc_concomp_cnt = 0;
593 const int nbr_cnt = 4;
596 int x_del[nbr_cnt] = {-1, 0, 1, -1},
597 y_del[nbr_cnt] = {-1, -1, -1, 0};
600 for (y = 0; y <
hgt_; y++) {
601 for (x = 0; x <
wid_; x++) {
604 int master_concomp_id = 0;
605 ConComp *master_concomp = NULL;
608 for (
int nbr = 0; nbr < nbr_cnt; nbr++) {
609 x_nbr = x + x_del[nbr];
610 y_nbr = y + y_del[nbr];
612 if (x_nbr < 0 || y_nbr < 0 || x_nbr >=
wid_ || y_nbr >=
hgt_) {
619 concomp_id = out_bmp_array[y_nbr][x_nbr];
622 if (concomp_id < 1 || concomp_id > alloc_concomp_cnt) {
623 fprintf(stderr,
"Cube ERROR (Bmp8::FindConComps): illegal " 624 "connected component id: %d\n", concomp_id);
625 FreeBmpBuffer(out_bmp_array);
626 delete []concomp_array;
632 if (master_concomp != NULL && concomp_id != master_concomp_id) {
635 while (pt_ptr != NULL) {
636 out_bmp_array[pt_ptr->
y()][pt_ptr->
x()] = master_concomp_id;
637 pt_ptr = pt_ptr->
Next();
641 if (!master_concomp->
Merge(concomp_array[concomp_id - 1])) {
642 fprintf(stderr,
"Cube ERROR (Bmp8::FindConComps): could not " 643 "merge connected component: %d\n", concomp_id);
644 FreeBmpBuffer(out_bmp_array);
645 delete []concomp_array;
650 delete concomp_array[concomp_id - 1];
651 concomp_array[concomp_id - 1] = NULL;
654 master_concomp_id = concomp_id;
655 master_concomp = concomp_array[master_concomp_id - 1];
657 out_bmp_array[y][x] = master_concomp_id;
659 if (!master_concomp->
Add(x, y)) {
660 fprintf(stderr,
"Cube ERROR (Bmp8::FindConComps): could not " 661 "add connected component (%d,%d)\n", x, y);
662 FreeBmpBuffer(out_bmp_array);
663 delete []concomp_array;
671 if (master_concomp == NULL) {
672 master_concomp =
new ConComp();
673 if (master_concomp->
Add(x, y) ==
false) {
674 fprintf(stderr,
"Cube ERROR (Bmp8::FindConComps): could not " 675 "allocate or add a connected component\n");
676 FreeBmpBuffer(out_bmp_array);
677 delete []concomp_array;
686 if (alloc_concomp_cnt > 0) {
687 memcpy(temp_con_comp, concomp_array,
688 alloc_concomp_cnt *
sizeof(*concomp_array));
690 delete []concomp_array;
693 concomp_array = temp_con_comp;
696 concomp_array[alloc_concomp_cnt++] = master_concomp;
697 out_bmp_array[y][x] = alloc_concomp_cnt;
704 FreeBmpBuffer(out_bmp_array);
706 if (alloc_concomp_cnt > 0 && concomp_array != NULL) {
712 for (
int concomp_idx = 0; concomp_idx < alloc_concomp_cnt; concomp_idx++) {
713 concomp = concomp_array[concomp_idx];
716 if (concomp != NULL) {
718 if (concomp->
PtCnt() > min_size) {
721 concomp->
SetID((*concomp_cnt));
722 concomp_array[(*concomp_cnt)++] = concomp;
730 return concomp_array;
734 bool Bmp8::ComputeTanTable() {
742 for (ang_idx = 0, ang_val = kMinDeslantAngle;
744 tan_table_[ang_idx] = tan(ang_val * M_PI / 180.0f);
745 ang_val += kDeslantAngleDelta;
770 if (tan_table_ == NULL && !ComputeTanTable()) {
775 min_des_x =
static_cast<int>(0.5f + (
hgt_ - 1) * tan_table_[0]);
776 max_des_x = (
wid_ - 1) +
779 des_wid = max_des_x - min_des_x + 1;
784 angle_hist[ang_idx] =
new int[des_wid];
785 memset(angle_hist[ang_idx], 0, des_wid *
sizeof(*angle_hist[ang_idx]));
789 for (y = 0; y <
hgt_; y++) {
790 for (x = 0; x <
wid_; x++) {
793 des_y =
hgt_ - y - 1;
796 des_x = x +
static_cast<int>(0.5f + (des_y * tan_table_[ang_idx]));
797 if (des_x >= min_des_x && des_x <= max_des_x) {
798 angle_hist[ang_idx][des_x - min_des_x]++;
807 double best_entropy = 0.0f;
814 for (x = min_des_x; x <= max_des_x; x++) {
815 if (angle_hist[ang_idx][x - min_des_x] > 0) {
816 norm_val = (1.0f * angle_hist[ang_idx][x - min_des_x] /
hgt_);
817 entropy += (-1.0f * norm_val * log(norm_val));
821 if (best_ang == -1 || entropy < best_entropy) {
823 best_entropy = entropy;
827 delete[] angle_hist[ang_idx];
832 if (best_ang != -1) {
833 unsigned char **dest_lines;
838 dest_lines = CreateBmpBuffer();
839 if (dest_lines == NULL) {
843 for (y = 0; y <
hgt_; y++) {
844 for (x = 0; x < old_wid; x++) {
847 des_y =
hgt_ - y - 1;
849 des_x = x +
static_cast<int>(0.5f + (des_y * tan_table_[best_ang]));
850 dest_lines[y][des_x - min_des_x] = 0;
868 unsigned char *raw_data = (*raw_data_ptr);
874 memcpy(&val32, raw_data,
sizeof(val32));
875 raw_data +=
sizeof(val32);
877 if (val32 != kMagicNumber) {
882 memcpy(&wid, raw_data,
sizeof(wid));
883 raw_data +=
sizeof(wid);
885 memcpy(&hgt, raw_data,
sizeof(hgt));
886 raw_data +=
sizeof(hgt);
889 memcpy(&buf_size, raw_data,
sizeof(buf_size));
890 raw_data +=
sizeof(buf_size);
893 if (buf_size != (3 * wid * hgt)) {
906 for (y = 0, pix = 0; y <
hgt_; y++) {
907 for (x = 0; x <
wid_; x++, pix += 3) {
910 if (raw_data[pix] != raw_data[pix + 1] ||
911 raw_data[pix] != raw_data[pix + 2]) {
919 (*raw_data_ptr) = raw_data + buf_size;
930 for (
int y = 0; y <
hgt_; y++) {
931 for (
int x = 0; x <
wid_; x++) {
932 fore_cnt += (
line_buff_[y][x] == 0xff ? 0 : 1);
936 return (1.0 * (fore_cnt /
hgt_) /
wid_);
951 if (tan_table_ == NULL && !ComputeTanTable()) {
956 min_des_y = min(0, static_cast<int>((
wid_ - 1) * tan_table_[0]));
957 max_des_y = (
hgt_ - 1) +
960 des_hgt = max_des_y - min_des_y + 1;
965 angle_hist[ang_idx] =
new int[des_hgt];
966 memset(angle_hist[ang_idx], 0, des_hgt *
sizeof(*angle_hist[ang_idx]));
970 for (y = 0; y <
hgt_; y++) {
971 for (x = 0; x <
wid_; x++) {
976 des_y = y -
static_cast<int>(x * tan_table_[ang_idx]);
977 if (des_y >= min_des_y && des_y <= max_des_y) {
978 angle_hist[ang_idx][des_y - min_des_y]++;
987 float best_entropy = 0.0f;
994 for (y = min_des_y; y <= max_des_y; y++) {
995 if (angle_hist[ang_idx][y - min_des_y] > 0) {
996 norm_val = (1.0f * angle_hist[ang_idx][y - min_des_y] /
wid_);
997 entropy += (-1.0f * norm_val * log(norm_val));
1001 if (best_ang == -1 || entropy < best_entropy) {
1003 best_entropy = entropy;
1007 delete[] angle_hist[ang_idx];
1009 delete[] angle_hist;
1011 (*deslant_angle) = 0.0;
1014 if (best_ang != -1) {
1015 unsigned char **dest_lines;
1019 min_des_y = min(0, static_cast<int>((
wid_ - 1) * -tan_table_[best_ang]));
1020 max_des_y = (
hgt_ - 1) +
1021 max(0, static_cast<int>((
wid_ - 1) * -tan_table_[best_ang]));
1022 hgt_ = max_des_y - min_des_y + 1;
1023 dest_lines = CreateBmpBuffer();
1024 if (dest_lines == NULL) {
1028 for (y = 0; y < old_hgt; y++) {
1029 for (x = 0; x <
wid_; x++) {
1033 des_y = y -
static_cast<int>((x * tan_table_[best_ang]));
1034 dest_lines[des_y - min_des_y][x] = 0;
1043 (*deslant_angle) = kMinDeslantAngle + (best_ang * kDeslantAngleDelta);
1050 float entropy = 0.0f;
1053 for (
int y = 0; y <
hgt_; y++) {
1056 for (
int x = 0; x <
wid_; x++) {
1064 float norm_val = (1.0f * pix_cnt /
wid_);
1065 entropy += (-1.0f * norm_val * log(norm_val));
1069 return entropy /
hgt_;
1073 int *hist =
new int[
hgt_];
1076 for (
int y = 0; y <
hgt_; y++) {
1079 for (
int x = 0; x <
wid_; x++) {
bool ScaleFrom(Bmp8 *bmp, bool isotropic=true)
Bmp8(unsigned short wid, unsigned short hgt)
void Copy(int x, int y, int wid, int hgt, Bmp8 *bmp_dest) const
static Bmp8 * FromCharDumpFile(CachedFile *fp)
void SetLeftMost(bool left_most)
static const int kConCompAllocChunk
bool IsBlankRow(int y) const
void Crop(int *xst_src, int *yst_src, int *wid, int *hgt)
int * HorizontalHistogram() const
float ForegroundRatio() const
int Read(void *read_buff, int bytes)
bool LoadFromCharDumpFile(CachedFile *fp)
bool HorizontalDeslant(double *deslant_angle)
unsigned char ** line_buff_
static const int kDeslantAngleCount
bool LoadFromRawData(unsigned char *data)
ConComp ** FindConComps(int *concomp_cnt, int min_size) const
void SetRightMost(bool right_most)
bool IsBlankColumn(int x) const
bool SaveBmp2CharDumpFile(FILE *fp) const
bool Merge(ConComp *con_comp)
float MeanHorizontalHistogramEntropy() const
bool IsIdentical(Bmp8 *pBmp) const