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