tesseract  5.0.0
tesseract::QSPLINE Class Reference

#include <quspline.h>

Public Member Functions

 QSPLINE ()
 
 QSPLINE (const QSPLINE &src)
 
 QSPLINE (int32_t count, int32_t *xstarts, double *coeffs)
 
 ~QSPLINE ()
 
 QSPLINE (int xstarts[], int segcount, int xcoords[], int ycoords[], int blobcount, int degree)
 
double step (double x1, double x2)
 
double y (double x) const
 
void move (ICOORD vec)
 
bool overlap (QSPLINE *spline2, double fraction)
 
void extrapolate (double gradient, int left, int right)
 
void plot (ScrollView *window, ScrollView::Color colour) const
 
void plot (Image pix) const
 
QSPLINEoperator= (const QSPLINE &source)
 

Friends

void make_first_baseline (TBOX *, int, int *, int *, QSPLINE *, QSPLINE *, float)
 
void make_holed_baseline (TBOX *, int, QSPLINE *, QSPLINE *, float)
 
void tweak_row_baseline (ROW *, double, double)
 

Detailed Description

Definition at line 36 of file quspline.h.

Constructor & Destructor Documentation

◆ QSPLINE() [1/4]

tesseract::QSPLINE::QSPLINE ( )
inline

Definition at line 42 of file quspline.h.

42  { // empty constructor
43  segments = 0;
44  xcoords = nullptr; // everything empty
45  quadratics = nullptr;
46  }

◆ QSPLINE() [2/4]

tesseract::QSPLINE::QSPLINE ( const QSPLINE src)

Definition at line 136 of file quspline.cpp.

137  {
138  segments = 0;
139  xcoords = nullptr;
140  quadratics = nullptr;
141  *this = src;
142 }

◆ QSPLINE() [3/4]

tesseract::QSPLINE::QSPLINE ( int32_t  count,
int32_t *  xstarts,
double *  coeffs 
)

Definition at line 43 of file quspline.cpp.

47  {
48  int32_t index; // segment index
49 
50  // get memory
51  xcoords = new int32_t[count + 1];
52  quadratics = new QUAD_COEFFS[count];
53  segments = count;
54  for (index = 0; index < segments; index++) {
55  // copy them
56  xcoords[index] = xstarts[index];
57  quadratics[index] =
58  QUAD_COEFFS(coeffs[index * 3], coeffs[index * 3 + 1], coeffs[index * 3 + 2]);
59  }
60  // right edge
61  xcoords[index] = xstarts[index];
62 }

◆ ~QSPLINE()

tesseract::QSPLINE::~QSPLINE ( )

Definition at line 150 of file quspline.cpp.

150  {
151  delete[] xcoords;
152  delete[] quadratics;
153 }

◆ QSPLINE() [4/4]

tesseract::QSPLINE::QSPLINE ( int  xstarts[],
int  segcount,
int  xcoords[],
int  ycoords[],
int  blobcount,
int  degree 
)

Definition at line 70 of file quspline.cpp.

76  {
77  int pointindex; /*no along text line */
78  int segment; /*segment no */
79  int32_t *ptcounts; // no in each segment
80  QLSQ qlsq; /*accumulator */
81 
82  segments = segcount;
83  xcoords = new int32_t[segcount + 1];
84  ptcounts = new int32_t[segcount + 1];
85  quadratics = new QUAD_COEFFS[segcount];
86  memmove(xcoords, xstarts, (segcount + 1) * sizeof(int32_t));
87  ptcounts[0] = 0; /*none in any yet */
88  for (segment = 0, pointindex = 0; pointindex < pointcount; pointindex++) {
89  while (segment < segcount && xpts[pointindex] >= xstarts[segment]) {
90  segment++; /*try next segment */
91  /*cumulative counts */
92  ptcounts[segment] = ptcounts[segment - 1];
93  }
94  ptcounts[segment]++; /*no in previous partition */
95  }
96  while (segment < segcount) {
97  segment++;
98  /*zero the rest */
99  ptcounts[segment] = ptcounts[segment - 1];
100  }
101 
102  for (segment = 0; segment < segcount; segment++) {
103  qlsq.clear();
104  /*first blob */
105  pointindex = ptcounts[segment];
106  if (pointindex > 0 && xpts[pointindex] != xpts[pointindex - 1] &&
107  xpts[pointindex] != xstarts[segment]) {
108  qlsq.add(xstarts[segment],
109  ypts[pointindex - 1] + (ypts[pointindex] - ypts[pointindex - 1]) *
110  (xstarts[segment] - xpts[pointindex - 1]) /
111  (xpts[pointindex] - xpts[pointindex - 1]));
112  }
113  for (; pointindex < ptcounts[segment + 1]; pointindex++) {
114  qlsq.add(xpts[pointindex], ypts[pointindex]);
115  }
116  if (pointindex > 0 && pointindex < pointcount && xpts[pointindex] != xstarts[segment + 1]) {
117  qlsq.add(xstarts[segment + 1],
118  ypts[pointindex - 1] + (ypts[pointindex] - ypts[pointindex - 1]) *
119  (xstarts[segment + 1] - xpts[pointindex - 1]) /
120  (xpts[pointindex] - xpts[pointindex - 1]));
121  }
122  qlsq.fit(degree);
123  quadratics[segment].a = qlsq.get_a();
124  quadratics[segment].b = qlsq.get_b();
125  quadratics[segment].c = qlsq.get_c();
126  }
127  delete[] ptcounts;
128 }

Member Function Documentation

◆ extrapolate()

void tesseract::QSPLINE::extrapolate ( double  gradient,
int  left,
int  right 
)

Definition at line 284 of file quspline.cpp.

288  {
289  int segment; /*current segment of spline */
290  int dest_segment; // dest index
291  int32_t *xstarts; // new boundaries
292  QUAD_COEFFS *quads; // new ones
293  int increment; // in size
294 
295  increment = xmin < xcoords[0] ? 1 : 0;
296  if (xmax > xcoords[segments]) {
297  increment++;
298  }
299  if (increment == 0) {
300  return;
301  }
302  xstarts = new int32_t[segments + 1 + increment];
303  quads = new QUAD_COEFFS[segments + increment];
304  if (xmin < xcoords[0]) {
305  xstarts[0] = xmin;
306  quads[0].a = 0;
307  quads[0].b = gradient;
308  quads[0].c = y(xcoords[0]) - quads[0].b * xcoords[0];
309  dest_segment = 1;
310  } else {
311  dest_segment = 0;
312  }
313  for (segment = 0; segment < segments; segment++) {
314  xstarts[dest_segment] = xcoords[segment];
315  quads[dest_segment] = quadratics[segment];
316  dest_segment++;
317  }
318  xstarts[dest_segment] = xcoords[segment];
319  if (xmax > xcoords[segments]) {
320  quads[dest_segment].a = 0;
321  quads[dest_segment].b = gradient;
322  quads[dest_segment].c = y(xcoords[segments]) - quads[dest_segment].b * xcoords[segments];
323  dest_segment++;
324  xstarts[dest_segment] = xmax + 1;
325  }
326  segments = dest_segment;
327  delete[] xcoords;
328  delete[] quadratics;
329  xcoords = xstarts;
330  quadratics = quads;
331 }
double y(double x) const
Definition: quspline.cpp:203

◆ move()

void tesseract::QSPLINE::move ( ICOORD  vec)

Definition at line 244 of file quspline.cpp.

246  {
247  int32_t segment; // index of segment
248  int16_t x_shift = vec.x();
249 
250  for (segment = 0; segment < segments; segment++) {
251  xcoords[segment] += x_shift;
252  quadratics[segment].move(vec);
253  }
254  xcoords[segment] += x_shift;
255 }
void move(ICOORD vec)
Definition: quadratc.h:43

◆ operator=()

QSPLINE & tesseract::QSPLINE::operator= ( const QSPLINE source)

Definition at line 161 of file quspline.cpp.

162  {
163  delete[] xcoords;
164  delete[] quadratics;
165 
166  segments = source.segments;
167  xcoords = new int32_t[segments + 1];
168  quadratics = new QUAD_COEFFS[segments];
169  memmove(xcoords, source.xcoords, (segments + 1) * sizeof(int32_t));
170  memmove(quadratics, source.quadratics, segments * sizeof(QUAD_COEFFS));
171  return *this;
172 }

◆ overlap()

bool tesseract::QSPLINE::overlap ( QSPLINE spline2,
double  fraction 
)

Definition at line 264 of file quspline.cpp.

267  {
268  int leftlimit = xcoords[1]; /*common left limit */
269  int rightlimit = xcoords[segments - 1]; /*common right limit */
270  /*or too non-overlap */
271  return !(spline2->segments < 3 ||
272  spline2->xcoords[1] > leftlimit + fraction * (rightlimit - leftlimit) ||
273  spline2->xcoords[spline2->segments - 1] <
274  rightlimit - fraction * (rightlimit - leftlimit));
275 }

◆ plot() [1/2]

void tesseract::QSPLINE::plot ( Image  pix) const

Definition at line 365 of file quspline.cpp.

365  {
366  if (pix == nullptr) {
367  return;
368  }
369 
370  int32_t segment; // Index of segment
371  int16_t step; // Index of poly piece
372  double increment; // x increment
373  double x; // x coord
374  auto height = static_cast<double>(pixGetHeight(pix));
375  Pta *points = ptaCreate(QSPLINE_PRECISION * segments);
376  const int kLineWidth = 5;
377 
378  for (segment = 0; segment < segments; segment++) {
379  increment = static_cast<double>((xcoords[segment + 1] - xcoords[segment])) / QSPLINE_PRECISION;
380  x = xcoords[segment];
381  for (step = 0; step <= QSPLINE_PRECISION; step++) {
382  double y = height - quadratics[segment].y(x);
383  ptaAddPt(points, x, y);
384  x += increment;
385  }
386  }
387 
388  switch (pixGetDepth(pix)) {
389  case 1:
390  pixRenderPolyline(pix, points, kLineWidth, L_SET_PIXELS, 1);
391  break;
392  case 32:
393  pixRenderPolylineArb(pix, points, kLineWidth, 255, 0, 0, 1);
394  break;
395  default:
396  pixRenderPolyline(pix, points, kLineWidth, L_CLEAR_PIXELS, 1);
397  break;
398  }
399  ptaDestroy(&points);
400 }
#define QSPLINE_PRECISION
Definition: quspline.cpp:35
float y(float x) const
Definition: quadratc.h:38
double step(double x1, double x2)
Definition: quspline.cpp:180

◆ plot() [2/2]

void tesseract::QSPLINE::plot ( ScrollView window,
ScrollView::Color  colour 
) const

Definition at line 340 of file quspline.cpp.

343  {
344  int32_t segment; // index of segment
345  int16_t step; // index of poly piece
346  double increment; // x increment
347  double x; // x coord
348 
349  window->Pen(colour);
350  for (segment = 0; segment < segments; segment++) {
351  increment = static_cast<double>(xcoords[segment + 1] - xcoords[segment]) / QSPLINE_PRECISION;
352  x = xcoords[segment];
353  for (step = 0; step <= QSPLINE_PRECISION; step++) {
354  if (segment == 0 && step == 0) {
355  window->SetCursor(x, quadratics[segment].y(x));
356  } else {
357  window->DrawTo(x, quadratics[segment].y(x));
358  }
359  x += increment;
360  }
361  }
362 }

◆ step()

double tesseract::QSPLINE::step ( double  x1,
double  x2 
)

Definition at line 180 of file quspline.cpp.

182  {
183  int index1, index2; // indices of coords
184  double total; /*total steps */
185 
186  index1 = spline_index(x1);
187  index2 = spline_index(x2);
188  total = 0;
189  while (index1 < index2) {
190  total += static_cast<double>(quadratics[index1 + 1].y(static_cast<float>(xcoords[index1 + 1])));
191  total -= static_cast<double>(quadratics[index1].y(static_cast<float>(xcoords[index1 + 1])));
192  index1++; /*next segment */
193  }
194  return total; /*total steps */
195 }

◆ y()

double tesseract::QSPLINE::y ( double  x) const

Definition at line 203 of file quspline.cpp.

205  {
206  int32_t index; // segment index
207 
208  index = spline_index(x);
209  return quadratics[index].y(x); // in correct segment
210 }

Friends And Related Function Documentation

◆ make_first_baseline

void make_first_baseline ( TBOX ,
int  ,
int *  ,
int *  ,
QSPLINE ,
QSPLINE ,
float   
)
friend

◆ make_holed_baseline

void make_holed_baseline ( TBOX ,
int  ,
QSPLINE ,
QSPLINE ,
float   
)
friend

◆ tweak_row_baseline

void tweak_row_baseline ( ROW ,
double  ,
double   
)
friend

Definition at line 864 of file tordmain.cpp.

864  {
865  TBOX blob_box; // bounding box
866  C_BLOB *blob; // current blob
867  WERD *word; // current word
868  int32_t blob_count; // no of blobs
869  int32_t src_index; // source segment
870  int32_t dest_index; // destination segment
871  float ydiff; // baseline error
872  float x_centre; // centre of blob
873  // words of row
874  WERD_IT word_it = row->word_list();
875  C_BLOB_IT blob_it; // blob iterator
876 
877  blob_count = 0;
878  for (word_it.mark_cycle_pt(); !word_it.cycled_list(); word_it.forward()) {
879  word = word_it.data(); // current word
880  // get total blobs
881  blob_count += word->cblob_list()->length();
882  }
883  if (blob_count == 0) {
884  return;
885  }
886  // spline segments
887  std::vector<int32_t> xstarts(blob_count + row->baseline.segments + 1);
888  // spline coeffs
889  std::vector<double> coeffs((blob_count + row->baseline.segments) * 3);
890 
891  src_index = 0;
892  dest_index = 0;
893  xstarts[0] = row->baseline.xcoords[0];
894  for (word_it.mark_cycle_pt(); !word_it.cycled_list(); word_it.forward()) {
895  word = word_it.data(); // current word
896  // blobs in word
897  blob_it.set_to_list(word->cblob_list());
898  for (blob_it.mark_cycle_pt(); !blob_it.cycled_list(); blob_it.forward()) {
899  blob = blob_it.data();
900  blob_box = blob->bounding_box();
901  x_centre = (blob_box.left() + blob_box.right()) / 2.0;
902  ydiff = blob_box.bottom() - row->base_line(x_centre);
903  if (ydiff < 0) {
904  ydiff = -ydiff / row->x_height();
905  } else {
906  ydiff = ydiff / row->x_height();
907  }
908  if (ydiff < blshift_maxshift && blob_box.height() / row->x_height() > blshift_xfraction) {
909  if (xstarts[dest_index] >= x_centre) {
910  xstarts[dest_index] = blob_box.left();
911  }
912  coeffs[dest_index * 3] = 0;
913  coeffs[dest_index * 3 + 1] = 0;
914  coeffs[dest_index * 3 + 2] = blob_box.bottom();
915  // shift it
916  dest_index++;
917  xstarts[dest_index] = blob_box.right() + 1;
918  } else {
919  if (xstarts[dest_index] <= x_centre) {
920  while (row->baseline.xcoords[src_index + 1] <= x_centre &&
921  src_index < row->baseline.segments - 1) {
922  if (row->baseline.xcoords[src_index + 1] > xstarts[dest_index]) {
923  coeffs[dest_index * 3] = row->baseline.quadratics[src_index].a;
924  coeffs[dest_index * 3 + 1] = row->baseline.quadratics[src_index].b;
925  coeffs[dest_index * 3 + 2] = row->baseline.quadratics[src_index].c;
926  dest_index++;
927  xstarts[dest_index] = row->baseline.xcoords[src_index + 1];
928  }
929  src_index++;
930  }
931  coeffs[dest_index * 3] = row->baseline.quadratics[src_index].a;
932  coeffs[dest_index * 3 + 1] = row->baseline.quadratics[src_index].b;
933  coeffs[dest_index * 3 + 2] = row->baseline.quadratics[src_index].c;
934  dest_index++;
935  xstarts[dest_index] = row->baseline.xcoords[src_index + 1];
936  }
937  }
938  }
939  }
940  while (src_index < row->baseline.segments &&
941  row->baseline.xcoords[src_index + 1] <= xstarts[dest_index]) {
942  src_index++;
943  }
944  while (src_index < row->baseline.segments) {
945  coeffs[dest_index * 3] = row->baseline.quadratics[src_index].a;
946  coeffs[dest_index * 3 + 1] = row->baseline.quadratics[src_index].b;
947  coeffs[dest_index * 3 + 2] = row->baseline.quadratics[src_index].c;
948  dest_index++;
949  src_index++;
950  xstarts[dest_index] = row->baseline.xcoords[src_index];
951  }
952  // turn to spline
953  row->baseline = QSPLINE(dest_index, &xstarts[0], &coeffs[0]);
954 }
@ TBOX
@ baseline
Definition: mfoutline.h:53

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