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;
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;
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);
const int kDefaultPadFactor
void rotate(const FCOORD &vec)
void PlotGradedBlobs(BLOBNBOX_LIST *blobs, ScrollView *win)
BLOBNBOX_LIST large_blobs
int HorizontalDistance(bool debug, int x1, int x2, int y) const
int EvaluateBox(const TBOX &box, const DENORM *denorm, bool debug) const
int VerticalDistance(bool debug, int x, int y1, int y2) const
int DistanceOfBoxFromBox(const TBOX &from_box, const TBOX &to_box, bool horizontal_textline, const DENORM *denorm, bool debug) const
inT16 x() const
access function
bool UniquelyVertical() const
TextlineProjection(int resolution)
const int kMinLineSpacingFactor
int IntCastRounded(double x)
const int kWrongWayPenalty
const int kMaxTabStopOverrun
int y_gap(const TBOX &box) const
void ConstructProjection(TO_BLOCK *input_block, const FCOORD &rotation, Pix *nontext_map)
void DenormTransform(const DENORM *last_denorm, const TPOINT &pt, TPOINT *original) const
void Rectangle(int x1, int y1, int x2, int y2)
const TBOX & bounding_box() const
inT16 y() const
access_function
T ClipToRange(const T &x, const T &lower_bound, const T &upper_bound)
int DistanceOfBoxFromPartition(const TBOX &box, const ColPartition &part, const DENORM *denorm, bool debug) const
void pad(int xpad, int ypad)
BLOBNBOX * neighbour(BlobNeighbourDir n) const
void DisplayProjection() const
void MoveNonTextlineBlobs(BLOBNBOX_LIST *blobs, BLOBNBOX_LIST *small_blobs) const
static bool WithinTestRegion(int detail_level, int x, int y)
int EvaluateColPartition(const ColPartition &part, const DENORM *denorm, bool debug) const
const int kParaPerpDistRatio
const int kOrientedPadFactor
bool UniquelyHorizontal() const
void Image(struct Pix *image, int x_pos, int y_pos)
bool BoxOutOfHTextline(const TBOX &box, const DENORM *denorm, bool debug) const
int median_bottom() const
bool IsHorizontalType() const
const TBOX & bounding_box() const
void rotate(const FCOORD &vec)
int DivRounded(int a, int b)
int x_gap(const TBOX &box) const