15 #include "config_auto.h" 19 #include "allheaders.h" 46 : x_origin_(0), y_origin_(0), pix_(NULL) {
49 if (scale_factor_ < 1) scale_factor_ = 1;
66 TBOX image_box(0, 0, pixGetWidth(nontext_map), pixGetHeight(nontext_map));
68 y_origin_ = image_box.
height();
69 int width = (image_box.
width() + scale_factor_ - 1) / scale_factor_;
70 int height = (image_box.
height() + scale_factor_ - 1) / scale_factor_;
72 pix_ = pixCreate(width, height, 8);
73 ProjectBlobs(&input_block->
blobs, rotation, image_box, nontext_map);
74 ProjectBlobs(&input_block->
large_blobs, rotation, image_box, nontext_map);
75 Pix* final_pix = pixBlockconv(pix_, 1, 1);
84 #ifndef GRAPHICS_DISABLED 85 BLOBNBOX_IT it(blobs);
86 for (it.mark_cycle_pt(); !it.cycled_list(); it.forward()) {
97 #endif // GRAPHICS_DISABLED 105 BLOBNBOX_LIST* blobs, BLOBNBOX_LIST* small_blobs)
const {
106 BLOBNBOX_IT it(blobs);
107 BLOBNBOX_IT small_it(small_blobs);
108 for (it.mark_cycle_pt(); !it.cycled_list(); it.forward()) {
115 small_it.add_to_end(it.extract());
122 #ifndef GRAPHICS_DISABLED 123 int width = pixGetWidth(pix_);
124 int height = pixGetHeight(pix_);
125 Pix* pixc = pixCreate(width, height, 32);
126 int src_wpl = pixGetWpl(pix_);
127 int col_wpl = pixGetWpl(pixc);
128 uinT32* src_data = pixGetData(pix_);
129 uinT32* col_data = pixGetData(pixc);
130 for (
int y = 0; y < height; ++y, src_data += src_wpl, col_data += col_wpl) {
131 for (
int x = 0; x < width; ++x) {
132 int pixel = GET_DATA_BYTE(src_data, x);
135 composeRGBPixel(0, 0, pixel * 15, &result);
136 else if (pixel <= 145)
137 composeRGBPixel(0, (pixel - 17) * 2, 255, &result);
139 composeRGBPixel((pixel - 145) * 2, 255, 255, &result);
140 col_data[x] = result;
144 width, height, width, height);
145 win->
Image(pixc, 0, 0);
148 #endif // GRAPHICS_DISABLED 197 bool horizontal_textline,
202 int parallel_gap = 0;
207 if (horizontal_textline) {
208 parallel_gap = from_box.
x_gap(to_box) + from_box.
width();
209 start_pt.
x = (from_box.
left() + from_box.
right()) / 2;
210 end_pt.
x = start_pt.
x;
212 start_pt.
y = from_box.
top();
213 end_pt.
y =
MIN(to_box.
top(), start_pt.
y);
215 start_pt.
y = from_box.
bottom();
219 parallel_gap = from_box.
y_gap(to_box) + from_box.
height();
221 start_pt.
x = from_box.
right();
224 start_pt.
x = from_box.
left();
225 end_pt.
x =
MAX(to_box.
left(), start_pt.
x);
227 start_pt.
y = (from_box.
bottom() + from_box.
top()) / 2;
228 end_pt.
y = start_pt.
y;
234 int perpendicular_gap = 0;
238 if (start_pt.
x != end_pt.
x || start_pt.
y != end_pt.
y) {
239 if (denorm != NULL) {
244 if (abs(start_pt.
y - end_pt.
y) >= abs(start_pt.
x - end_pt.
x)) {
275 int y1,
int y2)
const {
276 x = ImageXToProjectionX(x);
277 y1 = ImageYToProjectionY(y1);
278 y2 = ImageYToProjectionY(y2);
279 if (y1 == y2)
return 0;
280 int wpl = pixGetWpl(pix_);
281 int step = y1 < y2 ? 1 : -1;
282 uinT32* data = pixGetData(pix_) + y1 * wpl;
284 int prev_pixel = GET_DATA_BYTE(data, x);
286 int right_way_steps = 0;
287 for (
int y = y1; y != y2; y += step) {
289 int pixel = GET_DATA_BYTE(data, x);
291 tprintf(
"At (%d,%d), pix = %d, prev=%d\n",
292 x, y + step, pixel, prev_pixel);
293 if (pixel < prev_pixel)
295 else if (pixel > prev_pixel)
301 return distance * scale_factor_ +
309 x1 = ImageXToProjectionX(x1);
310 x2 = ImageXToProjectionX(x2);
311 y = ImageYToProjectionY(y);
312 if (x1 == x2)
return 0;
313 int wpl = pixGetWpl(pix_);
314 int step = x1 < x2 ? 1 : -1;
315 uinT32* data = pixGetData(pix_) + y * wpl;
316 int prev_pixel = GET_DATA_BYTE(data, x1);
318 int right_way_steps = 0;
319 for (
int x = x1; x != x2; x += step) {
320 int pixel = GET_DATA_BYTE(data, x + step);
322 tprintf(
"At (%d,%d), pix = %d, prev=%d\n",
323 x + step, y, pixel, prev_pixel);
324 if (pixel < prev_pixel)
326 else if (pixel > prev_pixel)
332 return distance * scale_factor_ +
344 EvaluateBoxInternal(box, denorm, debug, &grad1, &grad2, NULL, NULL);
345 int worst_result =
MIN(grad1, grad2);
346 int total_result = grad1 + grad2;
347 if (total_result >= 6)
return false;
350 if (worst_result < 0)
379 tprintf(
"Partition hresult=%d, vresult=%d from:", hresult, vresult);
383 return hresult >= -vresult ? hresult : vresult;
413 return EvaluateBoxInternal(box, denorm, debug, NULL, NULL, NULL, NULL);
419 int TextlineProjection::EvaluateBoxInternal(
const TBOX& box,
420 const DENORM* denorm,
bool debug,
421 int* hgrad1,
int* hgrad2,
422 int* vgrad1,
int* vgrad2)
const {
423 int top_gradient = BestMeanGradientInRow(denorm, box.
left(), box.
right(),
425 int bottom_gradient = -BestMeanGradientInRow(denorm, box.
left(), box.
right(),
427 int left_gradient = BestMeanGradientInColumn(denorm, box.
left(), box.
bottom(),
429 int right_gradient = -BestMeanGradientInColumn(denorm, box.
right(),
432 int top_clipped =
MAX(top_gradient, 0);
433 int bottom_clipped =
MAX(bottom_gradient, 0);
434 int left_clipped =
MAX(left_gradient, 0);
435 int right_clipped =
MAX(right_gradient, 0);
437 tprintf(
"Gradients: top = %d, bottom = %d, left= %d, right= %d for box:",
438 top_gradient, bottom_gradient, left_gradient, right_gradient);
441 int result =
MAX(top_clipped, bottom_clipped) -
442 MAX(left_clipped, right_clipped);
443 if (hgrad1 != NULL && hgrad2 != NULL) {
444 *hgrad1 = top_gradient;
445 *hgrad2 = bottom_gradient;
447 if (vgrad1 != NULL && vgrad2 != NULL) {
448 *vgrad1 = left_gradient;
449 *vgrad2 = right_gradient;
459 int TextlineProjection::BestMeanGradientInRow(
const DENORM* denorm,
461 bool best_is_max)
const {
462 TPOINT start_pt(min_x, y);
464 int upper = MeanPixelsInLineSegment(denorm, -2, start_pt, end_pt);
465 int lower = MeanPixelsInLineSegment(denorm, 2, start_pt, end_pt);
466 int best_gradient = lower - upper;
467 upper = MeanPixelsInLineSegment(denorm, -1, start_pt, end_pt);
468 lower = MeanPixelsInLineSegment(denorm, 3, start_pt, end_pt);
469 int gradient = lower - upper;
470 if ((gradient > best_gradient) == best_is_max)
471 best_gradient = gradient;
472 upper = MeanPixelsInLineSegment(denorm, -3, start_pt, end_pt);
473 lower = MeanPixelsInLineSegment(denorm, 1, start_pt, end_pt);
474 gradient = lower - upper;
475 if ((gradient > best_gradient) == best_is_max)
476 best_gradient = gradient;
477 return best_gradient;
486 int TextlineProjection::BestMeanGradientInColumn(
const DENORM* denorm,
inT16 x,
488 bool best_is_max)
const {
489 TPOINT start_pt(x, min_y);
491 int left = MeanPixelsInLineSegment(denorm, -2, start_pt, end_pt);
492 int right = MeanPixelsInLineSegment(denorm, 2, start_pt, end_pt);
493 int best_gradient = right - left;
494 left = MeanPixelsInLineSegment(denorm, -1, start_pt, end_pt);
495 right = MeanPixelsInLineSegment(denorm, 3, start_pt, end_pt);
496 int gradient = right - left;
497 if ((gradient > best_gradient) == best_is_max)
498 best_gradient = gradient;
499 left = MeanPixelsInLineSegment(denorm, -3, start_pt, end_pt);
500 right = MeanPixelsInLineSegment(denorm, 1, start_pt, end_pt);
501 gradient = right - left;
502 if ((gradient > best_gradient) == best_is_max)
503 best_gradient = gradient;
504 return best_gradient;
517 int TextlineProjection::MeanPixelsInLineSegment(
const DENORM* denorm,
521 TransformToPixCoords(denorm, &start_pt);
522 TransformToPixCoords(denorm, &end_pt);
523 TruncateToImageBounds(&start_pt);
524 TruncateToImageBounds(&end_pt);
525 int wpl = pixGetWpl(pix_);
526 uinT32* data = pixGetData(pix_);
529 int x_delta = end_pt.
x - start_pt.
x;
530 int y_delta = end_pt.
y - start_pt.
y;
531 if (abs(x_delta) >= abs(y_delta)) {
535 int x_step = x_delta > 0 ? 1 : -1;
538 start_pt.
y += offset;
540 TruncateToImageBounds(&start_pt);
541 TruncateToImageBounds(&end_pt);
542 x_delta = end_pt.
x - start_pt.
x;
543 y_delta = end_pt.
y - start_pt.
y;
544 count = x_delta * x_step + 1;
545 for (
int x = start_pt.
x; x != end_pt.
x; x += x_step) {
546 int y = start_pt.
y +
DivRounded(y_delta * (x - start_pt.
x), x_delta);
547 total += GET_DATA_BYTE(data + wpl * y, x);
551 int y_step = y_delta > 0 ? 1 : -1;
555 start_pt.
x += offset;
557 TruncateToImageBounds(&start_pt);
558 TruncateToImageBounds(&end_pt);
559 x_delta = end_pt.
x - start_pt.
x;
560 y_delta = end_pt.
y - start_pt.
y;
561 count = y_delta * y_step + 1;
562 for (
int y = start_pt.
y; y != end_pt.
y; y += y_step) {
563 int x = start_pt.
x +
DivRounded(x_delta * (y - start_pt.
y), y_delta);
564 total += GET_DATA_BYTE(data + wpl * y, x);
575 static TBOX BoundsWithinBox(Pix* pix,
const TBOX& box) {
576 int im_height = pixGetHeight(pix);
577 Box* input_box = boxCreate(box.
left(), im_height - box.
top(),
579 Box* output_box = NULL;
580 pixClipBoxToForeground(pix, input_box, NULL, &output_box);
582 if (output_box != NULL) {
583 l_int32 x, y, width, height;
584 boxGetGeometry(output_box, &x, &y, &width, &height);
587 result_box.
set_top(im_height - y);
589 boxDestroy(&output_box);
591 boxDestroy(&input_box);
599 static void TruncateBoxToMissNonText(
int x_middle,
int y_middle,
600 bool split_on_x, Pix* nontext_map,
607 im_box = BoundsWithinBox(nontext_map, box1);
610 im_box = BoundsWithinBox(nontext_map, box2);
614 im_box = BoundsWithinBox(nontext_map, box1);
617 im_box = BoundsWithinBox(nontext_map, box2);
627 void TextlineProjection::IncrementRectangle8Bit(
const TBOX& box) {
628 int scaled_left = ImageXToProjectionX(box.
left());
629 int scaled_top = ImageYToProjectionY(box.
top());
630 int scaled_right = ImageXToProjectionX(box.
right());
631 int scaled_bottom = ImageYToProjectionY(box.
bottom());
632 int wpl = pixGetWpl(pix_);
633 uinT32* data = pixGetData(pix_) + scaled_top * wpl;
634 for (
int y = scaled_top; y <= scaled_bottom; ++y) {
635 for (
int x = scaled_left; x <= scaled_right; ++x) {
636 int pixel = GET_DATA_BYTE(data, x);
638 SET_DATA_BYTE(data, x, pixel + 1);
650 void TextlineProjection::ProjectBlobs(BLOBNBOX_LIST* blobs,
652 const TBOX& nontext_map_box,
654 BLOBNBOX_IT blob_it(blobs);
655 for (blob_it.mark_cycle_pt(); !blob_it.cycled_list(); blob_it.forward()) {
660 bool spreading_horizontally = PadBlobBox(blob, &bbox);
664 if (rotation.
x() == 0.0f)
665 spreading_horizontally = !spreading_horizontally;
667 bbox &= nontext_map_box;
669 TruncateBoxToMissNonText(middle.
x(), middle.
y(), spreading_horizontally,
671 if (bbox.
area() > 0) {
672 IncrementRectangle8Bit(bbox);
680 bool TextlineProjection::PadBlobBox(
BLOBNBOX* blob,
TBOX* bbox) {
690 bool padding_horizontally =
false;
693 padding_horizontally =
true;
701 ypad = scale_factor_;
709 xpad = scale_factor_;
723 padding_horizontally =
true;
726 bbox->
pad(xpad, ypad);
736 return padding_horizontally;
741 void TextlineProjection::TransformToPixCoords(
const DENORM* denorm,
743 if (denorm != NULL) {
747 pt->
x = ImageXToProjectionX(pt->
x);
748 pt->
y = ImageYToProjectionY(pt->
y);
752 #pragma optimize("g", off) 755 void TextlineProjection::TruncateToImageBounds(
TPOINT* pt)
const {
756 pt->
x = ClipToRange<int>(pt->
x, 0, pixGetWidth(pix_) - 1);
757 pt->
y = ClipToRange<int>(pt->
y, 0, pixGetHeight(pix_) - 1);
760 #pragma optimize("", on) 764 int TextlineProjection::ImageXToProjectionX(
int x)
const {
765 x =
ClipToRange((x - x_origin_) / scale_factor_, 0, pixGetWidth(pix_) - 1);
768 int TextlineProjection::ImageYToProjectionY(
int y)
const {
769 y =
ClipToRange((y_origin_ - y) / scale_factor_, 0, pixGetHeight(pix_) - 1);
static bool WithinTestRegion(int detail_level, int x, int y)
const int kMinLineSpacingFactor
const TBOX & bounding_box() const
int HorizontalDistance(bool debug, int x1, int x2, int y) const
int VerticalDistance(bool debug, int x, int y1, int y2) const
inT16 x() const
access function
void Rectangle(int x1, int y1, int x2, int y2)
bool IsHorizontalType() const
bool UniquelyHorizontal() const
void DenormTransform(const DENORM *last_denorm, const TPOINT &pt, TPOINT *original) const
T ClipToRange(const T &x, const T &lower_bound, const T &upper_bound)
int DistanceOfBoxFromBox(const TBOX &from_box, const TBOX &to_box, bool horizontal_textline, const DENORM *denorm, bool debug) const
void DisplayProjection() const
int DivRounded(int a, int b)
int y_gap(const TBOX &box) const
TextlineProjection(int resolution)
const TBOX & bounding_box() const
const int kWrongWayPenalty
void rotate(const FCOORD &vec)
int median_bottom() const
bool BoxOutOfHTextline(const TBOX &box, const DENORM *denorm, bool debug) const
void pad(int xpad, int ypad)
void ConstructProjection(TO_BLOCK *input_block, const FCOORD &rotation, Pix *nontext_map)
const int kOrientedPadFactor
int x_gap(const TBOX &box) const
BLOBNBOX * neighbour(BlobNeighbourDir n) const
inT16 y() const
access_function
const int kParaPerpDistRatio
void rotate(const FCOORD &vec)
bool UniquelyVertical() const
void MoveNonTextlineBlobs(BLOBNBOX_LIST *blobs, BLOBNBOX_LIST *small_blobs) const
void PlotGradedBlobs(BLOBNBOX_LIST *blobs, ScrollView *win)
const int kMaxTabStopOverrun
BLOBNBOX_LIST large_blobs
int IntCastRounded(double x)
int DistanceOfBoxFromPartition(const TBOX &box, const ColPartition &part, const DENORM *denorm, bool debug) const
void Image(struct Pix *image, int x_pos, int y_pos)
int EvaluateBox(const TBOX &box, const DENORM *denorm, bool debug) const
int EvaluateColPartition(const ColPartition &part, const DENORM *denorm, bool debug) const
const int kDefaultPadFactor