tesseract v5.3.3.20231005
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}
int * count

◆ ~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: