Leptonica  1.77.0
Image processing and image analysis suite
boxfunc2.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 
65 #include <math.h>
66 #include "allheaders.h"
67 
68  /* For more than this number of c.c. in a binarized image of
69  * semi-perimeter (w + h) about 5000 or less, the O(n) binsort
70  * is faster than the O(nlogn) shellsort. */
71 static const l_int32 MIN_COMPS_FOR_BIN_SORT = 200;
72 
73 
74 /*---------------------------------------------------------------------*
75  * Boxa/Box transform (shift, scale) and orthogonal rotation *
76  *---------------------------------------------------------------------*/
92 BOXA *
94  l_int32 shiftx,
95  l_int32 shifty,
96  l_float32 scalex,
97  l_float32 scaley)
98 {
99 l_int32 i, n;
100 BOX *boxs, *boxd;
101 BOXA *boxad;
102 
103  PROCNAME("boxaTransform");
104 
105  if (!boxas)
106  return (BOXA *)ERROR_PTR("boxas not defined", procName, NULL);
107  n = boxaGetCount(boxas);
108  if ((boxad = boxaCreate(n)) == NULL)
109  return (BOXA *)ERROR_PTR("boxad not made", procName, NULL);
110  for (i = 0; i < n; i++) {
111  if ((boxs = boxaGetBox(boxas, i, L_CLONE)) == NULL) {
112  boxaDestroy(&boxad);
113  return (BOXA *)ERROR_PTR("boxs not found", procName, NULL);
114  }
115  boxd = boxTransform(boxs, shiftx, shifty, scalex, scaley);
116  boxDestroy(&boxs);
117  boxaAddBox(boxad, boxd, L_INSERT);
118  }
119 
120  return boxad;
121 }
122 
123 
140 BOX *
142  l_int32 shiftx,
143  l_int32 shifty,
144  l_float32 scalex,
145  l_float32 scaley)
146 {
147  PROCNAME("boxTransform");
148 
149  if (!box)
150  return (BOX *)ERROR_PTR("box not defined", procName, NULL);
151  if (box->w <= 0 || box->h <= 0)
152  return boxCreate(0, 0, 0, 0);
153  else
154  return boxCreate((l_int32)(scalex * (box->x + shiftx) + 0.5),
155  (l_int32)(scaley * (box->y + shifty) + 0.5),
156  (l_int32)(L_MAX(1.0, scalex * box->w + 0.5)),
157  (l_int32)(L_MAX(1.0, scaley * box->h + 0.5)));
158 }
159 
160 
197 BOXA *
199  l_int32 shiftx,
200  l_int32 shifty,
201  l_float32 scalex,
202  l_float32 scaley,
203  l_int32 xcen,
204  l_int32 ycen,
205  l_float32 angle,
206  l_int32 order)
207 {
208 l_int32 i, n;
209 BOX *boxs, *boxd;
210 BOXA *boxad;
211 
212  PROCNAME("boxaTransformOrdered");
213 
214  if (!boxas)
215  return (BOXA *)ERROR_PTR("boxas not defined", procName, NULL);
216  n = boxaGetCount(boxas);
217  if ((boxad = boxaCreate(n)) == NULL)
218  return (BOXA *)ERROR_PTR("boxad not made", procName, NULL);
219  for (i = 0; i < n; i++) {
220  if ((boxs = boxaGetBox(boxas, i, L_CLONE)) == NULL) {
221  boxaDestroy(&boxad);
222  return (BOXA *)ERROR_PTR("boxs not found", procName, NULL);
223  }
224  boxd = boxTransformOrdered(boxs, shiftx, shifty, scalex, scaley,
225  xcen, ycen, angle, order);
226  boxDestroy(&boxs);
227  boxaAddBox(boxad, boxd, L_INSERT);
228  }
229 
230  return boxad;
231 }
232 
233 
287 BOX *
289  l_int32 shiftx,
290  l_int32 shifty,
291  l_float32 scalex,
292  l_float32 scaley,
293  l_int32 xcen,
294  l_int32 ycen,
295  l_float32 angle,
296  l_int32 order)
297 {
298 l_int32 bx, by, bw, bh, tx, ty, tw, th;
299 l_int32 xcent, ycent; /* transformed center of rotation due to scaling */
300 l_float32 sina, cosa, xdif, ydif, rx, ry, rw, rh;
301 BOX *boxd;
302 
303  PROCNAME("boxTransformOrdered");
304 
305  if (!boxs)
306  return (BOX *)ERROR_PTR("boxs not defined", procName, NULL);
307  if (order != L_TR_SC_RO && order != L_SC_RO_TR && order != L_RO_TR_SC &&
308  order != L_TR_RO_SC && order != L_RO_SC_TR && order != L_SC_TR_RO)
309  return (BOX *)ERROR_PTR("order invalid", procName, NULL);
310 
311  boxGetGeometry(boxs, &bx, &by, &bw, &bh);
312  if (bw <= 0 || bh <= 0) /* invalid */
313  return boxCreate(0, 0, 0, 0);
314  if (angle != 0.0) {
315  sina = sin(angle);
316  cosa = cos(angle);
317  }
318 
319  if (order == L_TR_SC_RO) {
320  tx = (l_int32)(scalex * (bx + shiftx) + 0.5);
321  ty = (l_int32)(scaley * (by + shifty) + 0.5);
322  tw = (l_int32)(L_MAX(1.0, scalex * bw + 0.5));
323  th = (l_int32)(L_MAX(1.0, scaley * bh + 0.5));
324  xcent = (l_int32)(scalex * xcen + 0.5);
325  ycent = (l_int32)(scaley * ycen + 0.5);
326  if (angle == 0.0) {
327  boxd = boxCreate(tx, ty, tw, th);
328  } else {
329  xdif = tx + 0.5 * tw - xcent;
330  ydif = ty + 0.5 * th - ycent;
331  rw = L_ABS(tw * cosa) + L_ABS(th * sina);
332  rh = L_ABS(th * cosa) + L_ABS(tw * sina);
333  rx = xcent + xdif * cosa - ydif * sina - 0.5 * rw;
334  ry = ycent + ydif * cosa + xdif * sina - 0.5 * rh;
335  boxd = boxCreate((l_int32)rx, (l_int32)ry, (l_int32)rw,
336  (l_int32)rh);
337  }
338  } else if (order == L_SC_TR_RO) {
339  tx = (l_int32)(scalex * bx + shiftx + 0.5);
340  ty = (l_int32)(scaley * by + shifty + 0.5);
341  tw = (l_int32)(L_MAX(1.0, scalex * bw + 0.5));
342  th = (l_int32)(L_MAX(1.0, scaley * bh + 0.5));
343  xcent = (l_int32)(scalex * xcen + 0.5);
344  ycent = (l_int32)(scaley * ycen + 0.5);
345  if (angle == 0.0) {
346  boxd = boxCreate(tx, ty, tw, th);
347  } else {
348  xdif = tx + 0.5 * tw - xcent;
349  ydif = ty + 0.5 * th - ycent;
350  rw = L_ABS(tw * cosa) + L_ABS(th * sina);
351  rh = L_ABS(th * cosa) + L_ABS(tw * sina);
352  rx = xcent + xdif * cosa - ydif * sina - 0.5 * rw;
353  ry = ycent + ydif * cosa + xdif * sina - 0.5 * rh;
354  boxd = boxCreate((l_int32)rx, (l_int32)ry, (l_int32)rw,
355  (l_int32)rh);
356  }
357  } else if (order == L_RO_TR_SC) {
358  if (angle == 0.0) {
359  rx = bx;
360  ry = by;
361  rw = bw;
362  rh = bh;
363  } else {
364  xdif = bx + 0.5 * bw - xcen;
365  ydif = by + 0.5 * bh - ycen;
366  rw = L_ABS(bw * cosa) + L_ABS(bh * sina);
367  rh = L_ABS(bh * cosa) + L_ABS(bw * sina);
368  rx = xcen + xdif * cosa - ydif * sina - 0.5 * rw;
369  ry = ycen + ydif * cosa + xdif * sina - 0.5 * rh;
370  }
371  tx = (l_int32)(scalex * (rx + shiftx) + 0.5);
372  ty = (l_int32)(scaley * (ry + shifty) + 0.5);
373  tw = (l_int32)(L_MAX(1.0, scalex * rw + 0.5));
374  th = (l_int32)(L_MAX(1.0, scaley * rh + 0.5));
375  boxd = boxCreate(tx, ty, tw, th);
376  } else if (order == L_RO_SC_TR) {
377  if (angle == 0.0) {
378  rx = bx;
379  ry = by;
380  rw = bw;
381  rh = bh;
382  } else {
383  xdif = bx + 0.5 * bw - xcen;
384  ydif = by + 0.5 * bh - ycen;
385  rw = L_ABS(bw * cosa) + L_ABS(bh * sina);
386  rh = L_ABS(bh * cosa) + L_ABS(bw * sina);
387  rx = xcen + xdif * cosa - ydif * sina - 0.5 * rw;
388  ry = ycen + ydif * cosa + xdif * sina - 0.5 * rh;
389  }
390  tx = (l_int32)(scalex * rx + shiftx + 0.5);
391  ty = (l_int32)(scaley * ry + shifty + 0.5);
392  tw = (l_int32)(L_MAX(1.0, scalex * rw + 0.5));
393  th = (l_int32)(L_MAX(1.0, scaley * rh + 0.5));
394  boxd = boxCreate(tx, ty, tw, th);
395  } else if (order == L_TR_RO_SC) {
396  tx = bx + shiftx;
397  ty = by + shifty;
398  if (angle == 0.0) {
399  rx = tx;
400  ry = ty;
401  rw = bw;
402  rh = bh;
403  } else {
404  xdif = tx + 0.5 * bw - xcen;
405  ydif = ty + 0.5 * bh - ycen;
406  rw = L_ABS(bw * cosa) + L_ABS(bh * sina);
407  rh = L_ABS(bh * cosa) + L_ABS(bw * sina);
408  rx = xcen + xdif * cosa - ydif * sina - 0.5 * rw;
409  ry = ycen + ydif * cosa + xdif * sina - 0.5 * rh;
410  }
411  tx = (l_int32)(scalex * rx + 0.5);
412  ty = (l_int32)(scaley * ry + 0.5);
413  tw = (l_int32)(L_MAX(1.0, scalex * rw + 0.5));
414  th = (l_int32)(L_MAX(1.0, scaley * rh + 0.5));
415  boxd = boxCreate(tx, ty, tw, th);
416  } else { /* order == L_SC_RO_TR) */
417  tx = (l_int32)(scalex * bx + 0.5);
418  ty = (l_int32)(scaley * by + 0.5);
419  tw = (l_int32)(L_MAX(1.0, scalex * bw + 0.5));
420  th = (l_int32)(L_MAX(1.0, scaley * bh + 0.5));
421  xcent = (l_int32)(scalex * xcen + 0.5);
422  ycent = (l_int32)(scaley * ycen + 0.5);
423  if (angle == 0.0) {
424  rx = tx;
425  ry = ty;
426  rw = tw;
427  rh = th;
428  } else {
429  xdif = tx + 0.5 * tw - xcent;
430  ydif = ty + 0.5 * th - ycent;
431  rw = L_ABS(tw * cosa) + L_ABS(th * sina);
432  rh = L_ABS(th * cosa) + L_ABS(tw * sina);
433  rx = xcent + xdif * cosa - ydif * sina - 0.5 * rw;
434  ry = ycent + ydif * cosa + xdif * sina - 0.5 * rh;
435  }
436  tx = (l_int32)(rx + shiftx + 0.5);
437  ty = (l_int32)(ry + shifty + 0.5);
438  tw = (l_int32)(rw + 0.5);
439  th = (l_int32)(rh + 0.5);
440  boxd = boxCreate(tx, ty, tw, th);
441  }
442 
443  return boxd;
444 }
445 
446 
461 BOXA *
463  l_int32 w,
464  l_int32 h,
465  l_int32 rotation)
466 {
467 l_int32 i, n;
468 BOX *boxs, *boxd;
469 BOXA *boxad;
470 
471  PROCNAME("boxaRotateOrth");
472 
473  if (!boxas)
474  return (BOXA *)ERROR_PTR("boxas not defined", procName, NULL);
475  if (rotation < 0 || rotation > 3)
476  return (BOXA *)ERROR_PTR("rotation not in {0,1,2,3}", procName, NULL);
477  if (rotation == 0)
478  return boxaCopy(boxas, L_COPY);
479 
480  n = boxaGetCount(boxas);
481  if ((boxad = boxaCreate(n)) == NULL)
482  return (BOXA *)ERROR_PTR("boxad not made", procName, NULL);
483  for (i = 0; i < n; i++) {
484  if ((boxs = boxaGetBox(boxas, i, L_CLONE)) == NULL) {
485  boxaDestroy(&boxad);
486  return (BOXA *)ERROR_PTR("boxs not found", procName, NULL);
487  }
488  boxd = boxRotateOrth(boxs, w, h, rotation);
489  boxDestroy(&boxs);
490  boxaAddBox(boxad, boxd, L_INSERT);
491  }
492 
493  return boxad;
494 }
495 
496 
513 BOX *
515  l_int32 w,
516  l_int32 h,
517  l_int32 rotation)
518 {
519 l_int32 bx, by, bw, bh, xdist, ydist;
520 
521  PROCNAME("boxRotateOrth");
522 
523  if (!box)
524  return (BOX *)ERROR_PTR("box not defined", procName, NULL);
525  if (rotation < 0 || rotation > 3)
526  return (BOX *)ERROR_PTR("rotation not in {0,1,2,3}", procName, NULL);
527  if (rotation == 0)
528  return boxCopy(box);
529 
530  boxGetGeometry(box, &bx, &by, &bw, &bh);
531  if (bw <= 0 || bh <= 0) /* invalid */
532  return boxCreate(0, 0, 0, 0);
533  ydist = h - by - bh; /* below box */
534  xdist = w - bx - bw; /* to right of box */
535  if (rotation == 1) /* 90 deg cw */
536  return boxCreate(ydist, bx, bh, bw);
537  else if (rotation == 2) /* 180 deg cw */
538  return boxCreate(xdist, ydist, bw, bh);
539  else /* rotation == 3, 270 deg cw */
540  return boxCreate(by, xdist, bh, bw);
541 }
542 
543 
544 /*---------------------------------------------------------------------*
545  * Boxa sort *
546  *---------------------------------------------------------------------*/
567 BOXA *
568 boxaSort(BOXA *boxas,
569  l_int32 sorttype,
570  l_int32 sortorder,
571  NUMA **pnaindex)
572 {
573 l_int32 i, n, x, y, w, h, size;
574 BOXA *boxad;
575 NUMA *na, *naindex;
576 
577  PROCNAME("boxaSort");
578 
579  if (pnaindex) *pnaindex = NULL;
580  if (!boxas)
581  return (BOXA *)ERROR_PTR("boxas not defined", procName, NULL);
582  if ((n = boxaGetCount(boxas)) == 0) {
583  L_WARNING("boxas is empty\n", procName);
584  return boxaCopy(boxas, L_COPY);
585  }
586  if (sorttype != L_SORT_BY_X && sorttype != L_SORT_BY_Y &&
587  sorttype != L_SORT_BY_RIGHT && sorttype != L_SORT_BY_BOT &&
588  sorttype != L_SORT_BY_WIDTH && sorttype != L_SORT_BY_HEIGHT &&
589  sorttype != L_SORT_BY_MIN_DIMENSION &&
590  sorttype != L_SORT_BY_MAX_DIMENSION &&
591  sorttype != L_SORT_BY_PERIMETER &&
592  sorttype != L_SORT_BY_AREA &&
593  sorttype != L_SORT_BY_ASPECT_RATIO)
594  return (BOXA *)ERROR_PTR("invalid sort type", procName, NULL);
595  if (sortorder != L_SORT_INCREASING && sortorder != L_SORT_DECREASING)
596  return (BOXA *)ERROR_PTR("invalid sort order", procName, NULL);
597 
598  /* Use O(n) binsort if possible */
599  if (n > MIN_COMPS_FOR_BIN_SORT &&
600  ((sorttype == L_SORT_BY_X) || (sorttype == L_SORT_BY_Y) ||
601  (sorttype == L_SORT_BY_WIDTH) || (sorttype == L_SORT_BY_HEIGHT) ||
602  (sorttype == L_SORT_BY_PERIMETER)))
603  return boxaBinSort(boxas, sorttype, sortorder, pnaindex);
604 
605  /* Build up numa of specific data */
606  if ((na = numaCreate(n)) == NULL)
607  return (BOXA *)ERROR_PTR("na not made", procName, NULL);
608  for (i = 0; i < n; i++) {
609  boxaGetBoxGeometry(boxas, i, &x, &y, &w, &h);
610  switch (sorttype)
611  {
612  case L_SORT_BY_X:
613  numaAddNumber(na, x);
614  break;
615  case L_SORT_BY_Y:
616  numaAddNumber(na, y);
617  break;
618  case L_SORT_BY_RIGHT:
619  numaAddNumber(na, x + w - 1);
620  break;
621  case L_SORT_BY_BOT:
622  numaAddNumber(na, y + h - 1);
623  break;
624  case L_SORT_BY_WIDTH:
625  numaAddNumber(na, w);
626  break;
627  case L_SORT_BY_HEIGHT:
628  numaAddNumber(na, h);
629  break;
631  size = L_MIN(w, h);
632  numaAddNumber(na, size);
633  break;
635  size = L_MAX(w, h);
636  numaAddNumber(na, size);
637  break;
638  case L_SORT_BY_PERIMETER:
639  size = w + h;
640  numaAddNumber(na, size);
641  break;
642  case L_SORT_BY_AREA:
643  size = w * h;
644  numaAddNumber(na, size);
645  break;
647  numaAddNumber(na, (l_float32)w / (l_float32)h);
648  break;
649  default:
650  L_WARNING("invalid sort type\n", procName);
651  }
652  }
653 
654  /* Get the sort index for data array */
655  naindex = numaGetSortIndex(na, sortorder);
656  numaDestroy(&na);
657  if (!naindex)
658  return (BOXA *)ERROR_PTR("naindex not made", procName, NULL);
659 
660  /* Build up sorted boxa using sort index */
661  boxad = boxaSortByIndex(boxas, naindex);
662 
663  if (pnaindex)
664  *pnaindex = naindex;
665  else
666  numaDestroy(&naindex);
667  return boxad;
668 }
669 
670 
691 BOXA *
693  l_int32 sorttype,
694  l_int32 sortorder,
695  NUMA **pnaindex)
696 {
697 l_int32 i, n, x, y, w, h;
698 BOXA *boxad;
699 NUMA *na, *naindex;
700 
701  PROCNAME("boxaBinSort");
702 
703  if (pnaindex) *pnaindex = NULL;
704  if (!boxas)
705  return (BOXA *)ERROR_PTR("boxas not defined", procName, NULL);
706  if ((n = boxaGetCount(boxas)) == 0) {
707  L_WARNING("boxas is empty\n", procName);
708  return boxaCopy(boxas, L_COPY);
709  }
710  if (sorttype != L_SORT_BY_X && sorttype != L_SORT_BY_Y &&
711  sorttype != L_SORT_BY_WIDTH && sorttype != L_SORT_BY_HEIGHT &&
712  sorttype != L_SORT_BY_PERIMETER)
713  return (BOXA *)ERROR_PTR("invalid sort type", procName, NULL);
714  if (sortorder != L_SORT_INCREASING && sortorder != L_SORT_DECREASING)
715  return (BOXA *)ERROR_PTR("invalid sort order", procName, NULL);
716 
717  /* Generate Numa of appropriate box dimensions */
718  if ((na = numaCreate(n)) == NULL)
719  return (BOXA *)ERROR_PTR("na not made", procName, NULL);
720  for (i = 0; i < n; i++) {
721  boxaGetBoxGeometry(boxas, i, &x, &y, &w, &h);
722  switch (sorttype)
723  {
724  case L_SORT_BY_X:
725  numaAddNumber(na, x);
726  break;
727  case L_SORT_BY_Y:
728  numaAddNumber(na, y);
729  break;
730  case L_SORT_BY_WIDTH:
731  numaAddNumber(na, w);
732  break;
733  case L_SORT_BY_HEIGHT:
734  numaAddNumber(na, h);
735  break;
736  case L_SORT_BY_PERIMETER:
737  numaAddNumber(na, w + h);
738  break;
739  default:
740  L_WARNING("invalid sort type\n", procName);
741  }
742  }
743 
744  /* Get the sort index for data array */
745  naindex = numaGetBinSortIndex(na, sortorder);
746  numaDestroy(&na);
747  if (!naindex)
748  return (BOXA *)ERROR_PTR("naindex not made", procName, NULL);
749 
750  /* Build up sorted boxa using the sort index */
751  boxad = boxaSortByIndex(boxas, naindex);
752 
753  if (pnaindex)
754  *pnaindex = naindex;
755  else
756  numaDestroy(&naindex);
757  return boxad;
758 }
759 
760 
768 BOXA *
770  NUMA *naindex)
771 {
772 l_int32 i, n, index;
773 BOX *box;
774 BOXA *boxad;
775 
776  PROCNAME("boxaSortByIndex");
777 
778  if (!boxas)
779  return (BOXA *)ERROR_PTR("boxas not defined", procName, NULL);
780  if ((n = boxaGetCount(boxas)) == 0) {
781  L_WARNING("boxas is empty\n", procName);
782  return boxaCopy(boxas, L_COPY);
783  }
784  if (!naindex)
785  return (BOXA *)ERROR_PTR("naindex not defined", procName, NULL);
786 
787  boxad = boxaCreate(n);
788  for (i = 0; i < n; i++) {
789  numaGetIValue(naindex, i, &index);
790  box = boxaGetBox(boxas, index, L_COPY);
791  boxaAddBox(boxad, box, L_INSERT);
792  }
793 
794  return boxad;
795 }
796 
797 
844 BOXAA *
846  NUMAA **pnaad,
847  l_int32 delta1,
848  l_int32 delta2,
849  l_int32 minh1)
850 {
851 l_int32 i, index, h, nt, ne, n, m, ival;
852 BOX *box;
853 BOXA *boxa, *boxae, *boxan, *boxa1, *boxa2, *boxa3, *boxav, *boxavs;
854 BOXAA *baa, *baa1, *baad;
855 NUMA *naindex, *nae, *nan, *nah, *nav, *na1, *na2, *nad, *namap;
856 NUMAA *naa, *naa1, *naad;
857 
858  PROCNAME("boxaSort2d");
859 
860  if (pnaad) *pnaad = NULL;
861  if (!boxas)
862  return (BOXAA *)ERROR_PTR("boxas not defined", procName, NULL);
863  if (boxaGetCount(boxas) == 0)
864  return (BOXAA *)ERROR_PTR("boxas is empty", procName, NULL);
865 
866  /* Sort from left to right */
867  if ((boxa = boxaSort(boxas, L_SORT_BY_X, L_SORT_INCREASING, &naindex))
868  == NULL)
869  return (BOXAA *)ERROR_PTR("boxa not made", procName, NULL);
870 
871  /* First pass: assign taller boxes to boxa by row */
872  nt = boxaGetCount(boxa);
873  baa = boxaaCreate(0);
874  naa = numaaCreate(0);
875  boxae = boxaCreate(0); /* save small height boxes here */
876  nae = numaCreate(0); /* keep track of small height boxes */
877  for (i = 0; i < nt; i++) {
878  box = boxaGetBox(boxa, i, L_CLONE);
879  boxGetGeometry(box, NULL, NULL, NULL, &h);
880  if (h < minh1) { /* save for 2nd pass */
881  boxaAddBox(boxae, box, L_INSERT);
882  numaAddNumber(nae, i);
883  } else {
884  n = boxaaGetCount(baa);
885  boxaaAlignBox(baa, box, delta1, &index);
886  if (index < n) { /* append to an existing boxa */
887  boxaaAddBox(baa, index, box, L_INSERT);
888  } else { /* doesn't align, need new boxa */
889  boxan = boxaCreate(0);
890  boxaAddBox(boxan, box, L_INSERT);
891  boxaaAddBoxa(baa, boxan, L_INSERT);
892  nan = numaCreate(0);
893  numaaAddNuma(naa, nan, L_INSERT);
894  }
895  numaGetIValue(naindex, i, &ival);
896  numaaAddNumber(naa, index, ival);
897  }
898  }
899  boxaDestroy(&boxa);
900  numaDestroy(&naindex);
901 
902  /* Second pass: feed in small height boxes */
903  ne = boxaGetCount(boxae);
904  for (i = 0; i < ne; i++) {
905  box = boxaGetBox(boxae, i, L_CLONE);
906  n = boxaaGetCount(baa);
907  boxaaAlignBox(baa, box, delta2, &index);
908  if (index < n) { /* append to an existing boxa */
909  boxaaAddBox(baa, index, box, L_INSERT);
910  } else { /* doesn't align, need new boxa */
911  boxan = boxaCreate(0);
912  boxaAddBox(boxan, box, L_INSERT);
913  boxaaAddBoxa(baa, boxan, L_INSERT);
914  nan = numaCreate(0);
915  numaaAddNuma(naa, nan, L_INSERT);
916  }
917  numaGetIValue(nae, i, &ival); /* location in original boxas */
918  numaaAddNumber(naa, index, ival);
919  }
920 
921  /* Third pass: merge some boxa whose extent is overlapping.
922  * Think of these boxa as text lines, where the bounding boxes
923  * of the text lines can overlap, but likely won't have
924  * a huge overlap.
925  * First do a greedy find of pairs of overlapping boxa, where
926  * the two boxa overlap by at least 50% of the smaller, and
927  * the smaller is not more than half the area of the larger.
928  * For such pairs, call the larger one the primary boxa. The
929  * boxes in the smaller one are appended to those in the primary
930  * in pass 3a, and the primaries are extracted in pass 3b.
931  * In this way, all boxes in the original baa are saved. */
932  n = boxaaGetCount(baa);
933  boxaaGetExtent(baa, NULL, NULL, NULL, &boxa3);
934  boxa1 = boxaHandleOverlaps(boxa3, L_REMOVE_SMALL, 1000, 0.5, 0.5, &namap);
935  boxaDestroy(&boxa1);
936  boxaDestroy(&boxa3);
937  for (i = 0; i < n; i++) { /* Pass 3a: join selected copies of boxa */
938  numaGetIValue(namap, i, &ival);
939  if (ival >= 0) { /* join current to primary boxa[ival] */
940  boxa1 = boxaaGetBoxa(baa, i, L_COPY);
941  boxa2 = boxaaGetBoxa(baa, ival, L_CLONE);
942  boxaJoin(boxa2, boxa1, 0, -1);
943  boxaDestroy(&boxa2);
944  boxaDestroy(&boxa1);
945  na1 = numaaGetNuma(naa, i, L_COPY);
946  na2 = numaaGetNuma(naa, ival, L_CLONE);
947  numaJoin(na2, na1, 0, -1);
948  numaDestroy(&na1);
949  numaDestroy(&na2);
950  }
951  }
952  baa1 = boxaaCreate(n);
953  naa1 = numaaCreate(n);
954  for (i = 0; i < n; i++) { /* Pass 3b: save primary boxa */
955  numaGetIValue(namap, i, &ival);
956  if (ival == -1) {
957  boxa1 = boxaaGetBoxa(baa, i, L_CLONE);
958  boxaaAddBoxa(baa1, boxa1, L_INSERT);
959  na1 = numaaGetNuma(naa, i, L_CLONE);
960  numaaAddNuma(naa1, na1, L_INSERT);
961  }
962  }
963  numaDestroy(&namap);
964  boxaaDestroy(&baa);
965  baa = baa1;
966  numaaDestroy(&naa);
967  naa = naa1;
968 
969  /* Sort the boxes in each boxa horizontally */
970  m = boxaaGetCount(baa);
971  for (i = 0; i < m; i++) {
972  boxa1 = boxaaGetBoxa(baa, i, L_CLONE);
973  boxa2 = boxaSort(boxa1, L_SORT_BY_X, L_SORT_INCREASING, &nah);
974  boxaaReplaceBoxa(baa, i, boxa2);
975  na1 = numaaGetNuma(naa, i, L_CLONE);
976  na2 = numaSortByIndex(na1, nah);
977  numaaReplaceNuma(naa, i, na2);
978  boxaDestroy(&boxa1);
979  numaDestroy(&na1);
980  numaDestroy(&nah);
981  }
982 
983  /* Sort the boxa vertically within boxaa, using the first box
984  * in each boxa. */
985  m = boxaaGetCount(baa);
986  boxav = boxaCreate(m); /* holds first box in each boxa in baa */
987  naad = numaaCreate(m);
988  if (pnaad)
989  *pnaad = naad;
990  baad = boxaaCreate(m);
991  for (i = 0; i < m; i++) {
992  boxa1 = boxaaGetBoxa(baa, i, L_CLONE);
993  box = boxaGetBox(boxa1, 0, L_CLONE);
994  boxaAddBox(boxav, box, L_INSERT);
995  boxaDestroy(&boxa1);
996  }
997  boxavs = boxaSort(boxav, L_SORT_BY_Y, L_SORT_INCREASING, &nav);
998  for (i = 0; i < m; i++) {
999  numaGetIValue(nav, i, &index);
1000  boxa = boxaaGetBoxa(baa, index, L_CLONE);
1001  boxaaAddBoxa(baad, boxa, L_INSERT);
1002  nad = numaaGetNuma(naa, index, L_CLONE);
1003  numaaAddNuma(naad, nad, L_INSERT);
1004  }
1005 
1006 
1007 /* fprintf(stderr, "box count = %d, numaa count = %d\n", nt,
1008  numaaGetNumberCount(naad)); */
1009 
1010  boxaaDestroy(&baa);
1011  boxaDestroy(&boxav);
1012  boxaDestroy(&boxavs);
1013  boxaDestroy(&boxae);
1014  numaDestroy(&nav);
1015  numaDestroy(&nae);
1016  numaaDestroy(&naa);
1017  if (!pnaad)
1018  numaaDestroy(&naad);
1019 
1020  return baad;
1021 }
1022 
1023 
1031 BOXAA *
1033  NUMAA *naa)
1034 {
1035 l_int32 ntot, boxtot, i, j, n, nn, index;
1036 BOX *box;
1037 BOXA *boxa;
1038 BOXAA *baa;
1039 NUMA *na;
1040 
1041  PROCNAME("boxaSort2dByIndex");
1042 
1043  if (!boxas)
1044  return (BOXAA *)ERROR_PTR("boxas not defined", procName, NULL);
1045  if ((boxtot = boxaGetCount(boxas)) == 0)
1046  return (BOXAA *)ERROR_PTR("boxas is empty", procName, NULL);
1047  if (!naa)
1048  return (BOXAA *)ERROR_PTR("naindex not defined", procName, NULL);
1049 
1050  /* Check counts */
1051  ntot = numaaGetNumberCount(naa);
1052  if (ntot != boxtot)
1053  return (BOXAA *)ERROR_PTR("element count mismatch", procName, NULL);
1054 
1055  n = numaaGetCount(naa);
1056  baa = boxaaCreate(n);
1057  for (i = 0; i < n; i++) {
1058  na = numaaGetNuma(naa, i, L_CLONE);
1059  nn = numaGetCount(na);
1060  boxa = boxaCreate(nn);
1061  for (j = 0; j < nn; j++) {
1062  numaGetIValue(na, i, &index);
1063  box = boxaGetBox(boxas, index, L_COPY);
1064  boxaAddBox(boxa, box, L_INSERT);
1065  }
1066  boxaaAddBoxa(baa, boxa, L_INSERT);
1067  numaDestroy(&na);
1068  }
1069 
1070  return baa;
1071 }
1072 
1073 
1074 /*---------------------------------------------------------------------*
1075  * Boxa array extraction *
1076  *---------------------------------------------------------------------*/
1100 l_ok
1102  NUMA **pnal,
1103  NUMA **pnat,
1104  NUMA **pnar,
1105  NUMA **pnab,
1106  NUMA **pnaw,
1107  NUMA **pnah,
1108  l_int32 keepinvalid)
1109 {
1110 l_int32 i, n, left, top, right, bot, w, h;
1111 
1112  PROCNAME("boxaExtractAsNuma");
1113 
1114  if (!pnal && !pnat && !pnar && !pnab && !pnaw && !pnah)
1115  return ERROR_INT("no output requested", procName, 1);
1116  if (pnal) *pnal = NULL;
1117  if (pnat) *pnat = NULL;
1118  if (pnar) *pnar = NULL;
1119  if (pnab) *pnab = NULL;
1120  if (pnaw) *pnaw = NULL;
1121  if (pnah) *pnah = NULL;
1122  if (!boxa)
1123  return ERROR_INT("boxa not defined", procName, 1);
1124  if (!keepinvalid && boxaGetValidCount(boxa) == 0)
1125  return ERROR_INT("no valid boxes", procName, 1);
1126 
1127  n = boxaGetCount(boxa);
1128  if (pnal) *pnal = numaCreate(n);
1129  if (pnat) *pnat = numaCreate(n);
1130  if (pnar) *pnar = numaCreate(n);
1131  if (pnab) *pnab = numaCreate(n);
1132  if (pnaw) *pnaw = numaCreate(n);
1133  if (pnah) *pnah = numaCreate(n);
1134  for (i = 0; i < n; i++) {
1135  boxaGetBoxGeometry(boxa, i, &left, &top, &w, &h);
1136  if (!keepinvalid && (w <= 0 || h <= 0))
1137  continue;
1138  right = left + w - 1;
1139  bot = top + h - 1;
1140  if (pnal) numaAddNumber(*pnal, left);
1141  if (pnat) numaAddNumber(*pnat, top);
1142  if (pnar) numaAddNumber(*pnar, right);
1143  if (pnab) numaAddNumber(*pnab, bot);
1144  if (pnaw) numaAddNumber(*pnaw, w);
1145  if (pnah) numaAddNumber(*pnah, h);
1146  }
1147 
1148  return 0;
1149 }
1150 
1151 
1177 l_ok
1179  PTA **pptal,
1180  PTA **pptat,
1181  PTA **pptar,
1182  PTA **pptab,
1183  PTA **pptaw,
1184  PTA **pptah,
1185  l_int32 keepinvalid)
1186 {
1187 l_int32 i, n, left, top, right, bot, w, h;
1188 
1189  PROCNAME("boxaExtractAsPta");
1190 
1191  if (!pptal && !pptar && !pptat && !pptab && !pptaw && !pptah)
1192  return ERROR_INT("no output requested", procName, 1);
1193  if (pptal) *pptal = NULL;
1194  if (pptat) *pptat = NULL;
1195  if (pptar) *pptar = NULL;
1196  if (pptab) *pptab = NULL;
1197  if (pptaw) *pptaw = NULL;
1198  if (pptah) *pptah = NULL;
1199  if (!boxa)
1200  return ERROR_INT("boxa not defined", procName, 1);
1201  if (!keepinvalid && boxaGetValidCount(boxa) == 0)
1202  return ERROR_INT("no valid boxes", procName, 1);
1203 
1204  n = boxaGetCount(boxa);
1205  if (pptal) *pptal = ptaCreate(n);
1206  if (pptat) *pptat = ptaCreate(n);
1207  if (pptar) *pptar = ptaCreate(n);
1208  if (pptab) *pptab = ptaCreate(n);
1209  if (pptaw) *pptaw = ptaCreate(n);
1210  if (pptah) *pptah = ptaCreate(n);
1211  for (i = 0; i < n; i++) {
1212  boxaGetBoxGeometry(boxa, i, &left, &top, &w, &h);
1213  if (!keepinvalid && (w <= 0 || h <= 0))
1214  continue;
1215  right = left + w - 1;
1216  bot = top + h - 1;
1217  if (pptal) ptaAddPt(*pptal, i, left);
1218  if (pptat) ptaAddPt(*pptat, i, top);
1219  if (pptar) ptaAddPt(*pptar, i, right);
1220  if (pptab) ptaAddPt(*pptab, i, bot);
1221  if (pptaw) ptaAddPt(*pptaw, i, w);
1222  if (pptah) ptaAddPt(*pptah, i, h);
1223  }
1224 
1225  return 0;
1226 }
1227 
1228 
1229 /*---------------------------------------------------------------------*
1230  * Boxa statistics *
1231  *---------------------------------------------------------------------*/
1263 l_ok
1265  l_float32 fract,
1266  l_int32 *px,
1267  l_int32 *py,
1268  l_int32 *pr,
1269  l_int32 *pb,
1270  l_int32 *pw,
1271  l_int32 *ph)
1272 {
1273 l_float32 xval, yval, rval, bval, wval, hval;
1274 NUMA *nax, *nay, *nar, *nab, *naw, *nah;
1275 
1276  PROCNAME("boxaGetRankVals");
1277 
1278  if (px) *px = 0;
1279  if (py) *py = 0;
1280  if (pr) *pr = 0;
1281  if (pb) *pb = 0;
1282  if (pw) *pw = 0;
1283  if (ph) *ph = 0;
1284  if (!boxa)
1285  return ERROR_INT("boxa not defined", procName, 1);
1286  if (fract < 0.0 || fract > 1.0)
1287  return ERROR_INT("fract not in [0.0 ... 1.0]", procName, 1);
1288  if (boxaGetValidCount(boxa) == 0)
1289  return ERROR_INT("no valid boxes in boxa", procName, 1);
1290 
1291  /* Use only the valid boxes */
1292  boxaExtractAsNuma(boxa, &nax, &nay, &nar, &nab, &naw, &nah, 0);
1293 
1294  if (px) {
1295  numaGetRankValue(nax, 1.0 - fract, NULL, 1, &xval);
1296  *px = (l_int32)xval;
1297  }
1298  if (py) {
1299  numaGetRankValue(nay, 1.0 - fract, NULL, 1, &yval);
1300  *py = (l_int32)yval;
1301  }
1302  if (pr) {
1303  numaGetRankValue(nar, fract, NULL, 1, &rval);
1304  *pr = (l_int32)rval;
1305  }
1306  if (pb) {
1307  numaGetRankValue(nab, fract, NULL, 1, &bval);
1308  *pb = (l_int32)bval;
1309  }
1310  if (pw) {
1311  numaGetRankValue(naw, fract, NULL, 1, &wval);
1312  *pw = (l_int32)wval;
1313  }
1314  if (ph) {
1315  numaGetRankValue(nah, fract, NULL, 1, &hval);
1316  *ph = (l_int32)hval;
1317  }
1318  numaDestroy(&nax);
1319  numaDestroy(&nay);
1320  numaDestroy(&nar);
1321  numaDestroy(&nab);
1322  numaDestroy(&naw);
1323  numaDestroy(&nah);
1324  return 0;
1325 }
1326 
1327 
1345 l_ok
1347  l_int32 *px,
1348  l_int32 *py,
1349  l_int32 *pr,
1350  l_int32 *pb,
1351  l_int32 *pw,
1352  l_int32 *ph)
1353 {
1354  PROCNAME("boxaGetMedianVals");
1355 
1356  if (!boxa)
1357  return ERROR_INT("boxa not defined", procName, 1);
1358  if (boxaGetValidCount(boxa) == 0)
1359  return ERROR_INT("no valid boxes in boxa", procName, 1);
1360 
1361  return boxaGetRankVals(boxa, 0.5, px, py, pr, pb, pw, ph);
1362 }
1363 
1364 
1373 l_ok
1375  l_float32 *pw,
1376  l_float32 *ph)
1377 {
1378 l_int32 i, n, bw, bh;
1379 l_float32 sumw, sumh;
1380 
1381  PROCNAME("boxaGetAverageSize");
1382 
1383  if (pw) *pw = 0.0;
1384  if (ph) *ph = 0.0;
1385  if (!boxa)
1386  return ERROR_INT("boxa not defined", procName, 1);
1387  if ((n = boxaGetCount(boxa)) == 0)
1388  return ERROR_INT("boxa is empty", procName, 1);
1389 
1390  sumw = sumh = 0.0;
1391  for (i = 0; i < n; i++) {
1392  boxaGetBoxGeometry(boxa, i, NULL, NULL, &bw, &bh);
1393  sumw += bw;
1394  sumh += bh;
1395  }
1396 
1397  if (pw) *pw = sumw / n;
1398  if (ph) *ph = sumh / n;
1399  return 0;
1400 }
1401 
1402 
1403 /*---------------------------------------------------------------------*
1404  * Other Boxaa functions *
1405  *---------------------------------------------------------------------*/
1428 l_ok
1430  l_int32 *pw,
1431  l_int32 *ph,
1432  BOX **pbox,
1433  BOXA **pboxa)
1434 {
1435 l_int32 i, n, x, y, w, h, xmax, ymax, xmin, ymin, found;
1436 BOX *box1;
1437 BOXA *boxa, *boxa1;
1438 
1439  PROCNAME("boxaaGetExtent");
1440 
1441  if (!pw && !ph && !pbox && !pboxa)
1442  return ERROR_INT("no ptrs defined", procName, 1);
1443  if (pw) *pw = 0;
1444  if (ph) *ph = 0;
1445  if (pbox) *pbox = NULL;
1446  if (pboxa) *pboxa = NULL;
1447  if (!baa)
1448  return ERROR_INT("baa not defined", procName, 1);
1449 
1450  n = boxaaGetCount(baa);
1451  if (n == 0)
1452  return ERROR_INT("no boxa in baa", procName, 1);
1453 
1454  boxa = boxaCreate(n);
1455  xmax = ymax = 0;
1456  xmin = ymin = 100000000;
1457  found = FALSE;
1458  for (i = 0; i < n; i++) {
1459  boxa1 = boxaaGetBoxa(baa, i, L_CLONE);
1460  boxaGetExtent(boxa1, NULL, NULL, &box1);
1461  boxaDestroy(&boxa1);
1462  boxGetGeometry(box1, &x, &y, &w, &h);
1463  if (w > 0 && h > 0) { /* a valid extent box */
1464  found = TRUE; /* found at least one valid extent box */
1465  xmin = L_MIN(xmin, x);
1466  ymin = L_MIN(ymin, y);
1467  xmax = L_MAX(xmax, x + w);
1468  ymax = L_MAX(ymax, y + h);
1469  }
1470  boxaAddBox(boxa, box1, L_INSERT);
1471  }
1472  if (found == FALSE) /* no valid extent boxes */
1473  xmin = ymin = 0;
1474 
1475  if (pw) *pw = xmax;
1476  if (ph) *ph = ymax;
1477  if (pbox)
1478  *pbox = boxCreate(xmin, ymin, xmax - xmin, ymax - ymin);
1479  if (pboxa)
1480  *pboxa = boxa;
1481  else
1482  boxaDestroy(&boxa);
1483  return 0;
1484 }
1485 
1486 
1508 BOXA *
1510  NUMA **pnaindex,
1511  l_int32 copyflag)
1512 {
1513 l_int32 i, j, m, n;
1514 BOXA *boxa, *boxat;
1515 BOX *box;
1516 NUMA *naindex;
1517 
1518  PROCNAME("boxaaFlattenToBoxa");
1519 
1520  if (pnaindex) *pnaindex = NULL;
1521  if (!baa)
1522  return (BOXA *)ERROR_PTR("baa not defined", procName, NULL);
1523  if (copyflag != L_COPY && copyflag != L_CLONE)
1524  return (BOXA *)ERROR_PTR("invalid copyflag", procName, NULL);
1525  if (pnaindex) {
1526  naindex = numaCreate(0);
1527  *pnaindex = naindex;
1528  }
1529 
1530  n = boxaaGetCount(baa);
1531  boxa = boxaCreate(n);
1532  for (i = 0; i < n; i++) {
1533  boxat = boxaaGetBoxa(baa, i, L_CLONE);
1534  m = boxaGetCount(boxat);
1535  if (m == 0) { /* placeholder box */
1536  box = boxCreate(0, 0, 0, 0);
1537  boxaAddBox(boxa, box, L_INSERT);
1538  if (pnaindex)
1539  numaAddNumber(naindex, i); /* save 'row' number */
1540  } else {
1541  for (j = 0; j < m; j++) {
1542  box = boxaGetBox(boxat, j, copyflag);
1543  boxaAddBox(boxa, box, L_INSERT);
1544  if (pnaindex)
1545  numaAddNumber(naindex, i); /* save 'row' number */
1546  }
1547  }
1548  boxaDestroy(&boxat);
1549  }
1550 
1551  return boxa;
1552 }
1553 
1554 
1574 BOXA *
1576  l_int32 num,
1577  BOX *fillerbox,
1578  l_int32 copyflag)
1579 {
1580 l_int32 i, j, m, n, mval, nshort;
1581 BOXA *boxat, *boxad;
1582 BOX *box;
1583 
1584  PROCNAME("boxaaFlattenAligned");
1585 
1586  if (!baa)
1587  return (BOXA *)ERROR_PTR("baa not defined", procName, NULL);
1588  if (copyflag != L_COPY && copyflag != L_CLONE)
1589  return (BOXA *)ERROR_PTR("invalid copyflag", procName, NULL);
1590 
1591  n = boxaaGetCount(baa);
1592  boxad = boxaCreate(n);
1593  for (i = 0; i < n; i++) {
1594  boxat = boxaaGetBoxa(baa, i, L_CLONE);
1595  m = boxaGetCount(boxat);
1596  mval = L_MIN(m, num);
1597  nshort = num - mval;
1598  for (j = 0; j < mval; j++) { /* take the first %num if possible */
1599  box = boxaGetBox(boxat, j, copyflag);
1600  boxaAddBox(boxad, box, L_INSERT);
1601  }
1602  for (j = 0; j < nshort; j++) { /* add fillers if necessary */
1603  if (fillerbox) {
1604  boxaAddBox(boxad, fillerbox, L_COPY);
1605  } else {
1606  box = boxCreate(0, 0, 0, 0); /* invalid placeholder box */
1607  boxaAddBox(boxad, box, L_INSERT);
1608  }
1609  }
1610  boxaDestroy(&boxat);
1611  }
1612 
1613  return boxad;
1614 }
1615 
1616 
1632 BOXAA *
1634  l_int32 num,
1635  l_int32 copyflag)
1636 {
1637 l_int32 i, j, n, nbaa, index;
1638 BOX *box;
1639 BOXA *boxat;
1640 BOXAA *baa;
1641 
1642  PROCNAME("boxaEncapsulateAligned");
1643 
1644  if (!boxa)
1645  return (BOXAA *)ERROR_PTR("boxa not defined", procName, NULL);
1646  if (copyflag != L_COPY && copyflag != L_CLONE)
1647  return (BOXAA *)ERROR_PTR("invalid copyflag", procName, NULL);
1648 
1649  n = boxaGetCount(boxa);
1650  nbaa = n / num;
1651  if (num * nbaa != n)
1652  L_ERROR("inconsistent alignment: num doesn't divide n\n", procName);
1653  baa = boxaaCreate(nbaa);
1654  for (i = 0, index = 0; i < nbaa; i++) {
1655  boxat = boxaCreate(num);
1656  for (j = 0; j < num; j++, index++) {
1657  box = boxaGetBox(boxa, index, copyflag);
1658  boxaAddBox(boxat, box, L_INSERT);
1659  }
1660  boxaaAddBoxa(baa, boxat, L_INSERT);
1661  }
1662 
1663  return baa;
1664 }
1665 
1666 
1686 BOXAA *
1688 {
1689 l_int32 i, j, ny, nb, nbox;
1690 BOX *box;
1691 BOXA *boxa;
1692 BOXAA *baad;
1693 
1694  PROCNAME("boxaaTranspose");
1695 
1696  if (!baas)
1697  return (BOXAA *)ERROR_PTR("baas not defined", procName, NULL);
1698  if ((ny = boxaaGetCount(baas)) == 0)
1699  return (BOXAA *)ERROR_PTR("baas empty", procName, NULL);
1700 
1701  /* Make sure that each boxa in baas has the same number of boxes */
1702  for (i = 0; i < ny; i++) {
1703  if ((boxa = boxaaGetBoxa(baas, i, L_CLONE)) == NULL)
1704  return (BOXAA *)ERROR_PTR("baas is missing a boxa", procName, NULL);
1705  nb = boxaGetCount(boxa);
1706  boxaDestroy(&boxa);
1707  if (i == 0)
1708  nbox = nb;
1709  else if (nb != nbox)
1710  return (BOXAA *)ERROR_PTR("boxa are not all the same size",
1711  procName, NULL);
1712  }
1713 
1714  /* baad[i][j] = baas[j][i] */
1715  baad = boxaaCreate(nbox);
1716  for (i = 0; i < nbox; i++) {
1717  boxa = boxaCreate(ny);
1718  for (j = 0; j < ny; j++) {
1719  box = boxaaGetBox(baas, j, i, L_COPY);
1720  boxaAddBox(boxa, box, L_INSERT);
1721  }
1722  boxaaAddBoxa(baad, boxa, L_INSERT);
1723  }
1724  return baad;
1725 }
1726 
1727 
1745 l_ok
1747  BOX *box,
1748  l_int32 delta,
1749  l_int32 *pindex)
1750 {
1751 l_int32 i, n, m, y, yt, h, ht, ovlp, maxovlp, maxindex;
1752 BOX *boxt;
1753 BOXA *boxa;
1754 
1755  PROCNAME("boxaaAlignBox");
1756 
1757  if (pindex) *pindex = 0;
1758  if (!baa)
1759  return ERROR_INT("baa not defined", procName, 1);
1760  if (!box)
1761  return ERROR_INT("box not defined", procName, 1);
1762  if (!pindex)
1763  return ERROR_INT("&index not defined", procName, 1);
1764 
1765  n = boxaaGetCount(baa);
1766  boxGetGeometry(box, NULL, &y, NULL, &h);
1767  maxovlp = -10000000;
1768  for (i = 0; i < n; i++) {
1769  boxa = boxaaGetBoxa(baa, i, L_CLONE);
1770  if ((m = boxaGetCount(boxa)) == 0) {
1771  boxaDestroy(&boxa);
1772  L_WARNING("no boxes in boxa\n", procName);
1773  continue;
1774  }
1775  boxaGetExtent(boxa, NULL, NULL, &boxt);
1776  boxGetGeometry(boxt, NULL, &yt, NULL, &ht);
1777  boxDestroy(&boxt);
1778  boxaDestroy(&boxa);
1779 
1780  /* Overlap < 0 means the components do not overlap vertically */
1781  if (yt >= y)
1782  ovlp = y + h - 1 - yt;
1783  else
1784  ovlp = yt + ht - 1 - y;
1785  if (ovlp > maxovlp) {
1786  maxovlp = ovlp;
1787  maxindex = i;
1788  }
1789  }
1790 
1791  if (maxovlp + delta >= 0)
1792  *pindex = maxindex;
1793  else
1794  *pindex = n;
1795  return 0;
1796 }
BOXAA * boxaSort2dByIndex(BOXA *boxas, NUMAA *naa)
boxaSort2dByIndex()
Definition: boxfunc2.c:1032
BOX * boxRotateOrth(BOX *box, l_int32 w, l_int32 h, l_int32 rotation)
boxRotateOrth()
Definition: boxfunc2.c:514
l_ok boxaJoin(BOXA *boxad, BOXA *boxas, l_int32 istart, l_int32 iend)
boxaJoin()
Definition: boxfunc1.c:2351
Definition: pix.h:717
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
NUMA * numaGetSortIndex(NUMA *na, l_int32 sortorder)
numaGetSortIndex()
Definition: numafunc1.c:2637
BOXA * boxaSort(BOXA *boxas, l_int32 sorttype, l_int32 sortorder, NUMA **pnaindex)
boxaSort()
Definition: boxfunc2.c:568
l_ok boxaaReplaceBoxa(BOXAA *baa, l_int32 index, BOXA *boxa)
boxaaReplaceBoxa()
Definition: boxbasic.c:1634
NUMA * numaSortByIndex(NUMA *nas, NUMA *naindex)
numaSortByIndex()
Definition: numafunc1.c:2786
l_ok ptaAddPt(PTA *pta, l_float32 x, l_float32 y)
ptaAddPt()
Definition: ptabasic.c:342
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
l_int32 numaaGetNumberCount(NUMAA *naa)
numaaGetNumberCount()
Definition: numabasic.c:1589
l_ok boxaaGetExtent(BOXAA *baa, l_int32 *pw, l_int32 *ph, BOX **pbox, BOXA **pboxa)
boxaaGetExtent()
Definition: boxfunc2.c:1429
l_int32 boxaaGetCount(BOXAA *baa)
boxaaGetCount()
Definition: boxbasic.c:1424
NUMA * numaGetBinSortIndex(NUMA *nas, l_int32 sortorder)
numaGetBinSortIndex()
Definition: numafunc1.c:2713
PTA * ptaCreate(l_int32 n)
ptaCreate()
Definition: ptabasic.c:116
l_int32 y
Definition: pix.h:483
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
BOX * boxTransform(BOX *box, l_int32 shiftx, l_int32 shifty, l_float32 scalex, l_float32 scaley)
boxTransform()
Definition: boxfunc2.c:141
BOXA * boxaHandleOverlaps(BOXA *boxas, l_int32 op, l_int32 range, l_float32 min_overlap, l_float32 max_ratio, NUMA **pnamap)
boxaHandleOverlaps()
Definition: boxfunc1.c:853
NUMAA * numaaCreate(l_int32 n)
numaaCreate()
Definition: numabasic.c:1340
Definition: pix.h:492
BOX * boxTransformOrdered(BOX *boxs, l_int32 shiftx, l_int32 shifty, l_float32 scalex, l_float32 scaley, l_int32 xcen, l_int32 ycen, l_float32 angle, l_int32 order)
boxTransformOrdered()
Definition: boxfunc2.c:288
void numaaDestroy(NUMAA **pnaa)
numaaDestroy()
Definition: numabasic.c:1444
Definition: pix.h:502
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 boxaaAddBoxa(BOXAA *baa, BOXA *ba, l_int32 copyflag)
boxaaAddBoxa()
Definition: boxbasic.c:1327
l_ok boxaGetRankVals(BOXA *boxa, l_float32 fract, l_int32 *px, l_int32 *py, l_int32 *pr, l_int32 *pb, l_int32 *pw, l_int32 *ph)
boxaGetRankVals()
Definition: boxfunc2.c:1264
NUMA * numaaGetNuma(NUMAA *naa, l_int32 index, l_int32 accessflag)
numaaGetNuma()
Definition: numabasic.c:1659
l_ok numaGetIValue(NUMA *na, l_int32 index, l_int32 *pival)
numaGetIValue()
Definition: numabasic.c:727
Definition: array.h:59
void boxaaDestroy(BOXAA **pbaa)
boxaaDestroy()
Definition: boxbasic.c:1289
l_ok boxaGetAverageSize(BOXA *boxa, l_float32 *pw, l_float32 *ph)
boxaGetAverageSize()
Definition: boxfunc2.c:1374
BOXA * boxaTransformOrdered(BOXA *boxas, l_int32 shiftx, l_int32 shifty, l_float32 scalex, l_float32 scaley, l_int32 xcen, l_int32 ycen, l_float32 angle, l_int32 order)
boxaTransformOrdered()
Definition: boxfunc2.c:198
BOXA * boxaTransform(BOXA *boxas, l_int32 shiftx, l_int32 shifty, l_float32 scalex, l_float32 scaley)
boxaTransform()
Definition: boxfunc2.c:93
l_int32 numaGetCount(NUMA *na)
numaGetCount()
Definition: numabasic.c:631
l_int32 w
Definition: pix.h:484
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
l_ok boxaAddBox(BOXA *boxa, BOX *box, l_int32 copyflag)
boxaAddBox()
Definition: boxbasic.c:618
l_ok boxaaAddBox(BOXAA *baa, l_int32 index, BOX *box, l_int32 accessflag)
boxaaAddBox()
Definition: boxbasic.c:1761
l_ok boxaaAlignBox(BOXAA *baa, BOX *box, l_int32 delta, l_int32 *pindex)
boxaaAlignBox()
Definition: boxfunc2.c:1746
Definition: array.h:71
BOX * boxaGetBox(BOXA *boxa, l_int32 index, l_int32 accessflag)
boxaGetBox()
Definition: boxbasic.c:763
BOXA * boxaaFlattenAligned(BOXAA *baa, l_int32 num, BOX *fillerbox, l_int32 copyflag)
boxaaFlattenAligned()
Definition: boxfunc2.c:1575
l_ok numaaReplaceNuma(NUMAA *naa, l_int32 index, NUMA *na)
numaaReplaceNuma()
Definition: numabasic.c:1695
l_ok numaaAddNumber(NUMAA *naa, l_int32 index, l_float32 val)
numaaAddNumber()
Definition: numabasic.c:1771
l_int32 x
Definition: pix.h:482
l_ok boxaGetExtent(BOXA *boxa, l_int32 *pw, l_int32 *ph, BOX **pbox)
boxaGetExtent()
Definition: boxfunc4.c:943
void numaDestroy(NUMA **pna)
numaDestroy()
Definition: numabasic.c:360
BOXAA * boxaaTranspose(BOXAA *baas)
boxaaTranspose()
Definition: boxfunc2.c:1687
BOXA * boxaBinSort(BOXA *boxas, l_int32 sorttype, l_int32 sortorder, NUMA **pnaindex)
boxaBinSort()
Definition: boxfunc2.c:692
BOXAA * boxaaCreate(l_int32 n)
boxaaCreate()
Definition: boxbasic.c:1223
BOXA * boxaRotateOrth(BOXA *boxas, l_int32 w, l_int32 h, l_int32 rotation)
boxaRotateOrth()
Definition: boxfunc2.c:462
l_int32 boxaGetValidCount(BOXA *boxa)
boxaGetValidCount()
Definition: boxbasic.c:735
l_ok numaJoin(NUMA *nad, NUMA *nas, l_int32 istart, l_int32 iend)
numaJoin()
Definition: numafunc1.c:3370
l_int32 numaaGetCount(NUMAA *naa)
numaaGetCount()
Definition: numabasic.c:1550
Definition: pix.h:718
l_int32 h
Definition: pix.h:485
BOX * boxCopy(BOX *box)
boxCopy()
Definition: boxbasic.c:230
Definition: pix.h:719
BOX * boxaaGetBox(BOXAA *baa, l_int32 iboxa, l_int32 ibox, l_int32 accessflag)
boxaaGetBox()
Definition: boxbasic.c:1501
BOXA * boxaCreate(l_int32 n)
boxaCreate()
Definition: boxbasic.c:499
void boxDestroy(BOX **pbox)
boxDestroy()
Definition: boxbasic.c:278
BOXAA * boxaSort2d(BOXA *boxas, NUMAA **pnaad, l_int32 delta1, l_int32 delta2, l_int32 minh1)
boxaSort2d()
Definition: boxfunc2.c:845
l_int32 boxaGetCount(BOXA *boxa)
boxaGetCount()
Definition: boxbasic.c:718
BOXAA * boxaEncapsulateAligned(BOXA *boxa, l_int32 num, l_int32 copyflag)
boxaEncapsulateAligned()
Definition: boxfunc2.c:1633
BOXA * boxaaFlattenToBoxa(BOXAA *baa, NUMA **pnaindex, l_int32 copyflag)
boxaaFlattenToBoxa()
Definition: boxfunc2.c:1509
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
BOX * boxCreate(l_int32 x, l_int32 y, l_int32 w, l_int32 h)
boxCreate()
Definition: boxbasic.c:165
l_ok numaGetRankValue(NUMA *na, l_float32 fract, NUMA *nasort, l_int32 usebins, l_float32 *pval)
numaGetRankValue()
Definition: numafunc1.c:3081
l_ok numaaAddNuma(NUMAA *naa, NUMA *na, l_int32 copyflag)
numaaAddNuma()
Definition: numabasic.c:1482
Definition: pix.h:517
BOXA * boxaaGetBoxa(BOXAA *baa, l_int32 index, l_int32 accessflag)
boxaaGetBoxa()
Definition: boxbasic.c:1471
BOXA * boxaSortByIndex(BOXA *boxas, NUMA *naindex)
boxaSortByIndex()
Definition: boxfunc2.c:769