15 #include "allheaders.h"
42 : x_origin_(0), y_origin_(0), pix_(
NULL) {
45 if (scale_factor_ < 1) scale_factor_ = 1;
62 TBOX image_box(0, 0, pixGetWidth(nontext_map), pixGetHeight(nontext_map));
64 y_origin_ = image_box.
height();
65 int width = (image_box.
width() + scale_factor_ - 1) / scale_factor_;
66 int height = (image_box.
height() + scale_factor_ - 1) / scale_factor_;
68 pix_ = pixCreate(width, height, 8);
69 ProjectBlobs(&input_block->
blobs, rotation, image_box, nontext_map);
70 ProjectBlobs(&input_block->
large_blobs, rotation, image_box, nontext_map);
71 Pix* final_pix = pixBlockconv(pix_, 1, 1);
80 #ifndef GRAPHICS_DISABLED
81 BLOBNBOX_IT it(blobs);
82 for (it.mark_cycle_pt(); !it.cycled_list(); it.forward()) {
93 #endif // GRAPHICS_DISABLED
101 BLOBNBOX_LIST* blobs, BLOBNBOX_LIST* small_blobs)
const {
102 BLOBNBOX_IT it(blobs);
103 BLOBNBOX_IT small_it(small_blobs);
104 for (it.mark_cycle_pt(); !it.cycled_list(); it.forward()) {
111 small_it.add_to_end(it.extract());
118 int width = pixGetWidth(pix_);
119 int height = pixGetHeight(pix_);
120 Pix* pixc = pixCreate(width, height, 32);
121 int src_wpl = pixGetWpl(pix_);
122 int col_wpl = pixGetWpl(pixc);
123 uinT32* src_data = pixGetData(pix_);
124 uinT32* col_data = pixGetData(pixc);
125 for (
int y = 0; y < height; ++y, src_data += src_wpl, col_data += col_wpl) {
126 for (
int x = 0; x < width; ++x) {
127 int pixel = GET_DATA_BYTE(src_data, x);
130 composeRGBPixel(0, 0, pixel * 15, &result);
131 else if (pixel <= 145)
132 composeRGBPixel(0, (pixel - 17) * 2, 255, &result);
134 composeRGBPixel((pixel - 145) * 2, 255, 255, &result);
135 col_data[x] = result;
141 width, height, width, height);
142 win->
Image(pixc, 0, 0);
145 pixWrite(
"projection.png", pixc, IFF_PNG);
196 bool horizontal_textline,
201 int parallel_gap = 0;
206 if (horizontal_textline) {
207 parallel_gap = from_box.
x_gap(to_box) + from_box.
width();
208 start_pt.
x = (from_box.
left() + from_box.
right()) / 2;
209 end_pt.
x = start_pt.
x;
211 start_pt.
y = from_box.
top();
212 end_pt.
y =
MIN(to_box.
top(), start_pt.
y);
214 start_pt.
y = from_box.
bottom();
218 parallel_gap = from_box.
y_gap(to_box) + from_box.
height();
220 start_pt.
x = from_box.
right();
223 start_pt.
x = from_box.
left();
224 end_pt.
x =
MAX(to_box.
left(), start_pt.
x);
226 start_pt.
y = (from_box.
bottom() + from_box.
top()) / 2;
227 end_pt.
y = start_pt.
y;
233 int perpendicular_gap = 0;
237 if (start_pt.
x != end_pt.
x || start_pt.
y != end_pt.
y) {
238 if (denorm !=
NULL) {
243 if (abs(start_pt.
y - end_pt.
y) >= abs(start_pt.
x - end_pt.
x)) {
274 int y1,
int y2)
const {
275 x = ImageXToProjectionX(x);
276 y1 = ImageYToProjectionY(y1);
277 y2 = ImageYToProjectionY(y2);
278 if (y1 == y2)
return 0;
279 int wpl = pixGetWpl(pix_);
280 int step = y1 < y2 ? 1 : -1;
281 uinT32* data = pixGetData(pix_) + y1 * wpl;
283 int prev_pixel = GET_DATA_BYTE(data, x);
285 int right_way_steps = 0;
286 for (
int y = y1; y != y2; y += step) {
288 int pixel = GET_DATA_BYTE(data, x);
290 tprintf(
"At (%d,%d), pix = %d, prev=%d\n",
291 x, y + step, pixel, prev_pixel);
292 if (pixel < prev_pixel)
294 else if (pixel > prev_pixel)
300 return distance * scale_factor_ +
308 x1 = ImageXToProjectionX(x1);
309 x2 = ImageXToProjectionX(x2);
310 y = ImageYToProjectionY(y);
311 if (x1 == x2)
return 0;
312 int wpl = pixGetWpl(pix_);
313 int step = x1 < x2 ? 1 : -1;
314 uinT32* data = pixGetData(pix_) + y * wpl;
315 int prev_pixel = GET_DATA_BYTE(data, x1);
317 int right_way_steps = 0;
318 for (
int x = x1; x != x2; x += step) {
319 int pixel = GET_DATA_BYTE(data, x + step);
321 tprintf(
"At (%d,%d), pix = %d, prev=%d\n",
322 x + step, y, pixel, prev_pixel);
323 if (pixel < prev_pixel)
325 else if (pixel > prev_pixel)
331 return distance * scale_factor_ +
343 EvaluateBoxInternal(box, denorm, debug, &grad1, &grad2,
NULL,
NULL);
344 int worst_result =
MIN(grad1, grad2);
345 int total_result = grad1 + grad2;
346 if (total_result >= 6)
return false;
349 if (worst_result < 0)
378 tprintf(
"Partition hresult=%d, vresult=%d from:", hresult, vresult);
382 return hresult >= -vresult ? hresult : vresult;
418 int TextlineProjection::EvaluateBoxInternal(
const TBOX& box,
419 const DENORM* denorm,
bool debug,
420 int* hgrad1,
int* hgrad2,
421 int* vgrad1,
int* vgrad2)
const {
422 int top_gradient = BestMeanGradientInRow(denorm, box.
left(), box.
right(),
424 int bottom_gradient = -BestMeanGradientInRow(denorm, box.
left(), box.
right(),
426 int left_gradient = BestMeanGradientInColumn(denorm, box.
left(), box.
bottom(),
428 int right_gradient = -BestMeanGradientInColumn(denorm, box.
right(),
431 int top_clipped =
MAX(top_gradient, 0);
432 int bottom_clipped =
MAX(bottom_gradient, 0);
433 int left_clipped =
MAX(left_gradient, 0);
434 int right_clipped =
MAX(right_gradient, 0);
436 tprintf(
"Gradients: top = %d, bottom = %d, left= %d, right= %d for box:",
437 top_gradient, bottom_gradient, left_gradient, right_gradient);
440 int result =
MAX(top_clipped, bottom_clipped) -
441 MAX(left_clipped, right_clipped);
442 if (hgrad1 !=
NULL && hgrad2 !=
NULL) {
443 *hgrad1 = top_gradient;
444 *hgrad2 = bottom_gradient;
446 if (vgrad1 !=
NULL && vgrad2 !=
NULL) {
447 *vgrad1 = left_gradient;
448 *vgrad2 = right_gradient;
458 int TextlineProjection::BestMeanGradientInRow(
const DENORM* denorm,
460 bool best_is_max)
const {
461 TPOINT start_pt(min_x, y);
463 int upper = MeanPixelsInLineSegment(denorm, -2, start_pt, end_pt);
464 int lower = MeanPixelsInLineSegment(denorm, 2, start_pt, end_pt);
465 int best_gradient = lower - upper;
466 upper = MeanPixelsInLineSegment(denorm, -1, start_pt, end_pt);
467 lower = MeanPixelsInLineSegment(denorm, 3, start_pt, end_pt);
468 int gradient = lower - upper;
469 if ((gradient > best_gradient) == best_is_max)
470 best_gradient = gradient;
471 upper = MeanPixelsInLineSegment(denorm, -3, start_pt, end_pt);
472 lower = MeanPixelsInLineSegment(denorm, 1, start_pt, end_pt);
473 gradient = lower - upper;
474 if ((gradient > best_gradient) == best_is_max)
475 best_gradient = gradient;
476 return best_gradient;
485 int TextlineProjection::BestMeanGradientInColumn(
const DENORM* denorm,
inT16 x,
487 bool best_is_max)
const {
488 TPOINT start_pt(x, min_y);
490 int left = MeanPixelsInLineSegment(denorm, -2, start_pt, end_pt);
491 int right = MeanPixelsInLineSegment(denorm, 2, start_pt, end_pt);
492 int best_gradient = right - left;
493 left = MeanPixelsInLineSegment(denorm, -1, start_pt, end_pt);
494 right = MeanPixelsInLineSegment(denorm, 3, start_pt, end_pt);
495 int gradient = right - left;
496 if ((gradient > best_gradient) == best_is_max)
497 best_gradient = gradient;
498 left = MeanPixelsInLineSegment(denorm, -3, start_pt, end_pt);
499 right = MeanPixelsInLineSegment(denorm, 1, start_pt, end_pt);
500 gradient = right - left;
501 if ((gradient > best_gradient) == best_is_max)
502 best_gradient = gradient;
503 return best_gradient;
516 int TextlineProjection::MeanPixelsInLineSegment(
const DENORM* denorm,
520 TransformToPixCoords(denorm, &start_pt);
521 TransformToPixCoords(denorm, &end_pt);
522 TruncateToImageBounds(&start_pt);
523 TruncateToImageBounds(&end_pt);
524 int wpl = pixGetWpl(pix_);
525 uinT32* data = pixGetData(pix_);
528 int x_delta = end_pt.
x - start_pt.
x;
529 int y_delta = end_pt.
y - start_pt.
y;
530 if (abs(x_delta) >= abs(y_delta)) {
534 int x_step = x_delta > 0 ? 1 : -1;
537 start_pt.
y += offset;
539 TruncateToImageBounds(&start_pt);
540 TruncateToImageBounds(&end_pt);
541 x_delta = end_pt.
x - start_pt.
x;
542 y_delta = end_pt.
y - start_pt.
y;
543 count = x_delta * x_step + 1;
544 for (
int x = start_pt.
x; x != end_pt.
x; x += x_step) {
545 int y = start_pt.
y +
DivRounded(y_delta * (x - start_pt.
x), x_delta);
546 total += GET_DATA_BYTE(data + wpl * y, x);
550 int y_step = y_delta > 0 ? 1 : -1;
554 start_pt.
x += offset;
556 TruncateToImageBounds(&start_pt);
557 TruncateToImageBounds(&end_pt);
558 x_delta = end_pt.
x - start_pt.
x;
559 y_delta = end_pt.
y - start_pt.
y;
560 count = y_delta * y_step + 1;
561 for (
int y = start_pt.
y; y != end_pt.
y; y += y_step) {
562 int x = start_pt.
x +
DivRounded(x_delta * (y - start_pt.
y), y_delta);
563 total += GET_DATA_BYTE(data + wpl * y, x);
574 static TBOX BoundsWithinBox(Pix* pix,
const TBOX& box) {
575 int im_height = pixGetHeight(pix);
576 Box* input_box = boxCreate(box.
left(), im_height - box.
top(),
578 Box* output_box =
NULL;
579 pixClipBoxToForeground(pix, input_box,
NULL, &output_box);
581 if (output_box !=
NULL) {
582 l_int32 x, y, width, height;
583 boxGetGeometry(output_box, &x, &y, &width, &height);
586 result_box.
set_top(im_height - y);
588 boxDestroy(&output_box);
590 boxDestroy(&input_box);
598 static void TruncateBoxToMissNonText(
int x_middle,
int y_middle,
599 bool split_on_x, Pix* nontext_map,
606 im_box = BoundsWithinBox(nontext_map, box1);
608 box2.set_left(x_middle);
609 im_box = BoundsWithinBox(nontext_map, box2);
612 box1.set_bottom(y_middle);
613 im_box = BoundsWithinBox(nontext_map, box1);
615 box2.set_top(y_middle);
616 im_box = BoundsWithinBox(nontext_map, box2);
617 if (!im_box.
null_box()) box2.set_bottom(im_box.
top());
626 void TextlineProjection::IncrementRectangle8Bit(
const TBOX& box) {
627 int scaled_left = ImageXToProjectionX(box.
left());
628 int scaled_top = ImageYToProjectionY(box.
top());
629 int scaled_right = ImageXToProjectionX(box.
right());
630 int scaled_bottom = ImageYToProjectionY(box.
bottom());
631 int wpl = pixGetWpl(pix_);
632 uinT32* data = pixGetData(pix_) + scaled_top * wpl;
633 for (
int y = scaled_top; y <= scaled_bottom; ++y) {
634 for (
int x = scaled_left; x <= scaled_right; ++x) {
635 int pixel = GET_DATA_BYTE(data, x);
637 SET_DATA_BYTE(data, x, pixel + 1);
649 void TextlineProjection::ProjectBlobs(BLOBNBOX_LIST* blobs,
651 const TBOX& nontext_map_box,
653 BLOBNBOX_IT blob_it(blobs);
654 for (blob_it.mark_cycle_pt(); !blob_it.cycled_list(); blob_it.forward()) {
659 bool spreading_horizontally = PadBlobBox(blob, &bbox);
662 middle.rotate(rotation);
663 if (rotation.
x() == 0.0f)
664 spreading_horizontally = !spreading_horizontally;
666 bbox &= nontext_map_box;
668 TruncateBoxToMissNonText(middle.x(), middle.y(), spreading_horizontally,
670 if (bbox.
area() > 0) {
671 IncrementRectangle8Bit(bbox);
679 bool TextlineProjection::PadBlobBox(
BLOBNBOX* blob,
TBOX* bbox) {
689 bool padding_horizontally =
false;
692 padding_horizontally =
true;
700 ypad = scale_factor_;
708 xpad = scale_factor_;
722 padding_horizontally =
true;
725 bbox->
pad(xpad, ypad);
735 return padding_horizontally;
740 void TextlineProjection::TransformToPixCoords(
const DENORM* denorm,
742 if (denorm !=
NULL) {
746 pt->
x = ImageXToProjectionX(pt->
x);
747 pt->
y = ImageYToProjectionY(pt->
y);
751 void TextlineProjection::TruncateToImageBounds(
TPOINT* pt)
const {
752 pt->
x = ClipToRange<int>(pt->
x, 0, pixGetWidth(pix_) - 1);
753 pt->
y = ClipToRange<int>(pt->
y, 0, pixGetHeight(pix_) - 1);
757 int TextlineProjection::ImageXToProjectionX(
int x)
const {
758 x =
ClipToRange((x - x_origin_) / scale_factor_, 0, pixGetWidth(pix_) - 1);
761 int TextlineProjection::ImageYToProjectionY(
int y)
const {
762 y =
ClipToRange((y_origin_ - y) / scale_factor_, 0, pixGetHeight(pix_) - 1);