26 #include "config_auto.h" 69 int b0a1xb0b1, b0b1xb0a0;
70 int a1b1xa1a0, a1a0xa1b0;
72 TPOINT b0a1, b0a0, a1b1, b0b1, a1a0;
85 b0a1xb0b1 =
CROSS(b0a1, b0b1);
86 b0b1xb0a0 =
CROSS(b0b1, b0a0);
87 a1b1xa1a0 =
CROSS(a1b1, a1a0);
90 a1a0xa1b0 = -
CROSS(a1a0, b0a1);
92 return ((b0a1xb0b1 > 0 && b0b1xb0a0 > 0) ||
93 (b0a1xb0b1 < 0 && b0b1xb0a0 < 0)) &&
94 ((a1b1xa1a0 > 0 && a1a0xa1b0 > 0) || (a1b1xa1a0 < 0 && a1a0xa1b0 < 0));
100 result->loop = outline;
112 }
while (pt != outline);
114 result->SetupFromPos();
125 if (src.
loop !=
nullptr) {
130 newpt =
new EDGEPT(*srcpt);
131 if (prevpt ==
nullptr) {
134 newpt->
prev = prevpt;
135 prevpt->
next = newpt;
139 }
while (srcpt != src.
loop);
147 if (
loop ==
nullptr)
return;
153 this_edge = next_edge;
154 }
while (this_edge !=
loop);
164 }
while (pt !=
loop);
172 int tmp =
static_cast<int>(
173 floor(pt->
pos.
x * rot.
x() - pt->
pos.
y * rot.
y() + 0.5));
174 pt->
pos.
y =
static_cast<int>(
175 floor(pt->
pos.
y * rot.
x() + pt->
pos.
x * rot.
y() + 0.5));
178 }
while (pt !=
loop);
186 pt->
pos.
x += vec.
x();
187 pt->
pos.
y += vec.
y();
189 }
while (pt !=
loop);
197 pt->
pos.
x =
static_cast<int>(floor(pt->
pos.
x * factor + 0.5));
198 pt->
pos.
y =
static_cast<int>(floor(pt->
pos.
y * factor + 0.5));
200 }
while (pt !=
loop);
211 }
while (pt !=
loop);
218 int minx = INT32_MAX;
219 int miny = INT32_MAX;
220 int maxx = -INT32_MAX;
221 int maxy = -INT32_MAX;
228 if (this_edge->
pos.
x < minx) minx = this_edge->
pos.
x;
229 if (this_edge->
pos.
y < miny) miny = this_edge->
pos.
y;
230 if (this_edge->
pos.
x > maxx) maxx = this_edge->
pos.
x;
231 if (this_edge->
pos.
y > maxy) maxy = this_edge->
pos.
y;
233 this_edge = this_edge->
next;
234 }
while (this_edge !=
loop);
254 int product =
CROSS(this_edge->
pos, vec);
257 this_edge = this_edge->
next;
258 }
while (this_edge !=
loop);
265 #ifndef GRAPHICS_DISABLED 269 window->
Pen(child_color);
281 }
while (pt !=
loop);
283 #endif // GRAPHICS_DISABLED 307 static TESSLINE** ApproximateOutlineList(
bool allow_detailed_fx,
308 C_OUTLINE_LIST* outlines,
310 C_OUTLINE_IT ol_it(outlines);
311 for (ol_it.mark_cycle_pt(); !ol_it.cycled_list(); ol_it.forward()) {
317 tail = &tessline->
next;
319 if (!outline->
child()->empty()) {
320 tail = ApproximateOutlineList(allow_detailed_fx, outline->
child(),
true,
332 auto* tblob =
new TBLOB;
333 ApproximateOutlineList(allow_detailed_fx, src->
out_list(),
false,
340 auto* blob =
new TBLOB;
341 blob->denorm_ = src.denorm_;
351 TBLOB* rotated_blob =
nullptr;
354 if (denorm_.block() !=
nullptr &&
355 denorm_.block()->classify_rotation().y() != 0.0) {
357 int x_middle = (box.
left() + box.
right()) / 2;
358 int y_middle = (box.
top() + box.
bottom()) / 2;
359 rotated_blob =
new TBLOB(*
this);
360 const FCOORD& rotation = denorm_.block()->classify_rotation();
365 (rotation.
y() > 0 ? x_middle - box.
left() : box.
right() - x_middle);
366 rotated_blob->
Normalize(
nullptr, &rotation, &denorm_, x_middle, y_middle,
367 1.0f, 1.0f, 0.0f, target_y, denorm_.inverse(),
378 srcline = srcline->
next) {
379 auto* new_outline =
new TESSLINE(*srcline);
380 if (outlines ==
nullptr)
381 outlines = new_outline;
383 prev_outline->
next = new_outline;
384 prev_outline = new_outline;
386 denorm_ = src.denorm_;
391 for (
TESSLINE* next_outline =
nullptr; outlines !=
nullptr;
392 outlines = next_outline) {
393 next_outline = outlines->next;
402 const DENORM* predecessor,
float x_origin,
float y_origin,
403 float x_scale,
float y_scale,
float final_xshift,
404 float final_yshift,
bool inverse, Pix* pix) {
405 denorm_.SetupNormalization(block, rotation, predecessor, x_origin, y_origin,
406 x_scale, y_scale, final_xshift, final_yshift);
407 denorm_.set_inverse(inverse);
408 denorm_.set_pix(pix);
417 for (
TESSLINE* outline = outlines; outline !=
nullptr; outline = outline->
next) {
418 outline->Normalize(denorm_);
421 denorm_.LocalNormBlob(
this);
427 for (
TESSLINE* outline = outlines; outline !=
nullptr;
428 outline = outline->
next) {
429 outline->Rotate(rotation);
435 for (
TESSLINE* outline = outlines; outline !=
nullptr;
436 outline = outline->
next) {
443 for (
TESSLINE* outline = outlines; outline !=
nullptr;
444 outline = outline->
next) {
445 outline->Scale(factor);
451 for (
TESSLINE* outline = outlines; outline !=
nullptr;
452 outline = outline->
next) {
453 outline->ComputeBoundingBox();
460 for (
TESSLINE* outline = outlines; outline !=
nullptr;
461 outline = outline->
next)
473 if (outlines ==
nullptr)
return TBOX(0, 0, 0, 0);
476 for (outline = outline->
next; outline !=
nullptr; outline = outline->
next) {
485 for (
TESSLINE* outline = outlines; outline !=
nullptr;
486 outline = outline->
next) {
488 for (
TESSLINE* other_outline = outline->
next; other_outline !=
nullptr;
489 last_outline = other_outline, other_outline = other_outline->
next) {
490 if (outline->SameBox(*other_outline)) {
491 last_outline->
next = other_outline->
next;
493 other_outline->
loop =
nullptr;
494 delete other_outline;
495 other_outline = last_outline;
513 #ifndef GRAPHICS_DISABLED 516 for (
TESSLINE* outline = outlines; outline !=
nullptr;
517 outline = outline->
next)
518 outline->plot(window, color, child_color);
520 #endif // GRAPHICS_DISABLED 531 CollectEdges(box,
nullptr, &accumulator,
nullptr,
nullptr);
536 if (x2nd < 1.0) x2nd = 1.0;
537 if (y2nd < 1.0) y2nd = 1.0;
538 second_moments->
set_x(x2nd);
539 second_moments->
set_y(y2nd);
540 return accumulator.
count();
547 *precise_box =
TBOX();
548 CollectEdges(box, precise_box,
nullptr,
nullptr,
nullptr);
566 y_coords->init_to_size(box.
width(), empty);
567 CollectEdges(box,
nullptr,
nullptr, x_coords, y_coords);
569 for (
int i = 0; i < x_coords->size(); ++i) (*x_coords)[i].sort();
570 for (
int i = 0; i < y_coords->size(); ++i) (*y_coords)[i].sort();
575 static void SegmentLLSQ(
const FCOORD& pt1,
const FCOORD& pt2,
583 if (xstart == xend && ystart == yend)
return;
584 double weight = step.
length() / (xend - xstart + yend - ystart);
586 for (
int x = xstart; x < xend; ++x) {
587 double y = pt1.
y() + step.
y() * (x + 0.5 - pt1.
x()) / step.
x();
588 accumulator->
add(x + 0.5, y, weight);
591 for (
int y = ystart; y < yend; ++y) {
592 double x = pt1.
x() + step.
x() * (y + 0.5 - pt1.
y()) / step.
y();
593 accumulator->
add(x, y + 0.5, weight);
602 static void SegmentCoords(
const FCOORD& pt1,
const FCOORD& pt2,
int x_limit,
611 for (
int x = start; x < end; ++x) {
613 (*y_coords)[x].push_back(y);
617 for (
int y = start; y < end; ++y) {
619 (*x_coords)[y].push_back(x);
636 TBOX point(x1, std::min(y1, y2), x2, std::max(y1, y2));
646 TBOX point(std::min(x1, x2), y1, std::max(x1, x2), y2);
661 static void CollectEdgesOfRun(
const EDGEPT* startpt,
const EDGEPT* lastpt,
667 int x_limit = box.
width() - 1;
668 int y_limit = box.
height() - 1;
669 if (outline !=
nullptr) {
684 if (end_index <= start_index) end_index += step_length;
696 prev_normed -= origin;
697 for (
int index = start_index; index < end_index; ++index) {
698 ICOORD step = outline->
step(index % step_length);
711 pos_normed -= origin;
713 if (bounding_box !=
nullptr) {
714 SegmentBBox(pos_normed, prev_normed, bounding_box);
716 if (accumulator !=
nullptr) {
717 SegmentLLSQ(pos_normed, prev_normed, accumulator);
719 if (x_coords !=
nullptr && y_coords !=
nullptr) {
720 SegmentCoords(pos_normed, prev_normed, x_limit, y_limit, x_coords,
723 prev_normed = pos_normed;
730 const EDGEPT* pt = startpt;
735 if (bounding_box !=
nullptr) {
736 SegmentBBox(next_pos, pos, bounding_box);
738 if (accumulator !=
nullptr) {
739 SegmentLLSQ(next_pos, pos, accumulator);
741 if (x_coords !=
nullptr && y_coords !=
nullptr) {
742 SegmentCoords(next_pos, pos, x_limit, y_limit, x_coords, y_coords);
744 }
while ((pt = pt->
next) != endpt);
753 void TBLOB::CollectEdges(
const TBOX& box,
TBOX* bounding_box,
LLSQ* llsq,
757 for (
const TESSLINE* ol = outlines; ol !=
nullptr; ol = ol->
next) {
759 EDGEPT* loop_pt = ol->FindBestStartPt();
761 if (pt ==
nullptr)
continue;
767 last_pt = last_pt->
next;
768 }
while (last_pt != loop_pt && !last_pt->
IsHidden() &&
770 last_pt = last_pt->
prev;
771 CollectEdgesOfRun(pt, last_pt, denorm_, box, bounding_box, llsq, x_coords,
774 }
while ((pt = pt->
next) != loop_pt);
781 auto* tessword =
new TWERD;
784 for (b_it.mark_cycle_pt(); !b_it.cycled_list(); b_it.forward()) {
785 C_BLOB* blob = b_it.data();
787 tessword->blobs.push_back(tblob);
795 bool inverse,
float x_height,
float baseline_shift,
799 if (norm_box !=
nullptr) word_box = *norm_box;
800 float word_middle = (word_box.
left() + word_box.
right()) / 2.0f;
801 float input_y_offset = 0.0f;
804 if (row ==
nullptr) {
805 word_middle = word_box.
left();
806 input_y_offset = word_box.
bottom();
807 final_y_offset = 0.0f;
809 input_y_offset = row->
base_line(word_middle) + baseline_shift;
811 for (
int b = 0; b < blobs.size(); ++b) {
812 TBLOB* blob = blobs[b];
814 float mid_x = (blob_box.
left() + blob_box.
right()) / 2.0f;
816 float blob_scale = scale;
818 baseline = blob_box.
bottom();
820 scale, scale * 1.5f);
821 }
else if (row !=
nullptr) {
822 baseline = row->
base_line(mid_x) + baseline_shift;
830 blob->
Normalize(block,
nullptr,
nullptr, word_middle, baseline, blob_scale,
831 blob_scale, 0.0f, final_y_offset, inverse, pix);
833 if (word_denorm !=
nullptr) {
835 input_y_offset, scale, scale, 0.0f,
846 for (
int b = 0; b < src.
blobs.
size(); ++b) {
848 blobs.push_back(new_blob);
854 blobs.delete_data_pointers();
860 for (
int b = 0; b < blobs.size(); ++b) {
861 blobs[b]->ComputeBoundingBoxes();
867 for (
int b = 0; b < blobs.size(); ++b) {
868 TBOX box = blobs[b]->bounding_box();
877 if (start >= blobs.size() - 1)
return;
879 for (
int i = start + 1; i < end && i < blobs.size(); ++i) {
880 TBLOB* next_blob = blobs[i];
882 if (outline ==
nullptr) {
884 outline = blobs[
start]->outlines;
886 while (outline->
next !=
nullptr) outline = outline->
next;
895 for (
int i = start + 1; i < end && start + 1 < blobs.size(); ++i) {
896 blobs.remove(start + 1);
900 #ifndef GRAPHICS_DISABLED 903 for (
int b = 0; b < blobs.size(); ++b) {
908 #endif // GRAPHICS_DISABLED 924 outline1 = outline1->
next) {
925 if (outline1->is_hole)
continue;
927 static_cast<int16_t>((outline1->topleft.x + outline1->botright.x) / 2),
928 static_cast<int16_t>((outline1->topleft.y + outline1->botright.y) / 2));
929 int mid_prod1 =
CROSS(mid_pt1, vertical);
930 int min_prod1, max_prod1;
931 outline1->MinMaxCrossProduct(vertical, &min_prod1, &max_prod1);
932 for (
TESSLINE* outline2 = outline1->
next; outline2 !=
nullptr;
933 outline2 = outline2->
next) {
934 if (outline2->is_hole)
continue;
935 TPOINT mid_pt2(static_cast<int16_t>(
936 (outline2->topleft.x + outline2->botright.x) / 2),
937 static_cast<int16_t>(
938 (outline2->topleft.y + outline2->botright.y) / 2));
939 int mid_prod2 =
CROSS(mid_pt2, vertical);
940 int min_prod2, max_prod2;
941 outline2->MinMaxCrossProduct(vertical, &min_prod2, &max_prod2);
942 int mid_gap = abs(mid_prod2 - mid_prod1);
944 std::min(max_prod1, max_prod2) - std::max(min_prod1, min_prod2);
945 if (mid_gap - overlap / 4 > max_gap) {
946 max_gap = mid_gap - overlap / 4;
948 *location += mid_pt2;
955 return max_gap > vertical.
y;
975 int location_prod =
CROSS(location, vertical);
977 while (outline !=
nullptr) {
981 int mid_prod =
CROSS(mid_pt, vertical);
982 if (mid_prod < location_prod) {
985 outline1->
next = outline;
992 outline2->
next = outline;
997 outline = outline->
next;
1000 if (outline1) outline1->
next =
nullptr;
1001 if (outline2) outline2->
next =
nullptr;
int IntCastRounded(double x)
void MergeBlobs(int start, int end)
void Move(const ICOORD vec)
void Rotate(const FCOORD rotation)
bool divisible_blob(TBLOB *blob, bool italic_blob, TPOINT *location)
void UpdateRange(const T1 &x, T2 *lower_bound, T2 *upper_bound)
TBLOB * ClassifyNormalizeIfNeeded() const
void CopyFrom(const TBLOB &src)
C_OUTLINE_LIST * out_list()
static TWERD * PolygonalCopy(bool allow_detailed_fx, WERD *src)
Special case latin for y. splitting.
ICOORD step(int index) const
void MinMaxCrossProduct(const TPOINT vec, int *min_xp, int *max_xp) const
void plot(ScrollView *window, ScrollView::Color color, ScrollView::Color child_color)
void Move(const ICOORD vec)
const DENORM * RootDenorm() const
GenericVector< TBLOB * > blobs
void NormTransform(const DENORM *first_norm, const TPOINT &pt, TPOINT *transformed) const
void set_x(float xin)
rewrite function
void ComputeBoundingBox()
void DrawTo(int x, int y)
float length() const
find length
TBOX bounding_box() const
void set_y(float yin)
rewrite function
int edge_strength_at_index(int index) const
void add(double x, double y)
void CopyFrom(const TESSLINE &src)
void Rotate(const FCOORD rotation)
ICOORD position_at_index(int index) const
int ComputeMoments(FCOORD *center, FCOORD *second_moments) const
static ScrollView::Color NextColor(ScrollView::Color colour)
int16_t y() const
access_function
void CopyFrom(const TWERD &src)
static TESSLINE * BuildFromOutlineList(EDGEPT *outline)
void init_to_size(int size, const T &t)
void plot(ScrollView *window)
const ICOORD & botleft() const
const TPOINT kDivisibleVerticalUpright(0, 1)
void GetEdgeCoords(const TBOX &box, GenericVector< GenericVector< int > > *x_coords, GenericVector< GenericVector< int > > *y_coords) const
FCOORD sub_pixel_pos_at_index(const ICOORD &pos, int index) const
double x_variance() const
static TBLOB * ShallowCopy(const TBLOB &src)
void SetupNormalization(const BLOCK *block, const FCOORD *rotation, const DENORM *predecessor, float x_origin, float y_origin, float x_scale, float y_scale, float final_xshift, float final_yshift)
EDGEPT * FindBestStartPt() const
void GetPreciseBoundingBox(TBOX *precise_box) const
const int kBlnBaselineOffset
void plot(ScrollView *window, ScrollView::Color color, ScrollView::Color child_color)
void EliminateDuplicateOutlines()
TBOX bounding_box() const
void CorrectBlobOrder(TBLOB *next)
int32_t pathlength() const
double y_variance() const
int16_t x() const
access function
TBOX bounding_box() const
CLISTIZE(BLOCK_RES) ELISTIZE(ROW_RES) ELISTIZE(WERD_RES) static const double kStopperAmbiguityThresholdGain
T ClipToRange(const T &x, const T &lower_bound, const T &upper_bound)
float base_line(float xpos) const
FCOORD mean_point() const
bool flag(WERD_FLAGS mask) const
void ComputeBoundingBoxes()
void BLNormalize(const BLOCK *block, const ROW *row, Pix *pix, bool inverse, float x_height, float baseline_shift, bool numeric_mode, tesseract::OcrEngineMode hint, const TBOX *norm_box, DENORM *word_denorm)
void divide_blobs(TBLOB *blob, TBLOB *other_blob, bool italic_blob, const TPOINT &location)
void set_inverse(bool value)
void LocalNormTransform(const TPOINT &pt, TPOINT *transformed) const
void move(const ICOORD vec)
void SetCursor(int x, int y)
void ComputeBoundingBoxes()
TESSLINE * ApproximateOutline(bool allow_detailed_fx, C_OUTLINE *c_outline)
static TBLOB * PolygonalCopy(bool allow_detailed_fx, C_BLOB *src)
const TPOINT kDivisibleVerticalItalic(1, 5)
void Normalize(const DENORM &denorm)
void Normalize(const BLOCK *block, const FCOORD *rotation, const DENORM *predecessor, float x_origin, float y_origin, float x_scale, float y_scale, float final_xshift, float final_yshift, bool inverse, Pix *pix)
C_BLOB_LIST * cblob_list()