Leptonica 1.85.0
Image processing and image analysis suite
Loading...
Searching...
No Matches
boxfunc1.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
82#ifdef HAVE_CONFIG_H
83#include <config_auto.h>
84#endif /* HAVE_CONFIG_H */
85
86#include "allheaders.h"
87#include "pix_internal.h"
88
89static l_int32 boxHasOverlapInXorY(l_int32 c1, l_int32 s1, l_int32 c2,
90 l_int32 s2);
91static l_int32 boxGetDistanceInXorY(l_int32 c1, l_int32 s1, l_int32 c2,
92 l_int32 s2);
93
94
95/*---------------------------------------------------------------------*
96 * Box geometry *
97 *---------------------------------------------------------------------*/
106l_ok
108 BOX *box2,
109 l_int32 *presult)
110{
111l_int32 x1, y1, w1, h1, x2, y2, w2, h2, valid1, valid2;
112
113 if (!presult)
114 return ERROR_INT("&result not defined", __func__, 1);
115 *presult = 0;
116 if (!box1 || !box2)
117 return ERROR_INT("boxes not both defined", __func__, 1);
118 boxIsValid(box1, &valid1);
119 boxIsValid(box2, &valid2);
120 if (!valid1 || !valid2)
121 return ERROR_INT("boxes not both valid", __func__, 1);
122
123 boxGetGeometry(box1, &x1, &y1, &w1, &h1);
124 boxGetGeometry(box2, &x2, &y2, &w2, &h2);
125 if (x1 <= x2 && y1 <= y2 && (x1 + w1 >= x2 + w2) && (y1 + h1 >= y2 + h2))
126 *presult = 1;
127 return 0;
128}
129
130
139l_ok
141 BOX *box2,
142 l_int32 *presult)
143{
144l_int32 l1, l2, r1, r2, t1, t2, b1, b2, w1, h1, w2, h2, valid1, valid2;
145
146 if (!presult)
147 return ERROR_INT("&result not defined", __func__, 1);
148 *presult = 0;
149 if (!box1 || !box2)
150 return ERROR_INT("boxes not both defined", __func__, 1);
151 boxIsValid(box1, &valid1);
152 boxIsValid(box2, &valid2);
153 if (!valid1 || !valid2)
154 return ERROR_INT("boxes not both valid", __func__, 1);
155
156 boxGetGeometry(box1, &l1, &t1, &w1, &h1);
157 boxGetGeometry(box2, &l2, &t2, &w2, &h2);
158 r1 = l1 + w1 - 1;
159 r2 = l2 + w2 - 1;
160 b1 = t1 + h1 - 1;
161 b2 = t2 + h2 - 1;
162 if (b2 < t1 || b1 < t2 || r1 < l2 || r2 < l1)
163 *presult = 0;
164 else
165 *presult = 1;
166 return 0;
167}
168
169
184BOXA *
186 BOX *box)
187{
188l_int32 i, n, val, valid;
189BOX *box1;
190BOXA *boxad;
191
192 if (!boxas)
193 return (BOXA *)ERROR_PTR("boxas not defined", __func__, NULL);
194 if (!box)
195 return (BOXA *)ERROR_PTR("box not defined", __func__, NULL);
196 n = boxaGetCount(boxas);
197 boxIsValid(box, &valid);
198 if (n == 0 || !valid)
199 return boxaCreate(1); /* empty */
200
201 boxad = boxaCreate(0);
202 for (i = 0; i < n; i++) {
203 if ((box1 = boxaGetValidBox(boxas, i, L_CLONE)) == NULL)
204 continue;
205 boxContains(box, box1, &val);
206 if (val == 1)
207 boxaAddBox(boxad, box1, L_COPY);
208 boxDestroy(&box1); /* destroy the clone */
209 }
210
211 return boxad;
212}
213
214
228l_ok
230 BOX *box,
231 l_int32 *pcount)
232{
233l_int32 i, n, val, valid;
234BOX *box1;
235
236 if (!pcount)
237 return ERROR_INT("&count not defined", __func__, 1);
238 *pcount = 0;
239 if (!boxa)
240 return ERROR_INT("boxa not defined", __func__, 1);
241 if (!box)
242 return ERROR_INT("box not defined", __func__, 1);
243 n = boxaGetCount(boxa);
244 boxIsValid(box, &valid);
245 if (n == 0 || !valid)
246 return 0;
247
248 for (i = 0; i < n; i++) {
249 if ((box1 = boxaGetValidBox(boxa, i, L_CLONE)) == NULL)
250 continue;
251 boxContains(box, box1, &val);
252 if (val == 1)
253 (*pcount)++;
254 boxDestroy(&box1);
255 }
256 return 0;
257}
258
259
268l_ok
270 BOXA *boxa2,
271 l_int32 *pcontained)
272{
273l_int32 i, j, n1, n2, cont, result;
274BOX *box1, *box2;
275
276 if (!pcontained)
277 return ERROR_INT("&contained not defined", __func__, 1);
278 *pcontained = 0;
279 if (!boxa1 || !boxa2)
280 return ERROR_INT("boxa1 and boxa2 not both defined", __func__, 1);
281
282 n1 = boxaGetCount(boxa1);
283 n2 = boxaGetCount(boxa2);
284 for (i = 0; i < n2; i++) {
285 if ((box2 = boxaGetValidBox(boxa2, i, L_CLONE)) == NULL)
286 continue;
287 cont = 0;
288 for (j = 0; j < n1; j++) {
289 if ((box1 = boxaGetValidBox(boxa1, j, L_CLONE)) == NULL)
290 continue;
291 boxContains(box1, box2, &result);
292 boxDestroy(&box1);
293 if (result) {
294 cont = 1;
295 break;
296 }
297 }
298 boxDestroy(&box2);
299 if (!cont) return 0;
300 }
301
302 *pcontained = 1;
303 return 0;
304}
305
306
321BOXA *
323 BOX *box)
324{
325l_int32 i, n, val, valid;
326BOX *box1;
327BOXA *boxad;
328
329 if (!boxas)
330 return (BOXA *)ERROR_PTR("boxas not defined", __func__, NULL);
331 if (!box)
332 return (BOXA *)ERROR_PTR("box not defined", __func__, NULL);
333 n = boxaGetCount(boxas);
334 boxIsValid(box, &valid);
335 if (n == 0 || !valid)
336 return boxaCreate(1); /* empty */
337
338 boxad = boxaCreate(0);
339 for (i = 0; i < n; i++) {
340 if ((box1 = boxaGetValidBox(boxas, i, L_CLONE)) == NULL)
341 continue;
342 boxIntersects(box, box1, &val);
343 if (val == 1)
344 boxaAddBox(boxad, box1, L_COPY);
345 boxDestroy(&box1); /* destroy the clone */
346 }
347
348 return boxad;
349}
350
351
360l_ok
362 BOX *box,
363 l_int32 *pcount)
364{
365l_int32 i, n, val, valid;
366BOX *box1;
367
368 if (!pcount)
369 return ERROR_INT("&count not defined", __func__, 1);
370 *pcount = 0;
371 if (!boxa)
372 return ERROR_INT("boxa not defined", __func__, 1);
373 if (!box)
374 return ERROR_INT("box not defined", __func__, 1);
375 n = boxaGetCount(boxa);
376 boxIsValid(box, &valid);
377 if (n == 0 || !valid)
378 return 0;
379
380 for (i = 0; i < n; i++) {
381 if ((box1 = boxaGetValidBox(boxa, i, L_CLONE)) == NULL)
382 continue;
383 boxIntersects(box, box1, &val);
384 if (val == 1)
385 (*pcount)++;
386 boxDestroy(&box1);
387 }
388 return 0;
389}
390
391
405BOXA *
407 BOX *box)
408{
409l_int32 i, n, valid;
410BOX *box1, *boxo;
411BOXA *boxad;
412
413 if (!boxas)
414 return (BOXA *)ERROR_PTR("boxas not defined", __func__, NULL);
415 if (!box)
416 return (BOXA *)ERROR_PTR("box not defined", __func__, NULL);
417 n = boxaGetCount(boxas);
418 boxIsValid(box, &valid);
419 if (n == 0 || !valid)
420 return boxaCreate(1); /* empty */
421
422 boxad = boxaCreate(0);
423 for (i = 0; i < n; i++) {
424 if ((box1 = boxaGetValidBox(boxas, i, L_CLONE)) == NULL)
425 continue;
426 if ((boxo = boxOverlapRegion(box, box1)) != NULL)
427 boxaAddBox(boxad, boxo, L_INSERT);
428 boxDestroy(&box1);
429 }
430
431 return boxad;
432}
433
434
462BOXA *
464 PIXA *pixadb)
465{
466l_int32 i, j, w, h, n1, n2, overlap, niters;
467BOX *box1, *box2, *box3;
468BOXA *boxa1, *boxa2;
469PIX *pix1 = NULL;
470
471 if (!boxas)
472 return (BOXA *)ERROR_PTR("boxas not defined", __func__, NULL);
473
474 if (pixadb) boxaGetExtent(boxas, &w, &h, NULL);
475
476 boxa1 = boxaCopy(boxas, L_COPY);
477 n1 = boxaGetCount(boxa1);
478 niters = 0;
479 while (1) { /* loop until no change from previous iteration */
480 niters++;
481 if (pixadb) {
482 pix1 = pixCreate(w + 5, h + 5, 32);
483 pixSetAll(pix1);
484 pixRenderBoxaArb(pix1, boxa1, 2, 255, 0, 0);
485 pixaAddPix(pixadb, pix1, L_COPY);
486 }
487
488 /* Combine overlaps for this iteration */
489 for (i = 0; i < n1; i++) {
490 if ((box1 = boxaGetValidBox(boxa1, i, L_COPY)) == NULL)
491 continue;
492 for (j = i + 1; j < n1; j++) {
493 if ((box2 = boxaGetValidBox(boxa1, j, L_COPY)) == NULL)
494 continue;
495 boxIntersects(box1, box2, &overlap);
496 if (overlap) {
497 box3 = boxBoundingRegion(box1, box2);
498 boxaReplaceBox(boxa1, i, box3);
499 boxaReplaceBox(boxa1, j, boxCreate(0, 0, 0, 0));
500 boxDestroy(&box1);
501 box1 = boxCopy(box3);
502 }
503 boxDestroy(&box2);
504 }
505 boxDestroy(&box1);
506 }
507 boxa2 = boxaSaveValid(boxa1, L_COPY);
508 n2 = boxaGetCount(boxa2);
509 boxaDestroy(&boxa1);
510 boxa1 = boxa2;
511 if (n1 == n2) {
512 if (pixadb) pixDestroy(&pix1);
513 break;
514 }
515 n1 = n2;
516 if (pixadb) {
517 pixRenderBoxaArb(pix1, boxa1, 2, 0, 255, 0);
518 pixaAddPix(pixadb, pix1, L_INSERT);
519 }
520 }
521
522 if (pixadb)
523 L_INFO("number of iterations: %d\n", __func__, niters);
524 return boxa1;
525}
526
527
554l_ok
556 BOXA *boxas2,
557 BOXA **pboxad1,
558 BOXA **pboxad2,
559 PIXA *pixadb)
560{
561l_int32 i, j, w, h, w2, h2, n1, n2, n1i, n2i, niters;
562l_int32 overlap, bigger, area1, area2;
563BOX *box1, *box2, *box3;
564BOXA *boxa1, *boxa2, *boxac1, *boxac2;
565PIX *pix1;
566
567 if (pboxad1) *pboxad1 = NULL;
568 if (pboxad2) *pboxad2 = NULL;
569 if (!boxas1 || !boxas2)
570 return ERROR_INT("boxas1 and boxas2 not both defined", __func__, 1);
571 if (!pboxad1 || !pboxad2)
572 return ERROR_INT("&boxad1 and &boxad2 not both defined", __func__, 1);
573
574 if (pixadb) {
575 boxaGetExtent(boxas1, &w, &h, NULL);
576 boxaGetExtent(boxas2, &w2, &h2, NULL);
577 w = L_MAX(w, w2);
578 h = L_MAX(h, w2);
579 }
580
581 /* Let the boxa with the largest area have first crack at the other */
582 boxaGetArea(boxas1, &area1);
583 boxaGetArea(boxas2, &area2);
584 if (area1 >= area2) {
585 boxac1 = boxaCopy(boxas1, L_COPY);
586 boxac2 = boxaCopy(boxas2, L_COPY);
587 } else {
588 boxac1 = boxaCopy(boxas2, L_COPY);
589 boxac2 = boxaCopy(boxas1, L_COPY);
590 }
591
592 n1i = boxaGetCount(boxac1);
593 n2i = boxaGetCount(boxac2);
594 niters = 0;
595 while (1) {
596 niters++;
597 if (pixadb) {
598 pix1 = pixCreate(w + 5, h + 5, 32);
599 pixSetAll(pix1);
600 pixRenderBoxaArb(pix1, boxac1, 2, 255, 0, 0);
601 pixRenderBoxaArb(pix1, boxac2, 2, 0, 255, 0);
602 pixaAddPix(pixadb, pix1, L_INSERT);
603 }
604
605 /* First combine boxes in each set */
606 boxa1 = boxaCombineOverlaps(boxac1, NULL);
607 boxa2 = boxaCombineOverlaps(boxac2, NULL);
608
609 /* Now combine boxes between sets */
610 n1 = boxaGetCount(boxa1);
611 n2 = boxaGetCount(boxa2);
612 for (i = 0; i < n1; i++) { /* 1 eats 2 */
613 if ((box1 = boxaGetValidBox(boxa1, i, L_COPY)) == NULL)
614 continue;
615 for (j = 0; j < n2; j++) {
616 if ((box2 = boxaGetValidBox(boxa2, j, L_COPY)) == NULL)
617 continue;
618 boxIntersects(box1, box2, &overlap);
619 boxCompareSize(box1, box2, L_SORT_BY_AREA, &bigger);
620 if (overlap && (bigger == 1)) {
621 box3 = boxBoundingRegion(box1, box2);
622 boxaReplaceBox(boxa1, i, box3);
623 boxaReplaceBox(boxa2, j, boxCreate(0, 0, 0, 0));
624 boxDestroy(&box1);
625 box1 = boxCopy(box3);
626 }
627 boxDestroy(&box2);
628 }
629 boxDestroy(&box1);
630 }
631 for (i = 0; i < n2; i++) { /* 2 eats 1 */
632 if ((box2 = boxaGetValidBox(boxa2, i, L_COPY)) == NULL)
633 continue;
634 for (j = 0; j < n1; j++) {
635 if ((box1 = boxaGetValidBox(boxa1, j, L_COPY)) == NULL)
636 continue;
637 boxIntersects(box1, box2, &overlap);
638 boxCompareSize(box2, box1, L_SORT_BY_AREA, &bigger);
639 if (overlap && (bigger == 1)) {
640 box3 = boxBoundingRegion(box1, box2);
641 boxaReplaceBox(boxa2, i, box3);
642 boxaReplaceBox(boxa1, j, boxCreate(0, 0, 0, 0));
643 boxDestroy(&box2);
644 box2 = boxCopy(box3);
645 }
646 boxDestroy(&box1);
647 }
648 boxDestroy(&box2);
649 }
650 boxaDestroy(&boxac1);
651 boxaDestroy(&boxac2);
652 boxac1 = boxaSaveValid(boxa1, L_COPY); /* remove invalid boxes */
653 boxac2 = boxaSaveValid(boxa2, L_COPY);
654 boxaDestroy(&boxa1);
655 boxaDestroy(&boxa2);
656 n1 = boxaGetCount(boxac1);
657 n2 = boxaGetCount(boxac2);
658 if (n1 == n1i && n2 == n2i) break;
659 n1i = n1;
660 n2i = n2;
661 if (pixadb) {
662 pix1 = pixCreate(w + 5, h + 5, 32);
663 pixSetAll(pix1);
664 pixRenderBoxaArb(pix1, boxac1, 2, 255, 0, 0);
665 pixRenderBoxaArb(pix1, boxac2, 2, 0, 255, 0);
666 pixaAddPix(pixadb, pix1, L_INSERT);
667 }
668 }
669
670 if (pixadb)
671 L_INFO("number of iterations: %d\n", __func__, niters);
672 *pboxad1 = boxac1;
673 *pboxad2 = boxac2;
674 return 0;
675}
676
677
690BOX *
692 BOX *box2)
693{
694l_int32 l1, l2, r1, r2, t1, t2, b1, b2, w1, h1, w2, h2, ld, td, rd, bd;
695l_int32 valid1, valid2;
696
697 if (!box1 || !box2)
698 return (BOX *)ERROR_PTR("boxes not both defined", __func__, NULL);
699 boxIsValid(box1, &valid1);
700 boxIsValid(box2, &valid2);
701 if (!valid1 || !valid2) {
702 L_WARNING("at least one box is invalid\n", __func__);
703 return NULL;
704 }
705
706 boxGetGeometry(box1, &l1, &t1, &w1, &h1);
707 boxGetGeometry(box2, &l2, &t2, &w2, &h2);
708 r1 = l1 + w1 - 1;
709 r2 = l2 + w2 - 1;
710 b1 = t1 + h1 - 1;
711 b2 = t2 + h2 - 1;
712 if (b2 < t1 || b1 < t2 || r1 < l2 || r2 < l1)
713 return NULL;
714
715 ld = L_MAX(l1, l2);
716 td = L_MAX(t1, t2);
717 rd = L_MIN(r1, r2);
718 bd = L_MIN(b1, b2);
719 return boxCreate(ld, td, rd - ld + 1, bd - td + 1);
720}
721
722
738BOX *
740 BOX *box2)
741{
742l_int32 l1, l2, r1, r2, t1, t2, b1, b2, w1, h1, w2, h2, ld, td, rd, bd;
743l_int32 valid1, valid2;
744
745 if (!box1 || !box2)
746 return (BOX *)ERROR_PTR("boxes not both defined", __func__, NULL);
747 boxIsValid(box1, &valid1);
748 boxIsValid(box2, &valid2);
749 if (!valid1 && !valid2) {
750 L_WARNING("both boxes are invalid\n", __func__);
751 return boxCreate(0, 0, 0, 0);
752 }
753 if (valid1 && !valid2)
754 return boxCopy(box1);
755 if (!valid1 && valid2)
756 return boxCopy(box2);
757
758 boxGetGeometry(box1, &l1, &t1, &w1, &h1);
759 boxGetGeometry(box2, &l2, &t2, &w2, &h2);
760 r1 = l1 + w1 - 1;
761 r2 = l2 + w2 - 1;
762 b1 = t1 + h1 - 1;
763 b2 = t2 + h2 - 1;
764 ld = L_MIN(l1, l2);
765 td = L_MIN(t1, t2);
766 rd = L_MAX(r1, r2);
767 bd = L_MAX(b1, b2);
768 return boxCreate(ld, td, rd - ld + 1, bd - td + 1);
769}
770
771
786l_ok
788 BOX *box2,
789 l_float32 *pfract)
790{
791l_int32 w2, h2, w, h, valid1, valid2;
792BOX *boxo;
793
794 if (!pfract)
795 return ERROR_INT("&fract not defined", __func__, 1);
796 *pfract = 0.0;
797 if (!box1 || !box2)
798 return ERROR_INT("boxes not both defined", __func__, 1);
799 boxIsValid(box1, &valid1);
800 boxIsValid(box2, &valid2);
801 if (!valid1 || !valid2) {
802 L_WARNING("boxes not both valid\n", __func__);
803 return 0;
804 }
805
806 if ((boxo = boxOverlapRegion(box1, box2)) == NULL) /* no overlap */
807 return 0;
808
809 boxGetGeometry(box2, NULL, NULL, &w2, &h2);
810 boxGetGeometry(boxo, NULL, NULL, &w, &h);
811 *pfract = (l_float32)(w * h) / (l_float32)(w2 * h2);
812 boxDestroy(&boxo);
813 return 0;
814}
815
816
824l_ok
826 BOX *box2,
827 l_int32 *parea)
828{
829l_int32 w, h, valid1, valid2;
830BOX *box;
831
832 if (!parea)
833 return ERROR_INT("&area not defined", __func__, 1);
834 *parea = 0;
835 if (!box1 || !box2)
836 return ERROR_INT("boxes not both defined", __func__, 1);
837 boxIsValid(box1, &valid1);
838 boxIsValid(box2, &valid2);
839 if (!valid1 || !valid2)
840 return ERROR_INT("boxes not both valid", __func__, 1);
841
842 if ((box = boxOverlapRegion(box1, box2)) == NULL) /* no overlap */
843 return 0;
844
845 boxGetGeometry(box, NULL, NULL, &w, &h);
846 *parea = w * h;
847 boxDestroy(&box);
848 return 0;
849}
850
851
886BOXA *
888 l_int32 op,
889 l_int32 range,
890 l_float32 min_overlap,
891 l_float32 max_ratio,
892 NUMA **pnamap)
893{
894l_int32 i, j, n, w, h, area1, area2, val;
895l_int32 overlap_area;
896l_float32 overlap_ratio, area_ratio;
897BOX *box1, *box2, *box3;
898BOXA *boxat, *boxad;
899NUMA *namap;
900
901 if (pnamap) *pnamap = NULL;
902 if (!boxas)
903 return (BOXA *)ERROR_PTR("boxas not defined", __func__, NULL);
904 if (op != L_COMBINE && op != L_REMOVE_SMALL)
905 return (BOXA *)ERROR_PTR("invalid op", __func__, NULL);
906
907 n = boxaGetCount(boxas);
908 if (n == 0)
909 return boxaCreate(1); /* empty */
910 if (range == 0) {
911 L_WARNING("range is 0\n", __func__);
912 return boxaCopy(boxas, L_COPY);
913 }
914
915 /* Identify smaller boxes in overlap pairs, and mark to eliminate. */
916 namap = numaMakeConstant(-1, n);
917 for (i = 0; i < n; i++) {
918 if ((box1 = boxaGetValidBox(boxas, i, L_CLONE)) == NULL)
919 continue;
920 boxGetGeometry(box1, NULL, NULL, &w, &h);
921 area1 = w * h;
922 if (area1 == 0) {
923 boxDestroy(&box1);
924 continue;
925 }
926 for (j = i + 1; j < i + 1 + range && j < n; j++) {
927 if ((box2 = boxaGetValidBox(boxas, j, L_CLONE)) == NULL)
928 continue;
929 boxOverlapArea(box1, box2, &overlap_area);
930 if (overlap_area > 0) {
931 boxGetGeometry(box2, NULL, NULL, &w, &h);
932 area2 = w * h;
933 if (area2 == 0) {
934 /* do nothing */
935 } else if (area1 >= area2) {
936 overlap_ratio = (l_float32)overlap_area / (l_float32)area2;
937 area_ratio = (l_float32)area2 / (l_float32)area1;
938 if (overlap_ratio >= min_overlap &&
939 area_ratio <= max_ratio) {
940 numaSetValue(namap, j, i);
941 }
942 } else {
943 overlap_ratio = (l_float32)overlap_area / (l_float32)area1;
944 area_ratio = (l_float32)area1 / (l_float32)area2;
945 if (overlap_ratio >= min_overlap &&
946 area_ratio <= max_ratio) {
947 numaSetValue(namap, i, j);
948 }
949 }
950 }
951 boxDestroy(&box2);
952 }
953 boxDestroy(&box1);
954 }
955
956 boxat = boxaCopy(boxas, L_COPY);
957 if (op == L_COMBINE) {
958 /* Resize the larger of the pair to the bounding region */
959 for (i = 0; i < n; i++) {
960 numaGetIValue(namap, i, &val);
961 if (val >= 0) {
962 box1 = boxaGetBox(boxas, i, L_CLONE); /* smaller */
963 box2 = boxaGetBox(boxas, val, L_CLONE); /* larger */
964 box3 = boxBoundingRegion(box1, box2);
965 boxaReplaceBox(boxat, val, box3);
966 boxDestroy(&box1);
967 boxDestroy(&box2);
968 }
969 }
970 }
971
972 /* Remove the smaller of the pairs */
973 boxad = boxaCreate(n);
974 for (i = 0; i < n; i++) {
975 numaGetIValue(namap, i, &val);
976 if (val == -1) {
977 box1 = boxaGetBox(boxat, i, L_COPY);
978 boxaAddBox(boxad, box1, L_INSERT);
979 }
980 }
981 boxaDestroy(&boxat);
982 if (pnamap)
983 *pnamap = namap;
984 else
985 numaDestroy(&namap);
986 return boxad;
987}
988
989
1014l_ok
1016 BOX *box2,
1017 l_int32 *ph_ovl,
1018 l_int32 *pv_ovl)
1019{
1020l_int32 l1, t1, w1, h1, r1, b1, l2, t2, w2, h2, r2, b2, valid1, valid2;
1021
1022 if (!ph_ovl && !pv_ovl)
1023 return ERROR_INT("nothing to do", __func__, 1);
1024 if (ph_ovl) *ph_ovl = 0;
1025 if (pv_ovl) *pv_ovl = 0;
1026 if (!box1 || !box2)
1027 return ERROR_INT("boxes not both defined", __func__, 1);
1028 boxIsValid(box1, &valid1);
1029 boxIsValid(box2, &valid2);
1030 if (!valid1 || !valid2)
1031 return ERROR_INT("boxes not both valid", __func__, 1);
1032
1033 if (ph_ovl) {
1034 boxGetGeometry(box1, &l1, NULL, &w1, NULL);
1035 boxGetGeometry(box2, &l2, NULL, &w2, NULL);
1036 r1 = l1 + w1; /* 1 pixel to the right of box 1 */
1037 r2 = l2 + w2;
1038 if (l2 >= l1)
1039 *ph_ovl = r1 - l2;
1040 else
1041 *ph_ovl = r2 - l1;
1042 }
1043 if (pv_ovl) {
1044 boxGetGeometry(box1, NULL, &t1, NULL, &h1);
1045 boxGetGeometry(box2, NULL, &t2, NULL, &h2);
1046 b1 = t1 + h1; /* 1 pixel below box 1 */
1047 b2 = t2 + h2;
1048 if (t2 >= t1)
1049 *pv_ovl = b1 - t2;
1050 else
1051 *pv_ovl = b2 - t1;
1052 }
1053 return 0;
1054}
1055
1056
1085l_ok
1087 BOX *box2,
1088 l_int32 *ph_sep,
1089 l_int32 *pv_sep)
1090{
1091l_int32 h_ovl, v_ovl, valid1, valid2;
1092
1093 if (ph_sep) *ph_sep = 0;
1094 if (pv_sep) *pv_sep = 0;
1095 if (!ph_sep || !pv_sep)
1096 return ERROR_INT("&h_sep and &v_sep not both defined", __func__, 1);
1097 if (!box1 || !box2)
1098 return ERROR_INT("boxes not both defined", __func__, 1);
1099 boxIsValid(box1, &valid1);
1100 boxIsValid(box2, &valid2);
1101 if (!valid1 || !valid2)
1102 return ERROR_INT("boxes not both valid", __func__, 1);
1103
1104 boxOverlapDistance(box1, box2, &h_ovl, &v_ovl);
1105 if (h_ovl <= 0)
1106 *ph_sep = -h_ovl + 1;
1107 if (v_ovl <= 0)
1108 *pv_sep = -v_ovl + 1;
1109 return 0;
1110}
1111
1112
1128l_ok
1130 BOX *box2,
1131 l_int32 type,
1132 l_int32 *prel)
1133{
1134l_int32 w1, h1, w2, h2, size1, size2, valid1, valid2;
1135
1136 if (!prel)
1137 return ERROR_INT("&rel not defined", __func__, 1);
1138 *prel = 0;
1139 if (!box1 || !box2)
1140 return ERROR_INT("boxes not both defined", __func__, 1);
1141 boxIsValid(box1, &valid1);
1142 boxIsValid(box2, &valid2);
1143 if (!valid1 || !valid2)
1144 return ERROR_INT("boxes not both valid", __func__, 1);
1145 if (type != L_SORT_BY_WIDTH && type != L_SORT_BY_HEIGHT &&
1146 type != L_SORT_BY_MAX_DIMENSION && type != L_SORT_BY_PERIMETER &&
1147 type != L_SORT_BY_AREA)
1148 return ERROR_INT("invalid compare type", __func__, 1);
1149
1150 boxGetGeometry(box1, NULL, NULL, &w1, &h1);
1151 boxGetGeometry(box2, NULL, NULL, &w2, &h2);
1152 if (type == L_SORT_BY_WIDTH) {
1153 *prel = (w1 > w2) ? 1 : ((w1 == w2) ? 0 : -1);
1154 } else if (type == L_SORT_BY_HEIGHT) {
1155 *prel = (h1 > h2) ? 1 : ((h1 == h2) ? 0 : -1);
1156 } else if (type == L_SORT_BY_MAX_DIMENSION) {
1157 size1 = L_MAX(w1, h1);
1158 size2 = L_MAX(w2, h2);
1159 *prel = (size1 > size2) ? 1 : ((size1 == size2) ? 0 : -1);
1160 } else if (type == L_SORT_BY_PERIMETER) {
1161 size1 = w1 + h1;
1162 size2 = w2 + h2;
1163 *prel = (size1 > size2) ? 1 : ((size1 == size2) ? 0 : -1);
1164 } else if (type == L_SORT_BY_AREA) {
1165 size1 = w1 * h1;
1166 size2 = w2 * h2;
1167 *prel = (size1 > size2) ? 1 : ((size1 == size2) ? 0 : -1);
1168 }
1169 return 0;
1170}
1171
1172
1181l_ok
1183 l_float32 x,
1184 l_float32 y,
1185 l_int32 *pcontains)
1186{
1187l_int32 bx, by, bw, bh;
1188
1189 if (!pcontains)
1190 return ERROR_INT("&contains not defined", __func__, 1);
1191 *pcontains = 0;
1192 if (!box)
1193 return ERROR_INT("&box not defined", __func__, 1);
1194 boxGetGeometry(box, &bx, &by, &bw, &bh);
1195 if (x >= bx && x < bx + bw && y >= by && y < by + bh)
1196 *pcontains = 1;
1197 return 0;
1198}
1199
1200
1214BOX *
1216 l_int32 x,
1217 l_int32 y)
1218{
1219l_int32 i, n, minindex;
1220l_float32 delx, dely, dist, mindist, cx, cy;
1221BOX *box;
1222
1223 if (!boxa)
1224 return (BOX *)ERROR_PTR("boxa not defined", __func__, NULL);
1225 if ((n = boxaGetCount(boxa)) == 0)
1226 return (BOX *)ERROR_PTR("n = 0", __func__, NULL);
1227
1228 mindist = 1000000000.;
1229 minindex = 0;
1230 for (i = 0; i < n; i++) {
1231 if ((box = boxaGetValidBox(boxa, i, L_CLONE)) == NULL)
1232 continue;
1233 boxGetCenter(box, &cx, &cy);
1234 delx = (l_float32)(cx - x);
1235 dely = (l_float32)(cy - y);
1236 dist = delx * delx + dely * dely;
1237 if (dist < mindist) {
1238 minindex = i;
1239 mindist = dist;
1240 }
1241 boxDestroy(&box);
1242 }
1243
1244 return boxaGetBox(boxa, minindex, L_COPY);
1245}
1246
1247
1265BOX *
1267 l_int32 x,
1268 l_int32 y)
1269{
1270l_int32 i, n, minindex;
1271l_float32 dist, mindist, cx, cy;
1272BOX *box;
1273
1274 if (!boxa)
1275 return (BOX *)ERROR_PTR("boxa not defined", __func__, NULL);
1276 if ((n = boxaGetCount(boxa)) == 0)
1277 return (BOX *)ERROR_PTR("n = 0", __func__, NULL);
1278 if (y >= 0 && x >= 0)
1279 return (BOX *)ERROR_PTR("either x or y must be < 0", __func__, NULL);
1280 if (y < 0 && x < 0)
1281 return (BOX *)ERROR_PTR("either x or y must be >= 0", __func__, NULL);
1282
1283 mindist = 1000000000.;
1284 minindex = 0;
1285 for (i = 0; i < n; i++) {
1286 if ((box = boxaGetValidBox(boxa, i, L_CLONE)) == NULL)
1287 continue;
1288 boxGetCenter(box, &cx, &cy);
1289 if (x >= 0)
1290 dist = L_ABS(cx - (l_float32)x);
1291 else /* y >= 0 */
1292 dist = L_ABS(cy - (l_float32)y);
1293 if (dist < mindist) {
1294 minindex = i;
1295 mindist = dist;
1296 }
1297 boxDestroy(&box);
1298 }
1299
1300 return boxaGetBox(boxa, minindex, L_COPY);
1301}
1302
1303
1321l_ok
1323 l_int32 dist_select,
1324 l_int32 range,
1325 NUMAA **pnaaindex,
1326 NUMAA **pnaadist)
1327{
1328l_int32 i, n, index, dist;
1329NUMA *nai, *nad;
1330NUMAA *naai, *naad;
1331
1332 if (pnaaindex) *pnaaindex = NULL;
1333 if (pnaadist) *pnaadist = NULL;
1334 if (!pnaaindex)
1335 return ERROR_INT("&naaindex not defined", __func__, 1);
1336 if (!pnaadist)
1337 return ERROR_INT("&naadist not defined", __func__, 1);
1338 if (!boxa)
1339 return ERROR_INT("boxa not defined", __func__, 1);
1340
1341 n = boxaGetCount(boxa);
1342 naai = numaaCreate(n);
1343 naad = numaaCreate(n);
1344 *pnaaindex = naai;
1345 *pnaadist = naad;
1346 for (i = 0; i < n; i++) {
1347 nai = numaCreate(4);
1348 nad = numaCreate(4);
1349 boxaGetNearestByDirection(boxa, i, L_FROM_LEFT, dist_select,
1350 range, &index, &dist);
1351 numaAddNumber(nai, index);
1352 numaAddNumber(nad, dist);
1353 boxaGetNearestByDirection(boxa, i, L_FROM_RIGHT, dist_select,
1354 range, &index, &dist);
1355 numaAddNumber(nai, index);
1356 numaAddNumber(nad, dist);
1357 boxaGetNearestByDirection(boxa, i, L_FROM_TOP, dist_select,
1358 range, &index, &dist);
1359 numaAddNumber(nai, index);
1360 numaAddNumber(nad, dist);
1361 boxaGetNearestByDirection(boxa, i, L_FROM_BOT, dist_select,
1362 range, &index, &dist);
1363 numaAddNumber(nai, index);
1364 numaAddNumber(nad, dist);
1365 numaaAddNuma(naai, nai, L_INSERT);
1366 numaaAddNuma(naad, nad, L_INSERT);
1367 }
1368 return 0;
1369}
1370
1371
1400l_ok
1402 l_int32 i,
1403 l_int32 dir,
1404 l_int32 dist_select,
1405 l_int32 range,
1406 l_int32 *pindex,
1407 l_int32 *pdist)
1408{
1409l_int32 j, jmin, jmax, n, mindist, dist, index;
1410l_int32 x, y, w, h, bx, by, bw, bh;
1411
1412 if (pindex) *pindex = -1;
1413 if (pdist) *pdist = 100000;
1414 if (!pindex)
1415 return ERROR_INT("&index not defined", __func__, 1);
1416 if (!pdist)
1417 return ERROR_INT("&dist not defined", __func__, 1);
1418 if (!boxa)
1419 return ERROR_INT("boxa not defined", __func__, 1);
1420 if (dir != L_FROM_LEFT && dir != L_FROM_RIGHT &&
1421 dir != L_FROM_TOP && dir != L_FROM_BOT)
1422 return ERROR_INT("invalid dir", __func__, 1);
1423 if (dist_select != L_NON_NEGATIVE && dist_select != L_ALL)
1424 return ERROR_INT("invalid dist_select", __func__, 1);
1425 n = boxaGetCount(boxa);
1426 if (i < 0 || i >= n)
1427 return ERROR_INT("invalid box index", __func__, 1);
1428
1429 jmin = (range <= 0) ? 0 : L_MAX(0, i - range);
1430 jmax = (range <= 0) ? n - 1 : L_MIN(n -1, i + range);
1431 boxaGetBoxGeometry(boxa, i, &x, &y, &w, &h);
1432 mindist = 100000;
1433 index = -1;
1434 if (dir == L_FROM_LEFT || dir == L_FROM_RIGHT) {
1435 for (j = jmin; j <= jmax; j++) {
1436 if (j == i) continue;
1437 boxaGetBoxGeometry(boxa, j, &bx, &by, &bw, &bh);
1438 if ((bx >= x && dir == L_FROM_LEFT) || /* not to the left */
1439 (x >= bx && dir == L_FROM_RIGHT)) /* not to the right */
1440 continue;
1441 if (boxHasOverlapInXorY(y, h, by, bh) == 1) {
1442 dist = boxGetDistanceInXorY(x, w, bx, bw);
1443 if (dist_select == L_NON_NEGATIVE && dist < 0) continue;
1444 if (dist < mindist) {
1445 mindist = dist;
1446 index = j;
1447 }
1448 }
1449 }
1450 } else if (dir == L_FROM_TOP || dir == L_FROM_BOT) {
1451 for (j = jmin; j <= jmax; j++) {
1452 if (j == i) continue;
1453 boxaGetBoxGeometry(boxa, j, &bx, &by, &bw, &bh);
1454 if ((by >= y && dir == L_FROM_TOP) || /* not above */
1455 (y >= by && dir == L_FROM_BOT)) /* not below */
1456 continue;
1457 if (boxHasOverlapInXorY(x, w, bx, bw) == 1) {
1458 dist = boxGetDistanceInXorY(y, h, by, bh);
1459 if (dist_select == L_NON_NEGATIVE && dist < 0) continue;
1460 if (dist < mindist) {
1461 mindist = dist;
1462 index = j;
1463 }
1464 }
1465 }
1466 }
1467 *pindex = index;
1468 *pdist = mindist;
1469 return 0;
1470}
1471
1472
1488static l_int32
1490 l_int32 s1,
1491 l_int32 c2,
1492 l_int32 s2)
1493{
1494l_int32 ovlp;
1495
1496 if (c1 > c2)
1497 ovlp = c2 + s2 - 1 - c1;
1498 else
1499 ovlp = c1 + s1 - 1 - c2;
1500 return (ovlp < 0) ? 0 : 1;
1501}
1502
1503
1514static l_int32
1516 l_int32 s1,
1517 l_int32 c2,
1518 l_int32 s2)
1519{
1520l_int32 dist;
1521
1522 if (c1 > c2)
1523 dist = c1 - (c2 + s2 - 1);
1524 else
1525 dist = c2 - (c1 + s1 - 1);
1526 return dist;
1527}
1528
1529
1537l_ok
1539 l_float32 *pcx,
1540 l_float32 *pcy)
1541{
1542l_int32 x, y, w, h;
1543
1544 if (pcx) *pcx = 0;
1545 if (pcy) *pcy = 0;
1546 if (!pcx || !pcy)
1547 return ERROR_INT("&cx, &cy not both defined", __func__, 1);
1548 if (!box)
1549 return ERROR_INT("box not defined", __func__, 1);
1550 boxGetGeometry(box, &x, &y, &w, &h);
1551 if (w == 0 || h == 0) return 1;
1552 *pcx = (l_float32)(x + 0.5 * w);
1553 *pcy = (l_float32)(y + 0.5 * h);
1554
1555 return 0;
1556}
1557
1558
1577l_ok
1579 l_int32 x,
1580 l_int32 y,
1581 l_float32 slope,
1582 l_int32 *px1,
1583 l_int32 *py1,
1584 l_int32 *px2,
1585 l_int32 *py2,
1586 l_int32 *pn)
1587{
1588l_int32 bx, by, bw, bh, xp, yp, xt, yt, i, n;
1589l_float32 invslope;
1590PTA *pta;
1591
1592 if (px1) *px1 = 0;
1593 if (px2) *px2 = 0;
1594 if (py1) *py1 = 0;
1595 if (py2) *py2 = 0;
1596 if (pn) *pn = 0;
1597 if (!px1 || !py1 || !px2 || !py2)
1598 return ERROR_INT("&x1, &y1, &x2, &y2 not all defined", __func__, 1);
1599 if (!pn)
1600 return ERROR_INT("&n not defined", __func__, 1);
1601 if (!box)
1602 return ERROR_INT("box not defined", __func__, 1);
1603 boxGetGeometry(box, &bx, &by, &bw, &bh);
1604 if (bw == 0 || bh == 0) return 1;
1605
1606 if (slope == 0.0) {
1607 if (y >= by && y < by + bh) {
1608 *py1 = *py2 = y;
1609 *px1 = bx;
1610 *px2 = bx + bw - 1;
1611 }
1612 return 0;
1613 }
1614
1615 if (slope > 1000000.0) {
1616 if (x >= bx && x < bx + bw) {
1617 *px1 = *px2 = x;
1618 *py1 = by;
1619 *py2 = by + bh - 1;
1620 }
1621 return 0;
1622 }
1623
1624 /* Intersection with top and bottom lines of box */
1625 pta = ptaCreate(2);
1626 invslope = 1.0 / slope;
1627 xp = (l_int32)(x + invslope * (y - by));
1628 if (xp >= bx && xp < bx + bw)
1629 ptaAddPt(pta, xp, by);
1630 xp = (l_int32)(x + invslope * (y - by - bh + 1));
1631 if (xp >= bx && xp < bx + bw)
1632 ptaAddPt(pta, xp, by + bh - 1);
1633
1634 /* Intersection with left and right lines of box */
1635 yp = (l_int32)(y + slope * (x - bx));
1636 if (yp >= by && yp < by + bh)
1637 ptaAddPt(pta, bx, yp);
1638 yp = (l_int32)(y + slope * (x - bx - bw + 1));
1639 if (yp >= by && yp < by + bh)
1640 ptaAddPt(pta, bx + bw - 1, yp);
1641
1642 /* There is a maximum of 2 unique points; remove duplicates. */
1643 n = ptaGetCount(pta);
1644 if (n > 0) {
1645 ptaGetIPt(pta, 0, px1, py1); /* accept the first one */
1646 *pn = 1;
1647 }
1648 for (i = 1; i < n; i++) {
1649 ptaGetIPt(pta, i, &xt, &yt);
1650 if ((*px1 != xt) || (*py1 != yt)) {
1651 *px2 = xt;
1652 *py2 = yt;
1653 *pn = 2;
1654 break;
1655 }
1656 }
1657
1658 ptaDestroy(&pta);
1659 return 0;
1660}
1661
1662
1678BOX *
1680 l_int32 wi,
1681 l_int32 hi)
1682{
1683BOX *boxd;
1684
1685 if (!box)
1686 return (BOX *)ERROR_PTR("box not defined", __func__, NULL);
1687 if (box->x >= wi || box->y >= hi ||
1688 box->x + box->w <= 0 || box->y + box->h <= 0)
1689 return (BOX *)ERROR_PTR("box outside rectangle", __func__, NULL);
1690
1691 boxd = boxCopy(box);
1692 if (boxd->x < 0) {
1693 boxd->w += boxd->x;
1694 boxd->x = 0;
1695 }
1696 if (boxd->y < 0) {
1697 boxd->h += boxd->y;
1698 boxd->y = 0;
1699 }
1700 if (boxd->x + boxd->w > wi)
1701 boxd->w = wi - boxd->x;
1702 if (boxd->y + boxd->h > hi)
1703 boxd->h = hi - boxd->y;
1704 return boxd;
1705}
1706
1707
1733l_ok
1735 l_int32 w,
1736 l_int32 h,
1737 l_int32 *pxstart,
1738 l_int32 *pystart,
1739 l_int32 *pxend,
1740 l_int32 *pyend,
1741 l_int32 *pbw,
1742 l_int32 *pbh)
1743{
1744l_int32 bw, bh;
1745BOX *boxc;
1746
1747 if (pxstart) *pxstart = 0;
1748 if (pystart) *pystart = 0;
1749 if (pxend) *pxend = w;
1750 if (pyend) *pyend = h;
1751 if (pbw) *pbw = w;
1752 if (pbh) *pbh = h;
1753 if (!pxstart || !pystart || !pxend || !pyend)
1754 return ERROR_INT("invalid ptr input", __func__, 1);
1755 if (!box) return 0;
1756
1757 if ((boxc = boxClipToRectangle(box, w, h)) == NULL)
1758 return ERROR_INT("box outside image", __func__, 1);
1759 boxGetGeometry(boxc, pxstart, pystart, &bw, &bh);
1760 boxDestroy(&boxc);
1761
1762 if (pbw) *pbw = bw;
1763 if (pbh) *pbh = bh;
1764 if (bw == 0 || bh == 0)
1765 return ERROR_INT("invalid clipping box", __func__, 1);
1766 *pxend = *pxstart + bw; /* 1 past the end */
1767 *pyend = *pystart + bh; /* 1 past the end */
1768 return 0;
1769}
1770
1771
1793BOX *
1795 BOX *boxs,
1796 l_int32 loc,
1797 l_int32 sideflag)
1798{
1799l_int32 x, y, w, h;
1800
1801 if (!boxs)
1802 return (BOX *)ERROR_PTR("boxs not defined", __func__, NULL);
1803 if (!boxd)
1804 boxd = boxCopy(boxs);
1805
1806 boxGetGeometry(boxs, &x, &y, &w, &h);
1807 if (w == 0 || h == 0)
1808 return boxd;
1809 if (sideflag == L_FROM_LEFT)
1810 boxSetGeometry(boxd, loc, -1, w + x - loc, -1);
1811 else if (sideflag == L_FROM_RIGHT)
1812 boxSetGeometry(boxd, -1, -1, loc - x + 1, -1);
1813 else if (sideflag == L_FROM_TOP)
1814 boxSetGeometry(boxd, -1, loc, -1, h + y - loc);
1815 else if (sideflag == L_FROM_BOT)
1816 boxSetGeometry(boxd, -1, -1, -1, loc - y + 1);
1817 return boxd;
1818}
1819
1820
1837BOXA *
1839 l_int32 delleft,
1840 l_int32 delright,
1841 l_int32 deltop,
1842 l_int32 delbot)
1843{
1844l_int32 n, i, x, y;
1845BOX *box1, *box2;
1846BOXA *boxad;
1847
1848 if (!boxas)
1849 return (BOXA *)ERROR_PTR("boxas not defined", __func__, NULL);
1850
1851 n = boxaGetCount(boxas);
1852 boxad = boxaCreate(n);
1853 for (i = 0; i < n; i++) {
1854 box1 = boxaGetBox(boxas, i, L_COPY);
1855 box2 = boxAdjustSides(NULL, box1, delleft, delright, deltop, delbot);
1856 if (!box2) {
1857 boxGetGeometry(box1, &x, &y, NULL, NULL);
1858 box2 = boxCreate(x, y, 1, 1);
1859 }
1860 boxaAddBox(boxad, box2, L_INSERT);
1861 boxDestroy(&box1);
1862 }
1863
1864 return boxad;
1865}
1866
1867
1885l_ok
1887 l_int32 index,
1888 l_int32 delleft,
1889 l_int32 delright,
1890 l_int32 deltop,
1891 l_int32 delbot)
1892{
1893BOX *box;
1894
1895 if (!boxa)
1896 return ERROR_INT("boxa not defined", __func__, 1);
1897
1898 if ((box = boxaGetBox(boxa, index, L_CLONE)) == NULL)
1899 return ERROR_INT("invalid index", __func__, 1);
1900
1901 boxAdjustSides(box, box, delleft, delright, deltop, delbot);
1902 boxDestroy(&box); /* the clone */
1903 return 0;
1904}
1905
1906
1931BOX *
1933 BOX *boxs,
1934 l_int32 delleft,
1935 l_int32 delright,
1936 l_int32 deltop,
1937 l_int32 delbot)
1938{
1939l_int32 x, y, w, h, xl, xr, yt, yb, wnew, hnew;
1940
1941 if (!boxs)
1942 return (BOX *)ERROR_PTR("boxs not defined", __func__, NULL);
1943
1944 boxGetGeometry(boxs, &x, &y, &w, &h);
1945 xl = L_MAX(0, x + delleft);
1946 yt = L_MAX(0, y + deltop);
1947 xr = x + w + delright; /* one pixel beyond right edge */
1948 yb = y + h + delbot; /* one pixel below bottom edge */
1949 wnew = xr - xl;
1950 hnew = yb - yt;
1951
1952 if (wnew < 1 || hnew < 1)
1953 return (BOX *)ERROR_PTR("boxd has 0 area", __func__, NULL);
1954 if (!boxd)
1955 return boxCreate(xl, yt, wnew, hnew);
1956
1957 boxSetGeometry(boxd, xl, yt, wnew, hnew);
1958 return boxd;
1959}
1960
1961
1981BOXA *
1983 BOXA *boxas,
1984 l_int32 side,
1985 l_int32 val,
1986 l_int32 thresh)
1987{
1988l_int32 n, i;
1989BOX *box;
1990
1991 if (!boxas)
1992 return (BOXA *)ERROR_PTR("boxas not defined", __func__, NULL);
1993 if (boxad && (boxas != boxad))
1994 return (BOXA *)ERROR_PTR("not in-place", __func__, NULL);
1995 if (side != L_SET_LEFT && side != L_SET_RIGHT &&
1996 side != L_SET_TOP && side != L_SET_BOT)
1997 return (BOXA *)ERROR_PTR("invalid side", __func__, NULL);
1998 if (val < 0)
1999 return (BOXA *)ERROR_PTR("val < 0", __func__, NULL);
2000
2001 if (!boxad)
2002 boxad = boxaCopy(boxas, L_COPY);
2003 n = boxaGetCount(boxad);
2004 for (i = 0; i < n; i++) {
2005 box = boxaGetBox(boxad, i, L_CLONE);
2006 boxSetSide(box, side, val, thresh);
2007 boxDestroy(&box); /* the clone */
2008 }
2009
2010 return boxad;
2011}
2012
2013
2029l_ok
2031 l_int32 side,
2032 l_int32 val,
2033 l_int32 thresh)
2034{
2035l_int32 x, y, w, h, diff;
2036
2037 if (!boxs)
2038 return ERROR_INT("box not defined", __func__, 1);
2039 if (side != L_SET_LEFT && side != L_SET_RIGHT &&
2040 side != L_SET_TOP && side != L_SET_BOT)
2041 return ERROR_INT("invalid side", __func__, 1);
2042 if (val < 0)
2043 return ERROR_INT("val < 0", __func__, 1);
2044
2045 boxGetGeometry(boxs, &x, &y, &w, &h);
2046 if (side == L_SET_LEFT) {
2047 diff = x - val;
2048 if (L_ABS(diff) >= thresh)
2049 boxSetGeometry(boxs, val, y, w + diff, h);
2050 } else if (side == L_SET_RIGHT) {
2051 diff = x + w -1 - val;
2052 if (L_ABS(diff) >= thresh)
2053 boxSetGeometry(boxs, x, y, val - x + 1, h);
2054 } else if (side == L_SET_TOP) {
2055 diff = y - val;
2056 if (L_ABS(diff) >= thresh)
2057 boxSetGeometry(boxs, x, val, w, h + diff);
2058 } else { /* side == L_SET_BOT */
2059 diff = y + h - 1 - val;
2060 if (L_ABS(diff) >= thresh)
2061 boxSetGeometry(boxs, x, y, w, val - y + 1);
2062 }
2063
2064 return 0;
2065}
2066
2067
2089BOXA *
2091 BOXA *boxas,
2092 l_int32 sides,
2093 l_int32 target,
2094 l_int32 thresh)
2095{
2096l_int32 x, y, w, h, n, i, diff;
2097BOX *box;
2098
2099 if (!boxas)
2100 return (BOXA *)ERROR_PTR("boxas not defined", __func__, NULL);
2101 if (boxad && (boxas != boxad))
2102 return (BOXA *)ERROR_PTR("not in-place", __func__, NULL);
2103 if (sides != L_ADJUST_LEFT && sides != L_ADJUST_RIGHT &&
2104 sides != L_ADJUST_LEFT_AND_RIGHT)
2105 return (BOXA *)ERROR_PTR("invalid sides", __func__, NULL);
2106 if (target < 1)
2107 return (BOXA *)ERROR_PTR("target < 1", __func__, NULL);
2108
2109 if (!boxad)
2110 boxad = boxaCopy(boxas, L_COPY);
2111 n = boxaGetCount(boxad);
2112 for (i = 0; i < n; i++) {
2113 if ((box = boxaGetValidBox(boxad, i, L_CLONE)) == NULL)
2114 continue;
2115 boxGetGeometry(box, &x, &y, &w, &h);
2116 diff = w - target;
2117 if (sides == L_ADJUST_LEFT) {
2118 if (L_ABS(diff) >= thresh)
2119 boxSetGeometry(box, L_MAX(0, x + diff), y, target, h);
2120 } else if (sides == L_ADJUST_RIGHT) {
2121 if (L_ABS(diff) >= thresh)
2122 boxSetGeometry(box, x, y, target, h);
2123 } else { /* sides == L_ADJUST_LEFT_AND_RIGHT */
2124 if (L_ABS(diff) >= thresh)
2125 boxSetGeometry(box, L_MAX(0, x + diff/2), y, target, h);
2126 }
2127 boxDestroy(&box);
2128 }
2129
2130 return boxad;
2131}
2132
2133
2155BOXA *
2157 BOXA *boxas,
2158 l_int32 sides,
2159 l_int32 target,
2160 l_int32 thresh)
2161{
2162l_int32 x, y, w, h, n, i, diff;
2163BOX *box;
2164
2165 if (!boxas)
2166 return (BOXA *)ERROR_PTR("boxas not defined", __func__, NULL);
2167 if (boxad && (boxas != boxad))
2168 return (BOXA *)ERROR_PTR("not in-place", __func__, NULL);
2169 if (sides != L_ADJUST_TOP && sides != L_ADJUST_BOT &&
2170 sides != L_ADJUST_TOP_AND_BOT)
2171 return (BOXA *)ERROR_PTR("invalid sides", __func__, NULL);
2172 if (target < 1)
2173 return (BOXA *)ERROR_PTR("target < 1", __func__, NULL);
2174
2175 if (!boxad)
2176 boxad = boxaCopy(boxas, L_COPY);
2177 n = boxaGetCount(boxad);
2178 for (i = 0; i < n; i++) {
2179 if ((box = boxaGetValidBox(boxad, i, L_CLONE)) == NULL)
2180 continue;
2181 boxGetGeometry(box, &x, &y, &w, &h);
2182 diff = h - target;
2183 if (sides == L_ADJUST_TOP) {
2184 if (L_ABS(diff) >= thresh)
2185 boxSetGeometry(box, x, L_MAX(0, y + diff), w, target);
2186 } else if (sides == L_ADJUST_BOT) {
2187 if (L_ABS(diff) >= thresh)
2188 boxSetGeometry(box, x, y, w, target);
2189 } else { /* sides == L_ADJUST_TOP_AND_BOT */
2190 if (L_ABS(diff) >= thresh)
2191 boxSetGeometry(box, x, L_MAX(0, y + diff/2), w, target);
2192 }
2193 boxDestroy(&box);
2194 }
2195
2196 return boxad;
2197}
2198
2199
2208l_ok
2210 BOX *box2,
2211 l_int32 *psame)
2212{
2213 if (!psame)
2214 return ERROR_INT("&same not defined", __func__, 1);
2215 *psame = 0;
2216 if (!box1 || !box2)
2217 return ERROR_INT("boxes not both defined", __func__, 1);
2218 if (box1->x == box2->x && box1->y == box2->y &&
2219 box1->w == box2->w && box1->h == box2->h)
2220 *psame = 1;
2221 return 0;
2222}
2223
2224
2253l_ok
2255 BOXA *boxa2,
2256 l_int32 maxdist,
2257 NUMA **pnaindex,
2258 l_int32 *psame)
2259{
2260l_int32 i, j, n, jstart, jend, found, samebox;
2261l_int32 *countarray;
2262BOX *box1, *box2;
2263NUMA *na;
2264
2265 if (pnaindex) *pnaindex = NULL;
2266 if (!psame)
2267 return ERROR_INT("&same not defined", __func__, 1);
2268 *psame = 0;
2269 if (!boxa1 || !boxa2)
2270 return ERROR_INT("boxa1 and boxa2 not both defined", __func__, 1);
2271 n = boxaGetCount(boxa1);
2272 if (n != boxaGetCount(boxa2))
2273 return 0;
2274
2275 if ((countarray = (l_int32 *)LEPT_CALLOC(n, sizeof(l_int32))) == NULL)
2276 return ERROR_INT("calloc fail for countarray", __func__, 1);
2277 na = numaMakeConstant(0.0, n);
2278
2279 for (i = 0; i < n; i++) {
2280 box1 = boxaGetBox(boxa1, i, L_CLONE);
2281 jstart = L_MAX(0, i - maxdist);
2282 jend = L_MIN(n-1, i + maxdist);
2283 found = FALSE;
2284 for (j = jstart; j <= jend; j++) {
2285 box2 = boxaGetBox(boxa2, j, L_CLONE);
2286 boxEqual(box1, box2, &samebox);
2287 if (samebox && countarray[j] == 0) {
2288 countarray[j] = 1;
2289 numaReplaceNumber(na, i, j);
2290 found = TRUE;
2291 boxDestroy(&box2);
2292 break;
2293 }
2294 boxDestroy(&box2);
2295 }
2296 boxDestroy(&box1);
2297 if (!found) {
2298 numaDestroy(&na);
2299 LEPT_FREE(countarray);
2300 return 0;
2301 }
2302 }
2303
2304 *psame = 1;
2305 if (pnaindex)
2306 *pnaindex = na;
2307 else
2308 numaDestroy(&na);
2309 LEPT_FREE(countarray);
2310 return 0;
2311}
2312
2313
2330l_ok
2332 BOX *box2,
2333 l_int32 leftdiff,
2334 l_int32 rightdiff,
2335 l_int32 topdiff,
2336 l_int32 botdiff,
2337 l_int32 *psimilar)
2338{
2339l_int32 l1, l2, r1, r2, t1, t2, b1, b2, valid1, valid2;
2340
2341 if (!psimilar)
2342 return ERROR_INT("&similar not defined", __func__, 1);
2343 *psimilar = 0;
2344 if (!box1 || !box2)
2345 return ERROR_INT("boxes not both defined", __func__, 1);
2346 boxIsValid(box1, &valid1);
2347 boxIsValid(box2, &valid2);
2348 if (!valid1 || !valid2)
2349 return ERROR_INT("boxes not both valid", __func__, 1);
2350
2351 boxGetSideLocations(box1, &l1, &r1, &t1, &b1);
2352 boxGetSideLocations(box2, &l2, &r2, &t2, &b2);
2353 if (L_ABS(l1 - l2) > leftdiff)
2354 return 0;
2355 if (L_ABS(r1 - r2) > rightdiff)
2356 return 0;
2357 if (L_ABS(t1 - t2) > topdiff)
2358 return 0;
2359 if (L_ABS(b1 - b2) > botdiff)
2360 return 0;
2361
2362 *psimilar = 1;
2363 return 0;
2364}
2365
2366
2387l_ok
2389 BOXA *boxa2,
2390 l_int32 leftdiff,
2391 l_int32 rightdiff,
2392 l_int32 topdiff,
2393 l_int32 botdiff,
2394 l_int32 debug,
2395 l_int32 *psimilar,
2396 NUMA **pnasim)
2397{
2398l_int32 i, n1, n2, match, mismatch;
2399BOX *box1, *box2;
2400
2401 if (psimilar) *psimilar = 0;
2402 if (pnasim) *pnasim = NULL;
2403 if (!boxa1 || !boxa2)
2404 return ERROR_INT("boxa1 and boxa2 not both defined", __func__, 1);
2405 if (!psimilar)
2406 return ERROR_INT("&similar not defined", __func__, 1);
2407 n1 = boxaGetCount(boxa1);
2408 n2 = boxaGetCount(boxa2);
2409 if (n1 != n2) {
2410 L_ERROR("boxa counts differ: %d vs %d\n", __func__, n1, n2);
2411 return 1;
2412 }
2413 if (pnasim) *pnasim = numaCreate(n1);
2414
2415 mismatch = FALSE;
2416 for (i = 0; i < n1; i++) {
2417 box1 = boxaGetBox(boxa1, i, L_CLONE);
2418 box2 = boxaGetBox(boxa2, i, L_CLONE);
2419 boxSimilar(box1, box2, leftdiff, rightdiff, topdiff, botdiff,
2420 &match);
2421 boxDestroy(&box1);
2422 boxDestroy(&box2);
2423 if (pnasim)
2424 numaAddNumber(*pnasim, match);
2425 if (!match) {
2426 mismatch = TRUE;
2427 if (!debug && pnasim == NULL)
2428 return 0;
2429 else if (debug)
2430 L_INFO("box %d not similar\n", __func__, i);
2431 }
2432 }
2433
2434 if (!mismatch) *psimilar = 1;
2435 return 0;
2436}
2437
2438
2439/*----------------------------------------------------------------------*
2440 * Boxa combine and split *
2441 *----------------------------------------------------------------------*/
2459l_ok
2461 BOXA *boxas,
2462 l_int32 istart,
2463 l_int32 iend)
2464{
2465l_int32 n, i;
2466BOX *box;
2467
2468 if (!boxad)
2469 return ERROR_INT("boxad not defined", __func__, 1);
2470 if (!boxas || ((n = boxaGetCount(boxas)) == 0))
2471 return 0;
2472
2473 if (istart < 0)
2474 istart = 0;
2475 if (iend < 0 || iend >= n)
2476 iend = n - 1;
2477 if (istart > iend)
2478 return ERROR_INT("istart > iend; nothing to add", __func__, 1);
2479
2480 for (i = istart; i <= iend; i++) {
2481 box = boxaGetBox(boxas, i, L_CLONE);
2482 boxaAddBox(boxad, box, L_INSERT);
2483 }
2484
2485 return 0;
2486}
2487
2488
2506l_ok
2508 BOXAA *baas,
2509 l_int32 istart,
2510 l_int32 iend)
2511{
2512l_int32 n, i;
2513BOXA *boxa;
2514
2515 if (!baad)
2516 return ERROR_INT("baad not defined", __func__, 1);
2517 if (!baas)
2518 return 0;
2519
2520 if (istart < 0)
2521 istart = 0;
2522 n = boxaaGetCount(baas);
2523 if (iend < 0 || iend >= n)
2524 iend = n - 1;
2525 if (istart > iend)
2526 return ERROR_INT("istart > iend; nothing to add", __func__, 1);
2527
2528 for (i = istart; i <= iend; i++) {
2529 boxa = boxaaGetBoxa(baas, i, L_CLONE);
2530 boxaaAddBoxa(baad, boxa, L_INSERT);
2531 }
2532
2533 return 0;
2534}
2535
2536
2554l_ok
2556 l_int32 fillflag,
2557 BOXA **pboxae,
2558 BOXA **pboxao)
2559{
2560l_int32 i, n;
2561BOX *box, *box1;
2562
2563 if (pboxae) *pboxae = NULL;
2564 if (pboxao) *pboxao = NULL;
2565 if (!pboxae || !pboxao)
2566 return ERROR_INT("&boxae and &boxao not both defined", __func__, 1);
2567 if (!boxa)
2568 return ERROR_INT("boxa not defined", __func__, 1);
2569
2570 n = boxaGetCount(boxa);
2571 *pboxae = boxaCreate(n);
2572 *pboxao = boxaCreate(n);
2573 if (fillflag == 0) {
2574 /* don't fill with invalid boxes; end up with half-size boxa */
2575 for (i = 0; i < n; i++) {
2576 box = boxaGetBox(boxa, i, L_COPY);
2577 if ((i & 1) == 0)
2578 boxaAddBox(*pboxae, box, L_INSERT);
2579 else
2580 boxaAddBox(*pboxao, box, L_INSERT);
2581 }
2582 } else {
2583 for (i = 0; i < n; i++) {
2584 box = boxaGetBox(boxa, i, L_COPY);
2585 box1 = boxCreate(0, 0, 0, 0); /* empty placeholder */
2586 if ((i & 1) == 0) {
2587 boxaAddBox(*pboxae, box, L_INSERT);
2588 boxaAddBox(*pboxao, box1, L_INSERT);
2589 } else {
2590 boxaAddBox(*pboxae, box1, L_INSERT);
2591 boxaAddBox(*pboxao, box, L_INSERT);
2592 }
2593 }
2594 }
2595 return 0;
2596}
2597
2598
2616BOXA *
2618 BOXA *boxao,
2619 l_int32 fillflag)
2620{
2621l_int32 i, n, ne, no;
2622BOX *box;
2623BOXA *boxad;
2624
2625 if (!boxae || !boxao)
2626 return (BOXA *)ERROR_PTR("boxae and boxao not defined", __func__, NULL);
2627 ne = boxaGetCount(boxae);
2628 no = boxaGetCount(boxao);
2629 if (ne < no || ne > no + 1)
2630 return (BOXA *)ERROR_PTR("boxa sizes invalid", __func__, NULL);
2631
2632 boxad = boxaCreate(ne);
2633 if (fillflag == 0) { /* both are approx. half-sized; all valid boxes */
2634 n = ne + no;
2635 for (i = 0; i < n; i++) {
2636 if ((i & 1) == 0)
2637 box = boxaGetBox(boxae, i / 2, L_COPY);
2638 else
2639 box = boxaGetBox(boxao, i / 2, L_COPY);
2640 boxaAddBox(boxad, box, L_INSERT);
2641 }
2642 } else { /* both are full size and have invalid placeholders */
2643 for (i = 0; i < ne; i++) {
2644 if ((i & 1) == 0)
2645 box = boxaGetBox(boxae, i, L_COPY);
2646 else
2647 box = boxaGetBox(boxao, i, L_COPY);
2648 boxaAddBox(boxad, box, L_INSERT);
2649 }
2650 }
2651 return boxad;
2652}
BOX * boxaGetNearestToLine(BOXA *boxa, l_int32 x, l_int32 y)
boxaGetNearestToLine()
Definition boxfunc1.c:1266
BOXA * boxaContainedInBox(BOXA *boxas, BOX *box)
boxaContainedInBox()
Definition boxfunc1.c:185
l_ok boxEqual(BOX *box1, BOX *box2, l_int32 *psame)
boxEqual()
Definition boxfunc1.c:2209
l_ok boxCompareSize(BOX *box1, BOX *box2, l_int32 type, l_int32 *prel)
boxCompareSize()
Definition boxfunc1.c:1129
BOXA * boxaIntersectsBox(BOXA *boxas, BOX *box)
boxaIntersectsBox()
Definition boxfunc1.c:322
BOX * boxOverlapRegion(BOX *box1, BOX *box2)
boxOverlapRegion()
Definition boxfunc1.c:691
BOXA * boxaAdjustWidthToTarget(BOXA *boxad, BOXA *boxas, l_int32 sides, l_int32 target, l_int32 thresh)
boxaAdjustWidthToTarget()
Definition boxfunc1.c:2090
l_ok boxaGetNearestByDirection(BOXA *boxa, l_int32 i, l_int32 dir, l_int32 dist_select, l_int32 range, l_int32 *pindex, l_int32 *pdist)
boxaGetNearestByDirection()
Definition boxfunc1.c:1401
l_ok boxIntersectByLine(const BOX *box, l_int32 x, l_int32 y, l_float32 slope, l_int32 *px1, l_int32 *py1, l_int32 *px2, l_int32 *py2, l_int32 *pn)
boxIntersectByLine()
Definition boxfunc1.c:1578
l_ok boxaEqual(BOXA *boxa1, BOXA *boxa2, l_int32 maxdist, NUMA **pnaindex, l_int32 *psame)
boxaEqual()
Definition boxfunc1.c:2254
l_ok boxaAdjustBoxSides(BOXA *boxa, l_int32 index, l_int32 delleft, l_int32 delright, l_int32 deltop, l_int32 delbot)
boxaAdjustBoxSides()
Definition boxfunc1.c:1886
l_ok boxaJoin(BOXA *boxad, BOXA *boxas, l_int32 istart, l_int32 iend)
boxaJoin()
Definition boxfunc1.c:2460
l_ok boxaCombineOverlapsInPair(BOXA *boxas1, BOXA *boxas2, BOXA **pboxad1, BOXA **pboxad2, PIXA *pixadb)
boxaCombineOverlapsInPair()
Definition boxfunc1.c:555
l_ok boxGetCenter(const BOX *box, l_float32 *pcx, l_float32 *pcy)
boxGetCenter()
Definition boxfunc1.c:1538
l_ok boxOverlapDistance(BOX *box1, BOX *box2, l_int32 *ph_ovl, l_int32 *pv_ovl)
boxOverlapDistance()
Definition boxfunc1.c:1015
l_ok boxSimilar(BOX *box1, BOX *box2, l_int32 leftdiff, l_int32 rightdiff, l_int32 topdiff, l_int32 botdiff, l_int32 *psimilar)
boxSimilar()
Definition boxfunc1.c:2331
l_ok boxIntersects(BOX *box1, BOX *box2, l_int32 *presult)
boxIntersects()
Definition boxfunc1.c:140
BOXA * boxaCombineOverlaps(BOXA *boxas, PIXA *pixadb)
boxaCombineOverlaps()
Definition boxfunc1.c:463
l_ok boxaContainedInBoxa(BOXA *boxa1, BOXA *boxa2, l_int32 *pcontained)
boxaContainedInBoxa()
Definition boxfunc1.c:269
BOX * boxAdjustSides(BOX *boxd, BOX *boxs, l_int32 delleft, l_int32 delright, l_int32 deltop, l_int32 delbot)
boxAdjustSides()
Definition boxfunc1.c:1932
BOXA * boxaClipToBox(BOXA *boxas, BOX *box)
boxaClipToBox()
Definition boxfunc1.c:406
l_ok boxaFindNearestBoxes(BOXA *boxa, l_int32 dist_select, l_int32 range, NUMAA **pnaaindex, NUMAA **pnaadist)
boxaFindNearestBoxes()
Definition boxfunc1.c:1322
BOXA * boxaAdjustSides(BOXA *boxas, l_int32 delleft, l_int32 delright, l_int32 deltop, l_int32 delbot)
boxaAdjustSides()
Definition boxfunc1.c:1838
l_ok boxaSimilar(BOXA *boxa1, BOXA *boxa2, l_int32 leftdiff, l_int32 rightdiff, l_int32 topdiff, l_int32 botdiff, l_int32 debug, l_int32 *psimilar, NUMA **pnasim)
boxaSimilar()
Definition boxfunc1.c:2388
BOXA * boxaHandleOverlaps(BOXA *boxas, l_int32 op, l_int32 range, l_float32 min_overlap, l_float32 max_ratio, NUMA **pnamap)
boxaHandleOverlaps()
Definition boxfunc1.c:887
BOX * boxRelocateOneSide(BOX *boxd, BOX *boxs, l_int32 loc, l_int32 sideflag)
boxRelocateOneSide()
Definition boxfunc1.c:1794
BOX * boxBoundingRegion(BOX *box1, BOX *box2)
boxBoundingRegion()
Definition boxfunc1.c:739
l_ok boxaContainedInBoxCount(BOXA *boxa, BOX *box, l_int32 *pcount)
boxaContainedInBoxCount()
Definition boxfunc1.c:229
l_ok boxOverlapArea(BOX *box1, BOX *box2, l_int32 *parea)
boxOverlapArea()
Definition boxfunc1.c:825
l_ok boxaIntersectsBoxCount(BOXA *boxa, BOX *box, l_int32 *pcount)
boxaIntersectsBoxCount()
Definition boxfunc1.c:361
BOX * boxaGetNearestToPt(BOXA *boxa, l_int32 x, l_int32 y)
boxaGetNearestToPt()
Definition boxfunc1.c:1215
l_ok boxContains(BOX *box1, BOX *box2, l_int32 *presult)
boxContains()
Definition boxfunc1.c:107
l_ok boxSetSide(BOX *boxs, l_int32 side, l_int32 val, l_int32 thresh)
boxSetSide()
Definition boxfunc1.c:2030
static l_int32 boxHasOverlapInXorY(l_int32 c1, l_int32 s1, l_int32 c2, l_int32 s2)
boxHasOverlapInXorY()
Definition boxfunc1.c:1489
l_ok boxContainsPt(BOX *box, l_float32 x, l_float32 y, l_int32 *pcontains)
boxContainsPt()
Definition boxfunc1.c:1182
BOXA * boxaMergeEvenOdd(BOXA *boxae, BOXA *boxao, l_int32 fillflag)
boxaMergeEvenOdd()
Definition boxfunc1.c:2617
BOXA * boxaAdjustHeightToTarget(BOXA *boxad, BOXA *boxas, l_int32 sides, l_int32 target, l_int32 thresh)
boxaAdjustHeightToTarget()
Definition boxfunc1.c:2156
l_ok boxSeparationDistance(BOX *box1, BOX *box2, l_int32 *ph_sep, l_int32 *pv_sep)
boxSeparationDistance()
Definition boxfunc1.c:1086
l_ok boxaaJoin(BOXAA *baad, BOXAA *baas, l_int32 istart, l_int32 iend)
boxaaJoin()
Definition boxfunc1.c:2507
BOX * boxClipToRectangle(BOX *box, l_int32 wi, l_int32 hi)
boxClipToRectangle()
Definition boxfunc1.c:1679
static l_int32 boxGetDistanceInXorY(l_int32 c1, l_int32 s1, l_int32 c2, l_int32 s2)
boxGetDistanceInXorY()
Definition boxfunc1.c:1515
l_ok boxClipToRectangleParams(BOX *box, l_int32 w, l_int32 h, l_int32 *pxstart, l_int32 *pystart, l_int32 *pxend, l_int32 *pyend, l_int32 *pbw, l_int32 *pbh)
boxClipToRectangleParams()
Definition boxfunc1.c:1734
l_ok boxOverlapFraction(BOX *box1, BOX *box2, l_float32 *pfract)
boxOverlapFraction()
Definition boxfunc1.c:787
l_ok boxaSplitEvenOdd(BOXA *boxa, l_int32 fillflag, BOXA **pboxae, BOXA **pboxao)
boxaSplitEvenOdd()
Definition boxfunc1.c:2555
BOXA * boxaSetSide(BOXA *boxad, BOXA *boxas, l_int32 side, l_int32 val, l_int32 thresh)
boxaSetSide()
Definition boxfunc1.c:1982
@ L_SORT_BY_AREA
Definition pix.h:537
@ L_SORT_BY_PERIMETER
Definition pix.h:536
@ L_SORT_BY_WIDTH
Definition pix.h:532
@ L_SORT_BY_HEIGHT
Definition pix.h:533
@ L_SORT_BY_MAX_DIMENSION
Definition pix.h:535
@ L_COPY
Definition pix.h:505
@ L_CLONE
Definition pix.h:506
@ L_INSERT
Definition pix.h:504
@ L_SET_RIGHT
Definition pix.h:853
@ L_SET_LEFT
Definition pix.h:852
@ L_ADJUST_LEFT
Definition pix.h:844
@ L_SET_BOT
Definition pix.h:855
@ L_ADJUST_LEFT_AND_RIGHT
Definition pix.h:846
@ L_ADJUST_RIGHT
Definition pix.h:845
@ L_ADJUST_BOT
Definition pix.h:848
@ L_ADJUST_TOP
Definition pix.h:847
@ L_SET_TOP
Definition pix.h:854
@ L_ADJUST_TOP_AND_BOT
Definition pix.h:849
@ L_FROM_BOT
Definition pix.h:830
@ L_FROM_LEFT
Definition pix.h:827
@ L_FROM_RIGHT
Definition pix.h:828
@ L_FROM_TOP
Definition pix.h:829
@ L_REMOVE_SMALL
Definition pix.h:881
@ L_COMBINE
Definition pix.h:880
@ L_NON_NEGATIVE
Definition pix.h:749
@ L_ALL
Definition pix.h:753
l_int32 y
l_int32 x
l_int32 w
l_int32 h