Leptonica  1.77.0
Image processing and image analysis suite
boxfunc5.c
Go to the documentation of this file.
1 /*====================================================================*
2  - Copyright (C) 2001 Leptonica. All rights reserved.
3  -
4  - Redistribution and use in source and binary forms, with or without
5  - modification, are permitted provided that the following conditions
6  - are met:
7  - 1. Redistributions of source code must retain the above copyright
8  - notice, this list of conditions and the following disclaimer.
9  - 2. Redistributions in binary form must reproduce the above
10  - copyright notice, this list of conditions and the following
11  - disclaimer in the documentation and/or other materials
12  - provided with the distribution.
13  -
14  - THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
15  - ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
16  - LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
17  - A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL ANY
18  - CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
19  - EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
20  - PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
21  - PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
22  - OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
23  - NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
24  - SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
25  *====================================================================*/
26 
53 #include <math.h>
54 #include "allheaders.h"
55 
56 static l_int32 boxaTestEvenOddHeight(BOXA *boxa1, BOXA *boxa2, l_int32 start,
57  l_float32 *pdel1, l_float32 *pdel2);
58 static l_int32 boxaFillAll(BOXA *boxa);
59 
60 
61 /*---------------------------------------------------------------------*
62  * Boxa sequence fitting *
63  *---------------------------------------------------------------------*/
97 BOXA *
99  l_float32 factor,
100  l_int32 subflag,
101  l_int32 maxdiff,
102  l_int32 extrapixels,
103  l_int32 debug)
104 {
105 l_int32 n;
106 BOXA *boxae, *boxao, *boxalfe, *boxalfo, *boxame, *boxamo, *boxad;
107 
108  PROCNAME("boxaSmoothSequenceLS");
109 
110  if (!boxas)
111  return (BOXA *)ERROR_PTR("boxas not defined", procName, NULL);
112  if (factor <= 0.0) {
113  L_WARNING("factor must be > 0.0; returning copy\n", procName);
114  return boxaCopy(boxas, L_COPY);
115  }
116  if (maxdiff < 0) {
117  L_WARNING("maxdiff must be >= 0; returning copy\n", procName);
118  return boxaCopy(boxas, L_COPY);
119  }
120  if (subflag != L_USE_MINSIZE && subflag != L_USE_MAXSIZE &&
121  subflag != L_SUB_ON_LOC_DIFF && subflag != L_SUB_ON_SIZE_DIFF &&
122  subflag != L_USE_CAPPED_MIN && subflag != L_USE_CAPPED_MAX) {
123  L_WARNING("invalid subflag; returning copy\n", procName);
124  return boxaCopy(boxas, L_COPY);
125  }
126  if ((n = boxaGetCount(boxas)) < 4) {
127  L_WARNING("need at least 4 boxes; returning copy\n", procName);
128  return boxaCopy(boxas, L_COPY);
129  }
130 
131  boxaSplitEvenOdd(boxas, 1, &boxae, &boxao);
132  if (debug) {
133  lept_mkdir("lept/smooth");
134  boxaWriteDebug("/tmp/lept/smooth/boxae.ba", boxae);
135  boxaWriteDebug("/tmp/lept/smooth/boxao.ba", boxao);
136  }
137 
138  boxalfe = boxaLinearFit(boxae, factor, debug);
139  boxalfo = boxaLinearFit(boxao, factor, debug);
140  if (debug) {
141  boxaWriteDebug("/tmp/lept/smooth/boxalfe.ba", boxalfe);
142  boxaWriteDebug("/tmp/lept/smooth/boxalfo.ba", boxalfo);
143  }
144 
145  boxame = boxaModifyWithBoxa(boxae, boxalfe, subflag, maxdiff, extrapixels);
146  boxamo = boxaModifyWithBoxa(boxao, boxalfo, subflag, maxdiff, extrapixels);
147  if (debug) {
148  boxaWriteDebug("/tmp/lept/smooth/boxame.ba", boxame);
149  boxaWriteDebug("/tmp/lept/smooth/boxamo.ba", boxamo);
150  }
151 
152  boxad = boxaMergeEvenOdd(boxame, boxamo, 1);
153  boxaDestroy(&boxae);
154  boxaDestroy(&boxao);
155  boxaDestroy(&boxalfe);
156  boxaDestroy(&boxalfo);
157  boxaDestroy(&boxame);
158  boxaDestroy(&boxamo);
159  return boxad;
160 }
161 
162 
203 BOXA *
205  l_int32 halfwin,
206  l_int32 subflag,
207  l_int32 maxdiff,
208  l_int32 extrapixels,
209  l_int32 debug)
210 {
211 l_int32 n;
212 BOXA *boxae, *boxao, *boxamede, *boxamedo, *boxame, *boxamo, *boxad;
213 
214  PROCNAME("boxaSmoothSequenceMedian");
215 
216  if (!boxas)
217  return (BOXA *)ERROR_PTR("boxas not defined", procName, NULL);
218  if (halfwin <= 0) {
219  L_WARNING("halfwin must be > 0; returning copy\n", procName);
220  return boxaCopy(boxas, L_COPY);
221  }
222  if (maxdiff < 0) {
223  L_WARNING("maxdiff must be >= 0; returning copy\n", procName);
224  return boxaCopy(boxas, L_COPY);
225  }
226  if (subflag != L_USE_MINSIZE && subflag != L_USE_MAXSIZE &&
227  subflag != L_SUB_ON_LOC_DIFF && subflag != L_SUB_ON_SIZE_DIFF &&
228  subflag != L_USE_CAPPED_MIN && subflag != L_USE_CAPPED_MAX) {
229  L_WARNING("invalid subflag; returning copy\n", procName);
230  return boxaCopy(boxas, L_COPY);
231  }
232  if ((n = boxaGetCount(boxas)) < 6) {
233  L_WARNING("need at least 6 boxes; returning copy\n", procName);
234  return boxaCopy(boxas, L_COPY);
235  }
236 
237  boxaSplitEvenOdd(boxas, 0, &boxae, &boxao);
238  if (debug) {
239  lept_mkdir("lept/smooth");
240  boxaWriteDebug("/tmp/lept/smooth/boxae.ba", boxae);
241  boxaWriteDebug("/tmp/lept/smooth/boxao.ba", boxao);
242  }
243 
244  boxamede = boxaWindowedMedian(boxae, halfwin, debug);
245  boxamedo = boxaWindowedMedian(boxao, halfwin, debug);
246  if (debug) {
247  boxaWriteDebug("/tmp/lept/smooth/boxamede.ba", boxamede);
248  boxaWriteDebug("/tmp/lept/smooth/boxamedo.ba", boxamedo);
249  }
250 
251  boxame = boxaModifyWithBoxa(boxae, boxamede, subflag, maxdiff, extrapixels);
252  boxamo = boxaModifyWithBoxa(boxao, boxamedo, subflag, maxdiff, extrapixels);
253  if (debug) {
254  boxaWriteDebug("/tmp/lept/smooth/boxame.ba", boxame);
255  boxaWriteDebug("/tmp/lept/smooth/boxamo.ba", boxamo);
256  }
257 
258  boxad = boxaMergeEvenOdd(boxame, boxamo, 0);
259  if (debug) {
260  boxaPlotSides(boxas, NULL, NULL, NULL, NULL, NULL, NULL);
261  boxaPlotSides(boxad, NULL, NULL, NULL, NULL, NULL, NULL);
262  boxaPlotSizes(boxas, NULL, NULL, NULL, NULL);
263  boxaPlotSizes(boxad, NULL, NULL, NULL, NULL);
264  }
265 
266  boxaDestroy(&boxae);
267  boxaDestroy(&boxao);
268  boxaDestroy(&boxamede);
269  boxaDestroy(&boxamedo);
270  boxaDestroy(&boxame);
271  boxaDestroy(&boxamo);
272  return boxad;
273 }
274 
275 
309 BOXA *
311  l_float32 factor,
312  l_int32 debug)
313 {
314 l_int32 n, i, w, h, lval, tval, rval, bval, rejectlr, rejecttb;
315 l_float32 al, bl, at, bt, ar, br, ab, bb; /* LSF coefficients */
316 l_float32 medw, medh, medvarw, medvarh;
317 BOX *box, *boxempty;
318 BOXA *boxalr, *boxatb, *boxad;
319 NUMA *naw, *nah;
320 PTA *ptal, *ptat, *ptar, *ptab;
321 
322  PROCNAME("boxaLinearFit");
323 
324  if (!boxas)
325  return (BOXA *)ERROR_PTR("boxas not defined", procName, NULL);
326  if ((n = boxaGetCount(boxas)) < 2)
327  return (BOXA *)ERROR_PTR("need at least 2 boxes", procName, NULL);
328 
329  /* Remove outliers based on width and height.
330  * First find the median width and the median deviation from
331  * the median width. Ditto for the height. */
332  boxaExtractAsNuma(boxas, NULL, NULL, NULL, NULL, &naw, &nah, 0);
333  numaGetMedianDevFromMedian(naw, &medw, &medvarw);
334  numaGetMedianDevFromMedian(nah, &medh, &medvarh);
335  numaDestroy(&naw);
336  numaDestroy(&nah);
337 
338  if (debug) {
339  fprintf(stderr, "medw = %7.3f, medvarw = %7.3f\n", medw, medvarw);
340  fprintf(stderr, "medh = %7.3f, medvarh = %7.3f\n", medh, medvarh);
341  }
342 
343  /* To fit the left and right sides, only use boxes whose
344  * width is within (factor * medvarw) of the median width.
345  * Ditto for the top and bottom sides. Add empty boxes
346  * in as placeholders so that the index remains the same
347  * as in boxas. */
348  boxalr = boxaCreate(n);
349  boxatb = boxaCreate(n);
350  boxempty = boxCreate(0, 0, 0, 0); /* placeholders */
351  rejectlr = rejecttb = 0;
352  for (i = 0; i < n; i++) {
353  if ((box = boxaGetValidBox(boxas, i, L_CLONE)) == NULL) {
354  boxaAddBox(boxalr, boxempty, L_COPY);
355  boxaAddBox(boxatb, boxempty, L_COPY);
356  continue;
357  }
358  boxGetGeometry(box, NULL, NULL, &w, &h);
359  if (L_ABS(w - medw) <= factor * medvarw) {
360  boxaAddBox(boxalr, box, L_COPY);
361  } else {
362  rejectlr++;
363  boxaAddBox(boxalr, boxempty, L_COPY);
364  }
365  if (L_ABS(h - medh) <= factor * medvarh) {
366  boxaAddBox(boxatb, box, L_COPY);
367  } else {
368  rejecttb++;
369  boxaAddBox(boxatb, boxempty, L_COPY);
370  }
371  boxDestroy(&box);
372  }
373  boxDestroy(&boxempty);
374  if (boxaGetCount(boxalr) < 2 || boxaGetCount(boxatb) < 2) {
375  boxaDestroy(&boxalr);
376  boxaDestroy(&boxatb);
377  return (BOXA *)ERROR_PTR("need at least 2 valid boxes", procName, NULL);
378  }
379 
380  if (debug) {
381  L_INFO("# lr reject = %d, # tb reject = %d\n", procName,
382  rejectlr, rejecttb);
383  lept_mkdir("linfit");
384  boxaWriteDebug("/tmp/linfit/boxalr.ba", boxalr);
385  boxaWriteDebug("/tmp/linfit/boxatb.ba", boxatb);
386  }
387 
388  /* Extract the valid left and right box sides, along with the box
389  * index, from boxalr. This only extracts pts corresponding to
390  * valid boxes. Ditto: top and bottom sides from boxatb. */
391  boxaExtractAsPta(boxalr, &ptal, NULL, &ptar, NULL, NULL, NULL, 0);
392  boxaExtractAsPta(boxatb, NULL, &ptat, NULL, &ptab, NULL, NULL, 0);
393  boxaDestroy(&boxalr);
394  boxaDestroy(&boxatb);
395 
396  if (debug) {
397  ptaWriteDebug("/tmp/linfit/ptal.pta", ptal, 1);
398  ptaWriteDebug("/tmp/linfit/ptar.pta", ptar, 1);
399  ptaWriteDebug("/tmp/linfit/ptat.pta", ptat, 1);
400  ptaWriteDebug("/tmp/linfit/ptab.pta", ptab, 1);
401  }
402 
403  /* Do a linear LSF fit to the points that are width and height
404  * validated. Because we've eliminated the outliers, there is no
405  * need to use ptaNoisyLinearLSF(ptal, factor, NULL, &al, &bl, ...) */
406  ptaGetLinearLSF(ptal, &al, &bl, NULL);
407  ptaGetLinearLSF(ptat, &at, &bt, NULL);
408  ptaGetLinearLSF(ptar, &ar, &br, NULL);
409  ptaGetLinearLSF(ptab, &ab, &bb, NULL);
410 
411  /* Return the LSF smoothed values, interleaved with invalid
412  * boxes when the corresponding box in boxas is invalid. */
413  boxad = boxaCreate(n);
414  boxempty = boxCreate(0, 0, 0, 0); /* use for placeholders */
415  for (i = 0; i < n; i++) {
416  lval = (l_int32)(al * i + bl + 0.5);
417  tval = (l_int32)(at * i + bt + 0.5);
418  rval = (l_int32)(ar * i + br + 0.5);
419  bval = (l_int32)(ab * i + bb + 0.5);
420  if ((box = boxaGetValidBox(boxas, i, L_CLONE)) == NULL) {
421  boxaAddBox(boxad, boxempty, L_COPY);
422  } else {
423  boxDestroy(&box);
424  box = boxCreate(lval, tval, rval - lval + 1, bval - tval + 1);
425  boxaAddBox(boxad, box, L_INSERT);
426  }
427  }
428  boxDestroy(&boxempty);
429 
430  if (debug) {
431  boxaPlotSides(boxad, NULL, NULL, NULL, NULL, NULL, NULL);
432  boxaPlotSizes(boxad, NULL, NULL, NULL, NULL);
433  }
434 
435  ptaDestroy(&ptal);
436  ptaDestroy(&ptat);
437  ptaDestroy(&ptar);
438  ptaDestroy(&ptab);
439  return boxad;
440 }
441 
442 
461 BOXA *
463  l_int32 halfwin,
464  l_int32 debug)
465 {
466 l_int32 n, i, left, top, right, bot;
467 BOX *box;
468 BOXA *boxaf, *boxad;
469 NUMA *nal, *nat, *nar, *nab, *naml, *namt, *namr, *namb;
470 
471  PROCNAME("boxaWindowedMedian");
472 
473  if (!boxas)
474  return (BOXA *)ERROR_PTR("boxas not defined", procName, NULL);
475  if ((n = boxaGetCount(boxas)) < 3) {
476  L_WARNING("less than 3 boxes; returning a copy\n", procName);
477  return boxaCopy(boxas, L_COPY);
478  }
479  if (halfwin <= 0) {
480  L_WARNING("halfwin must be > 0; returning copy\n", procName);
481  return boxaCopy(boxas, L_COPY);
482  }
483 
484  /* Fill invalid boxes in the input sequence */
485  if ((boxaf = boxaFillSequence(boxas, L_USE_ALL_BOXES, debug)) == NULL)
486  return (BOXA *)ERROR_PTR("filled boxa not made", procName, NULL);
487 
488  /* Get the windowed median output from each of the sides */
489  boxaExtractAsNuma(boxaf, &nal, &nat, &nar, &nab, NULL, NULL, 0);
490  naml = numaWindowedMedian(nal, halfwin);
491  namt = numaWindowedMedian(nat, halfwin);
492  namr = numaWindowedMedian(nar, halfwin);
493  namb = numaWindowedMedian(nab, halfwin);
494 
495  n = boxaGetCount(boxaf);
496  boxad = boxaCreate(n);
497  for (i = 0; i < n; i++) {
498  numaGetIValue(naml, i, &left);
499  numaGetIValue(namt, i, &top);
500  numaGetIValue(namr, i, &right);
501  numaGetIValue(namb, i, &bot);
502  box = boxCreate(left, top, right - left + 1, bot - top + 1);
503  boxaAddBox(boxad, box, L_INSERT);
504  }
505 
506  if (debug) {
507  boxaPlotSides(boxaf, NULL, NULL, NULL, NULL, NULL, NULL);
508  boxaPlotSides(boxad, NULL, NULL, NULL, NULL, NULL, NULL);
509  boxaPlotSizes(boxaf, NULL, NULL, NULL, NULL);
510  boxaPlotSizes(boxad, NULL, NULL, NULL, NULL);
511  }
512 
513  boxaDestroy(&boxaf);
514  numaDestroy(&nal);
515  numaDestroy(&nat);
516  numaDestroy(&nar);
517  numaDestroy(&nab);
518  numaDestroy(&naml);
519  numaDestroy(&namt);
520  numaDestroy(&namr);
521  numaDestroy(&namb);
522  return boxad;
523 }
524 
525 
599 BOXA *
601  BOXA *boxam,
602  l_int32 subflag,
603  l_int32 maxdiff,
604  l_int32 extrapixels)
605 {
606 l_int32 n, i, ls, ts, rs, bs, ws, hs, lm, tm, rm, bm, wm, hm, ld, td, rd, bd;
607 BOX *boxs, *boxm, *boxd, *boxempty;
608 BOXA *boxad;
609 
610  PROCNAME("boxaModifyWithBoxa");
611 
612  if (!boxas)
613  return (BOXA *)ERROR_PTR("boxas not defined", procName, NULL);
614  if (!boxam) {
615  L_WARNING("boxam not defined; returning copy", procName);
616  return boxaCopy(boxas, L_COPY);
617  }
618  if (subflag != L_USE_MINSIZE && subflag != L_USE_MAXSIZE &&
619  subflag != L_SUB_ON_LOC_DIFF && subflag != L_SUB_ON_SIZE_DIFF &&
620  subflag != L_USE_CAPPED_MIN && subflag != L_USE_CAPPED_MAX) {
621  L_WARNING("invalid subflag; returning copy", procName);
622  return boxaCopy(boxas, L_COPY);
623  }
624  n = boxaGetCount(boxas);
625  if (n != boxaGetCount(boxam)) {
626  L_WARNING("boxas and boxam sizes differ; returning copy", procName);
627  return boxaCopy(boxas, L_COPY);
628  }
629 
630  boxad = boxaCreate(n);
631  boxempty = boxCreate(0, 0, 0, 0); /* placeholders */
632  for (i = 0; i < n; i++) {
633  boxs = boxaGetValidBox(boxas, i, L_CLONE);
634  boxm = boxaGetValidBox(boxam, i, L_CLONE);
635  if (!boxs || !boxm) {
636  boxaAddBox(boxad, boxempty, L_COPY);
637  } else {
638  boxGetGeometry(boxs, &ls, &ts, &ws, &hs);
639  boxGetGeometry(boxm, &lm, &tm, &wm, &hm);
640  rs = ls + ws - 1;
641  bs = ts + hs - 1;
642  rm = lm + wm - 1;
643  bm = tm + hm - 1;
644  if (subflag == L_USE_MINSIZE) {
645  ld = L_MAX(ls, lm);
646  rd = L_MIN(rs, rm);
647  td = L_MAX(ts, tm);
648  bd = L_MIN(bs, bm);
649  } else if (subflag == L_USE_MAXSIZE) {
650  ld = L_MIN(ls, lm);
651  rd = L_MAX(rs, rm);
652  td = L_MIN(ts, tm);
653  bd = L_MAX(bs, bm);
654  } else if (subflag == L_SUB_ON_LOC_DIFF) {
655  ld = (L_ABS(lm - ls) <= maxdiff) ? ls : lm - extrapixels;
656  td = (L_ABS(tm - ts) <= maxdiff) ? ts : tm - extrapixels;
657  rd = (L_ABS(rm - rs) <= maxdiff) ? rs : rm + extrapixels;
658  bd = (L_ABS(bm - bs) <= maxdiff) ? bs : bm + extrapixels;
659  } else if (subflag == L_SUB_ON_SIZE_DIFF) {
660  ld = (L_ABS(wm - ws) <= maxdiff) ? ls : lm - extrapixels;
661  td = (L_ABS(hm - hs) <= maxdiff) ? ts : tm - extrapixels;
662  rd = (L_ABS(wm - ws) <= maxdiff) ? rs : rm + extrapixels;
663  bd = (L_ABS(hm - hs) <= maxdiff) ? bs : bm + extrapixels;
664  } else if (subflag == L_USE_CAPPED_MIN) {
665  ld = L_MAX(lm, L_MIN(ls, lm + maxdiff));
666  td = L_MAX(tm, L_MIN(ts, tm + maxdiff));
667  rd = L_MIN(rm, L_MAX(rs, rm - maxdiff));
668  bd = L_MIN(bm, L_MAX(bs, bm - maxdiff));
669  } else { /* subflag == L_USE_CAPPED_MAX */
670  ld = L_MIN(lm, L_MAX(ls, lm - maxdiff));
671  td = L_MIN(tm, L_MAX(ts, tm - maxdiff));
672  rd = L_MAX(rm, L_MIN(rs, rm + maxdiff));
673  bd = L_MAX(bm, L_MIN(bs, bm + maxdiff));
674  }
675  boxd = boxCreate(ld, td, rd - ld + 1, bd - td + 1);
676  boxaAddBox(boxad, boxd, L_INSERT);
677  }
678  boxDestroy(&boxs);
679  boxDestroy(&boxm);
680  }
681  boxDestroy(&boxempty);
682 
683  return boxad;
684 }
685 
686 
715 BOXA *
717  l_int32 width,
718  l_int32 widthflag,
719  l_int32 height,
720  l_int32 heightflag)
721 {
722 l_int32 n, i, x, y, w, h, invalid;
723 l_int32 delw, delh, del_left, del_right, del_top, del_bot;
724 BOX *medbox, *boxs, *boxd;
725 BOXA *boxad;
726 
727  PROCNAME("boxaConstrainSize");
728 
729  if (!boxas)
730  return (BOXA *)ERROR_PTR("boxas not defined", procName, NULL);
731 
732  /* Need median values if requested or if there are invalid boxes */
733  invalid = boxaGetCount(boxas) - boxaGetValidCount(boxas);
734  medbox = NULL;
735  if (width == 0 || height == 0 || invalid > 0) {
736  if (boxaGetMedianVals(boxas, &x, &y, NULL, NULL, &w, &h)) {
737  L_ERROR("median vals not returned", procName);
738  return boxaCopy(boxas, L_COPY);
739  }
740  medbox = boxCreate(x, y, w, h);
741  if (width == 0) width = w;
742  if (height == 0) height = h;
743  }
744 
745  n = boxaGetCount(boxas);
746  boxad = boxaCreate(n);
747  for (i = 0; i < n; i++) {
748  if ((boxs = boxaGetValidBox(boxas, i, L_COPY)) == NULL)
749  boxs = boxCopy(medbox);
750  boxGetGeometry(boxs, NULL, NULL, &w, &h);
751  delw = width - w;
752  delh = height - h;
753  del_left = del_right = del_top = del_bot = 0;
754  if (widthflag == L_ADJUST_LEFT) {
755  del_left = -delw;
756  } else if (widthflag == L_ADJUST_RIGHT) {
757  del_right = delw;
758  } else {
759  del_left = -delw / 2;
760  del_right = delw / 2 + L_SIGN(delw) * (delw & 1);
761  }
762  if (heightflag == L_ADJUST_TOP) {
763  del_top = -delh;
764  } else if (heightflag == L_ADJUST_BOT) {
765  del_bot = delh;
766  } else {
767  del_top = -delh / 2;
768  del_bot = delh / 2 + L_SIGN(delh) * (delh & 1);
769  }
770  boxd = boxAdjustSides(NULL, boxs, del_left, del_right,
771  del_top, del_bot);
772  boxaAddBox(boxad, boxd, L_INSERT);
773  boxDestroy(&boxs);
774  }
775 
776  boxDestroy(&medbox);
777  return boxad;
778 }
779 
780 
824 BOXA *
826  l_int32 sides,
827  l_int32 delh,
828  l_int32 op,
829  l_float32 factor,
830  l_int32 start)
831 {
832 l_int32 n, he, ho, hmed, doeven;
833 l_float32 del1, del2;
834 BOXA *boxae, *boxao, *boxa1e, *boxa1o, *boxad;
835 
836  PROCNAME("boxaReconcileEvenOddHeight");
837 
838  if (!boxas)
839  return (BOXA *)ERROR_PTR("boxas not defined", procName, NULL);
840  if (sides != L_ADJUST_TOP && sides != L_ADJUST_BOT &&
841  sides != L_ADJUST_TOP_AND_BOT) {
842  L_WARNING("no action requested; returning copy\n", procName);
843  return boxaCopy(boxas, L_COPY);
844  }
845  if ((n = boxaGetValidCount(boxas)) < 6) {
846  L_WARNING("need at least 6 valid boxes; returning copy\n", procName);
847  return boxaCopy(boxas, L_COPY);
848  }
849  if (factor <= 0.0) {
850  L_WARNING("invalid factor; setting to 1.0\n", procName);
851  factor = 1.0;
852  }
853 
854  /* Require at least 3 valid boxes of both types */
855  boxaSplitEvenOdd(boxas, 0, &boxae, &boxao);
856  if (boxaGetValidCount(boxae) < 3 || boxaGetValidCount(boxao) < 3) {
857  boxaDestroy(&boxae);
858  boxaDestroy(&boxao);
859  return boxaCopy(boxas, L_COPY);
860  }
861 
862  /* Get the median heights for each set */
863  boxaGetMedianVals(boxae, NULL, NULL, NULL, NULL, NULL, &he);
864  boxaGetMedianVals(boxao, NULL, NULL, NULL, NULL, NULL, &ho);
865  L_INFO("median he = %d, median ho = %d\n", procName, he, ho);
866 
867  /* If the difference in median height reaches the threshold %delh,
868  * only adjust the side(s) of one of the sets. If we choose
869  * the minimum median height as the target, allow the target
870  * to be scaled by a factor, typically near 1.0, of the
871  * minimum median height. And similarly if the target is
872  * the maximum median height. */
873  if (L_ABS(he - ho) > delh) {
874  if (op == L_ADJUST_CHOOSE_MIN) {
875  doeven = (ho < he) ? TRUE : FALSE;
876  hmed = (l_int32)(factor * L_MIN(he, ho));
877  hmed = L_MIN(hmed, L_MAX(he, ho)); /* don't make it bigger! */
878  } else { /* max height */
879  doeven = (ho > he) ? TRUE : FALSE;
880  hmed = (l_int32)(factor * L_MAX(he, ho));
881  hmed = L_MAX(hmed, L_MIN(he, ho)); /* don't make it smaller! */
882  }
883  if (doeven) {
884  boxa1e = boxaAdjustHeightToTarget(NULL, boxae, sides, hmed, delh);
885  boxa1o = boxaCopy(boxao, L_COPY);
886  } else { /* !doeven */
887  boxa1e = boxaCopy(boxae, L_COPY);
888  boxa1o = boxaAdjustHeightToTarget(NULL, boxao, sides, hmed, delh);
889  }
890  } else {
891  boxa1e = boxaCopy(boxae, L_CLONE);
892  boxa1o = boxaCopy(boxao, L_CLONE);
893  }
894  boxaDestroy(&boxae);
895  boxaDestroy(&boxao);
896 
897  /* It can happen that the median is not a good measure for an
898  * entire book. In that case, the reconciliation above can do
899  * more harm than good. Sanity check by comparing height and y
900  * differences of adjacent even/odd boxes, before and after
901  * reconciliation. */
902  boxad = boxaMergeEvenOdd(boxa1e, boxa1o, 0);
903  boxaTestEvenOddHeight(boxas, boxad, start, &del1, &del2);
904  boxaDestroy(&boxa1e);
905  boxaDestroy(&boxa1o);
906  if (del2 < del1 + 10.)
907  return boxad;
908 
909  /* Using the median made it worse. Skip reconciliation:
910  * forcing all pairs of top and bottom values to have
911  * maximum extent does not improve the situation either. */
912  L_INFO("Got worse: del2 = %f > del1 = %f\n", procName, del2, del1);
913  boxaDestroy(&boxad);
914  return boxaCopy(boxas, L_COPY);
915 }
916 
917 
933 static l_int32
935  BOXA *boxa2,
936  l_int32 start,
937  l_float32 *pdel1,
938  l_float32 *pdel2)
939 {
940 l_int32 i, n, npairs, y1a, y1b, y2a, y2b, h1a, h1b, h2a, h2b;
941 l_float32 del1, del2;
942 
943  PROCNAME("boxaTestEvenOddHeight");
944 
945  if (pdel1) *pdel1 = 0.0;
946  if (pdel2) *pdel2 = 0.0;
947  if (!pdel1 || !pdel2)
948  return ERROR_INT("&del1 and &del2 not both defined", procName, 1);
949  if (!boxa1 || !boxa2)
950  return ERROR_INT("boxa1 and boxa2 not both defined", procName, 1);
951  n = L_MIN(boxaGetCount(boxa1), boxaGetCount(boxa2));
952 
953  /* For boxa1 and boxa2 separately, we expect the y and h values
954  * to be similar for adjacent boxes. Get a measure of similarity
955  * by finding the sum of squares of differences between
956  * y values and between h values, and adding them. */
957  del1 = del2 = 0.0;
958  npairs = (n - start) / 2;
959  for (i = start; i < 2 * npairs; i += 2) {
960  boxaGetBoxGeometry(boxa1, i, NULL, &y1a, NULL, &h1a);
961  boxaGetBoxGeometry(boxa1, i + 1, NULL, &y1b, NULL, &h1b);
962  del1 += (l_float32)(y1a - y1b) * (y1a - y1b)
963  + (h1a - h1b) * (h1a - h1b);
964  boxaGetBoxGeometry(boxa2, i, NULL, &y2a, NULL, &h2a);
965  boxaGetBoxGeometry(boxa2, i + 1, NULL, &y2b, NULL, &h2b);
966  del2 += (l_float32)(y2a - y2b) * (y2a - y2b)
967  + (h2a - h2b) * (h2a - h2b);
968  }
969 
970  /* Get the root of the average of the sum of square differences */
971  *pdel1 = (l_float32)sqrt((l_float64)del1 / (0.5 * n));
972  *pdel2 = (l_float32)sqrt((l_float64)del2 / (0.5 * n));
973  return 0;
974 }
975 
976 
1005 BOXA *
1007  l_int32 delw,
1008  l_int32 op,
1009  l_float32 factor,
1010  NUMA *na)
1011 {
1012 l_int32 i, ne, no, nmin, xe, we, xo, wo, inde, indo, x, w;
1013 BOX *boxe, *boxo;
1014 BOXA *boxae, *boxao, *boxad;
1015 
1016  PROCNAME("boxaReconcilePairWidth");
1017 
1018  if (!boxas)
1019  return (BOXA *)ERROR_PTR("boxas not defined", procName, NULL);
1020  if (factor <= 0.0) {
1021  L_WARNING("invalid factor; setting to 1.0\n", procName);
1022  factor = 1.0;
1023  }
1024 
1025  /* Taking the boxes in pairs, if the difference in width reaches
1026  * the threshold %delw, adjust the left or right side of one
1027  * of the pair. */
1028  boxaSplitEvenOdd(boxas, 0, &boxae, &boxao);
1029  ne = boxaGetCount(boxae);
1030  no = boxaGetCount(boxao);
1031  nmin = L_MIN(ne, no);
1032  for (i = 0; i < nmin; i++) {
1033  /* Set indicator values */
1034  if (na) {
1035  numaGetIValue(na, 2 * i, &inde);
1036  numaGetIValue(na, 2 * i + 1, &indo);
1037  } else {
1038  inde = indo = 1;
1039  }
1040  if (inde == 0 && indo == 0) continue;
1041 
1042  boxe = boxaGetBox(boxae, i, L_CLONE);
1043  boxo = boxaGetBox(boxao, i, L_CLONE);
1044  boxGetGeometry(boxe, &xe, NULL, &we, NULL);
1045  boxGetGeometry(boxo, &xo, NULL, &wo, NULL);
1046  if (we == 0 || wo == 0) { /* if either is invalid; skip */
1047  boxDestroy(&boxe);
1048  boxDestroy(&boxo);
1049  continue;
1050  } else if (L_ABS(we - wo) > delw) {
1051  if (op == L_ADJUST_CHOOSE_MIN) {
1052  if (we > wo && inde == 1) {
1053  /* move left side of even to the right */
1054  w = factor * wo;
1055  x = xe + (we - w);
1056  boxSetGeometry(boxe, x, -1, w, -1);
1057  } else if (we < wo && indo == 1) {
1058  /* move right side of odd to the left */
1059  w = factor * we;
1060  boxSetGeometry(boxo, -1, -1, w, -1);
1061  }
1062  } else { /* maximize width */
1063  if (we < wo && inde == 1) {
1064  /* move left side of even to the left */
1065  w = factor * wo;
1066  x = L_MAX(0, xe + (we - w));
1067  w = we + (xe - x); /* covers both cases for the max */
1068  boxSetGeometry(boxe, x, -1, w, -1);
1069  } else if (we > wo && indo == 1) {
1070  /* move right side of odd to the right */
1071  w = factor * we;
1072  boxSetGeometry(boxo, -1, -1, w, -1);
1073  }
1074  }
1075  }
1076  boxDestroy(&boxe);
1077  boxDestroy(&boxo);
1078  }
1079 
1080  boxad = boxaMergeEvenOdd(boxae, boxao, 0);
1081  boxaDestroy(&boxae);
1082  boxaDestroy(&boxao);
1083  return boxad;
1084 }
1085 
1086 
1128 l_ok
1130  l_int32 type,
1131  l_float32 threshp,
1132  l_float32 threshm,
1133  l_float32 *pfvarp,
1134  l_float32 *pfvarm,
1135  l_int32 *psame)
1136 {
1137 l_int32 i, n, bw1, bh1, bw2, bh2, npairs;
1138 l_float32 ave, fdiff, sumdiff, med, fvarp, fvarm;
1139 NUMA *na1;
1140 
1141  PROCNAME("boxaSizeConsistency1");
1142 
1143  if (pfvarp) *pfvarp = 0.0;
1144  if (pfvarm) *pfvarm = 0.0;
1145  if (!psame)
1146  return ERROR_INT("&same not defined", procName, 1);
1147  *psame = -1;
1148  if (!boxas)
1149  return ERROR_INT("boxas not defined", procName, 1);
1150  if (boxaGetValidCount(boxas) < 6)
1151  return ERROR_INT("need a least 6 valid boxes", procName, 1);
1152  if (type != L_CHECK_WIDTH && type != L_CHECK_HEIGHT)
1153  return ERROR_INT("invalid type", procName, 1);
1154  if (threshp < 0.0 || threshp >= 0.5)
1155  return ERROR_INT("invalid threshp", procName, 1);
1156  if (threshm < 0.0 || threshm >= 0.5)
1157  return ERROR_INT("invalid threshm", procName, 1);
1158  if (threshp == 0.0) threshp = 0.02;
1159  if (threshm == 0.0) threshm = 0.015;
1160 
1161  /* Evaluate pairwise variation */
1162  n = boxaGetCount(boxas);
1163  na1 = numaCreate(0);
1164  for (i = 0, npairs = 0, sumdiff = 0; i < n - 1; i += 2) {
1165  boxaGetBoxGeometry(boxas, i, NULL, NULL, &bw1, &bh1);
1166  boxaGetBoxGeometry(boxas, i + 1, NULL, NULL, &bw2, &bh2);
1167  if (bw1 == 0 || bh1 == 0 || bw2 == 0 || bh2 == 0)
1168  continue;
1169  npairs++;
1170  if (type == L_CHECK_WIDTH) {
1171  ave = (bw1 + bw2) / 2.0;
1172  fdiff = L_ABS(bw1 - bw2) / ave;
1173  numaAddNumber(na1, bw1);
1174  numaAddNumber(na1, bw2);
1175  } else { /* type == L_CHECK_HEIGHT) */
1176  ave = (bh1 + bh2) / 2.0;
1177  fdiff = L_ABS(bh1 - bh2) / ave;
1178  numaAddNumber(na1, bh1);
1179  numaAddNumber(na1, bh2);
1180  }
1181  sumdiff += fdiff;
1182  }
1183  fvarp = sumdiff / npairs;
1184  if (pfvarp) *pfvarp = fvarp;
1185 
1186  /* Evaluate the average abs fractional deviation from the median */
1187  numaGetMedian(na1, &med);
1188  if (med == 0.0) {
1189  L_WARNING("median value is 0\n", procName);
1190  } else {
1191  numaGetMeanDevFromMedian(na1, med, &fvarm);
1192  fvarm /= med;
1193  if (pfvarm) *pfvarm = fvarm;
1194  }
1195  numaDestroy(&na1);
1196 
1197  /* Make decision */
1198  if (fvarp < threshp && fvarm < threshm)
1199  *psame = 1;
1200  else if (fvarp < threshp && fvarm > threshm)
1201  *psame = 0;
1202  else
1203  *psame = -1; /* unknown */
1204  return 0;
1205 }
1206 
1207 
1240 l_ok
1242  l_float32 *pfdevw,
1243  l_float32 *pfdevh,
1244  l_int32 debug)
1245 {
1246 l_int32 i, n, bw1, bh1, bw2, bh2, npairs;
1247 l_float32 medw, medh, devw, devh, minw, maxw, minh, w;
1248 BOX *box;
1249 BOXA *boxa1;
1250 NUMA *naw, *nah;
1251 PIX *pix1, *pix2, *pix3;
1252 PIXA *pixa;
1253 
1254  PROCNAME("boxaSizeConsistency2");
1255 
1256  if (pfdevw) *pfdevw = 0.0;
1257  if (pfdevh) *pfdevh = 0.0;
1258  if (!boxas)
1259  return ERROR_INT("boxas not defined", procName, 1);
1260  if (!pfdevw || !pfdevh)
1261  return ERROR_INT("&fdevw and &fdevh not both defined", procName, 1);
1262  n = boxaGetCount(boxas);
1263  if (n < 10) {
1264  L_WARNING("small boxa; assuming OK", procName);
1265  return 0;
1266  }
1267 
1268  /* Regularize w and h in pairs; skip last box if n is odd */
1269  boxa1 = (debug) ? boxaCreate(n) : NULL;
1270  naw = numaCreate(0);
1271  nah = numaCreate(0);
1272  for (i = 0, npairs = 0; i < n - 1; i += 2) {
1273  boxaGetBoxGeometry(boxas, i, NULL, NULL, &bw1, &bh1);
1274  boxaGetBoxGeometry(boxas, i + 1, NULL, NULL, &bw2, &bh2);
1275  if (bw1 == 0 || bh1 == 0 || bw2 == 0 || bh2 == 0)
1276  continue;
1277  npairs++;
1278  minw = (l_float32)L_MIN(bw1, bw2);
1279  maxw = (l_float32)L_MAX(bw1, bw2);
1280  minh = (l_float32)L_MIN(bh1, bh2);
1281  w = (minw / minh > 0.5) ? minw : maxw;
1282  numaAddNumber(naw, w);
1283  numaAddNumber(nah, minh);
1284  if (debug) {
1285  box = boxCreate(0, 0, w, minh);
1286  boxaAddBox(boxa1, box, L_COPY);
1287  boxaAddBox(boxa1, box, L_INSERT);
1288  }
1289  }
1290  if (npairs == 0) {
1291  L_WARNING("no valid box pairs\n", procName);
1292  numaDestroy(&naw);
1293  numaDestroy(&nah);
1294  boxaDestroy(&boxa1);
1295  }
1296 
1297  /* Get the median value of the regularized sizes, and find
1298  * the average absolute fractional deviation from the median. */
1299  numaGetMedian(naw, &medw);
1300  numaGetMedian(nah, &medh);
1301  numaGetMeanDevFromMedian(naw, medw, &devw);
1302  numaGetMeanDevFromMedian(nah, medh, &devh);
1303  *pfdevw = devw / medw;
1304  *pfdevh = devh / medh;
1305  if (debug) {
1306  fprintf(stderr, "medw = %5.1f, medh = %5.1f\n", medw, medh);
1307  fprintf(stderr, "fdevw = %6.3f, fdevh = %6.3f\n", *pfdevw, *pfdevh);
1308  boxaPlotSizes(boxas, "input_boxa", NULL, NULL, &pix1);
1309  boxaPlotSizes(boxa1, "regularized_boxa", NULL, NULL, &pix2);
1310  pixDisplay(pix1, 500, 0);
1311  pixDisplay(pix2, 500, 1000);
1312  pixa = pixaCreate(2);
1313  pixaAddPix(pixa, pix1, L_INSERT);
1314  pixaAddPix(pixa, pix2, L_INSERT);
1315  pix3 = pixaDisplayTiledInColumns(pixa, 2, 1.0, 3, 2);
1316  lept_mkdir("lept/boxa");
1317  pixWrite("/tmp/lept/boxa/eval.png", pix3, IFF_PNG);
1318  pixDisplay(pix3, 100, 100);
1319  pixDestroy(&pix3);
1320  pixaDestroy(&pixa);
1321  boxaDestroy(&boxa1);
1322  }
1323 
1324  numaDestroy(&naw);
1325  numaDestroy(&nah);
1326  return 0;
1327 }
1328 
1329 
1369 BOXA *
1371  l_int32 type,
1372  l_float32 fract,
1373  l_float32 factor,
1374  NUMA **pnadelw,
1375  NUMA **pnadelh,
1376  l_float32 *pratiowh)
1377 {
1378 l_int32 i, n, ne, no, outfound, isvalid, ind, ldist, rdist, tdist, bdist;
1379 l_int32 medw, medh, newloc, bw, bh, left, right, top, bot;
1380 l_int32 medleft, medlefte, medlefto, medright, medrighte, medrighto;
1381 l_int32 medtop, medtope, medtopo, medbot, medbote, medboto;
1382 l_float32 brat;
1383 BOX *box;
1384 BOXA *boxa1, *boxae, *boxao, *boxad;
1385 NUMA *naind, *nadelw, *nadelh;
1386 
1387  PROCNAME("boxaReconcileSizeByMedian");
1388 
1389  if (pnadelw) *pnadelw = NULL;
1390  if (pnadelh) *pnadelh = NULL;
1391  if (pratiowh) *pratiowh = 0.0;
1392  if (!boxas)
1393  return (BOXA *)ERROR_PTR("boxas not defined", procName, NULL);
1394  if (type != L_CHECK_WIDTH && type != L_CHECK_HEIGHT &&
1395  type != L_CHECK_BOTH) {
1396  L_WARNING("invalid type; returning copy\n", procName);
1397  return boxaCopy(boxas, L_COPY);
1398  }
1399  if (fract <= 0.0 || fract >= 1.0) {
1400  L_WARNING("invalid fract; returning copy\n", procName);
1401  return boxaCopy(boxas, L_COPY);
1402  }
1403  if (factor < 0.7 || factor > 1.4)
1404  L_WARNING("factor %5.3f is typ. closer to 1.0\n", procName, factor);
1405  if (boxaGetValidCount(boxas) < 6) {
1406  L_WARNING("need at least 6 valid boxes; returning copy\n", procName);
1407  return boxaCopy(boxas, L_COPY);
1408  }
1409 
1410  /* If reconciling both width and height, optionally return array of
1411  * median deviations and even/odd ratio for width measurements */
1412  if (type == L_CHECK_BOTH) {
1413  boxa1 = boxaReconcileSizeByMedian(boxas, L_CHECK_WIDTH, fract,
1414  factor, pnadelw, NULL, pratiowh);
1415  boxad = boxaReconcileSizeByMedian(boxa1, L_CHECK_HEIGHT, fract,
1416  factor, NULL, pnadelh, NULL);
1417  boxaDestroy(&boxa1);
1418  return boxad;
1419  }
1420 
1421  n = boxaGetCount(boxas);
1422  naind = numaCreate(n); /* outlier indicator array */
1423  boxae = boxaCreate(0); /* even inliers */
1424  boxao = boxaCreate(0); /* odd inliers */
1425  outfound = FALSE;
1426  if (type == L_CHECK_WIDTH) {
1427  boxaMedianDimensions(boxas, &medw, &medh, NULL, NULL, NULL, NULL,
1428  &nadelw, NULL);
1429  if (pratiowh) {
1430  *pratiowh = (l_float32)medw / (l_float32)medh;
1431  L_INFO("median ratio w/h = %5.3f\n", procName, *pratiowh);
1432  }
1433  if (pnadelw)
1434  *pnadelw = nadelw;
1435  else
1436  numaDestroy(&nadelw);
1437 
1438  /* Check for outliers; assemble inliers */
1439  for (i = 0; i < n; i++) {
1440  if ((box = boxaGetValidBox(boxas, i, L_COPY)) == NULL) {
1441  numaAddNumber(naind, 0);
1442  continue;
1443  }
1444  boxGetGeometry(box, NULL, NULL, &bw, NULL);
1445  brat = (l_float32)bw / (l_float32)medw;
1446  if (brat < 1.0 - fract || brat > 1.0 + fract) {
1447  outfound = TRUE;
1448  numaAddNumber(naind, 1);
1449  boxDestroy(&box);
1450  } else { /* add to inliers */
1451  numaAddNumber(naind, 0);
1452  if (i % 2 == 0)
1453  boxaAddBox(boxae, box, L_INSERT);
1454  else
1455  boxaAddBox(boxao, box, L_INSERT);
1456  }
1457  }
1458  if (!outfound) { /* nothing to do */
1459  numaDestroy(&naind);
1460  boxaDestroy(&boxae);
1461  boxaDestroy(&boxao);
1462  L_INFO("no width outlier boxes found\n", procName);
1463  return boxaCopy(boxas, L_COPY);
1464  }
1465 
1466  /* Get left/right parameters from inliers. Handle the case
1467  * where there are no inliers for one of the sets. For example,
1468  * when all the even boxes have a different dimension from
1469  * the odd boxes, and the median arbitrarily gets assigned
1470  * to the even boxes, there are no odd inliers; in that case,
1471  * use the even inliers sides to decide whether to adjust
1472  * the left or the right sides of individual outliers. */
1473  L_INFO("fixing width of outlier boxes\n", procName);
1474  medlefte = medrighte = medlefto = medrighto = 0;
1475  if ((ne = boxaGetValidCount(boxae)) > 0)
1476  boxaGetMedianVals(boxae, &medlefte, NULL, &medrighte, NULL,
1477  NULL, NULL);
1478  if ((no = boxaGetValidCount(boxao)) > 0)
1479  boxaGetMedianVals(boxao, &medlefto, NULL, &medrighto, NULL,
1480  NULL, NULL);
1481  if (ne == 0) { /* use odd inliers values for both */
1482  medlefte = medlefto;
1483  medrighte = medrighto;
1484  } else if (no == 0) { /* use even inliers values for both */
1485  medlefto = medlefte;
1486  medrighto = medrighte;
1487  }
1488 
1489  /* Adjust sides of outliers */
1490  boxad = boxaCreate(n);
1491  for (i = 0; i < n; i++) {
1492  box = boxaGetBox(boxas, i, L_COPY);
1493  boxIsValid(box, &isvalid);
1494  numaGetIValue(naind, i, &ind);
1495  medleft = (i % 2 == 0) ? medlefte : medlefto;
1496  medright = (i % 2 == 0) ? medrighte : medrighto;
1497  if (ind == 1 && isvalid) { /* adjust side */
1498  boxGetSideLocations(box, &left, &right, NULL, NULL);
1499  ldist = L_ABS(left - medleft);
1500  rdist = L_ABS(right - medright);
1501  if (ldist > rdist) { /* adjust left */
1502  newloc = L_MAX(0, right - factor * medw);
1503  boxSetSide(box, L_SET_LEFT, newloc, 0);
1504  } else {
1505  newloc = left + factor * medw;
1506  boxSetSide(box, L_SET_RIGHT, newloc, 0);
1507  }
1508  }
1509  boxaAddBox(boxad, box, L_INSERT);
1510  }
1511  } else { /* L_CHECK_HEIGHT */
1512  boxaMedianDimensions(boxas, &medw, &medh, NULL, NULL, NULL, NULL,
1513  NULL, &nadelh);
1514  if (pratiowh) {
1515  *pratiowh = (l_float32)medw / (l_float32)medh;
1516  L_INFO("median ratio w/h = %5.3f\n", procName, *pratiowh);
1517  }
1518  if (pnadelh)
1519  *pnadelh = nadelh;
1520  else
1521  numaDestroy(&nadelh);
1522 
1523  /* Check for outliers; assemble inliers */
1524  for (i = 0; i < n; i++) {
1525  if ((box = boxaGetValidBox(boxas, i, L_COPY)) == NULL) {
1526  numaAddNumber(naind, 0);
1527  continue;
1528  }
1529  boxGetGeometry(box, NULL, NULL, NULL, &bh);
1530  brat = (l_float32)bh / (l_float32)medh;
1531  if (brat < 1.0 - fract || brat > 1.0 + fract) {
1532  outfound = TRUE;
1533  numaAddNumber(naind, 1);
1534  boxDestroy(&box);
1535  } else { /* add to inliers */
1536  numaAddNumber(naind, 0);
1537  if (i % 2 == 0)
1538  boxaAddBox(boxae, box, L_INSERT);
1539  else
1540  boxaAddBox(boxao, box, L_INSERT);
1541  }
1542  }
1543  if (!outfound) { /* nothing to do */
1544  numaDestroy(&naind);
1545  boxaDestroy(&boxae);
1546  boxaDestroy(&boxao);
1547  L_INFO("no height outlier boxes found\n", procName);
1548  return boxaCopy(boxas, L_COPY);
1549  }
1550 
1551  /* Get top/bot parameters from inliers. Handle the case
1552  * where there are no inliers for one of the sets. For example,
1553  * when all the even boxes have a different dimension from
1554  * the odd boxes, and the median arbitrarily gets assigned
1555  * to the even boxes, there are no odd inliers; in that case,
1556  * use the even inlier sides to decide whether to adjust
1557  * the top or the bottom sides of individual outliers. */
1558  L_INFO("fixing height of outlier boxes\n", procName);
1559  medlefte = medtope = medbote = medtopo = medboto = 0;
1560  if ((ne = boxaGetValidCount(boxae)) > 0)
1561  boxaGetMedianVals(boxae, NULL, &medtope, NULL, &medbote,
1562  NULL, NULL);
1563  if ((no = boxaGetValidCount(boxao)) > 0)
1564  boxaGetMedianVals(boxao, NULL, &medtopo, NULL, &medboto,
1565  NULL, NULL);
1566  if (ne == 0) { /* use odd inliers values for both */
1567  medtope = medtopo;
1568  medbote = medboto;
1569  } else if (no == 0) { /* use even inliers values for both */
1570  medtopo = medtope;
1571  medboto = medbote;
1572  }
1573 
1574  /* Adjust sides of outliers */
1575  boxad = boxaCreate(n);
1576  for (i = 0; i < n; i++) {
1577  box = boxaGetBox(boxas, i, L_COPY);
1578  boxIsValid(box, &isvalid);
1579  numaGetIValue(naind, i, &ind);
1580  medtop = (i % 2 == 0) ? medtope : medtopo;
1581  medbot = (i % 2 == 0) ? medbote : medboto;
1582  if (ind == 1 && isvalid) { /* adjust side */
1583  boxGetSideLocations(box, NULL, NULL, &top, &bot);
1584  tdist = L_ABS(top - medtop);
1585  bdist = L_ABS(bot - medbot);
1586  if (tdist > bdist) { /* adjust top */
1587  newloc = L_MAX(0, bot - factor * medh);
1588  boxSetSide(box, L_SET_TOP, newloc, 0);
1589  } else { /* adjust bottom */
1590  newloc = top + factor * medh;
1591  boxSetSide(box, L_SET_BOT, newloc, 0);
1592  }
1593  }
1594  boxaAddBox(boxad, box, L_INSERT);
1595  }
1596  }
1597  numaDestroy(&naind);
1598  boxaDestroy(&boxae);
1599  boxaDestroy(&boxao);
1600  return boxad;
1601 }
1602 
1603 
1628 l_ok
1630  const char *plotname,
1631  NUMA **pnal,
1632  NUMA **pnat,
1633  NUMA **pnar,
1634  NUMA **pnab,
1635  PIX **ppixd)
1636 {
1637 char buf[128], titlebuf[128];
1638 static l_int32 plotid = 0;
1639 l_int32 n, i, w, h, left, top, right, bot;
1640 BOXA *boxat;
1641 GPLOT *gplot;
1642 NUMA *nal, *nat, *nar, *nab;
1643 
1644  PROCNAME("boxaPlotSides");
1645 
1646  if (pnal) *pnal = NULL;
1647  if (pnat) *pnat = NULL;
1648  if (pnar) *pnar = NULL;
1649  if (pnab) *pnab = NULL;
1650  if (ppixd) *ppixd = NULL;
1651  if (!boxa)
1652  return ERROR_INT("boxa not defined", procName, 1);
1653  if ((n = boxaGetCount(boxa)) < 2)
1654  return ERROR_INT("less than 2 boxes", procName, 1);
1655 
1656  boxat = boxaFillSequence(boxa, L_USE_ALL_BOXES, 0);
1657 
1658  /* Build the numas for each side */
1659  nal = numaCreate(n);
1660  nat = numaCreate(n);
1661  nar = numaCreate(n);
1662  nab = numaCreate(n);
1663 
1664  for (i = 0; i < n; i++) {
1665  boxaGetBoxGeometry(boxat, i, &left, &top, &w, &h);
1666  right = left + w - 1;
1667  bot = top + h - 1;
1668  numaAddNumber(nal, left);
1669  numaAddNumber(nat, top);
1670  numaAddNumber(nar, right);
1671  numaAddNumber(nab, bot);
1672  }
1673  boxaDestroy(&boxat);
1674 
1675  lept_mkdir("lept/plots");
1676  if (plotname) {
1677  snprintf(buf, sizeof(buf), "/tmp/lept/plots/sides.%s", plotname);
1678  snprintf(titlebuf, sizeof(titlebuf), "%s: Box sides vs. box index",
1679  plotname);
1680  } else {
1681  snprintf(buf, sizeof(buf), "/tmp/lept/plots/sides.%d", plotid++);
1682  snprintf(titlebuf, sizeof(titlebuf), "Box sides vs. box index");
1683  }
1684  gplot = gplotCreate(buf, GPLOT_PNG, titlebuf,
1685  "box index", "side location");
1686  gplotAddPlot(gplot, NULL, nal, GPLOT_LINES, "left side");
1687  gplotAddPlot(gplot, NULL, nat, GPLOT_LINES, "top side");
1688  gplotAddPlot(gplot, NULL, nar, GPLOT_LINES, "right side");
1689  gplotAddPlot(gplot, NULL, nab, GPLOT_LINES, "bottom side");
1690  gplotMakeOutput(gplot);
1691  gplotDestroy(&gplot);
1692 
1693  if (ppixd) {
1694  stringCat(buf, sizeof(buf), ".png");
1695  *ppixd = pixRead(buf);
1696  }
1697 
1698  if (pnal)
1699  *pnal = nal;
1700  else
1701  numaDestroy(&nal);
1702  if (pnat)
1703  *pnat = nat;
1704  else
1705  numaDestroy(&nat);
1706  if (pnar)
1707  *pnar = nar;
1708  else
1709  numaDestroy(&nar);
1710  if (pnab)
1711  *pnab = nab;
1712  else
1713  numaDestroy(&nab);
1714  return 0;
1715 }
1716 
1717 
1740 l_ok
1742  const char *plotname,
1743  NUMA **pnaw,
1744  NUMA **pnah,
1745  PIX **ppixd)
1746 {
1747 char buf[128], titlebuf[128];
1748 static l_int32 plotid = 0;
1749 l_int32 n, i, w, h;
1750 BOXA *boxat;
1751 GPLOT *gplot;
1752 NUMA *naw, *nah;
1753 
1754  PROCNAME("boxaPlotSizes");
1755 
1756  if (pnaw) *pnaw = NULL;
1757  if (pnah) *pnah = NULL;
1758  if (ppixd) *ppixd = NULL;
1759  if (!boxa)
1760  return ERROR_INT("boxa not defined", procName, 1);
1761  if ((n = boxaGetCount(boxa)) < 2)
1762  return ERROR_INT("less than 2 boxes", procName, 1);
1763 
1764  boxat = boxaFillSequence(boxa, L_USE_ALL_BOXES, 0);
1765 
1766  /* Build the numas for the width and height */
1767  naw = numaCreate(n);
1768  nah = numaCreate(n);
1769 
1770  for (i = 0; i < n; i++) {
1771  boxaGetBoxGeometry(boxat, i, NULL, NULL, &w, &h);
1772  numaAddNumber(naw, w);
1773  numaAddNumber(nah, h);
1774  }
1775  boxaDestroy(&boxat);
1776 
1777  lept_mkdir("lept/plots");
1778  if (plotname) {
1779  snprintf(buf, sizeof(buf), "/tmp/lept/plots/size.%s", plotname);
1780  snprintf(titlebuf, sizeof(titlebuf), "%s: Box size vs. box index",
1781  plotname);
1782  } else {
1783  snprintf(buf, sizeof(buf), "/tmp/lept/plots/size.%d", plotid++);
1784  snprintf(titlebuf, sizeof(titlebuf), "Box size vs. box index");
1785  }
1786  gplot = gplotCreate(buf, GPLOT_PNG, titlebuf,
1787  "box index", "box dimension");
1788  gplotAddPlot(gplot, NULL, naw, GPLOT_LINES, "width");
1789  gplotAddPlot(gplot, NULL, nah, GPLOT_LINES, "height");
1790  gplotMakeOutput(gplot);
1791  gplotDestroy(&gplot);
1792 
1793  if (ppixd) {
1794  stringCat(buf, sizeof(buf), ".png");
1795  *ppixd = pixRead(buf);
1796  }
1797 
1798  if (pnaw)
1799  *pnaw = naw;
1800  else
1801  numaDestroy(&naw);
1802  if (pnah)
1803  *pnah = nah;
1804  else
1805  numaDestroy(&nah);
1806  return 0;
1807 }
1808 
1809 
1828 BOXA *
1830  l_int32 useflag,
1831  l_int32 debug)
1832 {
1833 l_int32 n, nv;
1834 BOXA *boxae, *boxao, *boxad;
1835 
1836  PROCNAME("boxaFillSequence");
1837 
1838  if (!boxas)
1839  return (BOXA *)ERROR_PTR("boxas not defined", procName, NULL);
1840  if (useflag != L_USE_ALL_BOXES && useflag != L_USE_SAME_PARITY_BOXES)
1841  return (BOXA *)ERROR_PTR("invalid useflag", procName, NULL);
1842 
1843  n = boxaGetCount(boxas);
1844  nv = boxaGetValidCount(boxas);
1845  if (n == nv)
1846  return boxaCopy(boxas, L_COPY); /* all valid */
1847  if (debug)
1848  L_INFO("%d valid boxes, %d invalid boxes\n", procName, nv, n - nv);
1849  if (useflag == L_USE_SAME_PARITY_BOXES && n < 3) {
1850  L_WARNING("n < 3; some invalid\n", procName);
1851  return boxaCopy(boxas, L_COPY);
1852  }
1853 
1854  if (useflag == L_USE_ALL_BOXES) {
1855  boxad = boxaCopy(boxas, L_COPY);
1856  boxaFillAll(boxad);
1857  } else {
1858  boxaSplitEvenOdd(boxas, 0, &boxae, &boxao);
1859  boxaFillAll(boxae);
1860  boxaFillAll(boxao);
1861  boxad = boxaMergeEvenOdd(boxae, boxao, 0);
1862  boxaDestroy(&boxae);
1863  boxaDestroy(&boxao);
1864  }
1865 
1866  nv = boxaGetValidCount(boxad);
1867  if (n != nv)
1868  L_WARNING("there are still %d invalid boxes\n", procName, n - nv);
1869 
1870  return boxad;
1871 }
1872 
1873 
1887 static l_int32
1889 {
1890 l_int32 n, nv, i, j, spandown, spanup;
1891 l_int32 *indic;
1892 BOX *box, *boxt;
1893 
1894  PROCNAME("boxaFillAll");
1895 
1896  if (!boxa)
1897  return ERROR_INT("boxa not defined", procName, 1);
1898  n = boxaGetCount(boxa);
1899  nv = boxaGetValidCount(boxa);
1900  if (n == nv) return 0;
1901  if (nv == 0) {
1902  L_WARNING("no valid boxes out of %d boxes\n", procName, n);
1903  return 0;
1904  }
1905 
1906  /* Make indicator array for valid boxes */
1907  if ((indic = (l_int32 *)LEPT_CALLOC(n, sizeof(l_int32))) == NULL)
1908  return ERROR_INT("indic not made", procName, 1);
1909  for (i = 0; i < n; i++) {
1910  box = boxaGetValidBox(boxa, i, L_CLONE);
1911  if (box)
1912  indic[i] = 1;
1913  boxDestroy(&box);
1914  }
1915 
1916  /* Replace invalid boxes with the nearest valid one */
1917  for (i = 0; i < n; i++) {
1918  box = boxaGetValidBox(boxa, i, L_CLONE);
1919  if (!box) {
1920  spandown = spanup = 10000000;
1921  for (j = i - 1; j >= 0; j--) {
1922  if (indic[j] == 1) {
1923  spandown = i - j;
1924  break;
1925  }
1926  }
1927  for (j = i + 1; j < n; j++) {
1928  if (indic[j] == 1) {
1929  spanup = j - i;
1930  break;
1931  }
1932  }
1933  if (spandown < spanup)
1934  boxt = boxaGetBox(boxa, i - spandown, L_COPY);
1935  else
1936  boxt = boxaGetBox(boxa, i + spanup, L_COPY);
1937  boxaReplaceBox(boxa, i, boxt);
1938  }
1939  boxDestroy(&box);
1940  }
1941 
1942  LEPT_FREE(indic);
1943  return 0;
1944 }
1945 
1946 
1971 l_ok
1973  l_int32 type,
1974  l_float32 *pdel_evenodd,
1975  l_float32 *prms_even,
1976  l_float32 *prms_odd,
1977  l_float32 *prms_all)
1978 {
1979 l_int32 n, ne, no, nmin, vale, valo, i;
1980 l_float32 sum;
1981 BOXA *boxae, *boxao;
1982 NUMA *nae, *nao, *na_all;
1983 
1984  PROCNAME("boxaSizeVariation");
1985 
1986  if (pdel_evenodd) *pdel_evenodd = 0.0;
1987  if (prms_even) *prms_even = 0.0;
1988  if (prms_odd) *prms_odd = 0.0;
1989  if (prms_all) *prms_all = 0.0;
1990  if (!boxa)
1991  return ERROR_INT("boxa not defined", procName, 1);
1992  if (type != L_SELECT_WIDTH && type != L_SELECT_HEIGHT)
1993  return ERROR_INT("invalid type", procName, 1);
1994  if (!pdel_evenodd && !prms_even && !prms_odd && !prms_all)
1995  return ERROR_INT("nothing to do", procName, 1);
1996  n = boxaGetCount(boxa);
1997  if (n < 4)
1998  return ERROR_INT("too few boxes", procName, 1);
1999 
2000  boxaSplitEvenOdd(boxa, 0, &boxae, &boxao);
2001  ne = boxaGetCount(boxae);
2002  no = boxaGetCount(boxao);
2003  nmin = L_MIN(ne, no);
2004  if (nmin == 0) {
2005  boxaDestroy(&boxae);
2006  boxaDestroy(&boxao);
2007  return ERROR_INT("either no even or no odd boxes", procName, 1);
2008  }
2009 
2010  if (type == L_SELECT_WIDTH) {
2011  boxaGetSizes(boxae, &nae, NULL);
2012  boxaGetSizes(boxao, &nao, NULL);
2013  boxaGetSizes(boxa, &na_all, NULL);
2014  } else { /* L_SELECT_HEIGHT) */
2015  boxaGetSizes(boxae, NULL, &nae);
2016  boxaGetSizes(boxao, NULL, &nao);
2017  boxaGetSizes(boxa, NULL, &na_all);
2018  }
2019 
2020  if (pdel_evenodd) {
2021  sum = 0.0;
2022  for (i = 0; i < nmin; i++) {
2023  numaGetIValue(nae, i, &vale);
2024  numaGetIValue(nao, i, &valo);
2025  sum += L_ABS(vale - valo);
2026  }
2027  *pdel_evenodd = sum / nmin;
2028  }
2029  if (prms_even)
2030  numaSimpleStats(nae, 0, -1, NULL, NULL, prms_even);
2031  if (prms_odd)
2032  numaSimpleStats(nao, 0, -1, NULL, NULL, prms_odd);
2033  if (prms_all)
2034  numaSimpleStats(na_all, 0, -1, NULL, NULL, prms_all);
2035 
2036  boxaDestroy(&boxae);
2037  boxaDestroy(&boxao);
2038  numaDestroy(&nae);
2039  numaDestroy(&nao);
2040  numaDestroy(&na_all);
2041  return 0;
2042 }
2043 
2044 
2074 l_ok
2076  l_int32 *pmedw,
2077  l_int32 *pmedh,
2078  l_int32 *pmedwe,
2079  l_int32 *pmedwo,
2080  l_int32 *pmedhe,
2081  l_int32 *pmedho,
2082  NUMA **pnadelw,
2083  NUMA **pnadelh)
2084 {
2085 l_int32 i, n, bw, bh, medw, medh, medwe, medwo, medhe, medho;
2086 BOXA *boxae, *boxao;
2087 NUMA *nadelw, *nadelh;
2088 
2089  PROCNAME("boxaMedianDimensions");
2090 
2091  if (pmedw) *pmedw = 0;
2092  if (pmedh) *pmedh = 0;
2093  if (pmedwe) *pmedwe= 0;
2094  if (pmedwo) *pmedwo= 0;
2095  if (pmedhe) *pmedhe= 0;
2096  if (pmedho) *pmedho= 0;
2097  if (pnadelw) *pnadelw = NULL;
2098  if (pnadelh) *pnadelh = NULL;
2099  if (!boxas)
2100  return ERROR_INT("boxas not defined", procName, 1);
2101  if (boxaGetValidCount(boxas) < 6)
2102  return ERROR_INT("need at least 6 valid boxes", procName, 1);
2103 
2104  /* Require at least 3 valid boxes of both types */
2105  boxaSplitEvenOdd(boxas, 0, &boxae, &boxao);
2106  if (boxaGetValidCount(boxae) < 3 || boxaGetValidCount(boxao) < 3) {
2107  boxaDestroy(&boxae);
2108  boxaDestroy(&boxao);
2109  return ERROR_INT("don't have 3+ valid boxes of each type", procName, 1);
2110  }
2111 
2112  /* Get the relevant median widths and heights */
2113  boxaGetMedianVals(boxas, NULL, NULL, NULL, NULL, &medw, &medh);
2114  boxaGetMedianVals(boxae, NULL, NULL, NULL, NULL, &medwe, &medhe);
2115  boxaGetMedianVals(boxao, NULL, NULL, NULL, NULL, &medwo, &medho);
2116  if (pmedw) *pmedw = medw;
2117  if (pmedh) *pmedh = medh;
2118  if (pmedwe) *pmedwe = medwe;
2119  if (pmedwo) *pmedwo = medwo;
2120  if (pmedhe) *pmedhe = medhe;
2121  if (pmedho) *pmedho = medho;
2122 
2123  /* Find the variation from median dimension for each box */
2124  n = boxaGetCount(boxas);
2125  nadelw = numaCreate(n);
2126  nadelh = numaCreate(n);
2127  for (i = 0; i < n; i++) {
2128  boxaGetBoxGeometry(boxas, i, NULL, NULL, &bw, &bh);
2129  if (bw == 0 || bh == 0) { /* invalid box */
2130  numaAddNumber(nadelw, 0);
2131  numaAddNumber(nadelh, 0);
2132  } else {
2133  numaAddNumber(nadelw, bw - medw);
2134  numaAddNumber(nadelh, bh - medh);
2135  }
2136  }
2137  if (pnadelw)
2138  *pnadelw = nadelw;
2139  else
2140  numaDestroy(&nadelw);
2141  if (pnadelh)
2142  *pnadelh = nadelh;
2143  else
2144  numaDestroy(&nadelh);
2145 
2146  boxaDestroy(&boxae);
2147  boxaDestroy(&boxao);
2148  return 0;
2149 }
2150 
void gplotDestroy(GPLOT **pgplot)
gplotDestroy()
Definition: gplot.c:197
BOXA * boxaReconcileEvenOddHeight(BOXA *boxas, l_int32 sides, l_int32 delh, l_int32 op, l_float32 factor, l_int32 start)
boxaReconcileEvenOddHeight()
Definition: boxfunc5.c:825
BOXA * boxaModifyWithBoxa(BOXA *boxas, BOXA *boxam, l_int32 subflag, l_int32 maxdiff, l_int32 extrapixels)
boxaModifyWithBoxa()
Definition: boxfunc5.c:600
l_int32 lept_mkdir(const char *subdir)
lept_mkdir()
Definition: utils2.c:1944
BOX * boxaGetValidBox(BOXA *boxa, l_int32 index, l_int32 accessflag)
boxaGetValidBox()
Definition: boxbasic.c:802
Definition: pix.h:717
l_ok gplotAddPlot(GPLOT *gplot, NUMA *nax, NUMA *nay, l_int32 plotstyle, const char *plottitle)
gplotAddPlot()
Definition: gplot.c:263
l_ok boxaExtractAsNuma(BOXA *boxa, NUMA **pnal, NUMA **pnat, NUMA **pnar, NUMA **pnab, NUMA **pnaw, NUMA **pnah, l_int32 keepinvalid)
boxaExtractAsNuma()
Definition: boxfunc2.c:1101
l_ok boxaPlotSides(BOXA *boxa, const char *plotname, NUMA **pnal, NUMA **pnat, NUMA **pnar, NUMA **pnab, PIX **ppixd)
boxaPlotSides()
Definition: boxfunc5.c:1629
l_ok numaSimpleStats(NUMA *na, l_int32 first, l_int32 last, l_float32 *pmean, l_float32 *pvar, l_float32 *prvar)
numaSimpleStats()
Definition: numafunc2.c:446
l_ok boxaSizeConsistency1(BOXA *boxas, l_int32 type, l_float32 threshp, l_float32 threshm, l_float32 *pfvarp, l_float32 *pfvarm, l_int32 *psame)
boxaSizeConsistency1()
Definition: boxfunc5.c:1129
BOXA * boxaMergeEvenOdd(BOXA *boxae, BOXA *boxao, l_int32 fillflag)
boxaMergeEvenOdd()
Definition: boxfunc1.c:2514
l_ok numaAddNumber(NUMA *na, l_float32 val)
numaAddNumber()
Definition: numabasic.c:473
l_ok boxaGetMedianVals(BOXA *boxa, l_int32 *px, l_int32 *py, l_int32 *pr, l_int32 *pb, l_int32 *pw, l_int32 *ph)
boxaGetMedianVals()
Definition: boxfunc2.c:1346
PIXA * pixaCreate(l_int32 n)
pixaCreate()
Definition: pixabasic.c:163
l_ok boxaGetSizes(BOXA *boxa, NUMA **pnaw, NUMA **pnah)
boxaGetSizes()
Definition: boxfunc4.c:1231
l_ok gplotMakeOutput(GPLOT *gplot)
gplotMakeOutput()
Definition: gplot.c:379
GPLOT * gplotCreate(const char *rootname, l_int32 outformat, const char *title, const char *xlabel, const char *ylabel)
gplotCreate()
Definition: gplot.c:138
BOXA * boxaReconcilePairWidth(BOXA *boxas, l_int32 delw, l_int32 op, l_float32 factor, NUMA *na)
boxaReconcilePairWidth()
Definition: boxfunc5.c:1006
BOXA * boxaFillSequence(BOXA *boxas, l_int32 useflag, l_int32 debug)
boxaFillSequence()
Definition: boxfunc5.c:1829
l_ok boxGetSideLocations(BOX *box, l_int32 *pl, l_int32 *pr, l_int32 *pt, l_int32 *pb)
boxGetSideLocations()
Definition: boxbasic.c:371
l_ok numaGetMedian(NUMA *na, l_float32 *pval)
numaGetMedian()
Definition: numafunc1.c:3135
l_ok boxaSplitEvenOdd(BOXA *boxa, l_int32 fillflag, BOXA **pboxae, BOXA **pboxao)
boxaSplitEvenOdd()
Definition: boxfunc1.c:2450
BOXA * boxaSmoothSequenceLS(BOXA *boxas, l_float32 factor, l_int32 subflag, l_int32 maxdiff, l_int32 extrapixels, l_int32 debug)
boxaSmoothSequenceLS()
Definition: boxfunc5.c:98
l_ok boxaReplaceBox(BOXA *boxa, l_int32 index, BOX *box)
boxaReplaceBox()
Definition: boxbasic.c:946
BOXA * boxaCopy(BOXA *boxa, l_int32 copyflag)
boxaCopy()
Definition: boxbasic.c:534
NUMA * numaCreate(l_int32 n)
numaCreate()
Definition: numabasic.c:187
void boxaDestroy(BOXA **pboxa)
boxaDestroy()
Definition: boxbasic.c:580
BOXA * boxaAdjustHeightToTarget(BOXA *boxad, BOXA *boxas, l_int32 sides, l_int32 target, l_int32 thresh)
boxaAdjustHeightToTarget()
Definition: boxfunc1.c:2038
NUMA * numaWindowedMedian(NUMA *nas, l_int32 halfwin)
numaWindowedMedian()
Definition: numafunc2.c:778
BOXA * boxaSmoothSequenceMedian(BOXA *boxas, l_int32 halfwin, l_int32 subflag, l_int32 maxdiff, l_int32 extrapixels, l_int32 debug)
boxaSmoothSequenceMedian()
Definition: boxfunc5.c:204
l_ok ptaGetLinearLSF(PTA *pta, l_float32 *pa, l_float32 *pb, NUMA **pnafit)
ptaGetLinearLSF()
Definition: ptafunc1.c:1044
Definition: pix.h:492
PIX * pixaDisplayTiledInColumns(PIXA *pixas, l_int32 nx, l_float32 scalefactor, l_int32 spacing, l_int32 border)
pixaDisplayTiledInColumns()
Definition: pixafunc2.c:1020
BOXA * boxaConstrainSize(BOXA *boxas, l_int32 width, l_int32 widthflag, l_int32 height, l_int32 heightflag)
boxaConstrainSize()
Definition: boxfunc5.c:716
l_ok boxaExtractAsPta(BOXA *boxa, PTA **pptal, PTA **pptat, PTA **pptar, PTA **pptab, PTA **pptaw, PTA **pptah, l_int32 keepinvalid)
boxaExtractAsPta()
Definition: boxfunc2.c:1178
l_ok boxaPlotSizes(BOXA *boxa, const char *plotname, NUMA **pnaw, NUMA **pnah, PIX **ppixd)
boxaPlotSizes()
Definition: boxfunc5.c:1741
l_int32 stringCat(char *dest, size_t size, const char *src)
stringCat()
Definition: utils2.c:414
l_ok numaGetIValue(NUMA *na, l_int32 index, l_int32 *pival)
numaGetIValue()
Definition: numabasic.c:727
l_ok pixaAddPix(PIXA *pixa, PIX *pix, l_int32 copyflag)
pixaAddPix()
Definition: pixabasic.c:503
Definition: array.h:59
l_ok numaGetMeanDevFromMedian(NUMA *na, l_float32 med, l_float32 *pdev)
numaGetMeanDevFromMedian()
Definition: numafunc1.c:3195
l_ok boxaGetBoxGeometry(BOXA *boxa, l_int32 index, l_int32 *px, l_int32 *py, l_int32 *pw, l_int32 *ph)
boxaGetBoxGeometry()
Definition: boxbasic.c:863
static l_int32 boxaFillAll(BOXA *boxa)
boxaFillAll()
Definition: boxfunc5.c:1888
l_ok boxaAddBox(BOXA *boxa, BOX *box, l_int32 copyflag)
boxaAddBox()
Definition: boxbasic.c:618
l_ok boxaSizeVariation(BOXA *boxa, l_int32 type, l_float32 *pdel_evenodd, l_float32 *prms_even, l_float32 *prms_odd, l_float32 *prms_all)
boxaSizeVariation()
Definition: boxfunc5.c:1972
l_ok boxaWriteDebug(const char *filename, BOXA *boxa)
boxaWriteDebug()
Definition: boxbasic.c:2188
BOX * boxAdjustSides(BOX *boxd, BOX *boxs, l_int32 delleft, l_int32 delright, l_int32 deltop, l_int32 delbot)
boxAdjustSides()
Definition: boxfunc1.c:1807
l_ok boxSetSide(BOX *boxs, l_int32 side, l_int32 val, l_int32 thresh)
boxSetSide()
Definition: boxfunc1.c:1909
Definition: gplot.h:75
void pixDestroy(PIX **ppix)
pixDestroy()
Definition: pix1.c:543
BOXA * boxaLinearFit(BOXA *boxas, l_float32 factor, l_int32 debug)
boxaLinearFit()
Definition: boxfunc5.c:310
BOX * boxaGetBox(BOXA *boxa, l_int32 index, l_int32 accessflag)
boxaGetBox()
Definition: boxbasic.c:763
Definition: pix.h:454
void numaDestroy(NUMA **pna)
numaDestroy()
Definition: numabasic.c:360
static l_int32 boxaTestEvenOddHeight(BOXA *boxa1, BOXA *boxa2, l_int32 start, l_float32 *pdel1, l_float32 *pdel2)
boxaTestEvenOddHeight()
Definition: boxfunc5.c:934
PIX * pixRead(const char *filename)
pixRead()
Definition: readfile.c:190
l_int32 boxaGetValidCount(BOXA *boxa)
boxaGetValidCount()
Definition: boxbasic.c:735
l_ok boxaMedianDimensions(BOXA *boxas, l_int32 *pmedw, l_int32 *pmedh, l_int32 *pmedwe, l_int32 *pmedwo, l_int32 *pmedhe, l_int32 *pmedho, NUMA **pnadelw, NUMA **pnadelh)
boxaMedianDimensions()
Definition: boxfunc5.c:2075
l_ok ptaWriteDebug(const char *filename, PTA *pta, l_int32 type)
ptaWriteDebug()
Definition: ptabasic.c:782
Definition: pix.h:718
l_ok boxaSizeConsistency2(BOXA *boxas, l_float32 *pfdevw, l_float32 *pfdevh, l_int32 debug)
boxaSizeConsistency2()
Definition: boxfunc5.c:1241
BOX * boxCopy(BOX *box)
boxCopy()
Definition: boxbasic.c:230
Definition: pix.h:134
Definition: pix.h:719
void ptaDestroy(PTA **ppta)
ptaDestroy()
Definition: ptabasic.c:192
l_ok numaGetMedianDevFromMedian(NUMA *na, l_float32 *pmed, l_float32 *pdev)
numaGetMedianDevFromMedian()
Definition: numafunc1.c:3241
BOXA * boxaCreate(l_int32 n)
boxaCreate()
Definition: boxbasic.c:499
BOXA * boxaWindowedMedian(BOXA *boxas, l_int32 halfwin, l_int32 debug)
boxaWindowedMedian()
Definition: boxfunc5.c:462
void boxDestroy(BOX **pbox)
boxDestroy()
Definition: boxbasic.c:278
l_int32 boxaGetCount(BOXA *boxa)
boxaGetCount()
Definition: boxbasic.c:718
l_ok boxSetGeometry(BOX *box, l_int32 x, l_int32 y, l_int32 w, l_int32 h)
boxSetGeometry()
Definition: boxbasic.c:340
l_ok boxIsValid(BOX *box, l_int32 *pvalid)
boxIsValid()
Definition: boxbasic.c:472
l_ok boxGetGeometry(BOX *box, l_int32 *px, l_int32 *py, l_int32 *pw, l_int32 *ph)
boxGetGeometry()
Definition: boxbasic.c:310
Definition: pix.h:480
void pixaDestroy(PIXA **ppixa)
pixaDestroy()
Definition: pixabasic.c:408
BOX * boxCreate(l_int32 x, l_int32 y, l_int32 w, l_int32 h)
boxCreate()
Definition: boxbasic.c:165
BOXA * boxaReconcileSizeByMedian(BOXA *boxas, l_int32 type, l_float32 fract, l_float32 factor, NUMA **pnadelw, NUMA **pnadelh, l_float32 *pratiowh)
boxaReconcileSizeByMedian()
Definition: boxfunc5.c:1370
Definition: pix.h:517