Leptonica  1.73
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  *---------------------------------------------------------------------*/
90 BOXA *
92  l_int32 shiftx,
93  l_int32 shifty,
94  l_float32 scalex,
95  l_float32 scaley)
96 {
97 l_int32 i, n;
98 BOX *boxs, *boxd;
99 BOXA *boxad;
100 
101  PROCNAME("boxaTransform");
102 
103  if (!boxas)
104  return (BOXA *)ERROR_PTR("boxas not defined", procName, NULL);
105  n = boxaGetCount(boxas);
106  if ((boxad = boxaCreate(n)) == NULL)
107  return (BOXA *)ERROR_PTR("boxad not made", procName, NULL);
108  for (i = 0; i < n; i++) {
109  if ((boxs = boxaGetBox(boxas, i, L_CLONE)) == NULL) {
110  boxaDestroy(&boxad);
111  return (BOXA *)ERROR_PTR("boxs not found", procName, NULL);
112  }
113  boxd = boxTransform(boxs, shiftx, shifty, scalex, scaley);
114  boxDestroy(&boxs);
115  boxaAddBox(boxad, boxd, L_INSERT);
116  }
117 
118  return boxad;
119 }
120 
121 
136 BOX *
138  l_int32 shiftx,
139  l_int32 shifty,
140  l_float32 scalex,
141  l_float32 scaley)
142 {
143  PROCNAME("boxTransform");
144 
145  if (!box)
146  return (BOX *)ERROR_PTR("box not defined", procName, NULL);
147  if (box->w <= 0 || box->h <= 0)
148  return boxCreate(0, 0, 0, 0);
149  else
150  return boxCreate((l_int32)(scalex * (box->x + shiftx) + 0.5),
151  (l_int32)(scaley * (box->y + shifty) + 0.5),
152  (l_int32)(L_MAX(1.0, scalex * box->w + 0.5)),
153  (l_int32)(L_MAX(1.0, scaley * box->h + 0.5)));
154 }
155 
156 
191 BOXA *
193  l_int32 shiftx,
194  l_int32 shifty,
195  l_float32 scalex,
196  l_float32 scaley,
197  l_int32 xcen,
198  l_int32 ycen,
199  l_float32 angle,
200  l_int32 order)
201 {
202 l_int32 i, n;
203 BOX *boxs, *boxd;
204 BOXA *boxad;
205 
206  PROCNAME("boxaTransformOrdered");
207 
208  if (!boxas)
209  return (BOXA *)ERROR_PTR("boxas not defined", procName, NULL);
210  n = boxaGetCount(boxas);
211  if ((boxad = boxaCreate(n)) == NULL)
212  return (BOXA *)ERROR_PTR("boxad not made", procName, NULL);
213  for (i = 0; i < n; i++) {
214  if ((boxs = boxaGetBox(boxas, i, L_CLONE)) == NULL) {
215  boxaDestroy(&boxad);
216  return (BOXA *)ERROR_PTR("boxs not found", procName, NULL);
217  }
218  boxd = boxTransformOrdered(boxs, shiftx, shifty, scalex, scaley,
219  xcen, ycen, angle, order);
220  boxDestroy(&boxs);
221  boxaAddBox(boxad, boxd, L_INSERT);
222  }
223 
224  return boxad;
225 }
226 
227 
279 BOX *
281  l_int32 shiftx,
282  l_int32 shifty,
283  l_float32 scalex,
284  l_float32 scaley,
285  l_int32 xcen,
286  l_int32 ycen,
287  l_float32 angle,
288  l_int32 order)
289 {
290 l_int32 bx, by, bw, bh, tx, ty, tw, th;
291 l_int32 xcent, ycent; /* transformed center of rotation due to scaling */
292 l_float32 sina, cosa, xdif, ydif, rx, ry, rw, rh;
293 BOX *boxd;
294 
295  PROCNAME("boxTransformOrdered");
296 
297  if (!boxs)
298  return (BOX *)ERROR_PTR("boxs not defined", procName, NULL);
299  if (order != L_TR_SC_RO && order != L_SC_RO_TR && order != L_RO_TR_SC &&
300  order != L_TR_RO_SC && order != L_RO_SC_TR && order != L_SC_TR_RO)
301  return (BOX *)ERROR_PTR("order invalid", procName, NULL);
302 
303  boxGetGeometry(boxs, &bx, &by, &bw, &bh);
304  if (bw <= 0 || bh <= 0) /* invalid */
305  return boxCreate(0, 0, 0, 0);
306  if (angle != 0.0) {
307  sina = sin(angle);
308  cosa = cos(angle);
309  }
310 
311  if (order == L_TR_SC_RO) {
312  tx = (l_int32)(scalex * (bx + shiftx) + 0.5);
313  ty = (l_int32)(scaley * (by + shifty) + 0.5);
314  tw = (l_int32)(L_MAX(1.0, scalex * bw + 0.5));
315  th = (l_int32)(L_MAX(1.0, scaley * bh + 0.5));
316  xcent = (l_int32)(scalex * xcen + 0.5);
317  ycent = (l_int32)(scaley * ycen + 0.5);
318  if (angle == 0.0) {
319  boxd = boxCreate(tx, ty, tw, th);
320  } else {
321  xdif = tx + 0.5 * tw - xcent;
322  ydif = ty + 0.5 * th - ycent;
323  rw = L_ABS(tw * cosa) + L_ABS(th * sina);
324  rh = L_ABS(th * cosa) + L_ABS(tw * sina);
325  rx = xcent + xdif * cosa - ydif * sina - 0.5 * rw;
326  ry = ycent + ydif * cosa + xdif * sina - 0.5 * rh;
327  boxd = boxCreate((l_int32)rx, (l_int32)ry, (l_int32)rw,
328  (l_int32)rh);
329  }
330  } else if (order == L_SC_TR_RO) {
331  tx = (l_int32)(scalex * bx + shiftx + 0.5);
332  ty = (l_int32)(scaley * by + shifty + 0.5);
333  tw = (l_int32)(L_MAX(1.0, scalex * bw + 0.5));
334  th = (l_int32)(L_MAX(1.0, scaley * bh + 0.5));
335  xcent = (l_int32)(scalex * xcen + 0.5);
336  ycent = (l_int32)(scaley * ycen + 0.5);
337  if (angle == 0.0) {
338  boxd = boxCreate(tx, ty, tw, th);
339  } else {
340  xdif = tx + 0.5 * tw - xcent;
341  ydif = ty + 0.5 * th - ycent;
342  rw = L_ABS(tw * cosa) + L_ABS(th * sina);
343  rh = L_ABS(th * cosa) + L_ABS(tw * sina);
344  rx = xcent + xdif * cosa - ydif * sina - 0.5 * rw;
345  ry = ycent + ydif * cosa + xdif * sina - 0.5 * rh;
346  boxd = boxCreate((l_int32)rx, (l_int32)ry, (l_int32)rw,
347  (l_int32)rh);
348  }
349  } else if (order == L_RO_TR_SC) {
350  if (angle == 0.0) {
351  rx = bx;
352  ry = by;
353  rw = bw;
354  rh = bh;
355  } else {
356  xdif = bx + 0.5 * bw - xcen;
357  ydif = by + 0.5 * bh - ycen;
358  rw = L_ABS(bw * cosa) + L_ABS(bh * sina);
359  rh = L_ABS(bh * cosa) + L_ABS(bw * sina);
360  rx = xcen + xdif * cosa - ydif * sina - 0.5 * rw;
361  ry = ycen + ydif * cosa + xdif * sina - 0.5 * rh;
362  }
363  tx = (l_int32)(scalex * (rx + shiftx) + 0.5);
364  ty = (l_int32)(scaley * (ry + shifty) + 0.5);
365  tw = (l_int32)(L_MAX(1.0, scalex * rw + 0.5));
366  th = (l_int32)(L_MAX(1.0, scaley * rh + 0.5));
367  boxd = boxCreate(tx, ty, tw, th);
368  } else if (order == L_RO_SC_TR) {
369  if (angle == 0.0) {
370  rx = bx;
371  ry = by;
372  rw = bw;
373  rh = bh;
374  } else {
375  xdif = bx + 0.5 * bw - xcen;
376  ydif = by + 0.5 * bh - ycen;
377  rw = L_ABS(bw * cosa) + L_ABS(bh * sina);
378  rh = L_ABS(bh * cosa) + L_ABS(bw * sina);
379  rx = xcen + xdif * cosa - ydif * sina - 0.5 * rw;
380  ry = ycen + ydif * cosa + xdif * sina - 0.5 * rh;
381  }
382  tx = (l_int32)(scalex * rx + shiftx + 0.5);
383  ty = (l_int32)(scaley * ry + shifty + 0.5);
384  tw = (l_int32)(L_MAX(1.0, scalex * rw + 0.5));
385  th = (l_int32)(L_MAX(1.0, scaley * rh + 0.5));
386  boxd = boxCreate(tx, ty, tw, th);
387  } else if (order == L_TR_RO_SC) {
388  tx = bx + shiftx;
389  ty = by + shifty;
390  if (angle == 0.0) {
391  rx = tx;
392  ry = ty;
393  rw = bw;
394  rh = bh;
395  } else {
396  xdif = tx + 0.5 * bw - xcen;
397  ydif = ty + 0.5 * bh - ycen;
398  rw = L_ABS(bw * cosa) + L_ABS(bh * sina);
399  rh = L_ABS(bh * cosa) + L_ABS(bw * sina);
400  rx = xcen + xdif * cosa - ydif * sina - 0.5 * rw;
401  ry = ycen + ydif * cosa + xdif * sina - 0.5 * rh;
402  }
403  tx = (l_int32)(scalex * rx + 0.5);
404  ty = (l_int32)(scaley * ry + 0.5);
405  tw = (l_int32)(L_MAX(1.0, scalex * rw + 0.5));
406  th = (l_int32)(L_MAX(1.0, scaley * rh + 0.5));
407  boxd = boxCreate(tx, ty, tw, th);
408  } else { /* order == L_SC_RO_TR) */
409  tx = (l_int32)(scalex * bx + 0.5);
410  ty = (l_int32)(scaley * by + 0.5);
411  tw = (l_int32)(L_MAX(1.0, scalex * bw + 0.5));
412  th = (l_int32)(L_MAX(1.0, scaley * bh + 0.5));
413  xcent = (l_int32)(scalex * xcen + 0.5);
414  ycent = (l_int32)(scaley * ycen + 0.5);
415  if (angle == 0.0) {
416  rx = tx;
417  ry = ty;
418  rw = tw;
419  rh = th;
420  } else {
421  xdif = tx + 0.5 * tw - xcent;
422  ydif = ty + 0.5 * th - ycent;
423  rw = L_ABS(tw * cosa) + L_ABS(th * sina);
424  rh = L_ABS(th * cosa) + L_ABS(tw * sina);
425  rx = xcent + xdif * cosa - ydif * sina - 0.5 * rw;
426  ry = ycent + ydif * cosa + xdif * sina - 0.5 * rh;
427  }
428  tx = (l_int32)(rx + shiftx + 0.5);
429  ty = (l_int32)(ry + shifty + 0.5);
430  tw = (l_int32)(rw + 0.5);
431  th = (l_int32)(rh + 0.5);
432  boxd = boxCreate(tx, ty, tw, th);
433  }
434 
435  return boxd;
436 }
437 
438 
453 BOXA *
455  l_int32 w,
456  l_int32 h,
457  l_int32 rotation)
458 {
459 l_int32 i, n;
460 BOX *boxs, *boxd;
461 BOXA *boxad;
462 
463  PROCNAME("boxaRotateOrth");
464 
465  if (!boxas)
466  return (BOXA *)ERROR_PTR("boxas not defined", procName, NULL);
467  if (rotation < 0 || rotation > 3)
468  return (BOXA *)ERROR_PTR("rotation not in {0,1,2,3}", procName, NULL);
469  if (rotation == 0)
470  return boxaCopy(boxas, L_COPY);
471 
472  n = boxaGetCount(boxas);
473  if ((boxad = boxaCreate(n)) == NULL)
474  return (BOXA *)ERROR_PTR("boxad not made", procName, NULL);
475  for (i = 0; i < n; i++) {
476  if ((boxs = boxaGetBox(boxas, i, L_CLONE)) == NULL) {
477  boxaDestroy(&boxad);
478  return (BOXA *)ERROR_PTR("boxs not found", procName, NULL);
479  }
480  boxd = boxRotateOrth(boxs, w, h, rotation);
481  boxDestroy(&boxs);
482  boxaAddBox(boxad, boxd, L_INSERT);
483  }
484 
485  return boxad;
486 }
487 
488 
505 BOX *
507  l_int32 w,
508  l_int32 h,
509  l_int32 rotation)
510 {
511 l_int32 bx, by, bw, bh, xdist, ydist;
512 
513  PROCNAME("boxRotateOrth");
514 
515  if (!box)
516  return (BOX *)ERROR_PTR("box not defined", procName, NULL);
517  if (rotation < 0 || rotation > 3)
518  return (BOX *)ERROR_PTR("rotation not in {0,1,2,3}", procName, NULL);
519  if (rotation == 0)
520  return boxCopy(box);
521 
522  boxGetGeometry(box, &bx, &by, &bw, &bh);
523  if (bw <= 0 || bh <= 0) /* invalid */
524  return boxCreate(0, 0, 0, 0);
525  ydist = h - by - bh; /* below box */
526  xdist = w - bx - bw; /* to right of box */
527  if (rotation == 1) /* 90 deg cw */
528  return boxCreate(ydist, bx, bh, bw);
529  else if (rotation == 2) /* 180 deg cw */
530  return boxCreate(xdist, ydist, bw, bh);
531  else /* rotation == 3, 270 deg cw */
532  return boxCreate(by, xdist, bh, bw);
533 }
534 
535 
536 /*---------------------------------------------------------------------*
537  * Boxa sort *
538  *---------------------------------------------------------------------*/
559 BOXA *
560 boxaSort(BOXA *boxas,
561  l_int32 sorttype,
562  l_int32 sortorder,
563  NUMA **pnaindex)
564 {
565 l_int32 i, n, x, y, w, h, size;
566 BOXA *boxad;
567 NUMA *na, *naindex;
568 
569  PROCNAME("boxaSort");
570 
571  if (pnaindex) *pnaindex = NULL;
572  if (!boxas)
573  return (BOXA *)ERROR_PTR("boxas not defined", procName, NULL);
574  if ((n = boxaGetCount(boxas)) == 0) {
575  L_WARNING("boxas is empty\n", procName);
576  return boxaCopy(boxas, L_COPY);
577  }
578  if (sorttype != L_SORT_BY_X && sorttype != L_SORT_BY_Y &&
579  sorttype != L_SORT_BY_RIGHT && sorttype != L_SORT_BY_BOT &&
580  sorttype != L_SORT_BY_WIDTH && sorttype != L_SORT_BY_HEIGHT &&
581  sorttype != L_SORT_BY_MIN_DIMENSION &&
582  sorttype != L_SORT_BY_MAX_DIMENSION &&
583  sorttype != L_SORT_BY_PERIMETER &&
584  sorttype != L_SORT_BY_AREA &&
585  sorttype != L_SORT_BY_ASPECT_RATIO)
586  return (BOXA *)ERROR_PTR("invalid sort type", procName, NULL);
587  if (sortorder != L_SORT_INCREASING && sortorder != L_SORT_DECREASING)
588  return (BOXA *)ERROR_PTR("invalid sort order", procName, NULL);
589 
590  /* Use O(n) binsort if possible */
591  if (n > MIN_COMPS_FOR_BIN_SORT &&
592  ((sorttype == L_SORT_BY_X) || (sorttype == L_SORT_BY_Y) ||
593  (sorttype == L_SORT_BY_WIDTH) || (sorttype == L_SORT_BY_HEIGHT) ||
594  (sorttype == L_SORT_BY_PERIMETER)))
595  return boxaBinSort(boxas, sorttype, sortorder, pnaindex);
596 
597  /* Build up numa of specific data */
598  if ((na = numaCreate(n)) == NULL)
599  return (BOXA *)ERROR_PTR("na not made", procName, NULL);
600  for (i = 0; i < n; i++) {
601  boxaGetBoxGeometry(boxas, i, &x, &y, &w, &h);
602  switch (sorttype)
603  {
604  case L_SORT_BY_X:
605  numaAddNumber(na, x);
606  break;
607  case L_SORT_BY_Y:
608  numaAddNumber(na, y);
609  break;
610  case L_SORT_BY_RIGHT:
611  numaAddNumber(na, x + w - 1);
612  break;
613  case L_SORT_BY_BOT:
614  numaAddNumber(na, y + h - 1);
615  break;
616  case L_SORT_BY_WIDTH:
617  numaAddNumber(na, w);
618  break;
619  case L_SORT_BY_HEIGHT:
620  numaAddNumber(na, h);
621  break;
623  size = L_MIN(w, h);
624  numaAddNumber(na, size);
625  break;
627  size = L_MAX(w, h);
628  numaAddNumber(na, size);
629  break;
630  case L_SORT_BY_PERIMETER:
631  size = w + h;
632  numaAddNumber(na, size);
633  break;
634  case L_SORT_BY_AREA:
635  size = w * h;
636  numaAddNumber(na, size);
637  break;
639  numaAddNumber(na, (l_float32)w / (l_float32)h);
640  break;
641  default:
642  L_WARNING("invalid sort type\n", procName);
643  }
644  }
645 
646  /* Get the sort index for data array */
647  naindex = numaGetSortIndex(na, sortorder);
648  numaDestroy(&na);
649  if (!naindex)
650  return (BOXA *)ERROR_PTR("naindex not made", procName, NULL);
651 
652  /* Build up sorted boxa using sort index */
653  boxad = boxaSortByIndex(boxas, naindex);
654 
655  if (pnaindex)
656  *pnaindex = naindex;
657  else
658  numaDestroy(&naindex);
659  return boxad;
660 }
661 
662 
683 BOXA *
685  l_int32 sorttype,
686  l_int32 sortorder,
687  NUMA **pnaindex)
688 {
689 l_int32 i, n, x, y, w, h;
690 BOXA *boxad;
691 NUMA *na, *naindex;
692 
693  PROCNAME("boxaBinSort");
694 
695  if (pnaindex) *pnaindex = NULL;
696  if (!boxas)
697  return (BOXA *)ERROR_PTR("boxas not defined", procName, NULL);
698  if ((n = boxaGetCount(boxas)) == 0) {
699  L_WARNING("boxas is empty\n", procName);
700  return boxaCopy(boxas, L_COPY);
701  }
702  if (sorttype != L_SORT_BY_X && sorttype != L_SORT_BY_Y &&
703  sorttype != L_SORT_BY_WIDTH && sorttype != L_SORT_BY_HEIGHT &&
704  sorttype != L_SORT_BY_PERIMETER)
705  return (BOXA *)ERROR_PTR("invalid sort type", procName, NULL);
706  if (sortorder != L_SORT_INCREASING && sortorder != L_SORT_DECREASING)
707  return (BOXA *)ERROR_PTR("invalid sort order", procName, NULL);
708 
709  /* Generate Numa of appropriate box dimensions */
710  if ((na = numaCreate(n)) == NULL)
711  return (BOXA *)ERROR_PTR("na not made", procName, NULL);
712  for (i = 0; i < n; i++) {
713  boxaGetBoxGeometry(boxas, i, &x, &y, &w, &h);
714  switch (sorttype)
715  {
716  case L_SORT_BY_X:
717  numaAddNumber(na, x);
718  break;
719  case L_SORT_BY_Y:
720  numaAddNumber(na, y);
721  break;
722  case L_SORT_BY_WIDTH:
723  numaAddNumber(na, w);
724  break;
725  case L_SORT_BY_HEIGHT:
726  numaAddNumber(na, h);
727  break;
728  case L_SORT_BY_PERIMETER:
729  numaAddNumber(na, w + h);
730  break;
731  default:
732  L_WARNING("invalid sort type\n", procName);
733  }
734  }
735 
736  /* Get the sort index for data array */
737  naindex = numaGetBinSortIndex(na, sortorder);
738  numaDestroy(&na);
739  if (!naindex)
740  return (BOXA *)ERROR_PTR("naindex not made", procName, NULL);
741 
742  /* Build up sorted boxa using the sort index */
743  boxad = boxaSortByIndex(boxas, naindex);
744 
745  if (pnaindex)
746  *pnaindex = naindex;
747  else
748  numaDestroy(&naindex);
749  return boxad;
750 }
751 
752 
760 BOXA *
762  NUMA *naindex)
763 {
764 l_int32 i, n, index;
765 BOX *box;
766 BOXA *boxad;
767 
768  PROCNAME("boxaSortByIndex");
769 
770  if (!boxas)
771  return (BOXA *)ERROR_PTR("boxas not defined", procName, NULL);
772  if ((n = boxaGetCount(boxas)) == 0) {
773  L_WARNING("boxas is empty\n", procName);
774  return boxaCopy(boxas, L_COPY);
775  }
776  if (!naindex)
777  return (BOXA *)ERROR_PTR("naindex not defined", procName, NULL);
778 
779  boxad = boxaCreate(n);
780  for (i = 0; i < n; i++) {
781  numaGetIValue(naindex, i, &index);
782  box = boxaGetBox(boxas, index, L_COPY);
783  boxaAddBox(boxad, box, L_INSERT);
784  }
785 
786  return boxad;
787 }
788 
789 
836 BOXAA *
838  NUMAA **pnaad,
839  l_int32 delta1,
840  l_int32 delta2,
841  l_int32 minh1)
842 {
843 l_int32 i, index, h, nt, ne, n, m, ival;
844 BOX *box;
845 BOXA *boxa, *boxae, *boxan, *boxa1, *boxa2, *boxa3, *boxav, *boxavs;
846 BOXAA *baa, *baa1, *baad;
847 NUMA *naindex, *nae, *nan, *nah, *nav, *na1, *na2, *nad, *namap;
848 NUMAA *naa, *naa1, *naad;
849 
850  PROCNAME("boxaSort2d");
851 
852  if (pnaad) *pnaad = NULL;
853  if (!boxas)
854  return (BOXAA *)ERROR_PTR("boxas not defined", procName, NULL);
855  if (boxaGetCount(boxas) == 0)
856  return (BOXAA *)ERROR_PTR("boxas is empty", procName, NULL);
857 
858  /* Sort from left to right */
859  if ((boxa = boxaSort(boxas, L_SORT_BY_X, L_SORT_INCREASING, &naindex))
860  == NULL)
861  return (BOXAA *)ERROR_PTR("boxa not made", procName, NULL);
862 
863  /* First pass: assign taller boxes to boxa by row */
864  nt = boxaGetCount(boxa);
865  baa = boxaaCreate(0);
866  naa = numaaCreate(0);
867  boxae = boxaCreate(0); /* save small height boxes here */
868  nae = numaCreate(0); /* keep track of small height boxes */
869  for (i = 0; i < nt; i++) {
870  box = boxaGetBox(boxa, i, L_CLONE);
871  boxGetGeometry(box, NULL, NULL, NULL, &h);
872  if (h < minh1) { /* save for 2nd pass */
873  boxaAddBox(boxae, box, L_INSERT);
874  numaAddNumber(nae, i);
875  } else {
876  n = boxaaGetCount(baa);
877  boxaaAlignBox(baa, box, delta1, &index);
878  if (index < n) { /* append to an existing boxa */
879  boxaaAddBox(baa, index, box, L_INSERT);
880  } else { /* doesn't align, need new boxa */
881  boxan = boxaCreate(0);
882  boxaAddBox(boxan, box, L_INSERT);
883  boxaaAddBoxa(baa, boxan, L_INSERT);
884  nan = numaCreate(0);
885  numaaAddNuma(naa, nan, L_INSERT);
886  }
887  numaGetIValue(naindex, i, &ival);
888  numaaAddNumber(naa, index, ival);
889  }
890  }
891  boxaDestroy(&boxa);
892  numaDestroy(&naindex);
893 
894  /* Second pass: feed in small height boxes */
895  ne = boxaGetCount(boxae);
896  for (i = 0; i < ne; i++) {
897  box = boxaGetBox(boxae, i, L_CLONE);
898  n = boxaaGetCount(baa);
899  boxaaAlignBox(baa, box, delta2, &index);
900  if (index < n) { /* append to an existing boxa */
901  boxaaAddBox(baa, index, box, L_INSERT);
902  } else { /* doesn't align, need new boxa */
903  boxan = boxaCreate(0);
904  boxaAddBox(boxan, box, L_INSERT);
905  boxaaAddBoxa(baa, boxan, L_INSERT);
906  nan = numaCreate(0);
907  numaaAddNuma(naa, nan, L_INSERT);
908  }
909  numaGetIValue(nae, i, &ival); /* location in original boxas */
910  numaaAddNumber(naa, index, ival);
911  }
912 
913  /* Third pass: merge some boxa whose extent is overlapping.
914  * Think of these boxa as text lines, where the bounding boxes
915  * of the text lines can overlap, but likely won't have
916  * a huge overlap.
917  * First do a greedy find of pairs of overlapping boxa, where
918  * the two boxa overlap by at least 50% of the smaller, and
919  * the smaller is not more than half the area of the larger.
920  * For such pairs, call the larger one the primary boxa. The
921  * boxes in the smaller one are appended to those in the primary
922  * in pass 3a, and the primaries are extracted in pass 3b.
923  * In this way, all boxes in the original baa are saved. */
924  n = boxaaGetCount(baa);
925  boxaaGetExtent(baa, NULL, NULL, NULL, &boxa3);
926  boxa1 = boxaHandleOverlaps(boxa3, L_REMOVE_SMALL, 1000, 0.5, 0.5, &namap);
927  boxaDestroy(&boxa1);
928  boxaDestroy(&boxa3);
929  for (i = 0; i < n; i++) { /* Pass 3a: join selected copies of boxa */
930  numaGetIValue(namap, i, &ival);
931  if (ival >= 0) { /* join current to primary boxa[ival] */
932  boxa1 = boxaaGetBoxa(baa, i, L_COPY);
933  boxa2 = boxaaGetBoxa(baa, ival, L_CLONE);
934  boxaJoin(boxa2, boxa1, 0, -1);
935  boxaDestroy(&boxa2);
936  boxaDestroy(&boxa1);
937  na1 = numaaGetNuma(naa, i, L_COPY);
938  na2 = numaaGetNuma(naa, ival, L_CLONE);
939  numaJoin(na2, na1, 0, -1);
940  numaDestroy(&na1);
941  numaDestroy(&na2);
942  }
943  }
944  baa1 = boxaaCreate(n);
945  naa1 = numaaCreate(n);
946  for (i = 0; i < n; i++) { /* Pass 3b: save primary boxa */
947  numaGetIValue(namap, i, &ival);
948  if (ival == -1) {
949  boxa1 = boxaaGetBoxa(baa, i, L_CLONE);
950  boxaaAddBoxa(baa1, boxa1, L_INSERT);
951  na1 = numaaGetNuma(naa, i, L_CLONE);
952  numaaAddNuma(naa1, na1, L_INSERT);
953  }
954  }
955  numaDestroy(&namap);
956  boxaaDestroy(&baa);
957  baa = baa1;
958  numaaDestroy(&naa);
959  naa = naa1;
960 
961  /* Sort the boxes in each boxa horizontally */
962  m = boxaaGetCount(baa);
963  for (i = 0; i < m; i++) {
964  boxa1 = boxaaGetBoxa(baa, i, L_CLONE);
965  boxa2 = boxaSort(boxa1, L_SORT_BY_X, L_SORT_INCREASING, &nah);
966  boxaaReplaceBoxa(baa, i, boxa2);
967  na1 = numaaGetNuma(naa, i, L_CLONE);
968  na2 = numaSortByIndex(na1, nah);
969  numaaReplaceNuma(naa, i, na2);
970  boxaDestroy(&boxa1);
971  numaDestroy(&na1);
972  numaDestroy(&nah);
973  }
974 
975  /* Sort the boxa vertically within boxaa, using the first box
976  * in each boxa. */
977  m = boxaaGetCount(baa);
978  boxav = boxaCreate(m); /* holds first box in each boxa in baa */
979  naad = numaaCreate(m);
980  if (pnaad)
981  *pnaad = naad;
982  baad = boxaaCreate(m);
983  for (i = 0; i < m; i++) {
984  boxa1 = boxaaGetBoxa(baa, i, L_CLONE);
985  box = boxaGetBox(boxa1, 0, L_CLONE);
986  boxaAddBox(boxav, box, L_INSERT);
987  boxaDestroy(&boxa1);
988  }
989  boxavs = boxaSort(boxav, L_SORT_BY_Y, L_SORT_INCREASING, &nav);
990  for (i = 0; i < m; i++) {
991  numaGetIValue(nav, i, &index);
992  boxa = boxaaGetBoxa(baa, index, L_CLONE);
993  boxaaAddBoxa(baad, boxa, L_INSERT);
994  nad = numaaGetNuma(naa, index, L_CLONE);
995  numaaAddNuma(naad, nad, L_INSERT);
996  }
997 
998 
999 /* fprintf(stderr, "box count = %d, numaa count = %d\n", nt,
1000  numaaGetNumberCount(naad)); */
1001 
1002  boxaaDestroy(&baa);
1003  boxaDestroy(&boxav);
1004  boxaDestroy(&boxavs);
1005  boxaDestroy(&boxae);
1006  numaDestroy(&nav);
1007  numaDestroy(&nae);
1008  numaaDestroy(&naa);
1009  if (!pnaad)
1010  numaaDestroy(&naad);
1011 
1012  return baad;
1013 }
1014 
1015 
1023 BOXAA *
1025  NUMAA *naa)
1026 {
1027 l_int32 ntot, boxtot, i, j, n, nn, index;
1028 BOX *box;
1029 BOXA *boxa;
1030 BOXAA *baa;
1031 NUMA *na;
1032 
1033  PROCNAME("boxaSort2dByIndex");
1034 
1035  if (!boxas)
1036  return (BOXAA *)ERROR_PTR("boxas not defined", procName, NULL);
1037  if ((boxtot = boxaGetCount(boxas)) == 0)
1038  return (BOXAA *)ERROR_PTR("boxas is empty", procName, NULL);
1039  if (!naa)
1040  return (BOXAA *)ERROR_PTR("naindex not defined", procName, NULL);
1041 
1042  /* Check counts */
1043  ntot = numaaGetNumberCount(naa);
1044  if (ntot != boxtot)
1045  return (BOXAA *)ERROR_PTR("element count mismatch", procName, NULL);
1046 
1047  n = numaaGetCount(naa);
1048  baa = boxaaCreate(n);
1049  for (i = 0; i < n; i++) {
1050  na = numaaGetNuma(naa, i, L_CLONE);
1051  nn = numaGetCount(na);
1052  boxa = boxaCreate(nn);
1053  for (j = 0; j < nn; j++) {
1054  numaGetIValue(na, i, &index);
1055  box = boxaGetBox(boxas, index, L_COPY);
1056  boxaAddBox(boxa, box, L_INSERT);
1057  }
1058  boxaaAddBoxa(baa, boxa, L_INSERT);
1059  numaDestroy(&na);
1060  }
1061 
1062  return baa;
1063 }
1064 
1065 
1066 /*---------------------------------------------------------------------*
1067  * Boxa array extraction *
1068  *---------------------------------------------------------------------*/
1092 l_int32
1094  NUMA **pnal,
1095  NUMA **pnat,
1096  NUMA **pnar,
1097  NUMA **pnab,
1098  NUMA **pnaw,
1099  NUMA **pnah,
1100  l_int32 keepinvalid)
1101 {
1102 l_int32 i, n, left, top, right, bot, w, h;
1103 
1104  PROCNAME("boxaExtractAsNuma");
1105 
1106  if (!pnal && !pnat && !pnar && !pnab && !pnaw && !pnah)
1107  return ERROR_INT("no output requested", procName, 1);
1108  if (pnal) *pnal = NULL;
1109  if (pnat) *pnat = NULL;
1110  if (pnar) *pnar = NULL;
1111  if (pnab) *pnab = NULL;
1112  if (pnaw) *pnaw = NULL;
1113  if (pnah) *pnah = NULL;
1114  if (!boxa)
1115  return ERROR_INT("boxa not defined", procName, 1);
1116  if (!keepinvalid && boxaGetValidCount(boxa) == 0)
1117  return ERROR_INT("no valid boxes", procName, 1);
1118 
1119  n = boxaGetCount(boxa);
1120  if (pnal) *pnal = numaCreate(n);
1121  if (pnat) *pnat = numaCreate(n);
1122  if (pnar) *pnar = numaCreate(n);
1123  if (pnab) *pnab = numaCreate(n);
1124  if (pnaw) *pnaw = numaCreate(n);
1125  if (pnah) *pnah = numaCreate(n);
1126  for (i = 0; i < n; i++) {
1127  boxaGetBoxGeometry(boxa, i, &left, &top, &w, &h);
1128  if (!keepinvalid && (w <= 0 || h <= 0))
1129  continue;
1130  right = left + w - 1;
1131  bot = top + h - 1;
1132  if (pnal) numaAddNumber(*pnal, left);
1133  if (pnat) numaAddNumber(*pnat, top);
1134  if (pnar) numaAddNumber(*pnar, right);
1135  if (pnab) numaAddNumber(*pnab, bot);
1136  if (pnaw) numaAddNumber(*pnaw, w);
1137  if (pnah) numaAddNumber(*pnah, h);
1138  }
1139 
1140  return 0;
1141 }
1142 
1143 
1169 l_int32
1171  PTA **pptal,
1172  PTA **pptat,
1173  PTA **pptar,
1174  PTA **pptab,
1175  PTA **pptaw,
1176  PTA **pptah,
1177  l_int32 keepinvalid)
1178 {
1179 l_int32 i, n, left, top, right, bot, w, h;
1180 
1181  PROCNAME("boxaExtractAsPta");
1182 
1183  if (!pptal && !pptar && !pptat && !pptab && !pptaw && !pptah)
1184  return ERROR_INT("no output requested", procName, 1);
1185  if (pptal) *pptal = NULL;
1186  if (pptat) *pptat = NULL;
1187  if (pptar) *pptar = NULL;
1188  if (pptab) *pptab = NULL;
1189  if (pptaw) *pptaw = NULL;
1190  if (pptah) *pptah = NULL;
1191  if (!boxa)
1192  return ERROR_INT("boxa not defined", procName, 1);
1193  if (!keepinvalid && boxaGetValidCount(boxa) == 0)
1194  return ERROR_INT("no valid boxes", procName, 1);
1195 
1196  n = boxaGetCount(boxa);
1197  if (pptal) *pptal = ptaCreate(n);
1198  if (pptat) *pptat = ptaCreate(n);
1199  if (pptar) *pptar = ptaCreate(n);
1200  if (pptab) *pptab = ptaCreate(n);
1201  if (pptaw) *pptaw = ptaCreate(n);
1202  if (pptah) *pptah = ptaCreate(n);
1203  for (i = 0; i < n; i++) {
1204  boxaGetBoxGeometry(boxa, i, &left, &top, &w, &h);
1205  if (!keepinvalid && (w <= 0 || h <= 0))
1206  continue;
1207  right = left + w - 1;
1208  bot = top + h - 1;
1209  if (pptal) ptaAddPt(*pptal, i, left);
1210  if (pptat) ptaAddPt(*pptat, i, top);
1211  if (pptar) ptaAddPt(*pptar, i, right);
1212  if (pptab) ptaAddPt(*pptab, i, bot);
1213  if (pptaw) ptaAddPt(*pptaw, i, w);
1214  if (pptah) ptaAddPt(*pptah, i, h);
1215  }
1216 
1217  return 0;
1218 }
1219 
1220 
1221 /*---------------------------------------------------------------------*
1222  * Boxa statistics *
1223  *---------------------------------------------------------------------*/
1250 l_int32
1252  l_float32 fract,
1253  l_int32 *px,
1254  l_int32 *py,
1255  l_int32 *pw,
1256  l_int32 *ph)
1257 {
1258 l_float32 xval, yval, wval, hval;
1259 NUMA *nax, *nay, *naw, *nah;
1260 
1261  PROCNAME("boxaGetRankVals");
1262 
1263  if (px) *px = 0;
1264  if (py) *py = 0;
1265  if (pw) *pw = 0;
1266  if (ph) *ph = 0;
1267  if (!boxa)
1268  return ERROR_INT("boxa not defined", procName, 1);
1269  if (fract < 0.0 || fract > 1.0)
1270  return ERROR_INT("fract not in [0.0 ... 1.0]", procName, 1);
1271  if (boxaGetValidCount(boxa) == 0)
1272  return ERROR_INT("no valid boxes in boxa", procName, 1);
1273 
1274  /* Use only the valid boxes */
1275  boxaExtractAsNuma(boxa, &nax, &nay, NULL, NULL, &naw, &nah, 0);
1276 
1277  if (px) {
1278  numaGetRankValue(nax, 1.0 - fract, NULL, 1, &xval);
1279  *px = (l_int32)xval;
1280  }
1281  if (py) {
1282  numaGetRankValue(nay, 1.0 - fract, NULL, 1, &yval);
1283  *py = (l_int32)yval;
1284  }
1285  if (pw) {
1286  numaGetRankValue(naw, fract, NULL, 1, &wval);
1287  *pw = (l_int32)wval;
1288  }
1289  if (ph) {
1290  numaGetRankValue(nah, fract, NULL, 1, &hval);
1291  *ph = (l_int32)hval;
1292  }
1293  numaDestroy(&nax);
1294  numaDestroy(&nay);
1295  numaDestroy(&naw);
1296  numaDestroy(&nah);
1297  return 0;
1298 }
1299 
1300 
1316 l_int32
1318  l_int32 *px,
1319  l_int32 *py,
1320  l_int32 *pw,
1321  l_int32 *ph)
1322 {
1323  PROCNAME("boxaGetMedianVals");
1324 
1325  if (!boxa)
1326  return ERROR_INT("boxa not defined", procName, 1);
1327  if (boxaGetValidCount(boxa) == 0)
1328  return ERROR_INT("no valid boxes in boxa", procName, 1);
1329 
1330  return boxaGetRankVals(boxa, 0.5, px, py, pw, ph);
1331 }
1332 
1333 
1342 l_int32
1344  l_float32 *pw,
1345  l_float32 *ph)
1346 {
1347 l_int32 i, n, bw, bh;
1348 l_float32 sumw, sumh;
1349 
1350  PROCNAME("boxaGetAverageSize");
1351 
1352  if (pw) *pw = 0.0;
1353  if (ph) *ph = 0.0;
1354  if (!boxa)
1355  return ERROR_INT("boxa not defined", procName, 1);
1356  if ((n = boxaGetCount(boxa)) == 0)
1357  return ERROR_INT("boxa is empty", procName, 1);
1358 
1359  sumw = sumh = 0.0;
1360  for (i = 0; i < n; i++) {
1361  boxaGetBoxGeometry(boxa, i, NULL, NULL, &bw, &bh);
1362  sumw += bw;
1363  sumh += bh;
1364  }
1365 
1366  if (pw) *pw = sumw / n;
1367  if (ph) *ph = sumh / n;
1368  return 0;
1369 }
1370 
1371 
1372 /*---------------------------------------------------------------------*
1373  * Other Boxaa functions *
1374  *---------------------------------------------------------------------*/
1397 l_int32
1399  l_int32 *pw,
1400  l_int32 *ph,
1401  BOX **pbox,
1402  BOXA **pboxa)
1403 {
1404 l_int32 i, n, x, y, w, h, xmax, ymax, xmin, ymin, found;
1405 BOX *box1;
1406 BOXA *boxa, *boxa1;
1407 
1408  PROCNAME("boxaaGetExtent");
1409 
1410  if (!pw && !ph && !pbox && !pboxa)
1411  return ERROR_INT("no ptrs defined", procName, 1);
1412  if (pw) *pw = 0;
1413  if (ph) *ph = 0;
1414  if (pbox) *pbox = NULL;
1415  if (pboxa) *pboxa = NULL;
1416  if (!baa)
1417  return ERROR_INT("baa not defined", procName, 1);
1418 
1419  n = boxaaGetCount(baa);
1420  if (n == 0)
1421  return ERROR_INT("no boxa in baa", procName, 1);
1422 
1423  boxa = boxaCreate(n);
1424  xmax = ymax = 0;
1425  xmin = ymin = 100000000;
1426  found = FALSE;
1427  for (i = 0; i < n; i++) {
1428  boxa1 = boxaaGetBoxa(baa, i, L_CLONE);
1429  boxaGetExtent(boxa1, NULL, NULL, &box1);
1430  boxaDestroy(&boxa1);
1431  boxGetGeometry(box1, &x, &y, &w, &h);
1432  if (w > 0 && h > 0) { /* a valid extent box */
1433  found = TRUE; /* found at least one valid extent box */
1434  xmin = L_MIN(xmin, x);
1435  ymin = L_MIN(ymin, y);
1436  xmax = L_MAX(xmax, x + w);
1437  ymax = L_MAX(ymax, y + h);
1438  }
1439  boxaAddBox(boxa, box1, L_INSERT);
1440  }
1441  if (found == FALSE) /* no valid extent boxes */
1442  xmin = ymin = 0;
1443 
1444  if (pw) *pw = xmax;
1445  if (ph) *ph = ymax;
1446  if (pbox)
1447  *pbox = boxCreate(xmin, ymin, xmax - xmin, ymax - ymin);
1448  if (pboxa)
1449  *pboxa = boxa;
1450  else
1451  boxaDestroy(&boxa);
1452  return 0;
1453 }
1454 
1455 
1477 BOXA *
1479  NUMA **pnaindex,
1480  l_int32 copyflag)
1481 {
1482 l_int32 i, j, m, n;
1483 BOXA *boxa, *boxat;
1484 BOX *box;
1485 NUMA *naindex;
1486 
1487  PROCNAME("boxaaFlattenToBoxa");
1488 
1489  if (pnaindex) *pnaindex = NULL;
1490  if (!baa)
1491  return (BOXA *)ERROR_PTR("baa not defined", procName, NULL);
1492  if (copyflag != L_COPY && copyflag != L_CLONE)
1493  return (BOXA *)ERROR_PTR("invalid copyflag", procName, NULL);
1494  if (pnaindex) {
1495  naindex = numaCreate(0);
1496  *pnaindex = naindex;
1497  }
1498 
1499  n = boxaaGetCount(baa);
1500  boxa = boxaCreate(n);
1501  for (i = 0; i < n; i++) {
1502  boxat = boxaaGetBoxa(baa, i, L_CLONE);
1503  m = boxaGetCount(boxat);
1504  if (m == 0) { /* placeholder box */
1505  box = boxCreate(0, 0, 0, 0);
1506  boxaAddBox(boxa, box, L_INSERT);
1507  if (pnaindex)
1508  numaAddNumber(naindex, i); /* save 'row' number */
1509  } else {
1510  for (j = 0; j < m; j++) {
1511  box = boxaGetBox(boxat, j, copyflag);
1512  boxaAddBox(boxa, box, L_INSERT);
1513  if (pnaindex)
1514  numaAddNumber(naindex, i); /* save 'row' number */
1515  }
1516  }
1517  boxaDestroy(&boxat);
1518  }
1519 
1520  return boxa;
1521 }
1522 
1523 
1543 BOXA *
1545  l_int32 num,
1546  BOX *fillerbox,
1547  l_int32 copyflag)
1548 {
1549 l_int32 i, j, m, n, mval, nshort;
1550 BOXA *boxat, *boxad;
1551 BOX *box;
1552 
1553  PROCNAME("boxaaFlattenAligned");
1554 
1555  if (!baa)
1556  return (BOXA *)ERROR_PTR("baa not defined", procName, NULL);
1557  if (copyflag != L_COPY && copyflag != L_CLONE)
1558  return (BOXA *)ERROR_PTR("invalid copyflag", procName, NULL);
1559 
1560  n = boxaaGetCount(baa);
1561  boxad = boxaCreate(n);
1562  for (i = 0; i < n; i++) {
1563  boxat = boxaaGetBoxa(baa, i, L_CLONE);
1564  m = boxaGetCount(boxat);
1565  mval = L_MIN(m, num);
1566  nshort = num - mval;
1567  for (j = 0; j < mval; j++) { /* take the first %num if possible */
1568  box = boxaGetBox(boxat, j, copyflag);
1569  boxaAddBox(boxad, box, L_INSERT);
1570  }
1571  for (j = 0; j < nshort; j++) { /* add fillers if necessary */
1572  if (fillerbox) {
1573  boxaAddBox(boxad, fillerbox, L_COPY);
1574  } else {
1575  box = boxCreate(0, 0, 0, 0); /* invalid placeholder box */
1576  boxaAddBox(boxad, box, L_INSERT);
1577  }
1578  }
1579  boxaDestroy(&boxat);
1580  }
1581 
1582  return boxad;
1583 }
1584 
1585 
1601 BOXAA *
1603  l_int32 num,
1604  l_int32 copyflag)
1605 {
1606 l_int32 i, j, n, nbaa, index;
1607 BOX *box;
1608 BOXA *boxat;
1609 BOXAA *baa;
1610 
1611  PROCNAME("boxaEncapsulateAligned");
1612 
1613  if (!boxa)
1614  return (BOXAA *)ERROR_PTR("boxa not defined", procName, NULL);
1615  if (copyflag != L_COPY && copyflag != L_CLONE)
1616  return (BOXAA *)ERROR_PTR("invalid copyflag", procName, NULL);
1617 
1618  n = boxaGetCount(boxa);
1619  nbaa = n / num;
1620  if (num * nbaa != n)
1621  L_ERROR("inconsistent alignment: num doesn't divide n\n", procName);
1622  baa = boxaaCreate(nbaa);
1623  for (i = 0, index = 0; i < nbaa; i++) {
1624  boxat = boxaCreate(num);
1625  for (j = 0; j < num; j++, index++) {
1626  box = boxaGetBox(boxa, index, copyflag);
1627  boxaAddBox(boxat, box, L_INSERT);
1628  }
1629  boxaaAddBoxa(baa, boxat, L_INSERT);
1630  }
1631 
1632  return baa;
1633 }
1634 
1635 
1655 BOXAA *
1657 {
1658 l_int32 i, j, ny, nb, nbox;
1659 BOX *box;
1660 BOXA *boxa;
1661 BOXAA *baad;
1662 
1663  PROCNAME("boxaaTranspose");
1664 
1665  if (!baas)
1666  return (BOXAA *)ERROR_PTR("baas not defined", procName, NULL);
1667  if ((ny = boxaaGetCount(baas)) == 0)
1668  return (BOXAA *)ERROR_PTR("baas empty", procName, NULL);
1669 
1670  /* Make sure that each boxa in baas has the same number of boxes */
1671  for (i = 0; i < ny; i++) {
1672  if ((boxa = boxaaGetBoxa(baas, i, L_CLONE)) == NULL)
1673  return (BOXAA *)ERROR_PTR("baas is missing a boxa", procName, NULL);
1674  nb = boxaGetCount(boxa);
1675  boxaDestroy(&boxa);
1676  if (i == 0)
1677  nbox = nb;
1678  else if (nb != nbox)
1679  return (BOXAA *)ERROR_PTR("boxa are not all the same size",
1680  procName, NULL);
1681  }
1682 
1683  /* baad[i][j] = baas[j][i] */
1684  baad = boxaaCreate(nbox);
1685  for (i = 0; i < nbox; i++) {
1686  boxa = boxaCreate(ny);
1687  for (j = 0; j < ny; j++) {
1688  box = boxaaGetBox(baas, j, i, L_COPY);
1689  boxaAddBox(boxa, box, L_INSERT);
1690  }
1691  boxaaAddBoxa(baad, boxa, L_INSERT);
1692  }
1693  return baad;
1694 }
1695 
1696 
1714 l_int32
1716  BOX *box,
1717  l_int32 delta,
1718  l_int32 *pindex)
1719 {
1720 l_int32 i, n, m, y, yt, h, ht, ovlp, maxovlp, maxindex;
1721 BOX *boxt;
1722 BOXA *boxa;
1723 
1724  PROCNAME("boxaaAlignBox");
1725 
1726  if (pindex) *pindex = 0;
1727  if (!baa)
1728  return ERROR_INT("baa not defined", procName, 1);
1729  if (!box)
1730  return ERROR_INT("box not defined", procName, 1);
1731  if (!pindex)
1732  return ERROR_INT("&index not defined", procName, 1);
1733 
1734  n = boxaaGetCount(baa);
1735  boxGetGeometry(box, NULL, &y, NULL, &h);
1736  maxovlp = -10000000;
1737  for (i = 0; i < n; i++) {
1738  boxa = boxaaGetBoxa(baa, i, L_CLONE);
1739  if ((m = boxaGetCount(boxa)) == 0) {
1740  boxaDestroy(&boxa);
1741  L_WARNING("no boxes in boxa\n", procName);
1742  continue;
1743  }
1744  boxaGetExtent(boxa, NULL, NULL, &boxt);
1745  boxGetGeometry(boxt, NULL, &yt, NULL, &ht);
1746  boxDestroy(&boxt);
1747  boxaDestroy(&boxa);
1748 
1749  /* Overlap < 0 means the components do not overlap vertically */
1750  if (yt >= y)
1751  ovlp = y + h - 1 - yt;
1752  else
1753  ovlp = yt + ht - 1 - y;
1754  if (ovlp > maxovlp) {
1755  maxovlp = ovlp;
1756  maxindex = i;
1757  }
1758  }
1759 
1760  if (maxovlp + delta >= 0)
1761  *pindex = maxindex;
1762  else
1763  *pindex = n;
1764  return 0;
1765 }
BOXAA * boxaSort2dByIndex(BOXA *boxas, NUMAA *naa)
boxaSort2dByIndex()
Definition: boxfunc2.c:1024
l_int32 numaaReplaceNuma(NUMAA *naa, l_int32 index, NUMA *na)
numaaReplaceNuma()
Definition: numabasic.c:1661
l_int32 boxaGetRankVals(BOXA *boxa, l_float32 fract, l_int32 *px, l_int32 *py, l_int32 *pw, l_int32 *ph)
boxaGetRankVals()
Definition: boxfunc2.c:1251
BOX * boxRotateOrth(BOX *box, l_int32 w, l_int32 h, l_int32 rotation)
boxRotateOrth()
Definition: boxfunc2.c:506
l_int32 boxaExtractAsPta(BOXA *boxa, PTA **pptal, PTA **pptat, PTA **pptar, PTA **pptab, PTA **pptaw, PTA **pptah, l_int32 keepinvalid)
boxaExtractAsPta()
Definition: boxfunc2.c:1170
l_int32 numaAddNumber(NUMA *na, l_float32 val)
numaAddNumber()
Definition: numabasic.c:472
l_int32 boxaExtractAsNuma(BOXA *boxa, NUMA **pnal, NUMA **pnat, NUMA **pnar, NUMA **pnab, NUMA **pnaw, NUMA **pnah, l_int32 keepinvalid)
boxaExtractAsNuma()
Definition: boxfunc2.c:1093
NUMA * numaGetSortIndex(NUMA *na, l_int32 sortorder)
numaGetSortIndex()
Definition: numafunc1.c:2621
BOXA * boxaSort(BOXA *boxas, l_int32 sorttype, l_int32 sortorder, NUMA **pnaindex)
boxaSort()
Definition: boxfunc2.c:560
NUMA * numaSortByIndex(NUMA *nas, NUMA *naindex)
numaSortByIndex()
Definition: numafunc1.c:2770
l_int32 boxaaGetExtent(BOXAA *baa, l_int32 *pw, l_int32 *ph, BOX **pbox, BOXA **pboxa)
boxaaGetExtent()
Definition: boxfunc2.c:1398
l_int32 ptaAddPt(PTA *pta, l_float32 x, l_float32 y)
ptaAddPt()
Definition: ptabasic.c:341
l_int32 numaaGetNumberCount(NUMAA *naa)
numaaGetNumberCount()
Definition: numabasic.c:1555
l_int32 boxaaGetCount(BOXAA *baa)
boxaaGetCount()
Definition: boxbasic.c:1438
NUMA * numaGetBinSortIndex(NUMA *nas, l_int32 sortorder)
numaGetBinSortIndex()
Definition: numafunc1.c:2697
PTA * ptaCreate(l_int32 n)
ptaCreate()
Definition: ptabasic.c:115
l_int32 y
Definition: pix.h:483
l_int32 boxaAddBox(BOXA *boxa, BOX *box, l_int32 copyflag)
boxaAddBox()
Definition: boxbasic.c:615
l_int32 numaJoin(NUMA *nad, NUMA *nas, l_int32 istart, l_int32 iend)
numaJoin()
Definition: numafunc1.c:3319
BOXA * boxaCopy(BOXA *boxa, l_int32 copyflag)
boxaCopy()
Definition: boxbasic.c:531
NUMA * numaCreate(l_int32 n)
numaCreate()
Definition: numabasic.c:186
void boxaDestroy(BOXA **pboxa)
boxaDestroy()
Definition: boxbasic.c:577
BOX * boxTransform(BOX *box, l_int32 shiftx, l_int32 shifty, l_float32 scalex, l_float32 scaley)
boxTransform()
Definition: boxfunc2.c:137
l_int32 boxaJoin(BOXA *boxad, BOXA *boxas, l_int32 istart, l_int32 iend)
boxaJoin()
Definition: boxfunc1.c:2312
l_int32 boxaGetBoxGeometry(BOXA *boxa, l_int32 index, l_int32 *px, l_int32 *py, l_int32 *pw, l_int32 *ph)
boxaGetBoxGeometry()
Definition: boxbasic.c:860
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:1307
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:280
l_int32 numaaAddNumber(NUMAA *naa, l_int32 index, l_float32 val)
numaaAddNumber()
Definition: numabasic.c:1737
void numaaDestroy(NUMAA **pnaa)
numaaDestroy()
Definition: numabasic.c:1410
l_int32 numaaAddNuma(NUMAA *naa, NUMA *na, l_int32 copyflag)
numaaAddNuma()
Definition: numabasic.c:1448
Definition: pix.h:502
NUMA * numaaGetNuma(NUMAA *naa, l_int32 index, l_int32 accessflag)
numaaGetNuma()
Definition: numabasic.c:1625
Definition: array.h:59
void boxaaDestroy(BOXAA **pbaa)
boxaaDestroy()
Definition: boxbasic.c:1303
static const l_int32 L_INSERT
Definition: pix.h:710
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:192
l_int32 boxaaAddBox(BOXAA *baa, l_int32 index, BOX *box, l_int32 accessflag)
boxaaAddBox()
Definition: boxbasic.c:1775
BOXA * boxaTransform(BOXA *boxas, l_int32 shiftx, l_int32 shifty, l_float32 scalex, l_float32 scaley)
boxaTransform()
Definition: boxfunc2.c:91
l_int32 numaGetCount(NUMA *na)
numaGetCount()
Definition: numabasic.c:630
l_int32 numaGetRankValue(NUMA *na, l_float32 fract, NUMA *nasort, l_int32 usebins, l_float32 *pval)
numaGetRankValue()
Definition: numafunc1.c:3065
l_int32 w
Definition: pix.h:484
l_int32 boxGetGeometry(BOX *box, l_int32 *px, l_int32 *py, l_int32 *pw, l_int32 *ph)
boxGetGeometry()
Definition: boxbasic.c:309
l_int32 boxaaAlignBox(BOXAA *baa, BOX *box, l_int32 delta, l_int32 *pindex)
boxaaAlignBox()
Definition: boxfunc2.c:1715
Definition: array.h:71
BOX * boxaGetBox(BOXA *boxa, l_int32 index, l_int32 accessflag)
boxaGetBox()
Definition: boxbasic.c:760
BOXA * boxaaFlattenAligned(BOXAA *baa, l_int32 num, BOX *fillerbox, l_int32 copyflag)
boxaaFlattenAligned()
Definition: boxfunc2.c:1544
l_int32 x
Definition: pix.h:482
void numaDestroy(NUMA **pna)
numaDestroy()
Definition: numabasic.c:359
BOXAA * boxaaTranspose(BOXAA *baas)
boxaaTranspose()
Definition: boxfunc2.c:1656
BOXA * boxaBinSort(BOXA *boxas, l_int32 sorttype, l_int32 sortorder, NUMA **pnaindex)
boxaBinSort()
Definition: boxfunc2.c:684
BOXAA * boxaaCreate(l_int32 n)
boxaaCreate()
Definition: boxbasic.c:1237
l_int32 boxaaReplaceBoxa(BOXAA *baa, l_int32 index, BOXA *boxa)
boxaaReplaceBoxa()
Definition: boxbasic.c:1648
BOXA * boxaRotateOrth(BOXA *boxas, l_int32 w, l_int32 h, l_int32 rotation)
boxaRotateOrth()
Definition: boxfunc2.c:454
l_int32 boxaGetAverageSize(BOXA *boxa, l_float32 *pw, l_float32 *ph)
boxaGetAverageSize()
Definition: boxfunc2.c:1343
l_int32 boxaGetValidCount(BOXA *boxa)
boxaGetValidCount()
Definition: boxbasic.c:732
l_int32 boxaGetMedianVals(BOXA *boxa, l_int32 *px, l_int32 *py, l_int32 *pw, l_int32 *ph)
boxaGetMedianVals()
Definition: boxfunc2.c:1317
l_int32 boxaaAddBoxa(BOXAA *baa, BOXA *ba, l_int32 copyflag)
boxaaAddBoxa()
Definition: boxbasic.c:1341
l_int32 numaaGetCount(NUMAA *naa)
numaaGetCount()
Definition: numabasic.c:1516
Definition: pix.h:705
l_int32 h
Definition: pix.h:485
BOX * boxCopy(BOX *box)
boxCopy()
Definition: boxbasic.c:229
Definition: pix.h:706
BOX * boxaaGetBox(BOXAA *baa, l_int32 iboxa, l_int32 ibox, l_int32 accessflag)
boxaaGetBox()
Definition: boxbasic.c:1515
BOXA * boxaCreate(l_int32 n)
boxaCreate()
Definition: boxbasic.c:496
void boxDestroy(BOX **pbox)
boxDestroy()
Definition: boxbasic.c:277
l_int32 boxaGetExtent(BOXA *boxa, l_int32 *pw, l_int32 *ph, BOX **pbox)
boxaGetExtent()
Definition: boxfunc4.c:2321
BOXAA * boxaSort2d(BOXA *boxas, NUMAA **pnaad, l_int32 delta1, l_int32 delta2, l_int32 minh1)
boxaSort2d()
Definition: boxfunc2.c:837
l_int32 boxaGetCount(BOXA *boxa)
boxaGetCount()
Definition: boxbasic.c:715
l_int32 numaGetIValue(NUMA *na, l_int32 index, l_int32 *pival)
numaGetIValue()
Definition: numabasic.c:726
BOXAA * boxaEncapsulateAligned(BOXA *boxa, l_int32 num, l_int32 copyflag)
boxaEncapsulateAligned()
Definition: boxfunc2.c:1602
BOXA * boxaaFlattenToBoxa(BOXAA *baa, NUMA **pnaindex, l_int32 copyflag)
boxaaFlattenToBoxa()
Definition: boxfunc2.c:1478
Definition: pix.h:480
BOX * boxCreate(l_int32 x, l_int32 y, l_int32 w, l_int32 h)
boxCreate()
Definition: boxbasic.c:164
Definition: pix.h:517
BOXA * boxaaGetBoxa(BOXAA *baa, l_int32 index, l_int32 accessflag)
boxaaGetBoxa()
Definition: boxbasic.c:1485
BOXA * boxaSortByIndex(BOXA *boxas, NUMA *naindex)
boxaSortByIndex()
Definition: boxfunc2.c:761