Leptonica 1.85.0
Image processing and image analysis suite
Loading...
Searching...
No Matches
pixafunc1.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
95#ifdef HAVE_CONFIG_H
96#include <config_auto.h>
97#endif /* HAVE_CONFIG_H */
98
99#include <string.h>
100#include "allheaders.h"
101#include "pix_internal.h"
102
103 /* For more than this number of c.c. in a binarized image of
104 * semi-perimeter (w + h) about 5000 or less, the O(n) binsort
105 * is faster than the O(nlogn) shellsort. */
106static const l_int32 MinCompsForBinSort = 200;
107
108 /* Don't rotate any angle smaller than this */
109static const l_float32 MinAngleToRotate = 0.001f; /* radians; ~0.06 deg */
110
111/*---------------------------------------------------------------------*
112 * Filters *
113 *---------------------------------------------------------------------*/
114/*
115 * These filters work on the connected components of 1 bpp images.
116 * They are typically used on pixa that have been generated from a Pix
117 * using pixConnComp(), so that the corresponding Boxa is available.
118 *
119 * The filters remove or retain c.c. based on these properties:
120 * (a) size [pixaFindDimensions()]
121 * (b) area-to-perimeter ratio [pixaFindAreaPerimRatio()]
122 * (c) foreground area as a fraction of bounding box area (w * h)
123 * [pixaFindForegroundArea()]
124 * (d) number of foreground pixels [pixaCountPixels()]
125 * (e) width/height aspect ratio [pixFindWidthHeightRatio()]
126 *
127 * We provide two different high-level interfaces:
128 * (1) Functions that use one of the filters on either
129 * a pix or the pixa of components.
130 * (2) A general method that generates numas of indicator functions,
131 * logically combines them, and efficiently removes or adds
132 * the selected components.
133 *
134 * For interface (1), the filtering is performed with a single function call.
135 * This is the easiest way to do simple filtering. These functions
136 * are named pixSelectBy*() and pixaSelectBy*(), where the '*' is one of:
137 * Size
138 * PerimToAreaRatio
139 * PerimSizeRatio
140 * Area
141 * AreaFraction
142 * WidthHeightRatio
143 *
144 * For more complicated filtering, use the general method (2).
145 * The numa indicator functions for a pixa are generated by these functions:
146 * pixaFindDimensions()
147 * pixaFindPerimToAreaRatio()
148 * pixaFindPerimSizeRatio()
149 * pixaFindAreaFraction()
150 * pixaCountPixels()
151 * pixaFindWidthHeightRatio()
152 * pixaFindWidthHeightProduct()
153 *
154 * Here is an illustration using the general method. Suppose you want
155 * all 8-connected components that have a height greater than 40 pixels,
156 * a width not more than 30 pixels, between 150 and 300 fg pixels,
157 * and a perimeter-to-size ratio between 1.2 and 2.0.
158 *
159 * // Generate the pixa of 8 cc pieces.
160 * boxa = pixConnComp(pixs, &pixa, 8);
161 *
162 * // Extract the data we need about each component.
163 * pixaFindDimensions(pixa, &naw, &nah);
164 * nas = pixaCountPixels(pixa);
165 * nar = pixaFindPerimSizeRatio(pixa);
166 *
167 * // Build the indicator arrays for the set of components,
168 * // based on thresholds and selection criteria.
169 * na1 = numaMakeThresholdIndicator(nah, 40, L_SELECT_IF_GT);
170 * na2 = numaMakeThresholdIndicator(naw, 30, L_SELECT_IF_LTE);
171 * na3 = numaMakeThresholdIndicator(nas, 150, L_SELECT_IF_GTE);
172 * na4 = numaMakeThresholdIndicator(nas, 300, L_SELECT_IF_LTE);
173 * na5 = numaMakeThresholdIndicator(nar, 1.2, L_SELECT_IF_GTE);
174 * na6 = numaMakeThresholdIndicator(nar, 2.0, L_SELECT_IF_LTE);
175 *
176 * // Combine the indicator arrays logically to find
177 * // the components that will be retained.
178 * nad = numaLogicalOp(NULL, na1, na2, L_INTERSECTION);
179 * numaLogicalOp(nad, nad, na3, L_INTERSECTION);
180 * numaLogicalOp(nad, nad, na4, L_INTERSECTION);
181 * numaLogicalOp(nad, nad, na5, L_INTERSECTION);
182 * numaLogicalOp(nad, nad, na6, L_INTERSECTION);
183 *
184 * // Invert to get the components that will be removed.
185 * numaInvert(nad, nad);
186 *
187 * // Remove the components, in-place.
188 * pixRemoveWithIndicator(pixs, pixa, nad);
189 */
190
191
219PIX *
221 l_int32 width,
222 l_int32 height,
223 l_int32 connectivity,
224 l_int32 type,
225 l_int32 relation,
226 l_int32 *pchanged)
227{
228l_int32 w, h, empty, changed, count;
229BOXA *boxa;
230PIX *pixd;
231PIXA *pixas, *pixad;
232
233 if (!pixs)
234 return (PIX *)ERROR_PTR("pixs not defined", __func__, NULL);
235 if (connectivity != 4 && connectivity != 8)
236 return (PIX *)ERROR_PTR("connectivity not 4 or 8", __func__, NULL);
237 if (type != L_SELECT_WIDTH && type != L_SELECT_HEIGHT &&
238 type != L_SELECT_IF_EITHER && type != L_SELECT_IF_BOTH)
239 return (PIX *)ERROR_PTR("invalid type", __func__, NULL);
240 if (relation != L_SELECT_IF_LT && relation != L_SELECT_IF_GT &&
241 relation != L_SELECT_IF_LTE && relation != L_SELECT_IF_GTE)
242 return (PIX *)ERROR_PTR("invalid relation", __func__, NULL);
243 if (pchanged) *pchanged = FALSE;
244
245 /* Check if any components exist */
246 pixZero(pixs, &empty);
247 if (empty)
248 return pixCopy(NULL, pixs);
249
250 /* Identify and select the components */
251 boxa = pixConnComp(pixs, &pixas, connectivity);
252 pixad = pixaSelectBySize(pixas, width, height, type, relation, &changed);
253 boxaDestroy(&boxa);
254 pixaDestroy(&pixas);
255
256 if (!changed) {
257 pixaDestroy(&pixad);
258 return pixCopy(NULL, pixs);
259 }
260
261 /* Render the result */
262 if (pchanged) *pchanged = TRUE;
263 pixGetDimensions(pixs, &w, &h, NULL);
264 count = pixaGetCount(pixad);
265 if (count == 0) { /* return empty pix */
266 pixd = pixCreateTemplate(pixs);
267 } else {
268 pixd = pixaDisplay(pixad, w, h);
269 pixCopyResolution(pixd, pixs);
270 pixCopyColormap(pixd, pixs);
271 pixCopyText(pixd, pixs);
272 pixCopyInputFormat(pixd, pixs);
273 }
274 pixaDestroy(&pixad);
275 return pixd;
276}
277
278
304PIXA *
306 l_int32 width,
307 l_int32 height,
308 l_int32 type,
309 l_int32 relation,
310 l_int32 *pchanged)
311{
312NUMA *na;
313PIXA *pixad;
314
315 if (!pixas)
316 return (PIXA *)ERROR_PTR("pixas not defined", __func__, NULL);
317 if (type != L_SELECT_WIDTH && type != L_SELECT_HEIGHT &&
318 type != L_SELECT_IF_EITHER && type != L_SELECT_IF_BOTH)
319 return (PIXA *)ERROR_PTR("invalid type", __func__, NULL);
320 if (relation != L_SELECT_IF_LT && relation != L_SELECT_IF_GT &&
321 relation != L_SELECT_IF_LTE && relation != L_SELECT_IF_GTE)
322 return (PIXA *)ERROR_PTR("invalid relation", __func__, NULL);
323
324 /* Compute the indicator array for saving components */
325 na = pixaMakeSizeIndicator(pixas, width, height, type, relation);
326
327 /* Filter to get output */
328 pixad = pixaSelectWithIndicator(pixas, na, pchanged);
329
330 numaDestroy(&na);
331 return pixad;
332}
333
334
358NUMA *
360 l_int32 width,
361 l_int32 height,
362 l_int32 type,
363 l_int32 relation)
364{
365l_int32 i, n, w, h, ival;
366NUMA *na;
367
368 if (!pixa)
369 return (NUMA *)ERROR_PTR("pixa not defined", __func__, NULL);
370 if (type != L_SELECT_WIDTH && type != L_SELECT_HEIGHT &&
371 type != L_SELECT_IF_EITHER && type != L_SELECT_IF_BOTH)
372 return (NUMA *)ERROR_PTR("invalid type", __func__, NULL);
373 if (relation != L_SELECT_IF_LT && relation != L_SELECT_IF_GT &&
374 relation != L_SELECT_IF_LTE && relation != L_SELECT_IF_GTE)
375 return (NUMA *)ERROR_PTR("invalid relation", __func__, NULL);
376
377 n = pixaGetCount(pixa);
378 na = numaCreate(n);
379 for (i = 0; i < n; i++) {
380 ival = 0;
381 pixaGetPixDimensions(pixa, i, &w, &h, NULL);
382 switch (type)
383 {
384 case L_SELECT_WIDTH:
385 if ((relation == L_SELECT_IF_LT && w < width) ||
386 (relation == L_SELECT_IF_GT && w > width) ||
387 (relation == L_SELECT_IF_LTE && w <= width) ||
388 (relation == L_SELECT_IF_GTE && w >= width))
389 ival = 1;
390 break;
391 case L_SELECT_HEIGHT:
392 if ((relation == L_SELECT_IF_LT && h < height) ||
393 (relation == L_SELECT_IF_GT && h > height) ||
394 (relation == L_SELECT_IF_LTE && h <= height) ||
395 (relation == L_SELECT_IF_GTE && h >= height))
396 ival = 1;
397 break;
399 if (((relation == L_SELECT_IF_LT) && (w < width || h < height)) ||
400 ((relation == L_SELECT_IF_GT) && (w > width || h > height)) ||
401 ((relation == L_SELECT_IF_LTE) && (w <= width || h <= height)) ||
402 ((relation == L_SELECT_IF_GTE) && (w >= width || h >= height)))
403 ival = 1;
404 break;
405 case L_SELECT_IF_BOTH:
406 if (((relation == L_SELECT_IF_LT) && (w < width && h < height)) ||
407 ((relation == L_SELECT_IF_GT) && (w > width && h > height)) ||
408 ((relation == L_SELECT_IF_LTE) && (w <= width && h <= height)) ||
409 ((relation == L_SELECT_IF_GTE) && (w >= width && h >= height)))
410 ival = 1;
411 break;
412 default:
413 L_WARNING("can't get here!\n", __func__);
414 break;
415 }
416 numaAddNumber(na, ival);
417 }
418
419 return na;
420}
421
422
447PIX *
449 l_float32 thresh,
450 l_int32 connectivity,
451 l_int32 type,
452 l_int32 *pchanged)
453{
454l_int32 w, h, empty, changed, count;
455BOXA *boxa;
456PIX *pixd;
457PIXA *pixas, *pixad;
458
459 if (!pixs)
460 return (PIX *)ERROR_PTR("pixs not defined", __func__, NULL);
461 if (connectivity != 4 && connectivity != 8)
462 return (PIX *)ERROR_PTR("connectivity not 4 or 8", __func__, NULL);
463 if (type != L_SELECT_IF_LT && type != L_SELECT_IF_GT &&
464 type != L_SELECT_IF_LTE && type != L_SELECT_IF_GTE)
465 return (PIX *)ERROR_PTR("invalid type", __func__, NULL);
466 if (pchanged) *pchanged = FALSE;
467
468 /* Check if any components exist */
469 pixZero(pixs, &empty);
470 if (empty)
471 return pixCopy(NULL, pixs);
472
473 /* Filter thin components */
474 boxa = pixConnComp(pixs, &pixas, connectivity);
475 pixad = pixaSelectByPerimToAreaRatio(pixas, thresh, type, &changed);
476 boxaDestroy(&boxa);
477 pixaDestroy(&pixas);
478
479 if (!changed) {
480 pixaDestroy(&pixad);
481 return pixCopy(NULL, pixs);
482 }
483
484 /* Render the result */
485 if (pchanged) *pchanged = TRUE;
486 pixGetDimensions(pixs, &w, &h, NULL);
487 count = pixaGetCount(pixad);
488 if (count == 0) { /* return empty pix */
489 pixd = pixCreateTemplate(pixs);
490 } else {
491 pixd = pixaDisplay(pixad, w, h);
492 pixCopyResolution(pixd, pixs);
493 pixCopyColormap(pixd, pixs);
494 pixCopyText(pixd, pixs);
495 pixCopyInputFormat(pixd, pixs);
496 }
497 pixaDestroy(&pixad);
498 return pixd;
499}
500
501
519PIXA *
521 l_float32 thresh,
522 l_int32 type,
523 l_int32 *pchanged)
524{
525NUMA *na, *nai;
526PIXA *pixad;
527
528 if (!pixas)
529 return (PIXA *)ERROR_PTR("pixas not defined", __func__, NULL);
530 if (type != L_SELECT_IF_LT && type != L_SELECT_IF_GT &&
531 type != L_SELECT_IF_LTE && type != L_SELECT_IF_GTE)
532 return (PIXA *)ERROR_PTR("invalid type", __func__, NULL);
533
534 /* Compute component ratios. */
535 na = pixaFindPerimToAreaRatio(pixas);
536
537 /* Generate indicator array for elements to be saved. */
538 nai = numaMakeThresholdIndicator(na, thresh, type);
539 numaDestroy(&na);
540
541 /* Filter to get output */
542 pixad = pixaSelectWithIndicator(pixas, nai, pchanged);
543
544 numaDestroy(&nai);
545 return pixad;
546}
547
548
574PIX *
576 l_float32 thresh,
577 l_int32 connectivity,
578 l_int32 type,
579 l_int32 *pchanged)
580{
581l_int32 w, h, empty, changed, count;
582BOXA *boxa;
583PIX *pixd;
584PIXA *pixas, *pixad;
585
586 if (!pixs)
587 return (PIX *)ERROR_PTR("pixs not defined", __func__, NULL);
588 if (connectivity != 4 && connectivity != 8)
589 return (PIX *)ERROR_PTR("connectivity not 4 or 8", __func__, NULL);
590 if (type != L_SELECT_IF_LT && type != L_SELECT_IF_GT &&
591 type != L_SELECT_IF_LTE && type != L_SELECT_IF_GTE)
592 return (PIX *)ERROR_PTR("invalid type", __func__, NULL);
593 if (pchanged) *pchanged = FALSE;
594
595 /* Check if any components exist */
596 pixZero(pixs, &empty);
597 if (empty)
598 return pixCopy(NULL, pixs);
599
600 /* Filter thin components */
601 boxa = pixConnComp(pixs, &pixas, connectivity);
602 pixad = pixaSelectByPerimSizeRatio(pixas, thresh, type, &changed);
603 boxaDestroy(&boxa);
604 pixaDestroy(&pixas);
605
606 if (!changed) {
607 pixaDestroy(&pixad);
608 return pixCopy(NULL, pixs);
609 }
610
611 /* Render the result */
612 if (pchanged) *pchanged = TRUE;
613 pixGetDimensions(pixs, &w, &h, NULL);
614 count = pixaGetCount(pixad);
615 if (count == 0) { /* return empty pix */
616 pixd = pixCreateTemplate(pixs);
617 } else {
618 pixd = pixaDisplay(pixad, w, h);
619 pixCopyResolution(pixd, pixs);
620 pixCopyColormap(pixd, pixs);
621 pixCopyText(pixd, pixs);
622 pixCopyInputFormat(pixd, pixs);
623 }
624 pixaDestroy(&pixad);
625 return pixd;
626}
627
628
646PIXA *
648 l_float32 thresh,
649 l_int32 type,
650 l_int32 *pchanged)
651{
652NUMA *na, *nai;
653PIXA *pixad;
654
655 if (!pixas)
656 return (PIXA *)ERROR_PTR("pixas not defined", __func__, NULL);
657 if (type != L_SELECT_IF_LT && type != L_SELECT_IF_GT &&
658 type != L_SELECT_IF_LTE && type != L_SELECT_IF_GTE)
659 return (PIXA *)ERROR_PTR("invalid type", __func__, NULL);
660
661 /* Compute component ratios. */
662 na = pixaFindPerimSizeRatio(pixas);
663
664 /* Generate indicator array for elements to be saved. */
665 nai = numaMakeThresholdIndicator(na, thresh, type);
666 numaDestroy(&na);
667
668 /* Filter to get output */
669 pixad = pixaSelectWithIndicator(pixas, nai, pchanged);
670
671 numaDestroy(&nai);
672 return pixad;
673}
674
675
700PIX *
702 l_float32 thresh,
703 l_int32 connectivity,
704 l_int32 type,
705 l_int32 *pchanged)
706{
707l_int32 w, h, empty, changed, count;
708BOXA *boxa;
709PIX *pixd;
710PIXA *pixas, *pixad;
711
712 if (!pixs)
713 return (PIX *)ERROR_PTR("pixs not defined", __func__, NULL);
714 if (connectivity != 4 && connectivity != 8)
715 return (PIX *)ERROR_PTR("connectivity not 4 or 8", __func__, NULL);
716 if (type != L_SELECT_IF_LT && type != L_SELECT_IF_GT &&
717 type != L_SELECT_IF_LTE && type != L_SELECT_IF_GTE)
718 return (PIX *)ERROR_PTR("invalid type", __func__, NULL);
719 if (pchanged) *pchanged = FALSE;
720
721 /* Check if any components exist */
722 pixZero(pixs, &empty);
723 if (empty)
724 return pixCopy(NULL, pixs);
725
726 /* Filter components */
727 boxa = pixConnComp(pixs, &pixas, connectivity);
728 pixad = pixaSelectByAreaFraction(pixas, thresh, type, &changed);
729 boxaDestroy(&boxa);
730 pixaDestroy(&pixas);
731
732 if (!changed) {
733 pixaDestroy(&pixad);
734 return pixCopy(NULL, pixs);
735 }
736
737 /* Render the result */
738 if (pchanged) *pchanged = TRUE;
739 pixGetDimensions(pixs, &w, &h, NULL);
740 count = pixaGetCount(pixad);
741 if (count == 0) { /* return empty pix */
742 pixd = pixCreateTemplate(pixs);
743 } else {
744 pixd = pixaDisplay(pixad, w, h);
745 pixCopyResolution(pixd, pixs);
746 pixCopyColormap(pixd, pixs);
747 pixCopyText(pixd, pixs);
748 pixCopyInputFormat(pixd, pixs);
749 }
750 pixaDestroy(&pixad);
751 return pixd;
752}
753
754
776PIXA *
778 l_float32 thresh,
779 l_int32 type,
780 l_int32 *pchanged)
781{
782NUMA *na, *nai;
783PIXA *pixad;
784
785 if (!pixas)
786 return (PIXA *)ERROR_PTR("pixas not defined", __func__, NULL);
787 if (type != L_SELECT_IF_LT && type != L_SELECT_IF_GT &&
788 type != L_SELECT_IF_LTE && type != L_SELECT_IF_GTE)
789 return (PIXA *)ERROR_PTR("invalid type", __func__, NULL);
790
791 /* Compute component ratios. */
792 na = pixaFindAreaFraction(pixas);
793
794 /* Generate indicator array for elements to be saved. */
795 nai = numaMakeThresholdIndicator(na, thresh, type);
796 numaDestroy(&na);
797
798 /* Filter to get output */
799 pixad = pixaSelectWithIndicator(pixas, nai, pchanged);
800
801 numaDestroy(&nai);
802 return pixad;
803}
804
805
830PIX *
832 l_float32 thresh,
833 l_int32 connectivity,
834 l_int32 type,
835 l_int32 *pchanged)
836{
837l_int32 w, h, empty, changed, count;
838BOXA *boxa;
839PIX *pixd;
840PIXA *pixas, *pixad;
841
842 if (!pixs)
843 return (PIX *)ERROR_PTR("pixs not defined", __func__, NULL);
844 if (connectivity != 4 && connectivity != 8)
845 return (PIX *)ERROR_PTR("connectivity not 4 or 8", __func__, NULL);
846 if (type != L_SELECT_IF_LT && type != L_SELECT_IF_GT &&
847 type != L_SELECT_IF_LTE && type != L_SELECT_IF_GTE)
848 return (PIX *)ERROR_PTR("invalid type", __func__, NULL);
849 if (pchanged) *pchanged = FALSE;
850
851 /* Check if any components exist */
852 pixZero(pixs, &empty);
853 if (empty)
854 return pixCopy(NULL, pixs);
855
856 /* Filter components */
857 boxa = pixConnComp(pixs, &pixas, connectivity);
858 pixad = pixaSelectByArea(pixas, thresh, type, &changed);
859 boxaDestroy(&boxa);
860 pixaDestroy(&pixas);
861
862 if (!changed) {
863 pixaDestroy(&pixad);
864 return pixCopy(NULL, pixs);
865 }
866
867 /* Render the result */
868 if (pchanged) *pchanged = TRUE;
869 pixGetDimensions(pixs, &w, &h, NULL);
870 count = pixaGetCount(pixad);
871 if (count == 0) { /* return empty pix */
872 pixd = pixCreateTemplate(pixs);
873 } else {
874 pixd = pixaDisplay(pixad, w, h);
875 pixCopyResolution(pixd, pixs);
876 pixCopyColormap(pixd, pixs);
877 pixCopyText(pixd, pixs);
878 pixCopyInputFormat(pixd, pixs);
879 }
880 pixaDestroy(&pixad);
881 return pixd;
882}
883
884
906PIXA *
908 l_float32 thresh,
909 l_int32 type,
910 l_int32 *pchanged)
911{
912NUMA *na, *nai;
913PIXA *pixad;
914
915 if (!pixas)
916 return (PIXA *)ERROR_PTR("pixas not defined", __func__, NULL);
917 if (type != L_SELECT_IF_LT && type != L_SELECT_IF_GT &&
918 type != L_SELECT_IF_LTE && type != L_SELECT_IF_GTE)
919 return (PIXA *)ERROR_PTR("invalid type", __func__, NULL);
920
921 /* Compute area of each component */
922 na = pixaCountPixels(pixas);
923
924 /* Generate indicator array for elements to be saved. */
925 nai = numaMakeThresholdIndicator(na, thresh, type);
926 numaDestroy(&na);
927
928 /* Filter to get output */
929 pixad = pixaSelectWithIndicator(pixas, nai, pchanged);
930
931 numaDestroy(&nai);
932 return pixad;
933}
934
935
959PIX *
961 l_float32 thresh,
962 l_int32 connectivity,
963 l_int32 type,
964 l_int32 *pchanged)
965{
966l_int32 w, h, empty, changed, count;
967BOXA *boxa;
968PIX *pixd;
969PIXA *pixas, *pixad;
970
971 if (!pixs)
972 return (PIX *)ERROR_PTR("pixs not defined", __func__, NULL);
973 if (connectivity != 4 && connectivity != 8)
974 return (PIX *)ERROR_PTR("connectivity not 4 or 8", __func__, NULL);
975 if (type != L_SELECT_IF_LT && type != L_SELECT_IF_GT &&
976 type != L_SELECT_IF_LTE && type != L_SELECT_IF_GTE)
977 return (PIX *)ERROR_PTR("invalid type", __func__, NULL);
978 if (pchanged) *pchanged = FALSE;
979
980 /* Check if any components exist */
981 pixZero(pixs, &empty);
982 if (empty)
983 return pixCopy(NULL, pixs);
984
985 /* Filter components */
986 boxa = pixConnComp(pixs, &pixas, connectivity);
987 pixad = pixaSelectByWidthHeightRatio(pixas, thresh, type, &changed);
988 boxaDestroy(&boxa);
989 pixaDestroy(&pixas);
990
991 if (!changed) {
992 pixaDestroy(&pixad);
993 return pixCopy(NULL, pixs);
994 }
995
996 /* Render the result */
997 if (pchanged) *pchanged = TRUE;
998 pixGetDimensions(pixs, &w, &h, NULL);
999 count = pixaGetCount(pixad);
1000 if (count == 0) { /* return empty pix */
1001 pixd = pixCreateTemplate(pixs);
1002 } else {
1003 pixd = pixaDisplay(pixad, w, h);
1004 pixCopyResolution(pixd, pixs);
1005 pixCopyColormap(pixd, pixs);
1006 pixCopyText(pixd, pixs);
1007 pixCopyInputFormat(pixd, pixs);
1008 }
1009 pixaDestroy(&pixad);
1010 return pixd;
1011}
1012
1013
1035PIXA *
1037 l_float32 thresh,
1038 l_int32 type,
1039 l_int32 *pchanged)
1040{
1041NUMA *na, *nai;
1042PIXA *pixad;
1043
1044 if (!pixas)
1045 return (PIXA *)ERROR_PTR("pixas not defined", __func__, NULL);
1046 if (type != L_SELECT_IF_LT && type != L_SELECT_IF_GT &&
1047 type != L_SELECT_IF_LTE && type != L_SELECT_IF_GTE)
1048 return (PIXA *)ERROR_PTR("invalid type", __func__, NULL);
1049
1050 /* Compute component ratios. */
1051 na = pixaFindWidthHeightRatio(pixas);
1052
1053 /* Generate indicator array for elements to be saved. */
1054 nai = numaMakeThresholdIndicator(na, thresh, type);
1055 numaDestroy(&na);
1056
1057 /* Filter to get output */
1058 pixad = pixaSelectWithIndicator(pixas, nai, pchanged);
1059
1060 numaDestroy(&nai);
1061 return pixad;
1062}
1063
1064
1083PIXA *
1085 l_int32 nmin,
1086 l_int32 nmax,
1087 l_int32 connectivity,
1088 l_int32 *pchanged)
1089{
1090l_int32 n, i, count;
1091NUMA *na;
1092PIX *pix;
1093PIXA *pixad;
1094
1095 if (pchanged) *pchanged = 0;
1096 if (!pixas)
1097 return (PIXA *)ERROR_PTR("pixas not defined", __func__, NULL);
1098 if (nmin > nmax)
1099 return (PIXA *)ERROR_PTR("nmin > nmax", __func__, NULL);
1100 if (connectivity != 4 && connectivity != 8)
1101 return (PIXA *)ERROR_PTR("connectivity not 4 or 8", __func__, NULL);
1102
1103 /* Get indicator array based on number of c.c. */
1104 n = pixaGetCount(pixas);
1105 na = numaCreate(n);
1106 for (i = 0; i < n; i++) {
1107 pix = pixaGetPix(pixas, i, L_CLONE);
1108 pixCountConnComp(pix, connectivity, &count);
1109 if (count >= nmin && count <= nmax)
1110 numaAddNumber(na, 1);
1111 else
1112 numaAddNumber(na, 0);
1113 pixDestroy(&pix);
1114 }
1115
1116 /* Filter to get output */
1117 pixad = pixaSelectWithIndicator(pixas, na, pchanged);
1118 numaDestroy(&na);
1119 return pixad;
1120}
1121
1122
1140PIXA *
1142 NUMA *na,
1143 l_int32 *pchanged)
1144{
1145l_int32 i, n, nbox, ival, nsave;
1146BOX *box;
1147PIX *pix1;
1148PIXA *pixad;
1149
1150 if (!pixas)
1151 return (PIXA *)ERROR_PTR("pixas not defined", __func__, NULL);
1152 if (!na)
1153 return (PIXA *)ERROR_PTR("na not defined", __func__, NULL);
1154
1155 nsave = 0;
1156 n = numaGetCount(na);
1157 for (i = 0; i < n; i++) {
1158 numaGetIValue(na, i, &ival);
1159 if (ival == 1) nsave++;
1160 }
1161
1162 if (nsave == n) {
1163 if (pchanged) *pchanged = FALSE;
1164 return pixaCopy(pixas, L_CLONE);
1165 }
1166 if (pchanged) *pchanged = TRUE;
1167 pixad = pixaCreate(nsave);
1168 nbox = pixaGetBoxaCount(pixas);
1169 for (i = 0; i < n; i++) {
1170 numaGetIValue(na, i, &ival);
1171 if (ival == 0) continue;
1172 pix1 = pixaGetPix(pixas, i, L_CLONE);
1173 pixaAddPix(pixad, pix1, L_INSERT);
1174 if (nbox == n) { /* fully populated boxa */
1175 box = pixaGetBox(pixas, i, L_CLONE);
1176 pixaAddBox(pixad, box, L_INSERT);
1177 }
1178 }
1179
1180 return pixad;
1181}
1182
1183
1198l_ok
1200 PIXA *pixa,
1201 NUMA *na)
1202{
1203l_int32 i, n, ival, x, y, w, h;
1204BOX *box;
1205PIX *pix;
1206
1207 if (!pixs)
1208 return ERROR_INT("pixs not defined", __func__, 1);
1209 if (!pixa)
1210 return ERROR_INT("pixa not defined", __func__, 1);
1211 if (!na)
1212 return ERROR_INT("na not defined", __func__, 1);
1213 n = pixaGetCount(pixa);
1214 if (n != numaGetCount(na))
1215 return ERROR_INT("pixa and na sizes not equal", __func__, 1);
1216
1217 for (i = 0; i < n; i++) {
1218 numaGetIValue(na, i, &ival);
1219 if (ival == 1) {
1220 pix = pixaGetPix(pixa, i, L_CLONE);
1221 box = pixaGetBox(pixa, i, L_CLONE);
1222 boxGetGeometry(box, &x, &y, &w, &h);
1223 pixRasterop(pixs, x, y, w, h, PIX_DST & PIX_NOT(PIX_SRC),
1224 pix, 0, 0);
1225 boxDestroy(&box);
1226 pixDestroy(&pix);
1227 }
1228 }
1229
1230 return 0;
1231}
1232
1233
1249l_ok
1251 PIXA *pixa,
1252 NUMA *na)
1253{
1254l_int32 i, n, ival, x, y, w, h;
1255BOX *box;
1256PIX *pix;
1257
1258 if (!pixs)
1259 return ERROR_INT("pixs not defined", __func__, 1);
1260 if (!pixa)
1261 return ERROR_INT("pixa not defined", __func__, 1);
1262 if (!na)
1263 return ERROR_INT("na not defined", __func__, 1);
1264 n = pixaGetCount(pixa);
1265 if (n != numaGetCount(na))
1266 return ERROR_INT("pixa and na sizes not equal", __func__, 1);
1267
1268 for (i = 0; i < n; i++) {
1269 numaGetIValue(na, i, &ival);
1270 if (ival == 1) {
1271 pix = pixaGetPix(pixa, i, L_CLONE);
1272 box = pixaGetBox(pixa, i, L_CLONE);
1273 boxGetGeometry(box, &x, &y, &w, &h);
1274 pixRasterop(pixs, x, y, w, h, PIX_SRC | PIX_DST, pix, 0, 0);
1275 boxDestroy(&box);
1276 pixDestroy(&pix);
1277 }
1278 }
1279
1280 return 0;
1281}
1282
1283
1300PIXA *
1302 const char *str,
1303 l_int32 *perror)
1304{
1305l_int32 i, nval, npix, nbox, val, imaxval;
1306l_float32 maxval;
1307BOX *box;
1308NUMA *na;
1309PIX *pix1;
1310PIXA *pixad;
1311
1312 if (perror) *perror = 0;
1313 if (!pixas)
1314 return (PIXA *)ERROR_PTR("pixas not defined", __func__, NULL);
1315 if (!str)
1316 return (PIXA *)ERROR_PTR("str not defined", __func__, NULL);
1317
1318 if ((na = numaCreateFromString(str)) == NULL)
1319 return (PIXA *)ERROR_PTR("na not made", __func__, NULL);
1320 if ((nval = numaGetCount(na)) == 0) {
1321 numaDestroy(&na);
1322 return (PIXA *)ERROR_PTR("no indices found", __func__, NULL);
1323 }
1324 numaGetMax(na, &maxval, NULL);
1325 imaxval = (l_int32)(maxval + 0.1);
1326 nbox = pixaGetBoxaCount(pixas);
1327 npix = pixaGetCount(pixas);
1328 if (imaxval >= npix) {
1329 if (perror) *perror = 1;
1330 L_ERROR("max index = %d, size of pixa = %d\n", __func__, imaxval, npix);
1331 }
1332
1333 pixad = pixaCreate(nval);
1334 for (i = 0; i < nval; i++) {
1335 numaGetIValue(na, i, &val);
1336 if (val < 0 || val >= npix) {
1337 L_ERROR("index %d out of range of pix\n", __func__, val);
1338 continue;
1339 }
1340 pix1 = pixaGetPix(pixas, val, L_COPY);
1341 pixaAddPix(pixad, pix1, L_INSERT);
1342 if (nbox == npix) { /* fully populated boxa */
1343 box = pixaGetBox(pixas, val, L_COPY);
1344 pixaAddBox(pixad, box, L_INSERT);
1345 }
1346 }
1347 numaDestroy(&na);
1348 return pixad;
1349}
1350
1351
1369PIX *
1371 PIXA *pixa,
1372 l_int32 index)
1373{
1374l_int32 n, x, y, w, h, same, maxd;
1375BOX *box;
1376BOXA *boxa;
1377PIX *pix;
1378
1379 if (!pixa)
1380 return (PIX *)ERROR_PTR("pixa not defined", __func__, pixs);
1381 n = pixaGetCount(pixa);
1382 if (index < 0 || index >= n)
1383 return (PIX *)ERROR_PTR("invalid index", __func__, pixs);
1384 if (pixs && (pixGetDepth(pixs) != 1))
1385 return (PIX *)ERROR_PTR("pixs not 1 bpp", __func__, pixs);
1386 pixaVerifyDepth(pixa, &same, &maxd);
1387 if (maxd > 1)
1388 return (PIX *)ERROR_PTR("not all pix with d == 1", __func__, pixs);
1389
1390 boxa = pixaGetBoxa(pixa, L_CLONE);
1391 if (!pixs) {
1392 boxaGetExtent(boxa, &w, &h, NULL);
1393 pixs = pixCreate(w, h, 1);
1394 }
1395
1396 pix = pixaGetPix(pixa, index, L_CLONE);
1397 box = boxaGetBox(boxa, index, L_CLONE);
1398 boxGetGeometry(box, &x, &y, &w, &h);
1399 pixRasterop(pixs, x, y, w, h, PIX_SRC | PIX_DST, pix, 0, 0);
1400 boxDestroy(&box);
1401 pixDestroy(&pix);
1402 boxaDestroy(&boxa);
1403
1404 return pixs;
1405}
1406
1407
1408/*---------------------------------------------------------------------*
1409 * Sort functions *
1410 *---------------------------------------------------------------------*/
1437PIXA *
1439 l_int32 sorttype,
1440 l_int32 sortorder,
1441 NUMA **pnaindex,
1442 l_int32 copyflag)
1443{
1444l_int32 i, n, nb, x, y, w, h;
1445BOXA *boxa;
1446NUMA *na, *naindex;
1447PIXA *pixad;
1448
1449 if (pnaindex) *pnaindex = NULL;
1450 if (!pixas)
1451 return (PIXA *)ERROR_PTR("pixas not defined", __func__, NULL);
1452 if (sorttype != L_SORT_BY_X && sorttype != L_SORT_BY_Y &&
1453 sorttype != L_SORT_BY_WIDTH && sorttype != L_SORT_BY_HEIGHT &&
1454 sorttype != L_SORT_BY_MIN_DIMENSION &&
1455 sorttype != L_SORT_BY_MAX_DIMENSION &&
1456 sorttype != L_SORT_BY_PERIMETER &&
1457 sorttype != L_SORT_BY_AREA &&
1458 sorttype != L_SORT_BY_ASPECT_RATIO)
1459 return (PIXA *)ERROR_PTR("invalid sort type", __func__, NULL);
1460 if (sortorder != L_SORT_INCREASING && sortorder != L_SORT_DECREASING)
1461 return (PIXA *)ERROR_PTR("invalid sort order", __func__, NULL);
1462 if (copyflag != L_COPY && copyflag != L_CLONE)
1463 return (PIXA *)ERROR_PTR("invalid copy flag", __func__, NULL);
1464
1465 /* Check the pixa and boxa counts. Make a boxa if required. */
1466 if ((n = pixaGetCount(pixas)) == 0) {
1467 L_INFO("no pix in pixa\n", __func__);
1468 return pixaCopy(pixas, copyflag);
1469 }
1470 if ((boxa = pixas->boxa) == NULL) /* not owned; do not destroy */
1471 return (PIXA *)ERROR_PTR("boxa not found!", __func__, NULL);
1472 nb = boxaGetCount(boxa);
1473 if (nb == 0) {
1474 pixaSetFullSizeBoxa(pixas);
1475 nb = n;
1476 boxa = pixas->boxa; /* not owned */
1477 if (sorttype == L_SORT_BY_X || sorttype == L_SORT_BY_Y)
1478 L_WARNING("sort by x or y where all values are 0\n", __func__);
1479 }
1480 if (nb != n)
1481 return (PIXA *)ERROR_PTR("boxa and pixa counts differ", __func__, NULL);
1482
1483 /* Use O(n) binsort if possible */
1484 if (n > MinCompsForBinSort &&
1485 ((sorttype == L_SORT_BY_X) || (sorttype == L_SORT_BY_Y) ||
1486 (sorttype == L_SORT_BY_WIDTH) || (sorttype == L_SORT_BY_HEIGHT) ||
1487 (sorttype == L_SORT_BY_PERIMETER)))
1488 return pixaBinSort(pixas, sorttype, sortorder, pnaindex, copyflag);
1489
1490 /* Build up numa of specific data */
1491 if ((na = numaCreate(n)) == NULL)
1492 return (PIXA *)ERROR_PTR("na not made", __func__, NULL);
1493 for (i = 0; i < n; i++) {
1494 boxaGetBoxGeometry(boxa, i, &x, &y, &w, &h);
1495 switch (sorttype)
1496 {
1497 case L_SORT_BY_X:
1498 numaAddNumber(na, x);
1499 break;
1500 case L_SORT_BY_Y:
1501 numaAddNumber(na, y);
1502 break;
1503 case L_SORT_BY_WIDTH:
1504 numaAddNumber(na, w);
1505 break;
1506 case L_SORT_BY_HEIGHT:
1507 numaAddNumber(na, h);
1508 break;
1510 numaAddNumber(na, L_MIN(w, h));
1511 break;
1513 numaAddNumber(na, L_MAX(w, h));
1514 break;
1516 numaAddNumber(na, w + h);
1517 break;
1518 case L_SORT_BY_AREA:
1519 numaAddNumber(na, w * h);
1520 break;
1522 numaAddNumber(na, (l_float32)w / (l_float32)h);
1523 break;
1524 default:
1525 L_WARNING("invalid sort type\n", __func__);
1526 }
1527 }
1528
1529 /* Get the sort index for data array */
1530 naindex = numaGetSortIndex(na, sortorder);
1531 numaDestroy(&na);
1532 if (!naindex)
1533 return (PIXA *)ERROR_PTR("naindex not made", __func__, NULL);
1534
1535 /* Build up sorted pixa using sort index */
1536 if ((pixad = pixaSortByIndex(pixas, naindex, copyflag)) == NULL) {
1537 numaDestroy(&naindex);
1538 return (PIXA *)ERROR_PTR("pixad not made", __func__, NULL);
1539 }
1540
1541 if (pnaindex)
1542 *pnaindex = naindex;
1543 else
1544 numaDestroy(&naindex);
1545 return pixad;
1546}
1547
1548
1575PIXA *
1577 l_int32 sorttype,
1578 l_int32 sortorder,
1579 NUMA **pnaindex,
1580 l_int32 copyflag)
1581{
1582l_int32 i, n, x, y, w, h;
1583BOXA *boxa;
1584NUMA *na, *naindex;
1585PIXA *pixad;
1586
1587 if (pnaindex) *pnaindex = NULL;
1588 if (!pixas)
1589 return (PIXA *)ERROR_PTR("pixas not defined", __func__, NULL);
1590 if (sorttype != L_SORT_BY_X && sorttype != L_SORT_BY_Y &&
1591 sorttype != L_SORT_BY_WIDTH && sorttype != L_SORT_BY_HEIGHT &&
1592 sorttype != L_SORT_BY_PERIMETER)
1593 return (PIXA *)ERROR_PTR("invalid sort type", __func__, NULL);
1594 if (sortorder != L_SORT_INCREASING && sortorder != L_SORT_DECREASING)
1595 return (PIXA *)ERROR_PTR("invalid sort order", __func__, NULL);
1596 if (copyflag != L_COPY && copyflag != L_CLONE)
1597 return (PIXA *)ERROR_PTR("invalid copy flag", __func__, NULL);
1598
1599 /* Verify that the pixa and its boxa have the same count */
1600 if ((boxa = pixas->boxa) == NULL) /* not owned; do not destroy */
1601 return (PIXA *)ERROR_PTR("boxa not found", __func__, NULL);
1602 n = pixaGetCount(pixas);
1603 if (boxaGetCount(boxa) != n)
1604 return (PIXA *)ERROR_PTR("boxa and pixa counts differ", __func__, NULL);
1605
1606 /* Generate Numa of appropriate box dimensions */
1607 if ((na = numaCreate(n)) == NULL)
1608 return (PIXA *)ERROR_PTR("na not made", __func__, NULL);
1609 for (i = 0; i < n; i++) {
1610 boxaGetBoxGeometry(boxa, i, &x, &y, &w, &h);
1611 switch (sorttype)
1612 {
1613 case L_SORT_BY_X:
1614 numaAddNumber(na, x);
1615 break;
1616 case L_SORT_BY_Y:
1617 numaAddNumber(na, y);
1618 break;
1619 case L_SORT_BY_WIDTH:
1620 numaAddNumber(na, w);
1621 break;
1622 case L_SORT_BY_HEIGHT:
1623 numaAddNumber(na, h);
1624 break;
1626 numaAddNumber(na, w + h);
1627 break;
1628 default:
1629 L_WARNING("invalid sort type\n", __func__);
1630 }
1631 }
1632
1633 /* Get the sort index for data array */
1634 naindex = numaGetBinSortIndex(na, sortorder);
1635 numaDestroy(&na);
1636 if (!naindex)
1637 return (PIXA *)ERROR_PTR("naindex not made", __func__, NULL);
1638
1639 /* Build up sorted pixa using sort index */
1640 if ((pixad = pixaSortByIndex(pixas, naindex, copyflag)) == NULL) {
1641 numaDestroy(&naindex);
1642 return (PIXA *)ERROR_PTR("pixad not made", __func__, NULL);
1643 }
1644
1645 if (pnaindex)
1646 *pnaindex = naindex;
1647 else
1648 numaDestroy(&naindex);
1649 return pixad;
1650}
1651
1652
1661PIXA *
1663 NUMA *naindex,
1664 l_int32 copyflag)
1665{
1666l_int32 i, n, index;
1667BOX *box;
1668PIX *pix;
1669PIXA *pixad;
1670
1671 if (!pixas)
1672 return (PIXA *)ERROR_PTR("pixas not defined", __func__, NULL);
1673 if (!naindex)
1674 return (PIXA *)ERROR_PTR("naindex not defined", __func__, NULL);
1675 if (copyflag != L_CLONE && copyflag != L_COPY)
1676 return (PIXA *)ERROR_PTR("invalid copyflag", __func__, NULL);
1677
1678 n = pixaGetCount(pixas);
1679 pixad = pixaCreate(n);
1680 for (i = 0; i < n; i++) {
1681 numaGetIValue(naindex, i, &index);
1682 pix = pixaGetPix(pixas, index, copyflag);
1683 box = pixaGetBox(pixas, index, copyflag);
1684 pixaAddPix(pixad, pix, L_INSERT);
1685 pixaAddBox(pixad, box, L_INSERT);
1686 }
1687
1688 return pixad;
1689}
1690
1691
1700PIXAA *
1702 NUMAA *naa,
1703 l_int32 copyflag)
1704{
1705l_int32 pixtot, ntot, i, j, n, nn, index;
1706BOX *box;
1707NUMA *na;
1708PIX *pix;
1709PIXA *pixa;
1710PIXAA *paa;
1711
1712 if (!pixas)
1713 return (PIXAA *)ERROR_PTR("pixas not defined", __func__, NULL);
1714 if (!naa)
1715 return (PIXAA *)ERROR_PTR("naindex not defined", __func__, NULL);
1716
1717 /* Check counts */
1718 ntot = numaaGetNumberCount(naa);
1719 pixtot = pixaGetCount(pixas);
1720 if (ntot != pixtot)
1721 return (PIXAA *)ERROR_PTR("element count mismatch", __func__, NULL);
1722
1723 n = numaaGetCount(naa);
1724 paa = pixaaCreate(n);
1725 for (i = 0; i < n; i++) {
1726 na = numaaGetNuma(naa, i, L_CLONE);
1727 nn = numaGetCount(na);
1728 pixa = pixaCreate(nn);
1729 for (j = 0; j < nn; j++) {
1730 numaGetIValue(na, j, &index);
1731 pix = pixaGetPix(pixas, index, copyflag);
1732 box = pixaGetBox(pixas, index, copyflag);
1733 pixaAddPix(pixa, pix, L_INSERT);
1734 pixaAddBox(pixa, box, L_INSERT);
1735 }
1736 pixaaAddPixa(paa, pixa, L_INSERT);
1737 numaDestroy(&na);
1738 }
1739
1740 return paa;
1741}
1742
1743
1744/*---------------------------------------------------------------------*
1745 * Pixa and Pixaa range selection *
1746 *---------------------------------------------------------------------*/
1763PIXA *
1765 l_int32 first,
1766 l_int32 last,
1767 l_int32 copyflag)
1768{
1769l_int32 n, npix, i;
1770PIX *pix;
1771PIXA *pixad;
1772
1773 if (!pixas)
1774 return (PIXA *)ERROR_PTR("pixas not defined", __func__, NULL);
1775 if (copyflag != L_COPY && copyflag != L_CLONE)
1776 return (PIXA *)ERROR_PTR("invalid copyflag", __func__, NULL);
1777 n = pixaGetCount(pixas);
1778 first = L_MAX(0, first);
1779 if (last < 0) last = n - 1;
1780 if (first >= n)
1781 return (PIXA *)ERROR_PTR("invalid first", __func__, NULL);
1782 if (last >= n) {
1783 L_WARNING("last = %d is beyond max index = %d; adjusting\n",
1784 __func__, last, n - 1);
1785 last = n - 1;
1786 }
1787 if (first > last)
1788 return (PIXA *)ERROR_PTR("first > last", __func__, NULL);
1789
1790 npix = last - first + 1;
1791 pixad = pixaCreate(npix);
1792 for (i = first; i <= last; i++) {
1793 pix = pixaGetPix(pixas, i, copyflag);
1794 pixaAddPix(pixad, pix, L_INSERT);
1795 }
1796 return pixad;
1797}
1798
1799
1816PIXAA *
1818 l_int32 first,
1819 l_int32 last,
1820 l_int32 copyflag)
1821{
1822l_int32 n, npixa, i;
1823PIXA *pixa;
1824PIXAA *paad;
1825
1826 if (!paas)
1827 return (PIXAA *)ERROR_PTR("paas not defined", __func__, NULL);
1828 if (copyflag != L_COPY && copyflag != L_CLONE)
1829 return (PIXAA *)ERROR_PTR("invalid copyflag", __func__, NULL);
1830 n = pixaaGetCount(paas, NULL);
1831 first = L_MAX(0, first);
1832 if (last < 0) last = n - 1;
1833 if (first >= n)
1834 return (PIXAA *)ERROR_PTR("invalid first", __func__, NULL);
1835 if (last >= n) {
1836 L_WARNING("last = %d is beyond max index = %d; adjusting\n",
1837 __func__, last, n - 1);
1838 last = n - 1;
1839 }
1840 if (first > last)
1841 return (PIXAA *)ERROR_PTR("first > last", __func__, NULL);
1842
1843 npixa = last - first + 1;
1844 paad = pixaaCreate(npixa);
1845 for (i = first; i <= last; i++) {
1846 pixa = pixaaGetPixa(paas, i, copyflag);
1847 pixaaAddPixa(paad, pixa, L_INSERT);
1848 }
1849 return paad;
1850}
1851
1852
1853/*---------------------------------------------------------------------*
1854 * Pixa and Pixaa scaling *
1855 *---------------------------------------------------------------------*/
1875PIXAA *
1877 l_int32 wd,
1878 l_int32 hd)
1879{
1880l_int32 n, i;
1881PIXA *pixa1, *pixa2;
1882PIXAA *paad;
1883
1884 if (!paas)
1885 return (PIXAA *)ERROR_PTR("paas not defined", __func__, NULL);
1886 if (wd <= 0 && hd <= 0)
1887 return (PIXAA *)ERROR_PTR("neither wd nor hd > 0", __func__, NULL);
1888
1889 n = pixaaGetCount(paas, NULL);
1890 paad = pixaaCreate(n);
1891 for (i = 0; i < n; i++) {
1892 pixa1 = pixaaGetPixa(paas, i, L_CLONE);
1893 pixa2 = pixaScaleToSize(pixa1, wd, hd);
1894 pixaaAddPixa(paad, pixa2, L_INSERT);
1895 pixaDestroy(&pixa1);
1896 }
1897 return paad;
1898}
1899
1900
1922PIXAA *
1924 NUMA *nawd,
1925 NUMA *nahd)
1926{
1927l_int32 n, i, wd, hd;
1928PIXA *pixa1, *pixa2;
1929PIXAA *paad;
1930
1931 if (!paas)
1932 return (PIXAA *)ERROR_PTR("paas not defined", __func__, NULL);
1933 if (!nawd && !nahd)
1934 return (PIXAA *)ERROR_PTR("!nawd && !nahd", __func__, NULL);
1935
1936 n = pixaaGetCount(paas, NULL);
1937 if (nawd && (n != numaGetCount(nawd)))
1938 return (PIXAA *)ERROR_PTR("nawd wrong size", __func__, NULL);
1939 if (nahd && (n != numaGetCount(nahd)))
1940 return (PIXAA *)ERROR_PTR("nahd wrong size", __func__, NULL);
1941 paad = pixaaCreate(n);
1942 for (i = 0; i < n; i++) {
1943 wd = hd = 0;
1944 if (nawd) numaGetIValue(nawd, i, &wd);
1945 if (nahd) numaGetIValue(nahd, i, &hd);
1946 pixa1 = pixaaGetPixa(paas, i, L_CLONE);
1947 pixa2 = pixaScaleToSize(pixa1, wd, hd);
1948 pixaaAddPixa(paad, pixa2, L_INSERT);
1949 pixaDestroy(&pixa1);
1950 }
1951 return paad;
1952}
1953
1954
1968PIXA *
1970 l_int32 wd,
1971 l_int32 hd)
1972{
1973l_int32 n, i;
1974PIX *pix1, *pix2;
1975PIXA *pixad;
1976
1977 if (!pixas)
1978 return (PIXA *)ERROR_PTR("pixas not defined", __func__, NULL);
1979
1980 if (wd <= 0 && hd <= 0) /* no scaling requested */
1981 return pixaCopy(pixas, L_CLONE);
1982
1983 n = pixaGetCount(pixas);
1984 pixad = pixaCreate(n);
1985 for (i = 0; i < n; i++) {
1986 pix1 = pixaGetPix(pixas, i, L_CLONE);
1987 pix2 = pixScaleToSize(pix1, wd, hd);
1988 pixCopyText(pix2, pix1);
1989 pixaAddPix(pixad, pix2, L_INSERT);
1990 pixDestroy(&pix1);
1991 }
1992 return pixad;
1993}
1994
1995
2011PIXA *
2013 l_int32 delw,
2014 l_int32 delh)
2015{
2016l_int32 n, i;
2017PIX *pix1, *pix2;
2018PIXA *pixad;
2019
2020 if (!pixas)
2021 return (PIXA *)ERROR_PTR("pixas not defined", __func__, NULL);
2022
2023 n = pixaGetCount(pixas);
2024 pixad = pixaCreate(n);
2025 for (i = 0; i < n; i++) {
2026 pix1 = pixaGetPix(pixas, i, L_CLONE);
2027 pix2 = pixScaleToSizeRel(pix1, delw, delh);
2028 if (pix2) {
2029 pixaAddPix(pixad, pix2, L_INSERT);
2030 } else {
2031 L_WARNING("relative scale to size failed; use a copy\n", __func__);
2032 pixaAddPix(pixad, pix1, L_COPY);
2033 }
2034 pixDestroy(&pix1);
2035 }
2036 return pixad;
2037}
2038
2039
2053PIXA *
2055 l_float32 scalex,
2056 l_float32 scaley)
2057{
2058l_int32 i, n, nb;
2059BOXA *boxa1, *boxa2;
2060PIX *pix1, *pix2;
2061PIXA *pixad;
2062
2063 if (!pixas)
2064 return (PIXA *)ERROR_PTR("pixas not defined", __func__, NULL);
2065 if (scalex <= 0.0 || scaley <= 0.0)
2066 return (PIXA *)ERROR_PTR("invalid scaling parameters", __func__, NULL);
2067
2068 n = pixaGetCount(pixas);
2069 pixad = pixaCreate(n);
2070 for (i = 0; i < n; i++) {
2071 pix1 = pixaGetPix(pixas, i, L_CLONE);
2072 pix2 = pixScale(pix1, scalex, scaley);
2073 pixCopyText(pix2, pix1);
2074 pixaAddPix(pixad, pix2, L_INSERT);
2075 pixDestroy(&pix1);
2076 }
2077
2078 boxa1 = pixaGetBoxa(pixas, L_CLONE);
2079 nb = boxaGetCount(boxa1);
2080 if (nb == n) {
2081 boxa2 = boxaTransform(boxa1, 0, 0, scalex, scaley);
2082 pixaSetBoxa(pixad, boxa2, L_INSERT);
2083 }
2084 boxaDestroy(&boxa1);
2085 return pixad;
2086}
2087
2088
2102PIXA *
2104 l_float32 scalex,
2105 l_float32 scaley)
2106{
2107l_int32 i, n, nb;
2108BOXA *boxa1, *boxa2;
2109PIX *pix1, *pix2;
2110PIXA *pixad;
2111
2112 if (!pixas)
2113 return (PIXA *)ERROR_PTR("pixas not defined", __func__, NULL);
2114 if (scalex <= 0.0 || scaley <= 0.0)
2115 return (PIXA *)ERROR_PTR("invalid scaling parameters", __func__, NULL);
2116
2117 n = pixaGetCount(pixas);
2118 pixad = pixaCreate(n);
2119 for (i = 0; i < n; i++) {
2120 pix1 = pixaGetPix(pixas, i, L_CLONE);
2121 pix2 = pixScaleBySampling(pix1, scalex, scaley);
2122 pixCopyText(pix2, pix1);
2123 pixaAddPix(pixad, pix2, L_INSERT);
2124 pixDestroy(&pix1);
2125 }
2126
2127 boxa1 = pixaGetBoxa(pixas, L_CLONE);
2128 nb = boxaGetCount(boxa1);
2129 if (nb == n) {
2130 boxa2 = boxaTransform(boxa1, 0, 0, scalex, scaley);
2131 pixaSetBoxa(pixad, boxa2, L_INSERT);
2132 }
2133 boxaDestroy(&boxa1);
2134 return pixad;
2135}
2136
2137
2138/*---------------------------------------------------------------------*
2139 * Pixa rotation and translation *
2140 *---------------------------------------------------------------------*/
2165PIXA *
2167 l_float32 angle,
2168 l_int32 type,
2169 l_int32 incolor,
2170 l_int32 width,
2171 l_int32 height)
2172{
2173l_int32 i, n;
2174BOXA *boxa;
2175PIX *pixs, *pixd;
2176PIXA *pixad;
2177
2178 if (!pixas)
2179 return (PIXA *)ERROR_PTR("pixas not defined", __func__, NULL);
2180 if (type != L_ROTATE_SHEAR && type != L_ROTATE_AREA_MAP &&
2181 type != L_ROTATE_SAMPLING)
2182 return (PIXA *)ERROR_PTR("invalid type", __func__, NULL);
2183 if (incolor != L_BRING_IN_WHITE && incolor != L_BRING_IN_BLACK)
2184 return (PIXA *)ERROR_PTR("invalid incolor", __func__, NULL);
2185 if (L_ABS(angle) < MinAngleToRotate)
2186 return pixaCopy(pixas, L_COPY);
2187
2188 n = pixaGetCount(pixas);
2189 if ((pixad = pixaCreate(n)) == NULL)
2190 return (PIXA *)ERROR_PTR("pixad not made", __func__, NULL);
2191 boxa = pixaGetBoxa(pixad, L_COPY);
2192 pixaSetBoxa(pixad, boxa, L_INSERT);
2193 for (i = 0; i < n; i++) {
2194 if ((pixs = pixaGetPix(pixas, i, L_CLONE)) == NULL) {
2195 pixaDestroy(&pixad);
2196 return (PIXA *)ERROR_PTR("pixs not found", __func__, NULL);
2197 }
2198 pixd = pixRotate(pixs, angle, type, incolor, width, height);
2199 pixaAddPix(pixad, pixd, L_INSERT);
2200 pixDestroy(&pixs);
2201 }
2202
2203 return pixad;
2204}
2205
2206
2221PIXA *
2223 l_int32 rotation)
2224{
2225l_int32 i, n, nb, w, h;
2226BOX *boxs, *boxd;
2227PIX *pixs, *pixd;
2228PIXA *pixad;
2229
2230 if (!pixas)
2231 return (PIXA *)ERROR_PTR("pixas not defined", __func__, NULL);
2232 if (rotation < 0 || rotation > 3)
2233 return (PIXA *)ERROR_PTR("rotation not in {0,1,2,3}", __func__, NULL);
2234 if (rotation == 0)
2235 return pixaCopy(pixas, L_COPY);
2236
2237 n = pixaGetCount(pixas);
2238 nb = pixaGetBoxaCount(pixas);
2239 if ((pixad = pixaCreate(n)) == NULL)
2240 return (PIXA *)ERROR_PTR("pixad not made", __func__, NULL);
2241 for (i = 0; i < n; i++) {
2242 if ((pixs = pixaGetPix(pixas, i, L_CLONE)) == NULL) {
2243 pixaDestroy(&pixad);
2244 return (PIXA *)ERROR_PTR("pixs not found", __func__, NULL);
2245 }
2246 pixd = pixRotateOrth(pixs, rotation);
2247 pixaAddPix(pixad, pixd, L_INSERT);
2248 if (n == nb) {
2249 boxs = pixaGetBox(pixas, i, L_COPY);
2250 pixGetDimensions(pixs, &w, &h, NULL);
2251 boxd = boxRotateOrth(boxs, w, h, rotation);
2252 pixaAddBox(pixad, boxd, L_INSERT);
2253 boxDestroy(&boxs);
2254 }
2255 pixDestroy(&pixs);
2256 }
2257
2258 return pixad;
2259}
2260
2261
2271PIXA *
2273 l_int32 hshift,
2274 l_int32 vshift,
2275 l_int32 incolor)
2276{
2277l_int32 i, n, nb;
2278BOXA *boxas, *boxad;
2279PIX *pixs, *pixd;
2280PIXA *pixad;
2281
2282 if (!pixas)
2283 return (PIXA *)ERROR_PTR("pixas not defined", __func__, NULL);
2284 if (hshift == 0 && vshift == 0)
2285 return pixaCopy(pixas, L_COPY);
2286
2287 n = pixaGetCount(pixas);
2288 nb = pixaGetBoxaCount(pixas);
2289 if ((pixad = pixaCreate(n)) == NULL)
2290 return (PIXA *)ERROR_PTR("pixad not made", __func__, NULL);
2291 for (i = 0; i < n; i++) {
2292 if ((pixs = pixaGetPix(pixas, i, L_CLONE)) == NULL) {
2293 pixaDestroy(&pixad);
2294 return (PIXA *)ERROR_PTR("pixs not found", __func__, NULL);
2295 }
2296 pixd = pixTranslate(NULL, pixs, hshift, vshift, incolor);
2297 pixaAddPix(pixad, pixd, L_INSERT);
2298 pixDestroy(&pixs);
2299 }
2300 if (n == nb) {
2301 boxas = pixaGetBoxa(pixas, L_CLONE);
2302 boxad = boxaTransform(boxas, hshift, vshift, 1.0, 1.0);
2303 pixaSetBoxa(pixad, boxad, L_INSERT);
2304 boxaDestroy(&boxas);
2305 }
2306
2307 return pixad;
2308}
2309
2310
2311/*---------------------------------------------------------------------*
2312 * Miscellaneous functions *
2313 *---------------------------------------------------------------------*/
2343PIXA *
2345 PIXA *pixas,
2346 l_int32 left,
2347 l_int32 right,
2348 l_int32 top,
2349 l_int32 bot,
2350 l_uint32 val)
2351{
2352l_int32 i, n, nbox;
2353BOX *box;
2354BOXA *boxad;
2355PIX *pixs, *pixd;
2356
2357 if (!pixas)
2358 return (PIXA *)ERROR_PTR("pixas not defined", __func__, pixad);
2359 if (left < 0 || right < 0 || top < 0 || bot < 0)
2360 return (PIXA *)ERROR_PTR("negative border added!", __func__, pixad);
2361 if (pixad && (pixad != pixas))
2362 return (PIXA *)ERROR_PTR("pixad defined but != pixas", __func__, pixad);
2363
2364 n = pixaGetCount(pixas);
2365 if (!pixad)
2366 pixad = pixaCreate(n);
2367 for (i = 0; i < n; i++) {
2368 pixs = pixaGetPix(pixas, i, L_CLONE);
2369 pixd = pixAddBorderGeneral(pixs, left, right, top, bot, val);
2370 if (pixad == pixas) /* replace */
2371 pixaReplacePix(pixad, i, pixd, NULL);
2372 else
2373 pixaAddPix(pixad, pixd, L_INSERT);
2374 pixDestroy(&pixs);
2375 }
2376
2377 nbox = pixaGetBoxaCount(pixas);
2378 boxad = pixaGetBoxa(pixad, L_CLONE);
2379 for (i = 0; i < nbox; i++) {
2380 if ((box = pixaGetBox(pixas, i, L_COPY)) == NULL) {
2381 L_WARNING("box %d not found\n", __func__, i);
2382 break;
2383 }
2384 boxAdjustSides(box, box, -left, right, -top, bot);
2385 if (pixad == pixas) /* replace */
2386 boxaReplaceBox(boxad, i, box);
2387 else
2388 boxaAddBox(boxad, box, L_INSERT);
2389 }
2390 boxaDestroy(&boxad);
2391
2392 return pixad;
2393}
2394
2395
2412PIXA *
2414 NUMA **pnaindex,
2415 l_int32 copyflag)
2416{
2417l_int32 i, j, m, mb, n;
2418BOX *box;
2419NUMA *naindex = NULL;
2420PIX *pix;
2421PIXA *pixa, *pixat;
2422
2423 if (pnaindex) *pnaindex = NULL;
2424 if (!paa)
2425 return (PIXA *)ERROR_PTR("paa not defined", __func__, NULL);
2426 if (copyflag != L_COPY && copyflag != L_CLONE)
2427 return (PIXA *)ERROR_PTR("invalid copyflag", __func__, NULL);
2428
2429 if (pnaindex) {
2430 naindex = numaCreate(0);
2431 *pnaindex = naindex;
2432 }
2433
2434 n = pixaaGetCount(paa, NULL);
2435 pixa = pixaCreate(n);
2436 for (i = 0; i < n; i++) {
2437 pixat = pixaaGetPixa(paa, i, L_CLONE);
2438 m = pixaGetCount(pixat);
2439 mb = pixaGetBoxaCount(pixat);
2440 for (j = 0; j < m; j++) {
2441 pix = pixaGetPix(pixat, j, copyflag);
2442 pixaAddPix(pixa, pix, L_INSERT);
2443 if (j < mb) {
2444 box = pixaGetBox(pixat, j, copyflag);
2445 pixaAddBox(pixa, box, L_INSERT);
2446 }
2447 if (pnaindex)
2448 numaAddNumber(naindex, i); /* save 'row' number */
2449 }
2450 pixaDestroy(&pixat);
2451 }
2452
2453 return pixa;
2454}
2455
2456
2465l_ok
2467 l_int32 *pminw,
2468 l_int32 *pminh,
2469 l_int32 *pmaxw,
2470 l_int32 *pmaxh)
2471{
2472l_int32 minw, minh, maxw, maxh, minpw, minph, maxpw, maxph, i, n;
2473PIXA *pixa;
2474
2475 if (pminw) *pminw = 0;
2476 if (pminh) *pminh = 0;
2477 if (pmaxw) *pmaxw = 0;
2478 if (pmaxh) *pmaxh = 0;
2479 if (!paa)
2480 return ERROR_INT("paa not defined", __func__, 1);
2481 if (!pminw && !pmaxw && !pminh && !pmaxh)
2482 return ERROR_INT("no data can be returned", __func__, 1);
2483
2484 minw = minh = 100000000;
2485 maxw = maxh = 0;
2486 n = pixaaGetCount(paa, NULL);
2487 for (i = 0; i < n; i++) {
2488 pixa = pixaaGetPixa(paa, i, L_CLONE);
2489 pixaSizeRange(pixa, &minpw, &minph, &maxpw, &maxph);
2490 if (minpw < minw)
2491 minw = minpw;
2492 if (minph < minh)
2493 minh = minph;
2494 if (maxpw > maxw)
2495 maxw = maxpw;
2496 if (maxph > maxh)
2497 maxh = maxph;
2498 pixaDestroy(&pixa);
2499 }
2500
2501 if (pminw) *pminw = minw;
2502 if (pminh) *pminh = minh;
2503 if (pmaxw) *pmaxw = maxw;
2504 if (pmaxh) *pmaxh = maxh;
2505 return 0;
2506}
2507
2508
2517l_ok
2519 l_int32 *pminw,
2520 l_int32 *pminh,
2521 l_int32 *pmaxw,
2522 l_int32 *pmaxh)
2523{
2524l_int32 minw, minh, maxw, maxh, i, n, w, h;
2525PIX *pix;
2526
2527 if (pminw) *pminw = 0;
2528 if (pminh) *pminh = 0;
2529 if (pmaxw) *pmaxw = 0;
2530 if (pmaxh) *pmaxh = 0;
2531 if (!pixa)
2532 return ERROR_INT("pixa not defined", __func__, 1);
2533 if (!pminw && !pmaxw && !pminh && !pmaxh)
2534 return ERROR_INT("no data can be returned", __func__, 1);
2535
2536 minw = minh = 1000000;
2537 maxw = maxh = 0;
2538 n = pixaGetCount(pixa);
2539 for (i = 0; i < n; i++) {
2540 pix = pixaGetPix(pixa, i, L_CLONE);
2541 w = pixGetWidth(pix);
2542 h = pixGetHeight(pix);
2543 if (w < minw)
2544 minw = w;
2545 if (h < minh)
2546 minh = h;
2547 if (w > maxw)
2548 maxw = w;
2549 if (h > maxh)
2550 maxh = h;
2551 pixDestroy(&pix);
2552 }
2553
2554 if (pminw) *pminw = minw;
2555 if (pminh) *pminh = minh;
2556 if (pmaxw) *pmaxw = maxw;
2557 if (pmaxh) *pmaxh = maxh;
2558
2559 return 0;
2560}
2561
2562
2585PIXA *
2587 PIX *pixs)
2588{
2589l_int32 i, n;
2590BOX *box;
2591PIX *pix, *pixc;
2592PIXA *pixad;
2593
2594 if (!pixas)
2595 return (PIXA *)ERROR_PTR("pixas not defined", __func__, NULL);
2596 if (!pixs)
2597 return (PIXA *)ERROR_PTR("pixs not defined", __func__, NULL);
2598
2599 n = pixaGetCount(pixas);
2600 if ((pixad = pixaCreate(n)) == NULL)
2601 return (PIXA *)ERROR_PTR("pixad not made", __func__, NULL);
2602
2603 for (i = 0; i < n; i++) {
2604 pix = pixaGetPix(pixas, i, L_CLONE);
2605 box = pixaGetBox(pixas, i, L_COPY);
2606 pixc = pixClipRectangle(pixs, box, NULL);
2607 pixAnd(pixc, pixc, pix);
2608 pixaAddPix(pixad, pixc, L_INSERT);
2609 pixaAddBox(pixad, box, L_INSERT);
2610 pixDestroy(&pix);
2611 }
2612
2613 return pixad;
2614}
2615
2616
2632l_ok
2634 PIXA **ppixad,
2635 BOXA **pboxa)
2636{
2637l_int32 i, n;
2638BOX *box1;
2639PIX *pix1, *pix2;
2640
2641 if (ppixad) *ppixad = NULL;
2642 if (pboxa) *pboxa = NULL;
2643 if (!pixas)
2644 return ERROR_INT("pixas not defined", __func__, 1);
2645 if (!ppixad && !pboxa)
2646 return ERROR_INT("no output requested", __func__, 1);
2647
2648 n = pixaGetCount(pixas);
2649 if (ppixad) *ppixad = pixaCreate(n);
2650 if (pboxa) *pboxa = boxaCreate(n);
2651 for (i = 0; i < n; i++) {
2652 pix1 = pixaGetPix(pixas, i, L_CLONE);
2653 pixClipToForeground(pix1, &pix2, &box1);
2654 pixDestroy(&pix1);
2655 if (ppixad)
2656 pixaAddPix(*ppixad, pix2, L_INSERT);
2657 else
2658 pixDestroy(&pix2);
2659 if (pboxa)
2660 boxaAddBox(*pboxa, box1, L_INSERT);
2661 else
2662 boxDestroy(&box1);
2663 }
2664
2665 return 0;
2666}
2667
2668
2687l_ok
2689 l_int32 *pdepth)
2690{
2691l_int32 hascolor, maxdepth;
2692
2693 if (!pdepth)
2694 return ERROR_INT("&depth not defined", __func__, 1);
2695 *pdepth = 0;
2696 if (!pixa)
2697 return ERROR_INT("pixa not defined", __func__, 1);
2698
2699 pixaHasColor(pixa, &hascolor);
2700 if (hascolor) {
2701 *pdepth = 32;
2702 return 0;
2703 }
2704
2705 pixaGetDepthInfo(pixa, &maxdepth, NULL);
2706 if (maxdepth == 1)
2707 *pdepth = 1;
2708 else /* 2, 4, 8 or 16 */
2709 *pdepth = 8;
2710 return 0;
2711}
2712
2713
2722l_ok
2724 l_int32 *phascolor)
2725{
2726l_int32 i, n, hascolor, d;
2727PIX *pix;
2728PIXCMAP *cmap;
2729
2730 if (!phascolor)
2731 return ERROR_INT("&hascolor not defined", __func__, 1);
2732 *phascolor = 0;
2733 if (!pixa)
2734 return ERROR_INT("pixa not defined", __func__, 1);
2735
2736 n = pixaGetCount(pixa);
2737 hascolor = 0;
2738 for (i = 0; i < n; i++) {
2739 pix = pixaGetPix(pixa, i, L_CLONE);
2740 if ((cmap = pixGetColormap(pix)) != NULL)
2741 pixcmapHasColor(cmap, &hascolor);
2742 d = pixGetDepth(pix);
2743 pixDestroy(&pix);
2744 if (d == 32 || hascolor == 1) {
2745 *phascolor = 1;
2746 break;
2747 }
2748 }
2749
2750 return 0;
2751}
2752
2753
2761l_ok
2763 l_int32 *phascmap)
2764{
2765l_int32 i, n;
2766PIX *pix;
2767PIXCMAP *cmap;
2768
2769 if (!phascmap)
2770 return ERROR_INT("&hascmap not defined", __func__, 1);
2771 *phascmap = 0;
2772 if (!pixa)
2773 return ERROR_INT("pixa not defined", __func__, 1);
2774
2775 n = pixaGetCount(pixa);
2776 for (i = 0; i < n; i++) {
2777 pix = pixaGetPix(pixa, i, L_CLONE);
2778 cmap = pixGetColormap(pix);
2779 pixDestroy(&pix);
2780 if (cmap) {
2781 *phascmap = 1;
2782 return 0;
2783 }
2784 }
2785
2786 return 0;
2787}
2788
2789
2798l_ok
2800 l_int32 *pmaxdepth,
2801 l_int32 *psame)
2802{
2803l_int32 i, n, d, d0;
2804l_int32 maxd, same; /* depth info */
2805
2806 if (pmaxdepth) *pmaxdepth = 0;
2807 if (psame) *psame = TRUE;
2808 if (!pmaxdepth && !psame) return 0;
2809 if (!pixa)
2810 return ERROR_INT("pixa not defined", __func__, 1);
2811 if ((n = pixaGetCount(pixa)) == 0)
2812 return ERROR_INT("pixa is empty", __func__, 1);
2813
2814 same = TRUE;
2815 maxd = 0;
2816 for (i = 0; i < n; i++) {
2817 pixaGetPixDimensions(pixa, i, NULL, NULL, &d);
2818 if (i == 0)
2819 d0 = d;
2820 else if (d != d0)
2821 same = FALSE;
2822 if (d > maxd) maxd = d;
2823 }
2824
2825 if (pmaxdepth) *pmaxdepth = maxd;
2826 if (psame) *psame = same;
2827 return 0;
2828}
2829
2830
2849PIXA *
2851{
2852l_int32 i, n, depth, same, hascmap, maxdepth;
2853BOXA *boxa;
2854PIX *pix1, *pix2;
2855PIXA *pixa1, *pixad;
2856
2857 if (!pixas)
2858 return (PIXA *)ERROR_PTR("pixas not defined", __func__, NULL);
2859 if ((n = pixaGetCount(pixas)) == 0)
2860 return (PIXA *)ERROR_PTR("no components", __func__, NULL);
2861
2862
2863 /* Remove colormaps if necessary */
2864 pixaGetRenderingDepth(pixas, &depth);
2865 pixaAnyColormaps(pixas, &hascmap);
2866 if (hascmap) {
2867 pixa1 = pixaCreate(n);
2868 for (i = 0; i < n; i++) {
2869 pix1 = pixaGetPix(pixas, i, L_CLONE);
2870 if (depth == 32)
2871 pix2 = pixConvertTo32(pix1);
2872 else /* depth = 8 */
2873 pix2 = pixConvertTo8(pix1, 0);
2874 pixaAddPix(pixa1, pix2, L_INSERT);
2875 pixDestroy(&pix1);
2876 }
2877 } else {
2878 pixa1 = pixaCopy(pixas, L_CLONE);
2879 }
2880
2881 pixaGetDepthInfo(pixa1, &maxdepth, &same);
2882 if (!same) { /* at least one pix has depth < maxdepth */
2883 pixad = pixaCreate(n);
2884 for (i = 0; i < n; i++) {
2885 pix1 = pixaGetPix(pixa1, i, L_CLONE);
2886 if (maxdepth <= 16)
2887 pix2 = pixConvertTo8(pix1, 0);
2888 else
2889 pix2 = pixConvertTo32(pix1);
2890 pixaAddPix(pixad, pix2, L_INSERT);
2891 pixDestroy(&pix1);
2892 }
2893 } else {
2894 pixad = pixaCopy(pixa1, L_CLONE);
2895 }
2896
2897 boxa = pixaGetBoxa(pixas, L_COPY);
2898 pixaSetBoxa(pixad, boxa, L_INSERT);
2899 pixaDestroy(&pixa1);
2900 return pixad;
2901}
2902
2903
2919PIXA *
2921 l_int32 depth)
2922{
2923l_int32 i, n, maxd;
2924BOXA *boxa;
2925PIX *pix1, *pix2;
2926PIXA *pixad;
2927
2928 if (!pixas)
2929 return (PIXA *)ERROR_PTR("pixas not defined", __func__, NULL);
2930 if ((n = pixaGetCount(pixas)) == 0)
2931 return (PIXA *)ERROR_PTR("no components", __func__, NULL);
2932 if (depth != 8 && depth != 32)
2933 return (PIXA *)ERROR_PTR("depth not 8 or 32", __func__, NULL);
2934
2935 /* Warn with 1 --> {8,32} or lossy conversions */
2936 pixaGetRenderingDepth(pixas, &maxd);
2937 if (maxd == 1)
2938 L_WARNING("All pix are 1 bpp; converting to %d bpp\n", __func__, depth);
2939 if (maxd > depth)
2940 L_WARNING("Lossy conversion: max rendering depth %d > input %d\n",
2941 __func__, maxd, depth);
2942
2943 pixad = pixaCreate(n);
2944 for (i = 0; i < n; i++) {
2945 pix1 = pixaGetPix(pixas, i, L_CLONE);
2946 if (depth == 32) {
2947 pix2 = (pixGetDepth(pix1) == 32) ? pixClone(pix1) :
2948 pixConvertTo32(pix1);
2949 } else { /* depth = 8 */
2950 pix2 = pixConvertTo8(pix1, 0);
2951 }
2952 pixaAddPix(pixad, pix2, L_INSERT);
2953 pixDestroy(&pix1);
2954 }
2955
2956 boxa = pixaGetBoxa(pixas, L_COPY);
2957 pixaSetBoxa(pixad, boxa, L_INSERT);
2958 return pixad;
2959}
2960
2961
2990l_ok
2992 PIXA *pixa2,
2993 l_int32 maxdist,
2994 NUMA **pnaindex,
2995 l_int32 *psame)
2996{
2997l_int32 i, j, n, empty1, empty2, same, sameboxa;
2998BOXA *boxa1, *boxa2;
2999NUMA *na;
3000PIX *pix1, *pix2;
3001
3002 if (pnaindex) *pnaindex = NULL;
3003 if (!psame)
3004 return ERROR_INT("&same not defined", __func__, 1);
3005 *psame = 0;
3006 sameboxa = 0;
3007 na = NULL;
3008 if (!pixa1 || !pixa2)
3009 return ERROR_INT("pixa1 and pixa2 not both defined", __func__, 1);
3010 n = pixaGetCount(pixa1);
3011 if (n != pixaGetCount(pixa2))
3012 return 0;
3013
3014 /* If there are no boxes, strict ordering of the pix in each
3015 * pixa is required. */
3016 boxa1 = pixaGetBoxa(pixa1, L_CLONE);
3017 boxa2 = pixaGetBoxa(pixa2, L_CLONE);
3018 empty1 = (boxaGetCount(boxa1) == 0) ? 1 : 0;
3019 empty2 = (boxaGetCount(boxa2) == 0) ? 1 : 0;
3020 if (!empty1 && !empty2) {
3021 boxaEqual(boxa1, boxa2, maxdist, &na, &sameboxa);
3022 if (!sameboxa) {
3023 boxaDestroy(&boxa1);
3024 boxaDestroy(&boxa2);
3025 numaDestroy(&na);
3026 return 0;
3027 }
3028 }
3029 boxaDestroy(&boxa1);
3030 boxaDestroy(&boxa2);
3031 if ((!empty1 && empty2) || (empty1 && !empty2))
3032 return 0;
3033
3034 for (i = 0; i < n; i++) {
3035 pix1 = pixaGetPix(pixa1, i, L_CLONE);
3036 if (na)
3037 numaGetIValue(na, i, &j);
3038 else
3039 j = i;
3040 pix2 = pixaGetPix(pixa2, j, L_CLONE);
3041 pixEqual(pix1, pix2, &same);
3042 pixDestroy(&pix1);
3043 pixDestroy(&pix2);
3044 if (!same) {
3045 numaDestroy(&na);
3046 return 0;
3047 }
3048 }
3049
3050 *psame = 1;
3051 if (pnaindex)
3052 *pnaindex = na;
3053 else
3054 numaDestroy(&na);
3055 return 0;
3056}
3057
3058
3072l_ok
3074{
3075l_int32 i, n, w, h;
3076BOX *box;
3077BOXA *boxa;
3078PIX *pix;
3079
3080 if (!pixa)
3081 return ERROR_INT("pixa not defined", __func__, 1);
3082 if ((n = pixaGetCount(pixa)) == 0) {
3083 L_INFO("pixa contains no pix\n", __func__);
3084 return 0;
3085 }
3086
3087 boxa = boxaCreate(n);
3088 pixaSetBoxa(pixa, boxa, L_INSERT);
3089 for (i = 0; i < n; i++) {
3090 pix = pixaGetPix(pixa, i, L_CLONE);
3091 pixGetDimensions(pix, &w, &h, NULL);
3092 box = boxCreate(0, 0, w, h);
3093 boxaAddBox(boxa, box, L_INSERT);
3094 pixDestroy(&pix);
3095 }
3096 return 0;
3097}
3098
#define PIX_DST
Definition pix.h:445
@ L_SELECT_IF_LTE
Definition pix.h:577
@ L_SELECT_IF_LT
Definition pix.h:575
@ L_SELECT_IF_GT
Definition pix.h:576
@ L_SELECT_IF_GTE
Definition pix.h:578
@ L_SELECT_IF_BOTH
Definition pix.h:599
@ L_SELECT_IF_EITHER
Definition pix.h:597
@ L_SELECT_WIDTH
Definition pix.h:593
@ L_SELECT_HEIGHT
Definition pix.h:594
@ L_SORT_BY_AREA
Definition pix.h:537
@ L_SORT_BY_MIN_DIMENSION
Definition pix.h:534
@ L_SORT_BY_PERIMETER
Definition pix.h:536
@ L_SORT_BY_WIDTH
Definition pix.h:532
@ L_SORT_BY_ASPECT_RATIO
Definition pix.h:538
@ L_SORT_BY_HEIGHT
Definition pix.h:533
@ L_SORT_BY_MAX_DIMENSION
Definition pix.h:535
@ L_SORT_BY_Y
Definition pix.h:529
@ L_SORT_BY_X
Definition pix.h:528
@ L_COPY
Definition pix.h:505
@ L_CLONE
Definition pix.h:506
@ L_INSERT
Definition pix.h:504
#define PIX_SRC
Definition pix.h:444
@ L_SORT_DECREASING
Definition pix.h:523
@ L_SORT_INCREASING
Definition pix.h:522
#define PIX_NOT(op)
Definition pix.h:446
@ L_BRING_IN_BLACK
Definition pix.h:663
@ L_BRING_IN_WHITE
Definition pix.h:662
@ L_ROTATE_SAMPLING
Definition pix.h:657
@ L_ROTATE_SHEAR
Definition pix.h:656
@ L_ROTATE_AREA_MAP
Definition pix.h:655
l_ok pixaGetRenderingDepth(PIXA *pixa, l_int32 *pdepth)
pixaGetRenderingDepth()
Definition pixafunc1.c:2688
PIXA * pixaSelectByNumConnComp(PIXA *pixas, l_int32 nmin, l_int32 nmax, l_int32 connectivity, l_int32 *pchanged)
pixaSelectByNumConnComp()
Definition pixafunc1.c:1084
PIXA * pixaAddBorderGeneral(PIXA *pixad, PIXA *pixas, l_int32 left, l_int32 right, l_int32 top, l_int32 bot, l_uint32 val)
pixaAddBorderGeneral()
Definition pixafunc1.c:2344
l_ok pixaHasColor(PIXA *pixa, l_int32 *phascolor)
pixaHasColor()
Definition pixafunc1.c:2723
PIXA * pixaSelectByPerimToAreaRatio(PIXA *pixas, l_float32 thresh, l_int32 type, l_int32 *pchanged)
pixaSelectByPerimToAreaRatio()
Definition pixafunc1.c:520
l_ok pixaSizeRange(PIXA *pixa, l_int32 *pminw, l_int32 *pminh, l_int32 *pmaxw, l_int32 *pmaxh)
pixaSizeRange()
Definition pixafunc1.c:2518
PIXA * pixaRotate(PIXA *pixas, l_float32 angle, l_int32 type, l_int32 incolor, l_int32 width, l_int32 height)
pixaRotate()
Definition pixafunc1.c:2166
PIXA * pixaSelectByAreaFraction(PIXA *pixas, l_float32 thresh, l_int32 type, l_int32 *pchanged)
pixaSelectByAreaFraction()
Definition pixafunc1.c:777
l_ok pixaaSizeRange(PIXAA *paa, l_int32 *pminw, l_int32 *pminh, l_int32 *pmaxw, l_int32 *pmaxh)
pixaaSizeRange()
Definition pixafunc1.c:2466
l_ok pixaSetFullSizeBoxa(PIXA *pixa)
pixaSetFullSizeBoxa()
Definition pixafunc1.c:3073
PIXAA * pixaaSelectRange(PIXAA *paas, l_int32 first, l_int32 last, l_int32 copyflag)
pixaaSelectRange()
Definition pixafunc1.c:1817
PIXAA * pixaaScaleToSizeVar(PIXAA *paas, NUMA *nawd, NUMA *nahd)
pixaaScaleToSizeVar()
Definition pixafunc1.c:1923
PIXA * pixaSelectByWidthHeightRatio(PIXA *pixas, l_float32 thresh, l_int32 type, l_int32 *pchanged)
pixaSelectByWidthHeightRatio()
Definition pixafunc1.c:1036
l_ok pixaAnyColormaps(PIXA *pixa, l_int32 *phascmap)
pixaAnyColormaps()
Definition pixafunc1.c:2762
PIXA * pixaaFlattenToPixa(PIXAA *paa, NUMA **pnaindex, l_int32 copyflag)
pixaaFlattenToPixa()
Definition pixafunc1.c:2413
PIXA * pixaSelectWithIndicator(PIXA *pixas, NUMA *na, l_int32 *pchanged)
pixaSelectWithIndicator()
Definition pixafunc1.c:1141
PIXA * pixaSelectRange(PIXA *pixas, l_int32 first, l_int32 last, l_int32 copyflag)
pixaSelectRange()
Definition pixafunc1.c:1764
PIXA * pixaConvertToGivenDepth(PIXA *pixas, l_int32 depth)
pixaConvertToGivenDepth()
Definition pixafunc1.c:2920
PIXA * pixaSelectByPerimSizeRatio(PIXA *pixas, l_float32 thresh, l_int32 type, l_int32 *pchanged)
pixaSelectByPerimSizeRatio()
Definition pixafunc1.c:647
PIX * pixSelectByWidthHeightRatio(PIX *pixs, l_float32 thresh, l_int32 connectivity, l_int32 type, l_int32 *pchanged)
pixSelectByWidthHeightRatio()
Definition pixafunc1.c:960
l_ok pixRemoveWithIndicator(PIX *pixs, PIXA *pixa, NUMA *na)
pixRemoveWithIndicator()
Definition pixafunc1.c:1199
PIXA * pixaScaleToSize(PIXA *pixas, l_int32 wd, l_int32 hd)
pixaScaleToSize()
Definition pixafunc1.c:1969
l_ok pixAddWithIndicator(PIX *pixs, PIXA *pixa, NUMA *na)
pixAddWithIndicator()
Definition pixafunc1.c:1250
PIXA * pixaConvertToSameDepth(PIXA *pixas)
pixaConvertToSameDepth()
Definition pixafunc1.c:2850
PIXA * pixaTranslate(PIXA *pixas, l_int32 hshift, l_int32 vshift, l_int32 incolor)
pixaTranslate()
Definition pixafunc1.c:2272
PIXA * pixaSelectBySize(PIXA *pixas, l_int32 width, l_int32 height, l_int32 type, l_int32 relation, l_int32 *pchanged)
pixaSelectBySize()
Definition pixafunc1.c:305
l_ok pixaClipToForeground(PIXA *pixas, PIXA **ppixad, BOXA **pboxa)
pixaClipToForeground()
Definition pixafunc1.c:2633
PIXA * pixaRotateOrth(PIXA *pixas, l_int32 rotation)
pixaRotateOrth()
Definition pixafunc1.c:2222
l_ok pixaGetDepthInfo(PIXA *pixa, l_int32 *pmaxdepth, l_int32 *psame)
pixaGetDepthInfo()
Definition pixafunc1.c:2799
PIX * pixSelectByPerimToAreaRatio(PIX *pixs, l_float32 thresh, l_int32 connectivity, l_int32 type, l_int32 *pchanged)
pixSelectByPerimToAreaRatio()
Definition pixafunc1.c:448
PIXA * pixaBinSort(PIXA *pixas, l_int32 sorttype, l_int32 sortorder, NUMA **pnaindex, l_int32 copyflag)
pixaBinSort()
Definition pixafunc1.c:1576
PIX * pixaRenderComponent(PIX *pixs, PIXA *pixa, l_int32 index)
pixaRenderComponent()
Definition pixafunc1.c:1370
PIXA * pixaSelectWithString(PIXA *pixas, const char *str, l_int32 *perror)
pixaSelectWithString()
Definition pixafunc1.c:1301
PIXA * pixaScale(PIXA *pixas, l_float32 scalex, l_float32 scaley)
pixaScale()
Definition pixafunc1.c:2054
PIXA * pixaSortByIndex(PIXA *pixas, NUMA *naindex, l_int32 copyflag)
pixaSortByIndex()
Definition pixafunc1.c:1662
PIXAA * pixaSort2dByIndex(PIXA *pixas, NUMAA *naa, l_int32 copyflag)
pixaSort2dByIndex()
Definition pixafunc1.c:1701
l_ok pixaEqual(PIXA *pixa1, PIXA *pixa2, l_int32 maxdist, NUMA **pnaindex, l_int32 *psame)
pixaEqual()
Definition pixafunc1.c:2991
PIX * pixSelectByArea(PIX *pixs, l_float32 thresh, l_int32 connectivity, l_int32 type, l_int32 *pchanged)
pixSelectByArea()
Definition pixafunc1.c:831
PIXA * pixaSort(PIXA *pixas, l_int32 sorttype, l_int32 sortorder, NUMA **pnaindex, l_int32 copyflag)
pixaSort()
Definition pixafunc1.c:1438
PIXA * pixaSelectByArea(PIXA *pixas, l_float32 thresh, l_int32 type, l_int32 *pchanged)
pixaSelectByArea()
Definition pixafunc1.c:907
PIXAA * pixaaScaleToSize(PIXAA *paas, l_int32 wd, l_int32 hd)
pixaaScaleToSize()
Definition pixafunc1.c:1876
PIX * pixSelectBySize(PIX *pixs, l_int32 width, l_int32 height, l_int32 connectivity, l_int32 type, l_int32 relation, l_int32 *pchanged)
pixSelectBySize()
Definition pixafunc1.c:220
NUMA * pixaMakeSizeIndicator(PIXA *pixa, l_int32 width, l_int32 height, l_int32 type, l_int32 relation)
pixaMakeSizeIndicator()
Definition pixafunc1.c:359
PIXA * pixaScaleToSizeRel(PIXA *pixas, l_int32 delw, l_int32 delh)
pixaScaleToSizeRel()
Definition pixafunc1.c:2012
PIXA * pixaScaleBySampling(PIXA *pixas, l_float32 scalex, l_float32 scaley)
pixaScaleBySampling()
Definition pixafunc1.c:2103
PIXA * pixaClipToPix(PIXA *pixas, PIX *pixs)
pixaClipToPix()
Definition pixafunc1.c:2586
PIX * pixSelectByAreaFraction(PIX *pixs, l_float32 thresh, l_int32 connectivity, l_int32 type, l_int32 *pchanged)
pixSelectByAreaFraction()
Definition pixafunc1.c:701
PIX * pixSelectByPerimSizeRatio(PIX *pixs, l_float32 thresh, l_int32 connectivity, l_int32 type, l_int32 *pchanged)
pixSelectByPerimSizeRatio()
Definition pixafunc1.c:575
struct Boxa * boxa