31 #include "config_auto.h" 75 int b0a1xb0b1, b0b1xb0a0;
76 int a1b1xa1a0, a1a0xa1b0;
78 TPOINT b0a1, b0a0, a1b1, b0b1, a1a0;
91 b0a1xb0b1 =
CROSS(b0a1, b0b1);
92 b0b1xb0a0 =
CROSS(b0b1, b0a0);
93 a1b1xa1a0 =
CROSS(a1b1, a1a0);
96 a1a0xa1b0 = -
CROSS(a1a0, b0a1);
98 return ((b0a1xb0b1 > 0 && b0b1xb0a0 > 0) ||
99 (b0a1xb0b1 < 0 && b0b1xb0a0 < 0)) &&
100 ((a1b1xa1a0 > 0 && a1a0xa1b0 > 0) || (a1b1xa1a0 < 0 && a1a0xa1b0 < 0));
106 result->
loop = outline;
118 }
while (pt != outline);
131 if (src.
loop !=
nullptr) {
136 newpt =
new EDGEPT(*srcpt);
137 if (prevpt ==
nullptr) {
140 newpt->
prev = prevpt;
141 prevpt->
next = newpt;
145 }
while (srcpt != src.
loop);
153 if (
loop ==
nullptr)
return;
159 this_edge = next_edge;
160 }
while (this_edge !=
loop);
170 }
while (pt !=
loop);
178 int tmp =
static_cast<int>(
179 floor(pt->
pos.
x * rot.
x() - pt->
pos.
y * rot.
y() + 0.5));
180 pt->
pos.
y =
static_cast<int>(
181 floor(pt->
pos.
y * rot.
x() + pt->
pos.
x * rot.
y() + 0.5));
184 }
while (pt !=
loop);
192 pt->
pos.
x += vec.
x();
193 pt->
pos.
y += vec.
y();
195 }
while (pt !=
loop);
203 pt->
pos.
x =
static_cast<int>(floor(pt->
pos.
x * factor + 0.5));
204 pt->
pos.
y =
static_cast<int>(floor(pt->
pos.
y * factor + 0.5));
206 }
while (pt !=
loop);
217 }
while (pt !=
loop);
224 int minx = INT32_MAX;
225 int miny = INT32_MAX;
226 int maxx = -INT32_MAX;
227 int maxy = -INT32_MAX;
234 if (this_edge->
pos.
x < minx) minx = this_edge->
pos.
x;
235 if (this_edge->
pos.
y < miny) miny = this_edge->
pos.
y;
236 if (this_edge->
pos.
x > maxx) maxx = this_edge->
pos.
x;
237 if (this_edge->
pos.
y > maxy) maxy = this_edge->
pos.
y;
239 this_edge = this_edge->
next;
240 }
while (this_edge !=
loop);
260 int product =
CROSS(this_edge->
pos, vec);
263 this_edge = this_edge->
next;
264 }
while (this_edge !=
loop);
271 #ifndef GRAPHICS_DISABLED 275 window->
Pen(child_color);
287 }
while (pt !=
loop);
289 #endif // GRAPHICS_DISABLED 313 static TESSLINE** ApproximateOutlineList(
bool allow_detailed_fx,
314 C_OUTLINE_LIST* outlines,
316 C_OUTLINE_IT ol_it(outlines);
317 for (ol_it.mark_cycle_pt(); !ol_it.cycled_list(); ol_it.forward()) {
323 tail = &tessline->
next;
325 if (!outline->
child()->empty()) {
326 tail = ApproximateOutlineList(allow_detailed_fx, outline->
child(),
true,
339 ApproximateOutlineList(allow_detailed_fx, src->
out_list(),
false,
347 blob->denorm_ = src.denorm_;
357 TBLOB* rotated_blob =
nullptr;
360 if (denorm_.
block() !=
nullptr &&
363 int x_middle = (box.
left() + box.
right()) / 2;
364 int y_middle = (box.
top() + box.
bottom()) / 2;
365 rotated_blob =
new TBLOB(*
this);
371 (rotation.
y() > 0 ? x_middle - box.
left() : box.
right() - x_middle);
372 rotated_blob->
Normalize(
nullptr, &rotation, &denorm_, x_middle, y_middle,
373 1.0f, 1.0f, 0.0f, target_y, denorm_.
inverse(),
384 srcline = srcline->
next) {
389 prev_outline->
next = new_outline;
390 prev_outline = new_outline;
392 denorm_ = src.denorm_;
408 const DENORM* predecessor,
float x_origin,
float y_origin,
409 float x_scale,
float y_scale,
float final_xshift,
410 float final_yshift,
bool inverse, Pix* pix) {
412 x_scale, y_scale, final_xshift, final_yshift);
423 for (
TESSLINE* outline =
outlines; outline !=
nullptr; outline = outline->next) {
424 outline->Normalize(denorm_);
434 outline = outline->next) {
435 outline->Rotate(rotation);
442 outline = outline->next) {
450 outline = outline->next) {
451 outline->Scale(factor);
458 outline = outline->next) {
459 outline->ComputeBoundingBox();
467 outline = outline->next)
482 for (outline = outline->
next; outline !=
nullptr; outline = outline->
next) {
492 outline = outline->next) {
494 for (
TESSLINE* other_outline = outline->next; other_outline !=
nullptr;
495 last_outline = other_outline, other_outline = other_outline->
next) {
496 if (outline->SameBox(*other_outline)) {
497 last_outline->
next = other_outline->
next;
499 other_outline->
loop =
nullptr;
500 delete other_outline;
501 other_outline = last_outline;
503 outline->is_hole =
false;
519 #ifndef GRAPHICS_DISABLED 523 outline = outline->next)
524 outline->
plot(window, color, child_color);
526 #endif // GRAPHICS_DISABLED 537 CollectEdges(box,
nullptr, &accumulator,
nullptr,
nullptr);
542 if (x2nd < 1.0) x2nd = 1.0;
543 if (y2nd < 1.0) y2nd = 1.0;
544 second_moments->
set_x(x2nd);
545 second_moments->
set_y(y2nd);
546 return accumulator.
count();
553 *precise_box =
TBOX();
554 CollectEdges(box, precise_box,
nullptr,
nullptr,
nullptr);
572 y_coords->init_to_size(box.
width(), empty);
573 CollectEdges(box,
nullptr,
nullptr, x_coords, y_coords);
575 for (
int i = 0; i < x_coords->size(); ++i) (*x_coords)[i].sort();
576 for (
int i = 0; i < y_coords->size(); ++i) (*y_coords)[i].sort();
581 static void SegmentLLSQ(
const FCOORD& pt1,
const FCOORD& pt2,
589 if (xstart == xend && ystart == yend)
return;
590 double weight = step.length() / (xend - xstart + yend - ystart);
592 for (
int x = xstart; x < xend; ++x) {
593 double y = pt1.
y() + step.y() * (x + 0.5 - pt1.
x()) / step.x();
594 accumulator->
add(x + 0.5, y, weight);
597 for (
int y = ystart; y < yend; ++y) {
598 double x = pt1.
x() + step.x() * (y + 0.5 - pt1.
y()) / step.y();
599 accumulator->
add(x, y + 0.5, weight);
608 static void SegmentCoords(
const FCOORD& pt1,
const FCOORD& pt2,
int x_limit,
617 for (
int x = start; x < end; ++x) {
618 int y =
IntCastRounded(pt1.
y() + step.y() * (x + 0.5 - pt1.
x()) / step.x());
619 (*y_coords)[x].push_back(y);
623 for (
int y = start; y < end; ++y) {
624 int x =
IntCastRounded(pt1.
x() + step.x() * (y + 0.5 - pt1.
y()) / step.y());
625 (*x_coords)[y].push_back(x);
642 TBOX point(x1, std::min(y1, y2), x2, std::max(y1, y2));
652 TBOX point(std::min(x1, x2), y1, std::max(x1, x2), y2);
667 static void CollectEdgesOfRun(
const EDGEPT* startpt,
const EDGEPT* lastpt,
669 TBOX* bounding_box,
LLSQ* accumulator,
673 int x_limit = box.
width() - 1;
674 int y_limit = box.
height() - 1;
675 if (outline !=
nullptr) {
690 if (end_index <= start_index) end_index += step_length;
702 prev_normed -= origin;
703 for (
int index = start_index; index < end_index; ++index) {
704 ICOORD step = outline->
step(index % step_length);
717 pos_normed -= origin;
719 if (bounding_box !=
nullptr) {
720 SegmentBBox(pos_normed, prev_normed, bounding_box);
722 if (accumulator !=
nullptr) {
723 SegmentLLSQ(pos_normed, prev_normed, accumulator);
725 if (x_coords !=
nullptr && y_coords !=
nullptr) {
726 SegmentCoords(pos_normed, prev_normed, x_limit, y_limit, x_coords,
729 prev_normed = pos_normed;
736 const EDGEPT* pt = startpt;
741 if (bounding_box !=
nullptr) {
742 SegmentBBox(next_pos, pos, bounding_box);
744 if (accumulator !=
nullptr) {
745 SegmentLLSQ(next_pos, pos, accumulator);
747 if (x_coords !=
nullptr && y_coords !=
nullptr) {
748 SegmentCoords(next_pos, pos, x_limit, y_limit, x_coords, y_coords);
750 }
while ((pt = pt->
next) != endpt);
759 void TBLOB::CollectEdges(
const TBOX& box,
TBOX* bounding_box,
LLSQ* llsq,
765 EDGEPT* loop_pt = ol->FindBestStartPt();
767 if (pt ==
nullptr)
continue;
773 last_pt = last_pt->
next;
774 }
while (last_pt != loop_pt && !last_pt->
IsHidden() &&
776 last_pt = last_pt->
prev;
777 CollectEdgesOfRun(pt, last_pt, denorm_, box,
bounding_box, llsq, x_coords,
780 }
while ((pt = pt->
next) != loop_pt);
790 for (b_it.mark_cycle_pt(); !b_it.cycled_list(); b_it.forward()) {
791 C_BLOB* blob = b_it.data();
801 bool inverse,
float x_height,
float baseline_shift,
805 if (norm_box !=
nullptr) word_box = *norm_box;
806 float word_middle = (word_box.
left() + word_box.
right()) / 2.0f;
807 float input_y_offset = 0.0f;
810 if (row ==
nullptr) {
811 word_middle = word_box.
left();
812 input_y_offset = word_box.
bottom();
813 final_y_offset = 0.0f;
815 input_y_offset = row->
base_line(word_middle) + baseline_shift;
820 float mid_x = (blob_box.
left() + blob_box.
right()) / 2.0f;
822 float blob_scale = scale;
826 scale, scale * 1.5f);
827 }
else if (row !=
nullptr) {
837 blob_scale, 0.0f, final_y_offset, inverse, pix);
839 if (word_denorm !=
nullptr) {
841 input_y_offset, scale, scale, 0.0f,
852 for (
int b = 0; b < src.
blobs.
size(); ++b) {
867 blobs[b]->ComputeBoundingBoxes();
885 for (
int i = start + 1; i < end && i <
blobs.
size(); ++i) {
888 if (outline ==
nullptr) {
890 outline =
blobs[start]->outlines;
892 while (outline->
next !=
nullptr) outline = outline->
next;
901 for (
int i = start + 1; i < end && start + 1 <
blobs.
size(); ++i) {
906 #ifndef GRAPHICS_DISABLED 914 #endif // GRAPHICS_DISABLED 930 outline1 = outline1->
next) {
931 if (outline1->is_hole)
continue;
933 static_cast<int16_t>((outline1->topleft.x + outline1->botright.x) / 2),
934 static_cast<int16_t>((outline1->topleft.y + outline1->botright.y) / 2));
935 int mid_prod1 =
CROSS(mid_pt1, vertical);
936 int min_prod1, max_prod1;
937 outline1->MinMaxCrossProduct(vertical, &min_prod1, &max_prod1);
938 for (
TESSLINE* outline2 = outline1->
next; outline2 !=
nullptr;
939 outline2 = outline2->
next) {
940 if (outline2->is_hole)
continue;
941 TPOINT mid_pt2(static_cast<int16_t>(
942 (outline2->topleft.x + outline2->botright.x) / 2),
943 static_cast<int16_t>(
944 (outline2->topleft.y + outline2->botright.y) / 2));
945 int mid_prod2 =
CROSS(mid_pt2, vertical);
946 int min_prod2, max_prod2;
947 outline2->MinMaxCrossProduct(vertical, &min_prod2, &max_prod2);
948 int mid_gap = abs(mid_prod2 - mid_prod1);
950 std::min(max_prod1, max_prod2) - std::max(min_prod1, min_prod2);
951 if (mid_gap - overlap / 4 > max_gap) {
952 max_gap = mid_gap - overlap / 4;
954 *location += mid_pt2;
961 return max_gap > vertical.
y;
981 int location_prod =
CROSS(location, vertical);
983 while (outline !=
nullptr) {
987 int mid_prod =
CROSS(mid_pt, vertical);
988 if (mid_prod < location_prod) {
991 outline1->
next = outline;
998 outline2->
next = outline;
1003 outline = outline->
next;
1006 if (outline1) outline1->
next =
nullptr;
1007 if (outline2) outline2->
next =
nullptr;
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)
int ComputeMoments(FCOORD *center, FCOORD *second_moments) const
void NormTransform(const DENORM *first_norm, const TPOINT &pt, TPOINT *transformed) const
void DrawTo(int x, int y)
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)
static TBLOB * PolygonalCopy(bool allow_detailed_fx, C_BLOB *src)
void LocalNormBlob(TBLOB *blob) const
void MinMaxCrossProduct(const TPOINT vec, int *min_xp, int *max_xp) const
const DENORM * RootDenorm() const
void CopyFrom(const TBLOB &src)
FCOORD sub_pixel_pos_at_index(const ICOORD &pos, int index) const
TBOX bounding_box() const
static ScrollView::Color NextColor(ScrollView::Color colour)
float base_line(float xpos) const
void plot(ScrollView *window, ScrollView::Color color, ScrollView::Color child_color)
int16_t y() const
access_function
void ComputeBoundingBox()
TBOX bounding_box() const
const BLOCK * block() const
void Rotate(const FCOORD rotation)
const TPOINT kDivisibleVerticalUpright(0, 1)
const int kBlnBaselineOffset
void Move(const ICOORD vec)
void set_x(float xin)
rewrite function
void SetCursor(int x, int y)
void move(const ICOORD vec)
bool divisible_blob(TBLOB *blob, bool italic_blob, TPOINT *location)
void Normalize(const DENORM &denorm)
void add(double x, double y)
FCOORD mean_point() const
bool flag(WERD_FLAGS mask) const
void EliminateDuplicateOutlines()
void LocalNormTransform(const TPOINT &pt, TPOINT *transformed) const
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)
int16_t x() const
access function
ICOORD position_at_index(int index) const
void init_to_size(int size, const T &t)
void CopyFrom(const TWERD &src)
int edge_strength_at_index(int index) const
int IntCastRounded(double x)
FCOORD classify_rotation() const
void plot(ScrollView *window)
void Rotate(const FCOORD rotation)
int32_t pathlength() const
const TPOINT kDivisibleVerticalItalic(1, 5)
TBOX bounding_box() const
TBLOB * ClassifyNormalizeIfNeeded() const
C_BLOB_LIST * cblob_list()
EDGEPT * FindBestStartPt() const
void plot(ScrollView *window, ScrollView::Color colour) const
const ICOORD & botleft() const
void set_inverse(bool value)
GenericVector< TBLOB * > blobs
void CopyFrom(const TESSLINE &src)
void plot(ScrollView *window, ScrollView::Color color, ScrollView::Color child_color)
void GetPreciseBoundingBox(TBOX *precise_box) const
void ComputeBoundingBoxes()
double y_variance() const
static TBLOB * ShallowCopy(const TBLOB &src)
void MergeBlobs(int start, int end)
C_OUTLINE_LIST * out_list()
void delete_data_pointers()
double x_variance() const
T ClipToRange(const T &x, const T &lower_bound, const T &upper_bound)
CLISTIZE(BLOCK_RES) ELISTIZE(ROW_RES) ELISTIZE(WERD_RES) static const double kStopperAmbiguityThresholdGain
void CorrectBlobOrder(TBLOB *next)
static TWERD * PolygonalCopy(bool allow_detailed_fx, WERD *src)
void ComputeBoundingBoxes()
void GetEdgeCoords(const TBOX &box, GenericVector< GenericVector< int > > *x_coords, GenericVector< GenericVector< int > > *y_coords) const
void set_y(float yin)
rewrite function
static TESSLINE * BuildFromOutlineList(EDGEPT *outline)
ICOORD step(int index) const
void Move(const ICOORD vec)
TESSLINE * ApproximateOutline(bool allow_detailed_fx, C_OUTLINE *c_outline)
void divide_blobs(TBLOB *blob, TBLOB *other_blob, bool italic_blob, const TPOINT &location)
void UpdateRange(const T1 &x, T2 *lower_bound, T2 *upper_bound)