/** Convert a TESSLINE into the float-based MFOUTLINE micro-feature format. */ MFOUTLINE ConvertOutline(TESSLINE *outline) { MFEDGEPT *NewPoint; MFOUTLINE MFOutline = NIL_LIST; EDGEPT *EdgePoint; EDGEPT *StartPoint; EDGEPT *NextPoint; if (outline == NULL || outline->loop == NULL) return MFOutline; StartPoint = outline->loop; EdgePoint = StartPoint; do { NextPoint = EdgePoint->next; /* filter out duplicate points */ if (EdgePoint->pos.x != NextPoint->pos.x || EdgePoint->pos.y != NextPoint->pos.y) { NewPoint = NewEdgePoint(); ClearMark(NewPoint); NewPoint->Hidden = EdgePoint->IsHidden(); NewPoint->Point.x = EdgePoint->pos.x; NewPoint->Point.y = EdgePoint->pos.y; MFOutline = push(MFOutline, NewPoint); } EdgePoint = NextPoint; } while (EdgePoint != StartPoint); if (MFOutline != NULL) MakeOutlineCircular(MFOutline); return MFOutline; }
// For all the edge steps in all the outlines, or polygonal approximation // where there are no edge steps, collects the steps into the bounding_box, // llsq and/or the x_coords/y_coords. Both are used in different kinds of // normalization. // For a description of x_coords, y_coords, see GetEdgeCoords above. void TBLOB::CollectEdges(const TBOX& box, TBOX* bounding_box, LLSQ* llsq, GenericVector<GenericVector<int> >* x_coords, GenericVector<GenericVector<int> >* y_coords) const { // Iterate the outlines. for (const TESSLINE* ol = outlines; ol != NULL; ol = ol->next) { // Iterate the polygon. EDGEPT* loop_pt = ol->FindBestStartPt(); EDGEPT* pt = loop_pt; if (pt == NULL) continue; do { if (pt->IsHidden()) continue; // Find a run of equal src_outline. EDGEPT* last_pt = pt; do { last_pt = last_pt->next; } while (last_pt != loop_pt && !last_pt->IsHidden() && last_pt->src_outline == pt->src_outline); last_pt = last_pt->prev; CollectEdgesOfRun(pt, last_pt, denorm_, box, bounding_box, llsq, x_coords, y_coords); pt = last_pt; } while ((pt = pt->next) != loop_pt); } }
// Undoes hide, so the outlines are cut by the SPLIT. void SPLIT::Reveal() const { EDGEPT* edgept = point1; do { edgept->Reveal(); edgept = edgept->next; } while (!edgept->EqualPos(*point2) && edgept != point1); edgept = point2; do { edgept->Reveal(); edgept = edgept->next; } while (!edgept->EqualPos(*point1) && edgept != point2); }
// Returns the first non-hidden EDGEPT that has a different src_outline to // its predecessor, or, if all the same, the lowest indexed point. EDGEPT* TESSLINE::FindBestStartPt() const { EDGEPT* best_start = loop; int best_step = loop->start_step; // Iterate the polygon. EDGEPT* pt = loop; do { if (pt->IsHidden()) continue; if (pt->prev->IsHidden() || pt->prev->src_outline != pt->src_outline) return pt; // Qualifies as the best. if (pt->start_step < best_step) { best_step = pt->start_step; best_start = pt; } } while ((pt = pt->next) != loop); return best_start; }
void TESSLINE::plot(ScrollView* window, ScrollView::Color color, ScrollView::Color child_color) { if (is_hole) window->Pen(child_color); else window->Pen(color); window->SetCursor(start.x, start.y); EDGEPT* pt = loop; do { bool prev_hidden = pt->IsHidden(); pt = pt->next; if (prev_hidden) window->SetCursor(pt->pos.x, pt->pos.y); else window->DrawTo(pt->pos.x, pt->pos.y); } while (pt != loop); }
// Extracts sets of 3-D features of length kStandardFeatureLength (=12.8), as // (x,y) position and angle as measured counterclockwise from the vector // <-1, 0>, from blob using two normalizations defined by bl_denorm and // cn_denorm. See SetpuBLCNDenorms for definitions. // If outline_cn_counts is not nullptr, on return it contains the cumulative // number of cn features generated for each outline in the blob (in order). // Thus after the first outline, there were (*outline_cn_counts)[0] features, // after the second outline, there were (*outline_cn_counts)[1] features etc. void Classify::ExtractFeatures(const TBLOB& blob, bool nonlinear_norm, GenericVector<INT_FEATURE_STRUCT>* bl_features, GenericVector<INT_FEATURE_STRUCT>* cn_features, INT_FX_RESULT_STRUCT* results, GenericVector<int>* outline_cn_counts) { DENORM bl_denorm, cn_denorm; tesseract::Classify::SetupBLCNDenorms(blob, nonlinear_norm, &bl_denorm, &cn_denorm, results); if (outline_cn_counts != nullptr) outline_cn_counts->truncate(0); // Iterate the outlines. for (TESSLINE* ol = blob.outlines; ol != nullptr; ol = ol->next) { // Iterate the polygon. EDGEPT* loop_pt = ol->FindBestStartPt(); EDGEPT* pt = loop_pt; if (pt == nullptr) continue; do { if (pt->IsHidden()) continue; // Find a run of equal src_outline. EDGEPT* last_pt = pt; do { last_pt = last_pt->next; } while (last_pt != loop_pt && !last_pt->IsHidden() && last_pt->src_outline == pt->src_outline); last_pt = last_pt->prev; // Until the adaptive classifier can be weaned off polygon segments, // we have to force extraction from the polygon for the bl_features. ExtractFeaturesFromRun(pt, last_pt, bl_denorm, kStandardFeatureLength, true, bl_features); ExtractFeaturesFromRun(pt, last_pt, cn_denorm, kStandardFeatureLength, false, cn_features); pt = last_pt; } while ((pt = pt->next) != loop_pt); if (outline_cn_counts != nullptr) outline_cn_counts->push_back(cn_features->size()); } results->NumBL = bl_features->size(); results->NumCN = cn_features->size(); results->YBottom = blob.bounding_box().bottom(); results->YTop = blob.bounding_box().top(); results->Width = blob.bounding_box().width(); }
/** * @name vertical_projection_point * * For one point on the outline, find the corresponding point on the * other side of the outline that is a likely projection for a split * point. This is done by iterating through the edge points until the * X value of the point being looked at is greater than the X value of * the split point. Ensure that the point being returned is not right * next to the split point. Return the edge point in *best_point as * a result, and any points that were newly created are also saved on * the new_points list. */ void Wordrec::vertical_projection_point(EDGEPT *split_point, EDGEPT *target_point, EDGEPT** best_point, EDGEPT_CLIST *new_points) { EDGEPT *p; /* Iterator */ EDGEPT *this_edgept; /* Iterator */ EDGEPT_C_IT new_point_it(new_points); int x = split_point->pos.x; /* X value of vertical */ int best_dist = LARGE_DISTANCE;/* Best point found */ if (*best_point != nullptr) best_dist = edgept_dist(split_point, *best_point); p = target_point; /* Look at each edge point */ do { if (((p->pos.x <= x && x <= p->next->pos.x) || (p->next->pos.x <= x && x <= p->pos.x)) && !same_point(split_point->pos, p->pos) && !same_point(split_point->pos, p->next->pos) && !p->IsChopPt() && (*best_point == nullptr || !same_point((*best_point)->pos, p->pos))) { if (near_point(split_point, p, p->next, &this_edgept)) { new_point_it.add_before_then_move(this_edgept); } if (*best_point == nullptr) best_dist = edgept_dist (split_point, this_edgept); this_edgept = pick_close_point(split_point, this_edgept, &best_dist); if (this_edgept) *best_point = this_edgept; } p = p->next; } while (p != target_point); }
/********************************************************************** * reveal_edge_pair * * Change the edge points that are referenced by this seam to make * them hidden edges. **********************************************************************/ void reveal_edge_pair(EDGEPT *pt1, EDGEPT *pt2) { EDGEPT *edgept; edgept = pt1; do { edgept->Reveal(); edgept = edgept->next; } while (!exact_point (edgept, pt2) && edgept != pt1); if (edgept == pt1) { /* tprintf("Hid entire outline at (%d,%d)!!\n", edgept->pos.x,edgept->pos.y); */ } edgept = pt2; do { edgept->Reveal(); edgept = edgept->next; } while (!exact_point (edgept, pt1) && edgept != pt2); if (edgept == pt2) { /* tprintf("Hid entire outline at (%d,%d)!!\n", edgept->pos.x,edgept->pos.y); */ } }