tesseract v5.3.3.20231005
tesseract::BaselineRow Class Reference

#include <baselinedetect.h>

Public Member Functions

 BaselineRow (double line_size, TO_ROW *to_row)
 
const TBOXbounding_box () const
 
void SetupOldLineParameters (TO_ROW *row) const
 
void Print () const
 
double BaselineAngle () const
 
double SpaceBetween (const BaselineRow &other) const
 
double PerpDisp (const FCOORD &direction) const
 
double StraightYAtX (double x) const
 
bool FitBaseline (bool use_box_bottoms)
 
void AdjustBaselineToParallel (int debug, const FCOORD &direction)
 
double AdjustBaselineToGrid (int debug, const FCOORD &direction, double line_spacing, double line_offset)
 

Detailed Description

Definition at line 37 of file baselinedetect.h.

Constructor & Destructor Documentation

◆ BaselineRow()

tesseract::BaselineRow::BaselineRow ( double  line_size,
TO_ROW to_row 
)

Definition at line 65 of file baselinedetect.cpp.

66 : blobs_(to_row->blob_list()),
67 baseline_pt1_(0.0f, 0.0f),
68 baseline_pt2_(0.0f, 0.0f),
69 baseline_error_(0.0),
70 good_baseline_(false) {
71 ComputeBoundingBox();
72 // Compute a scale factor for rounding to ints.
73 disp_quant_factor_ = kOffsetQuantizationFactor * line_spacing;
74 fit_halfrange_ = kFitHalfrangeFactor * line_spacing;
75 max_baseline_error_ = kMaxBaselineError * line_spacing;
76}
const double kFitHalfrangeFactor
const double kOffsetQuantizationFactor
const double kMaxBaselineError

Member Function Documentation

◆ AdjustBaselineToGrid()

double tesseract::BaselineRow::AdjustBaselineToGrid ( int  debug,
const FCOORD direction,
double  line_spacing,
double  line_offset 
)

Definition at line 235 of file baselinedetect.cpp.

237 {
238 if (blobs_->empty()) {
239 if (debug > 1) {
240 tprintf("Row empty at:");
241 bounding_box_.print();
242 }
243 return line_offset;
244 }
245 // Find the displacement_modes_ entry nearest to the grid.
246 double best_error = 0.0;
247 int best_index = -1;
248 for (unsigned i = 0; i < displacement_modes_.size(); ++i) {
249 double blob_y = displacement_modes_[i];
250 double error =
251 BaselineBlock::SpacingModelError(blob_y, line_spacing, line_offset);
252 if (debug > 1) {
253 tprintf("Mode at %g has error %g from model \n", blob_y, error);
254 }
255 if (best_index < 0 || error < best_error) {
256 best_error = error;
257 best_index = i;
258 }
259 }
260 // We will move the baseline only if the chosen mode is close enough to the
261 // model.
262 double model_margin = max_baseline_error_ - best_error;
263 if (best_index >= 0 && model_margin > 0.0) {
264 // But if the current baseline is already close to the mode there is no
265 // point, and only the potential to damage accuracy by changing its angle.
266 double perp_disp = PerpDisp(direction);
267 double shift = displacement_modes_[best_index] - perp_disp;
268 if (fabs(shift) > max_baseline_error_) {
269 if (debug > 1) {
270 tprintf("Attempting linespacing model fit with mode %g to row at:",
271 displacement_modes_[best_index]);
272 bounding_box_.print();
273 }
274 FitConstrainedIfBetter(debug, direction, model_margin,
275 displacement_modes_[best_index]);
276 } else if (debug > 1) {
277 tprintf("Linespacing model only moves current line by %g for row at:",
278 shift);
279 bounding_box_.print();
280 }
281 } else if (debug > 1) {
282 tprintf("Linespacing model not close enough to any mode for row at:");
283 bounding_box_.print();
284 }
285 return fmod(PerpDisp(direction), line_spacing);
286}
void tprintf(const char *format,...)
Definition: tprintf.cpp:41
void print() const
Definition: rect.h:289
double PerpDisp(const FCOORD &direction) const
static double SpacingModelError(double perp_disp, double line_spacing, double line_offset)

◆ AdjustBaselineToParallel()

void tesseract::BaselineRow::AdjustBaselineToParallel ( int  debug,
const FCOORD direction 
)

Definition at line 220 of file baselinedetect.cpp.

220 {
221 SetupBlobDisplacements(direction);
222 if (displacement_modes_.empty()) {
223 return;
224 }
225#ifdef kDebugYCoord
226 if (bounding_box_.bottom() < kDebugYCoord &&
227 bounding_box_.top() > kDebugYCoord && debug < 3)
228 debug = 3;
229#endif
230 FitConstrainedIfBetter(debug, direction, 0.0, displacement_modes_[0]);
231}
TDimension top() const
Definition: rect.h:68
TDimension bottom() const
Definition: rect.h:75

◆ BaselineAngle()

double tesseract::BaselineRow::BaselineAngle ( ) const

Definition at line 99 of file baselinedetect.cpp.

99 {
100 FCOORD baseline_dir(baseline_pt2_ - baseline_pt1_);
101 double angle = baseline_dir.angle();
102 // Baseline directions are only unique in a range of pi so constrain to
103 // [-pi/2, pi/2].
104 return fmod(angle + M_PI * 1.5, M_PI) - M_PI * 0.5;
105}

◆ bounding_box()

const TBOX & tesseract::BaselineRow::bounding_box ( ) const
inline

Definition at line 41 of file baselinedetect.h.

41 {
42 return bounding_box_;
43 }

◆ FitBaseline()

bool tesseract::BaselineRow::FitBaseline ( bool  use_box_bottoms)

Definition at line 145 of file baselinedetect.cpp.

145 {
146 // Deterministic fitting is used wherever possible.
147 fitter_.Clear();
148 // Linear least squares is a backup if the DetLineFit produces a bad line.
149 LLSQ llsq;
150 BLOBNBOX_IT blob_it(blobs_);
151
152 for (blob_it.mark_cycle_pt(); !blob_it.cycled_list(); blob_it.forward()) {
153 BLOBNBOX *blob = blob_it.data();
154 if (!use_box_bottoms) {
155 blob->EstimateBaselinePosition();
156 }
157 const TBOX &box = blob->bounding_box();
158 int x_middle = (box.left() + box.right()) / 2;
159#ifdef kDebugYCoord
160 if (box.bottom() < kDebugYCoord && box.top() > kDebugYCoord) {
161 tprintf("Box bottom = %d, baseline pos=%d for box at:", box.bottom(),
162 blob->baseline_position());
163 box.print();
164 }
165#endif
166 fitter_.Add(ICOORD(x_middle, blob->baseline_position()), box.width() / 2);
167 llsq.add(x_middle, blob->baseline_position());
168 }
169 // Fit the line.
170 ICOORD pt1, pt2;
171 baseline_error_ = fitter_.Fit(&pt1, &pt2);
172 baseline_pt1_ = pt1;
173 baseline_pt2_ = pt2;
174 if (baseline_error_ > max_baseline_error_ &&
176 // The fit was bad but there were plenty of points, so try skipping
177 // the first and last few, and use the new line if it dramatically improves
178 // the error of fit.
179 double error = fitter_.Fit(kNumSkipPoints, kNumSkipPoints, &pt1, &pt2);
180 if (error < baseline_error_ / 2.0) {
181 baseline_error_ = error;
182 baseline_pt1_ = pt1;
183 baseline_pt2_ = pt2;
184 }
185 }
186 int debug = 0;
187#ifdef kDebugYCoord
188 Print();
189 debug = bounding_box_.bottom() < kDebugYCoord &&
190 bounding_box_.top() > kDebugYCoord
191 ? 3
192 : 2;
193#endif
194 // Now we obtained a direction from that fit, see if we can improve the
195 // fit using the same direction and some other start point.
196 FCOORD direction(pt2 - pt1);
197 double target_offset = direction * pt1;
198 good_baseline_ = false;
199 FitConstrainedIfBetter(debug, direction, 0.0, target_offset);
200 // Wild lines can be produced because DetLineFit allows vertical lines, but
201 // vertical text has been rotated so angles over pi/4 should be disallowed.
202 // Near vertical lines can still be produced by vertically aligned components
203 // on very short lines.
204 double angle = BaselineAngle();
205 if (fabs(angle) > M_PI * 0.25) {
206 // Use the llsq fit as a backup.
207 baseline_pt1_ = llsq.mean_point();
208 baseline_pt2_ = baseline_pt1_ + FCOORD(1.0f, llsq.m());
209 // TODO(rays) get rid of this when m and c are no longer used.
210 double m = llsq.m();
211 double c = llsq.c(m);
212 baseline_error_ = llsq.rms(m, c);
213 good_baseline_ = false;
214 }
215 return good_baseline_;
216}
const int kNumSkipPoints
@ TBOX
void Add(const ICOORD &pt)
Definition: detlinefit.cpp:50
double Fit(ICOORD *pt1, ICOORD *pt2)
Definition: detlinefit.h:73
bool SufficientPointsForIndependentFit() const
Definition: detlinefit.cpp:164
double BaselineAngle() const

◆ PerpDisp()

double tesseract::BaselineRow::PerpDisp ( const FCOORD direction) const

Definition at line 123 of file baselinedetect.cpp.

123 {
124 float middle_x = (bounding_box_.left() + bounding_box_.right()) / 2.0f;
125 FCOORD middle_pos(middle_x, StraightYAtX(middle_x));
126 return direction * middle_pos / direction.length();
127}
TDimension left() const
Definition: rect.h:82
TDimension right() const
Definition: rect.h:89
double StraightYAtX(double x) const

◆ Print()

void tesseract::BaselineRow::Print ( ) const

Definition at line 89 of file baselinedetect.cpp.

89 {
90 tprintf("Baseline (%g,%g)->(%g,%g), angle=%g, intercept=%g\n",
91 baseline_pt1_.x(), baseline_pt1_.y(), baseline_pt2_.x(),
92 baseline_pt2_.y(), BaselineAngle(), StraightYAtX(0.0));
93 tprintf("Quant factor=%g, error=%g, good=%d, box:", disp_quant_factor_,
94 baseline_error_, good_baseline_);
95 bounding_box_.print();
96}
float y() const
Definition: points.h:209
float x() const
Definition: points.h:206

◆ SetupOldLineParameters()

void tesseract::BaselineRow::SetupOldLineParameters ( TO_ROW row) const

Definition at line 79 of file baselinedetect.cpp.

79 {
80 // TODO(rays) get rid of this when m and c are no longer used.
81 double gradient = tan(BaselineAngle());
82 // para_c is the actual intercept of the baseline on the y-axis.
83 float para_c = StraightYAtX(0.0);
84 row->set_line(gradient, para_c, baseline_error_);
85 row->set_parallel_line(gradient, para_c, baseline_error_);
86}

◆ SpaceBetween()

double tesseract::BaselineRow::SpaceBetween ( const BaselineRow other) const

Definition at line 109 of file baselinedetect.cpp.

109 {
110 // Find the x-centre of overlap of the lines.
111 float x = (std::max(bounding_box_.left(), other.bounding_box_.left()) +
112 std::min(bounding_box_.right(), other.bounding_box_.right())) /
113 2.0f;
114 // Find the vertical centre between them.
115 float y = (StraightYAtX(x) + other.StraightYAtX(x)) / 2.0f;
116 // Find the perpendicular distance of (x,y) from each line.
117 FCOORD pt(x, y);
118 return PerpDistanceFromBaseline(pt) + other.PerpDistanceFromBaseline(pt);
119}
const double y

◆ StraightYAtX()

double tesseract::BaselineRow::StraightYAtX ( double  x) const

Definition at line 131 of file baselinedetect.cpp.

131 {
132 double denominator = baseline_pt2_.x() - baseline_pt1_.x();
133 if (denominator == 0.0) {
134 return (baseline_pt1_.y() + baseline_pt2_.y()) / 2.0;
135 }
136 return baseline_pt1_.y() + (x - baseline_pt1_.x()) *
137 (baseline_pt2_.y() - baseline_pt1_.y()) /
138 denominator;
139}

The documentation for this class was generated from the following files: