32 #include "config_auto.h"
38 "Use original wiseowl xheight");
46 "Fix bug in modes threshold for xheights");
50 "Max lost before fallback line used");
53 "X fraction for new partition");
56 #define X_HEIGHT_FRACTION 0.7
57 #define DESCENDER_FRACTION 0.5
58 #define MIN_ASC_FRACTION 0.20
59 #define MIN_DESC_FRACTION 0.25
60 #define MINASCRISE 2.0
61 #define MAXHEIGHTVARIANCE 0.15
63 #define MAXOVERLAP 0.1
65 #define HEIGHTBUCKETS 200
66 #define DELTAHEIGHT 5.0
73 #define ABS(x) ((x)<0 ? (-(x)) : (x))
83 void Textord::make_old_baselines(
TO_BLOCK *block,
88 TO_ROW_IT row_it = block->
get_rows();
92 for (row_it.mark_cycle_pt(); !row_it.cycled_list(); row_it.forward()) {
94 find_textlines(block, row, 2,
NULL);
96 find_textlines(block, row, 2, prev_baseline);
100 prev_baseline =
NULL;
103 tprintf(
"Row baseline generation failed on row at (%d,%d)\n",
104 blob_it.data()->bounding_box().left(),
105 blob_it.data()->bounding_box().bottom());
108 correlate_lines(block, gradient);
121 void Textord::correlate_lines(
TO_BLOCK *block,
float gradient) {
124 register int rowindex;
126 TO_ROW_IT row_it = block->
get_rows ();
128 rowcount = row_it.length ();
136 for (row_it.mark_cycle_pt (); !row_it.cycled_list (); row_it.forward ())
138 rows[rowindex++] = row_it.data ();
141 correlate_neighbours(block, rows, rowcount);
144 block->
xheight = (float) correlate_with_stats(rows, rowcount, block);
163 void Textord::correlate_neighbours(
TO_BLOCK *block,
167 register int rowindex;
168 register int otherrow;
173 for (rowindex = 0; rowindex < rowcount; rowindex++) {
174 row = rows[rowindex];
177 for (otherrow = rowindex - 2;
179 && (rows[otherrow]->
xheight < 0.0
183 for (otherrow = rowindex + 1;
185 && (rows[otherrow]->
xheight < 0.0
190 find_textlines(block, row, 2, &rows[upperrow]->
baseline);
191 if (row->
xheight < 0 && lowerrow < rowcount)
192 find_textlines(block, row, 2, &rows[lowerrow]->
baseline);
195 find_textlines(block, row, 1, &rows[upperrow]->
baseline);
196 else if (lowerrow < rowcount)
197 find_textlines(block, row, 1, &rows[lowerrow]->
baseline);
202 for (biggest = 0.0f, rowindex = 0; rowindex < rowcount; rowindex++) {
203 row = rows[rowindex];
219 int Textord::correlate_with_stats(
TO_ROW **rows,
223 register int rowindex;
235 xcount = fullcount = desccount = 0;
236 lineheight = ascheight = fullheight = descheight = 0.0;
237 for (rowindex = 0; rowindex < rowcount; rowindex++) {
238 row = rows[rowindex];
256 lineheight /= xcount;
258 fullheight = lineheight + ascheight / xcount;
264 fullheight /= fullcount;
268 if (desccount > 0 && (!
oldbl_corrfix || desccount >= rowcount / 2))
269 descheight /= desccount;
274 if (lineheight > 0.0f)
279 for (rowindex = 0; rowindex < rowcount; rowindex++) {
280 row = rows[rowindex];
286 row->
ascrise = fullheight - lineheight;
305 if (row->
ascrise < minascheight)
309 if (row->
descdrop > mindescheight) {
318 return (
int) lineheight;
328 void Textord::find_textlines(
TO_BLOCK *block,
349 blobcount = row->
blob_list ()->length ();
350 partids = (
char *)
alloc_mem (blobcount *
sizeof (
char));
351 xcoords = (
int *)
alloc_mem (blobcount *
sizeof (
int));
352 ycoords = (
int *)
alloc_mem (blobcount *
sizeof (
int));
354 ydiffs = (
float *)
alloc_mem (blobcount *
sizeof (
float));
357 holed_line, blobcount);
365 (
"\nInput height=%g, Estimate x-height=%d pixels, jumplimit=%.2f\n",
366 block->
line_size, lineheight, jumplimit);
373 xcoords, ycoords, spline, &row->
baseline, jumplimit);
374 #ifndef GRAPHICS_DISABLED
380 &partcount, partids, partsizes,
383 partids, bestpart, xcoords, ycoords);
386 degree, pointcount, xstarts);
390 xcoords, ycoords, pointcount, degree);
394 xcoords, xstarts, segments));
416 blobcount, &row->
baseline, jumplimit);
419 blobcount, &row->
baseline, jumplimit);
450 register int blobindex;
456 if (blob_it.empty ())
460 blob_it.mark_cycle_pt ();
464 if (blobcoords[blobindex].height () > lineheight * 0.25)
465 heightstat.
add (blobcoords[blobindex].height (), 1);
467 || blobcoords[blobindex].height () > lineheight * 0.25
468 || blob_it.cycled_list ()) {
473 if (blobcoords[blobindex].height ()
475 && blobcoords[blobindex].
width ()
483 if (losscount > maxlosscount)
485 maxlosscount = losscount;
489 while (!blob_it.cycled_list ());
492 outcount = blobindex;
496 return (
int) heightstat.
ile (0.25);
498 return blobcoords[0].
height ();
524 float prevy, thisy, nexty;
526 float maxmax, minmin;
537 leftedge = blobcoords[0].
left ();
539 rightedge = blobcoords[blobcount - 1].
right ();
541 || spline->segments < 3
543 || spline->xcoords[1] > leftedge +
MAXOVERLAP * (rightedge - leftedge)
544 || spline->xcoords[spline->segments - 1] < rightedge
548 xstarts[0] = blobcoords[0].
left () - 1;
549 for (blobindex = 0; blobindex < blobcount; blobindex++) {
550 xcoords[blobindex] = (blobcoords[blobindex].
left ()
551 + blobcoords[blobindex].
right ()) / 2;
552 ycoords[blobindex] = blobcoords[blobindex].
bottom ();
554 xstarts[1] = blobcoords[blobcount - 1].
right () + 1;
558 *baseline =
QSPLINE (xstarts, segments, xcoords, ycoords, blobcount, 1);
560 if (blobcount >= 3) {
564 maxmax = minmin = 0.0f;
565 thisy = ycoords[0] - baseline->
y (xcoords[0]);
566 nexty = ycoords[1] - baseline->
y (xcoords[1]);
567 for (blobindex = 2; blobindex < blobcount; blobindex++) {
570 nexty = ycoords[blobindex] - baseline->
y (xcoords[blobindex]);
572 if (
ABS (thisy - prevy) < jumplimit &&
ABS (thisy - nexty) < jumplimit) {
578 if (ycount >= 3 && ((y1 < y2 && y2 >= y3)
580 || (y1 > y2 && y2 <= y3))) {
583 xturns[segment] = x2;
584 yturns[segment] = y2;
589 maxmax = minmin = y3;
598 x2 = blobcoords[blobindex - 1].
right ();
604 if (maxmax - minmin > jumplimit) {
606 for (blobindex = 0, segment = 1; blobindex < ycount;
608 if (yturns[blobindex] > minmin + jumplimit
609 || yturns[blobindex] < maxmax - jumplimit) {
612 || yturns[blobindex] > prevy + jumplimit
613 || yturns[blobindex] < prevy - jumplimit) {
615 xstarts[segment] = xturns[blobindex];
617 prevy = yturns[blobindex];
620 else if ((prevy > minmin + jumplimit && yturns[blobindex] > prevy)
622 || (prevy < maxmax - jumplimit && yturns[blobindex] < prevy)) {
623 xstarts[segment - 1] = xturns[blobindex];
625 prevy = yturns[blobindex];
629 xstarts[segment] = blobcoords[blobcount - 1].
right () + 1;
632 *baseline =
QSPLINE (xstarts, segments, xcoords, ycoords, blobcount, 1);
638 shift =
ICOORD (0, (
inT16) (blobcoords[0].bottom ()
639 - spline->
y (blobcoords[0].
right ())));
640 baseline->
move (shift);
673 leftedge = blobcoords[0].
left ();
675 rightedge = blobcoords[blobcount - 1].
right();
676 for (blobindex = 0; blobindex < blobcount; blobindex++) {
677 lms.
Add(
ICOORD((blobcoords[blobindex].left() +
678 blobcoords[blobindex].right()) / 2,
679 blobcoords[blobindex].bottom()));
682 xstarts[0] = leftedge;
683 xstarts[1] = rightedge;
685 coeffs[1] = gradient;
687 *baseline =
QSPLINE (1, xstarts, coeffs);
689 && spline->segments >= 3
691 && spline->xcoords[1] <= leftedge +
MAXOVERLAP * (rightedge - leftedge)
692 && spline->xcoords[spline->segments - 1] >= rightedge
695 x = (leftedge + rightedge) / 2.0;
696 shift =
ICOORD (0, (
inT16) (gradient * x + c - spline->
y (x)));
697 baseline->
move (shift);
722 register int blobindex;
729 for (bestpart = 0; bestpart <
MAXPARTS; bestpart++)
730 partsizes[bestpart] = 0;
732 startx =
get_ydiffs (blobcoords, blobcount, spline, ydiffs);
736 float last_delta = 0.0f;
737 for (blobindex = startx; blobindex < blobcount; blobindex++) {
739 diff = ydiffs[blobindex];
741 tprintf (
"%d(%d,%d), ", blobindex,
742 blobcoords[blobindex].left (),
743 blobcoords[blobindex].bottom ());
746 &drift, &last_delta, numparts);
748 partids[blobindex] = bestpart;
749 partsizes[bestpart]++;
757 for (blobindex = startx; blobindex >= 0; blobindex--) {
758 diff = ydiffs[blobindex];
760 tprintf (
"%d(%d,%d), ", blobindex,
761 blobcoords[blobindex].left (),
762 blobcoords[blobindex].bottom ());
765 &drift, &last_delta, numparts);
767 partids[blobindex] = bestpart;
768 partsizes[bestpart]++;
771 for (biggestpart = 0, bestpart = 1; bestpart < *numparts; bestpart++)
772 if (partsizes[bestpart] >= partsizes[biggestpart])
773 biggestpart = bestpart;
803 register int blobindex;
813 prevpart = biggestpart;
816 for (blobindex = 0; blobindex < blobcount; blobindex++) {
817 if (partids[blobindex] != prevpart) {
821 if (prevpart != biggestpart && runlength >
MAXBADRUN) {
823 for (test_blob = startx; test_blob < blobindex; test_blob++) {
824 coord =
FCOORD ((blobcoords[test_blob].left ()
825 + blobcoords[test_blob].right ()) / 2.0,
826 blobcoords[test_blob].bottom ());
827 stats.
add (coord.
x (), coord.
y ());
833 tprintf (
"Fitted line y=%g x + %g\n", m, c);
836 for (test_blob = 1; !found_one
837 && (startx - test_blob >= 0
838 || blobindex + test_blob <= blobcount); test_blob++) {
839 if (startx - test_blob >= 0
840 && partids[startx - test_blob] == biggestpart) {
842 coord =
FCOORD ((blobcoords[startx - test_blob].left ()
843 + blobcoords[startx -
844 test_blob].right ()) /
847 test_blob].bottom ());
848 diff = m * coord.
x () + c - coord.
y ();
851 (
"Diff of common blob to suspect part=%g at (%g,%g)\n",
852 diff, coord.
x (), coord.
y ());
853 if (diff < jumplimit && -diff < jumplimit)
856 if (blobindex + test_blob <= blobcount
857 && partids[blobindex + test_blob - 1] == biggestpart) {
860 FCOORD ((blobcoords[blobindex + test_blob - 1].
861 left () + blobcoords[blobindex + test_blob -
863 blobcoords[blobindex + test_blob -
865 diff = m * coord.
x () + c - coord.
y ();
868 (
"Diff of common blob to suspect part=%g at (%g,%g)\n",
869 diff, coord.
x (), coord.
y ());
870 if (diff < jumplimit && -diff < jumplimit)
877 (
"Merged %d blobs back into part %d from %d starting at (%d,%d)\n",
878 runlength, biggestpart, prevpart,
879 blobcoords[startx].left (),
880 blobcoords[startx].bottom ());
882 partsizes[prevpart] -= runlength;
883 for (test_blob = startx; test_blob < blobindex; test_blob++)
884 partids[test_blob] = biggestpart;
887 prevpart = partids[blobindex];
912 register int blobindex;
925 lastx = blobcoords[0].
left ();
927 for (blobindex = 0; blobindex < blobcount; blobindex++) {
929 xcentre = (blobcoords[blobindex].
left () + blobcoords[blobindex].
right ()) >> 1;
931 drift += spline->
step (lastx, xcentre);
933 diff = blobcoords[blobindex].
bottom ();
934 diff -= spline->
y (xcentre);
936 ydiffs[blobindex] = diff;
939 diffsum -=
ABS (ydiffs[blobindex - 3]);
940 diffsum +=
ABS (diff);
941 if (blobindex >= 2 && diffsum < bestsum) {
943 bestindex = blobindex - 1;
966 register int partition;
978 delta = diff - partdiffs[lastpart] - *drift;
980 tprintf (
"Diff=%.2f, Delta=%.3f, Drift=%.3f, ", diff, delta, *drift);
982 if (
ABS (delta) > jumplimit / 2) {
984 bestdelta = diff - partdiffs[0] - *drift;
986 for (partition = 1; partition < *partcount; partition++) {
987 delta = diff - partdiffs[partition] - *drift;
988 if (
ABS (delta) <
ABS (bestdelta)) {
990 bestpart = partition;
995 if (
ABS (bestdelta) > jumplimit
997 bestpart = (*partcount)++;
999 partdiffs[bestpart] = diff - *drift;
1004 bestpart = lastpart;
1007 if (bestpart == lastpart
1008 && (
ABS (delta - *lastdelta) < jumplimit / 2
1009 ||
ABS (delta) < jumplimit / 2))
1011 *drift = (3 * *drift + delta) / 3;
1092 register int blobindex;
1096 for (blobindex = 0; blobindex < blobcount; blobindex++) {
1097 if (partids[blobindex] == bestpart) {
1099 xcoords[pointcount] = (blobcoords[blobindex].
left () + blobcoords[blobindex].
right ()) >> 1;
1100 ycoords[pointcount++] = blobcoords[blobindex].
bottom ();
1120 int degree,
int pointcount,
1123 register int ptindex;
1124 register int segment;
1125 int lastmin, lastmax;
1130 xstarts[0] = xcoords[0] - 1;
1131 max_x = xcoords[pointcount - 1] + 1;
1135 if (pointcount > 3) {
1137 lastmax = lastmin = 0;
1138 while (ptindex < pointcount - 1 && turncount <
SPLINESIZE - 1) {
1140 if (ycoords[ptindex - 1] > ycoords[ptindex] && ycoords[ptindex] <= ycoords[ptindex + 1]) {
1141 if (ycoords[ptindex] < ycoords[lastmax] -
TURNLIMIT) {
1142 if (turncount == 0 || turnpoints[turncount - 1] != lastmax)
1144 turnpoints[turncount++] = lastmax;
1147 else if (ycoords[ptindex] < ycoords[lastmin]) {
1153 if (ycoords[ptindex - 1] < ycoords[ptindex] && ycoords[ptindex] >= ycoords[ptindex + 1]) {
1154 if (ycoords[ptindex] > ycoords[lastmin] +
TURNLIMIT) {
1155 if (turncount == 0 || turnpoints[turncount - 1] != lastmin)
1157 turnpoints[turncount++] = lastmin;
1160 else if (ycoords[ptindex] > ycoords[lastmax]) {
1167 if (ycoords[ptindex] < ycoords[lastmax] -
TURNLIMIT
1168 && (turncount == 0 || turnpoints[turncount - 1] != lastmax)) {
1171 turnpoints[turncount++] = lastmax;
1173 turnpoints[turncount++] = ptindex;
1175 else if (ycoords[ptindex] > ycoords[lastmin] +
TURNLIMIT
1177 && (turncount == 0 || turnpoints[turncount - 1] != lastmin)) {
1180 turnpoints[turncount++] = lastmin;
1182 turnpoints[turncount++] = ptindex;
1184 else if (turncount > 0 && turnpoints[turncount - 1] == lastmin
1186 if (ycoords[ptindex] > ycoords[lastmax])
1187 turnpoints[turncount++] = ptindex;
1189 turnpoints[turncount++] = lastmax;
1191 else if (turncount > 0 && turnpoints[turncount - 1] == lastmax
1193 if (ycoords[ptindex] < ycoords[lastmin])
1194 turnpoints[turncount++] = ptindex;
1196 turnpoints[turncount++] = lastmin;
1201 tprintf (
"First turn is %d at (%d,%d)\n",
1202 turnpoints[0], xcoords[turnpoints[0]], ycoords[turnpoints[0]]);
1203 for (segment = 1; segment < turncount; segment++) {
1205 lastmax = (ycoords[turnpoints[segment - 1]] + ycoords[turnpoints[segment]]) / 2;
1208 if (ycoords[turnpoints[segment - 1]] < ycoords[turnpoints[segment]])
1210 for (ptindex = turnpoints[segment - 1] + 1; ptindex < turnpoints[segment] && ycoords[ptindex + 1] <= lastmax; ptindex++);
1213 for (ptindex = turnpoints[segment - 1] + 1; ptindex < turnpoints[segment] && ycoords[ptindex + 1] >= lastmax; ptindex++);
1216 xstarts[segment] = (xcoords[ptindex - 1] + xcoords[ptindex]
1217 + xcoords[turnpoints[segment - 1]]
1218 + xcoords[turnpoints[segment]] + 2) / 4;
1221 tprintf (
"Turn %d is %d at (%d,%d), mid pt is %d@%d, final @%d\n",
1222 segment, turnpoints[segment],
1223 xcoords[turnpoints[segment]], ycoords[turnpoints[segment]],
1224 ptindex - 1, xcoords[ptindex - 1], xstarts[segment]);
1227 xstarts[segment] = max_x;
1248 register int segment;
1249 int startindex, centreindex, endindex;
1250 float leftcoord, rightcoord;
1251 int leftindex, rightindex;
1256 for (segment = 1; segment < segments - 1; segment++) {
1257 step = baseline->
step ((xstarts[segment - 1] + xstarts[segment]) / 2.0,
1258 (xstarts[segment] + xstarts[segment + 1]) / 2.0);
1261 if (step > jumplimit) {
1262 while (xcoords[startindex] < xstarts[segment - 1])
1264 centreindex = startindex;
1265 while (xcoords[centreindex] < xstarts[segment])
1267 endindex = centreindex;
1268 while (xcoords[endindex] < xstarts[segment + 1])
1272 tprintf (
"Too many segments to resegment spline!!\n");
1275 while (centreindex - startindex <
1278 while (endindex - centreindex <
1281 leftindex = (startindex + startindex + centreindex) / 3;
1282 rightindex = (centreindex + endindex + endindex) / 3;
1284 (xcoords[startindex] * 2 + xcoords[centreindex]) / 3.0;
1286 (xcoords[centreindex] + xcoords[endindex] * 2) / 3.0;
1287 while (xcoords[leftindex] > leftcoord
1290 while (xcoords[leftindex] < leftcoord
1291 && centreindex - leftindex >
1294 if (xcoords[leftindex] - leftcoord >
1295 leftcoord - xcoords[leftindex - 1])
1297 while (xcoords[rightindex] > rightcoord
1298 && rightindex - centreindex >
1301 while (xcoords[rightindex] < rightcoord
1304 if (xcoords[rightindex] - rightcoord >
1305 rightcoord - xcoords[rightindex - 1])
1308 tprintf (
"Splitting spline at %d with step %g at (%d,%d)\n",
1311 step ((xstarts[segment - 1] +
1312 xstarts[segment]) / 2.0,
1314 xstarts[segment + 1]) / 2.0),
1315 (xcoords[leftindex - 1] + xcoords[leftindex]) / 2,
1316 (xcoords[rightindex - 1] + xcoords[rightindex]) / 2);
1318 (xcoords[leftindex - 1] +
1319 xcoords[leftindex]) / 2,
1320 (xcoords[rightindex - 1] +
1321 xcoords[rightindex]) / 2, segments);
1326 (
"Resegmenting spline failed - insufficient pts (%d,%d,%d,%d)\n",
1327 startindex, centreindex, endindex,
1351 int coord2,
int &segments
1355 for (index = segments; index > segment; index--)
1356 xstarts[index + 1] = xstarts[index];
1358 xstarts[segment] = coord1;
1359 xstarts[segment + 1] = coord2;
1380 register int blobindex;
1381 register int partition;
1391 for (partition = 0; partition < partcount; partition++)
1392 partsteps[partition] = 0.0;
1393 for (runlength = 0, blobindex = 0; blobindex < blobcount; blobindex++) {
1394 xcentre = (blobcoords[blobindex].
left ()
1395 + blobcoords[blobindex].
right ()) >> 1;
1398 static_cast<int>(
static_cast<unsigned char>(partids[blobindex]));
1399 if (part_id != bestpart) {
1401 if (runlength > biggestrun)
1402 biggestrun = runlength;
1403 partsteps[part_id] += blobcoords[blobindex].
bottom()
1413 poscount = negcount = 0;
1415 for (partition = 0; partition < partcount; partition++) {
1416 if (partition != bestpart) {
1419 if (partsizes[partition]==0)
1420 partsteps[partition]=0;
1422 partsteps[partition] /= partsizes[partition];
1427 && partsizes[partition] > poscount) {
1428 poscount = partsizes[partition];
1431 && partsizes[partition] > negcount) {
1433 bestneg = partsteps[partition];
1435 negcount = partsizes[partition];
1440 partsteps[bestpart] /= blobcount;
1462 register int blobindex;
1472 register float diff;
1474 if (blobcount > 1) {
1475 for (blobindex = 0; blobindex < blobcount; blobindex++) {
1476 xcentre = (blobcoords[blobindex].
left ()
1477 + blobcoords[blobindex].
right ()) / 2;
1479 height = (int) (blobcoords[blobindex].top () - baseline->
y (xcentre) + 0.5);
1482 heightstat.
add (height, 1);
1485 lineheight = (int) heightstat.
ile (0.25);
1486 if (lineheight <= 0)
1487 lineheight = (int) heightstat.
ile (0.5);
1490 lineheight = initialheight;
1493 lineheight = (int) (blobcoords[0].top ()
1494 - baseline->
y ((blobcoords[0].left ()
1495 + blobcoords[0].right ()) / 2) +
1501 for (ascenders = 0.0f, asccount = 0, blobindex = 0; blobindex < blobcount;
1503 xcentre = (blobcoords[blobindex].
left ()
1504 + blobcoords[blobindex].
right ()) / 2;
1505 diff = blobcoords[blobindex].
top () - baseline->
y (xcentre);
1507 if (diff > lineheight + jumplimit) {
1511 else if (diff > lineheight - jumplimit) {
1519 xsum = (float) lineheight;
1522 row->
ascrise = ascenders / asccount - xsum;
1543 int init_lineheight,
1556 const int kBaselineTouch = 2;
1557 const int kGoodStrength = 8;
1558 const float kMinHeight = 0.25;
1560 sign_bit = row->
xheight > 0 ? 1 : -1;
1565 for (blobindex = 0; blobindex < blobcount; blobindex++) {
1566 int xcenter = (blobcoords[blobindex].
left () +
1567 blobcoords[blobindex].
right ()) / 2;
1568 float base = baseline->
y(xcenter);
1569 float bottomdiff = fabs(base - blobcoords[blobindex].bottom());
1571 bottomdiff <= kBaselineTouch ? kGoodStrength : 1;
1572 int height =
static_cast<int>(blobcoords[blobindex].
top () - base + 0.5);
1573 if (blobcoords[blobindex].height () > init_lineheight * kMinHeight) {
1576 heightstat.
add (height, strength);
1578 if (xcenter > rights[height])
1579 rights[height] = xcenter;
1580 if (xcenter > 0 && (lefts[height] == 0 || xcenter < lefts[height]))
1581 lefts[height] = xcenter;
1584 mode_count += strength;
1588 mode_threshold = (int) (blobcount * 0.1);
1590 mode_threshold = (int) (mode_count * 0.1);
1593 tprintf (
"blobcount=%d, mode_count=%d, mode_t=%d\n",
1594 blobcount, mode_count, mode_threshold);
1598 for (blobindex = 0; blobindex <
MODENUM; blobindex++)
1599 tprintf (
"mode[%d]=%d ", blobindex, modelist[blobindex]);
1602 pick_x_height(row, modelist, lefts, rights, &heightstat, mode_threshold);
1627 int modelist[],
int modenum
1638 for (mode_count = 0; mode_count < modenum; mode_count++) {
1640 for (i = 0; i < statnum; i++) {
1643 ((stats->
pile_count (i) == last_max) && (i > last_i))) {
1650 total_max += last_max;
1651 if (last_max <= total_max / mode_factor)
1653 modelist[mode_count] =
mode;
1666 int lefts[],
int rights[],
1668 int mode_threshold) {
1673 int found_one_bigger =
FALSE;
1674 int best_x_height = 0;
1678 for (x = 0; x <
MODENUM; x++) {
1679 for (y = 0; y <
MODENUM; y++) {
1681 if (modelist[x] && modelist[y] &&
1682 heightstat->
pile_count (modelist[x]) > mode_threshold &&
1684 MIN(rights[modelist[x]], rights[modelist[y]]) >
1685 MAX(lefts[modelist[x]], lefts[modelist[y]]))) {
1686 ratio = (float) modelist[y] / (
float) modelist[x];
1687 if (1.2 < ratio && ratio < 1.8) {
1689 best_x_height = modelist[x];
1690 num_in_best = heightstat->
pile_count (modelist[x]);
1694 found_one_bigger =
FALSE;
1695 for (z = 0; z <
MODENUM; z++) {
1696 if (modelist[z] == best_x_height + 1 &&
1698 MIN(rights[modelist[x]], rights[modelist[y]]) >
1699 MAX(lefts[modelist[x]], lefts[modelist[y]]))) {
1700 ratio = (float) modelist[y] / (
float) modelist[z];
1701 if ((1.2 < ratio && ratio < 1.8) &&
1704 num_in_best * 0.5) {
1706 found_one_bigger =
TRUE;
1712 while (found_one_bigger);
1716 best_asc = modelist[y];
1717 num_in_best = heightstat->
pile_count (modelist[y]);
1721 found_one_bigger =
FALSE;
1722 for (z = 0; z <
MODENUM; z++) {
1723 if (modelist[z] > best_asc &&
1725 MIN(rights[modelist[x]], rights[modelist[y]]) >
1726 MAX(lefts[modelist[x]], lefts[modelist[y]]))) {
1727 ratio = (float) modelist[z] / (
float) best_x_height;
1728 if ((1.2 < ratio && ratio < 1.8) &&
1731 num_in_best * 0.5) {
1732 best_asc = modelist[z];
1733 found_one_bigger =
TRUE;
1739 while (found_one_bigger);
1741 row->
xheight = (float) best_x_height;
1742 row->
ascrise = (float) best_asc - best_x_height;
1749 best_x_height = modelist[0];
1750 num_in_best = heightstat->
pile_count (best_x_height);
1753 found_one_bigger =
FALSE;
1754 for (z = 1; z <
MODENUM; z++) {
1756 if ((modelist[z] == best_x_height + 1) &&
1757 (heightstat->
pile_count (modelist[z]) > num_in_best * 0.5)) {
1759 found_one_bigger =
TRUE;
1764 while (found_one_bigger);
1767 row->
xheight = (float) best_x_height;
void old_first_xheight(TO_ROW *row, TBOX blobcoords[], int initialheight, int blobcount, QSPLINE *baseline, float jumplimit)
double step(double x1, double x2)
EXTERN bool textord_oldbl_merge_parts
EXTERN double textord_oldbl_jumplimit
void make_first_xheight(TO_ROW *row, TBOX blobcoords[], int lineheight, int init_lineheight, int blobcount, QSPLINE *baseline, float jumplimit)
int textord_spline_medianwin
#define double_VAR(name, val, comment)
void free_mem(void *oldchunk)
void compute_block_xheight(TO_BLOCK *block, float gradient)
void plot(ScrollView *window, ScrollView::Color colour) const
void find_lesser_parts(TO_ROW *row, TBOX blobcoords[], int blobcount, char partids[], int partsizes[], int partcount, int bestpart)
void add(inT32 value, inT32 count)
EXTERN bool textord_oldbl_debug
#define BOOL_VAR(name, val, comment)
void set_cell_over_xheight(float ratio)
void set_xheight(inT32 height)
set char size
void add(double x, double y)
int get_ydiffs(TBOX blobcoords[], int blobcount, QSPLINE *spline, float ydiffs[])
BLOBNBOX_LIST * blob_list()
EXTERN double oldbl_xhfract
EXTERN double oldbl_dot_error_size
EXTERN bool textord_oldbl_paradef
#define MIN_DESC_FRACTION
void merge_oldbl_parts(TBOX blobcoords[], int blobcount, char partids[], int partsizes[], int biggestpart, float jumplimit)
FCOORD classify_rotation() const
EXTERN ScrollView * to_win
int segment_spline(TBOX blobcoords[], int blobcount, int xcoords[], int ycoords[], int degree, int pointcount, int xstarts[])
double ile(double frac) const
BOOL8 split_stepped_spline(QSPLINE *baseline, float jumplimit, int xcoords[], int xstarts[], int &segments)
void insert_spline_point(int xstarts[], int segment, int coord1, int coord2, int &segments)
void extrapolate(double gradient, int left, int right)
void bounding_box(ICOORD &bottom_left, ICOORD &top_right) const
get box
void make_first_baseline(TBOX blobcoords[], int blobcount, int xcoords[], int ycoords[], QSPLINE *spline, QSPLINE *baseline, float jumplimit)
#define INT_VAR(name, val, comment)
EXTERN bool textord_ocropus_mode
void pick_x_height(TO_ROW *row, int modelist[], int lefts[], int rights[], STATS *heightstat, int mode_threshold)
#define DESCENDER_FRACTION
int choose_partition(register float diff, float partdiffs[], int lastpart, float jumplimit, float *drift, float *lastdelta, int *partcount)
void compute_row_xheight(TO_ROW *row, const FCOORD &rotation, float gradient, int block_line_size)
bool textord_show_final_rows
int partition_coords(TBOX blobcoords[], int blobcount, char partids[], int bestpart, int xcoords[], int ycoords[])
*merge_partitions(partids,partcount,blobcount,bestpart) discards funny looking
EXTERN bool oldbl_corrfix
void Add(const ICOORD &pt)
#define MAXHEIGHTVARIANCE
TBOX box_next_pre_chopped(BLOBNBOX_IT *it)
EXTERN int oldbl_holed_losscount
int get_blob_coords(TO_ROW *row, inT32 lineheight, TBOX *blobcoords, BOOL8 &holed_line, int &outcount)
BOOL8 overlap(QSPLINE *spline2, double fraction)
static const double kXHeightFraction
inT32 pile_count(inT32 value) const
const int kMinModeFactorOcropus
void * alloc_mem(inT32 count)
EXTERN bool textord_really_old_xheight
void make_holed_baseline(TBOX blobcoords[], int blobcount, QSPLINE *spline, QSPLINE *baseline, float gradient)
EXTERN bool textord_oldbl_split_splines
#define X_HEIGHT_FRACTION
void find_top_modes(STATS *stats, int statnum, int modelist[], int modenum)
EXTERN bool textord_debug_baselines
double ConstrainedFit(const FCOORD &direction, double min_dist, double max_dist, bool debug, ICOORD *line_pt)
int partition_line(TBOX blobcoords[], int blobcount, int *numparts, char partids[], int partsizes[], QSPLINE *spline, float jumplimit, float ydiffs[])