Leptonica 1.82.0
Image processing and image analysis suite
morph.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
165#ifdef HAVE_CONFIG_H
166#include <config_auto.h>
167#endif /* HAVE_CONFIG_H */
168
169#include <math.h>
170#include "allheaders.h"
171
172 /* Global constant; initialized here; must be declared extern
173 * in other files to access it directly. However, in most
174 * cases that is not necessary, because it can be reset
175 * using resetMorphBoundaryCondition(). */
176LEPT_DLL l_int32 MORPH_BC = ASYMMETRIC_MORPH_BC;
177
178 /* We accept this cost in extra rasterops for decomposing exactly. */
179static const l_int32 ACCEPTABLE_COST = 5;
180
181 /* Static helpers for arg processing */
182static PIX * processMorphArgs1(PIX *pixd, PIX *pixs, SEL *sel, PIX **ppixt);
183static PIX * processMorphArgs2(PIX *pixd, PIX *pixs, SEL *sel);
184
185
186/*-----------------------------------------------------------------*
187 * Generic binary morphological ops implemented with rasterop *
188 *-----------------------------------------------------------------*/
212PIX *
214 PIX *pixs,
215 SEL *sel)
216{
217l_int32 i, j, w, h, sx, sy, cx, cy, seldata;
218PIX *pixt;
219
220 PROCNAME("pixDilate");
221
222 if ((pixd = processMorphArgs1(pixd, pixs, sel, &pixt)) == NULL)
223 return (PIX *)ERROR_PTR("processMorphArgs1 failed", procName, pixd);
224
225 pixGetDimensions(pixs, &w, &h, NULL);
226 selGetParameters(sel, &sy, &sx, &cy, &cx);
227 pixClearAll(pixd);
228 for (i = 0; i < sy; i++) {
229 for (j = 0; j < sx; j++) {
230 seldata = sel->data[i][j];
231 if (seldata == 1) { /* src | dst */
232 pixRasterop(pixd, j - cx, i - cy, w, h, PIX_SRC | PIX_DST,
233 pixt, 0, 0);
234 }
235 }
236 }
237
238 pixDestroy(&pixt);
239 return pixd;
240}
241
242
266PIX *
268 PIX *pixs,
269 SEL *sel)
270{
271l_int32 i, j, w, h, sx, sy, cx, cy, seldata;
272l_int32 xp, yp, xn, yn;
273PIX *pixt;
274
275 PROCNAME("pixErode");
276
277 if ((pixd = processMorphArgs1(pixd, pixs, sel, &pixt)) == NULL)
278 return (PIX *)ERROR_PTR("processMorphArgs1 failed", procName, pixd);
279
280 pixGetDimensions(pixs, &w, &h, NULL);
281 selGetParameters(sel, &sy, &sx, &cy, &cx);
282 pixSetAll(pixd);
283 for (i = 0; i < sy; i++) {
284 for (j = 0; j < sx; j++) {
285 seldata = sel->data[i][j];
286 if (seldata == 1) { /* src & dst */
287 pixRasterop(pixd, cx - j, cy - i, w, h, PIX_SRC & PIX_DST,
288 pixt, 0, 0);
289 }
290 }
291 }
292
293 /* Clear near edges. We do this for the asymmetric boundary
294 * condition convention that implements erosion assuming all
295 * pixels surrounding the image are OFF. If you use a
296 * use a symmetric b.c. convention, where the erosion is
297 * implemented assuming pixels surrounding the image
298 * are ON, these operations are omitted. */
299 if (MORPH_BC == ASYMMETRIC_MORPH_BC) {
300 selFindMaxTranslations(sel, &xp, &yp, &xn, &yn);
301 if (xp > 0)
302 pixRasterop(pixd, 0, 0, xp, h, PIX_CLR, NULL, 0, 0);
303 if (xn > 0)
304 pixRasterop(pixd, w - xn, 0, xn, h, PIX_CLR, NULL, 0, 0);
305 if (yp > 0)
306 pixRasterop(pixd, 0, 0, w, yp, PIX_CLR, NULL, 0, 0);
307 if (yn > 0)
308 pixRasterop(pixd, 0, h - yn, w, yn, PIX_CLR, NULL, 0, 0);
309 }
310
311 pixDestroy(&pixt);
312 return pixd;
313}
314
315
341PIX *
343 PIX *pixs,
344 SEL *sel)
345{
346l_int32 i, j, w, h, sx, sy, cx, cy, firstrasterop, seldata;
347l_int32 xp, yp, xn, yn;
348PIX *pixt;
349
350 PROCNAME("pixHMT");
351
352 if ((pixd = processMorphArgs1(pixd, pixs, sel, &pixt)) == NULL)
353 return (PIX *)ERROR_PTR("processMorphArgs1 failed", procName, pixd);
354
355 pixGetDimensions(pixs, &w, &h, NULL);
356 selGetParameters(sel, &sy, &sx, &cy, &cx);
357 firstrasterop = TRUE;
358 for (i = 0; i < sy; i++) {
359 for (j = 0; j < sx; j++) {
360 seldata = sel->data[i][j];
361 if (seldata == 1) { /* hit */
362 if (firstrasterop == TRUE) { /* src only */
363 pixClearAll(pixd);
364 pixRasterop(pixd, cx - j, cy - i, w, h, PIX_SRC,
365 pixt, 0, 0);
366 firstrasterop = FALSE;
367 } else { /* src & dst */
368 pixRasterop(pixd, cx - j, cy - i, w, h, PIX_SRC & PIX_DST,
369 pixt, 0, 0);
370 }
371 } else if (seldata == 2) { /* miss */
372 if (firstrasterop == TRUE) { /* ~src only */
373 pixSetAll(pixd);
374 pixRasterop(pixd, cx - j, cy - i, w, h, PIX_NOT(PIX_SRC),
375 pixt, 0, 0);
376 firstrasterop = FALSE;
377 } else { /* ~src & dst */
378 pixRasterop(pixd, cx - j, cy - i, w, h,
380 pixt, 0, 0);
381 }
382 }
383 }
384 }
385
386 /* Clear near edges */
387 selFindMaxTranslations(sel, &xp, &yp, &xn, &yn);
388 if (xp > 0)
389 pixRasterop(pixd, 0, 0, xp, h, PIX_CLR, NULL, 0, 0);
390 if (xn > 0)
391 pixRasterop(pixd, w - xn, 0, xn, h, PIX_CLR, NULL, 0, 0);
392 if (yp > 0)
393 pixRasterop(pixd, 0, 0, w, yp, PIX_CLR, NULL, 0, 0);
394 if (yn > 0)
395 pixRasterop(pixd, 0, h - yn, w, yn, PIX_CLR, NULL, 0, 0);
396
397 pixDestroy(&pixt);
398 return pixd;
399}
400
401
425PIX *
427 PIX *pixs,
428 SEL *sel)
429{
430PIX *pixt;
431
432 PROCNAME("pixOpen");
433
434 if ((pixd = processMorphArgs2(pixd, pixs, sel)) == NULL)
435 return (PIX *)ERROR_PTR("pixd not returned", procName, pixd);
436
437 if ((pixt = pixErode(NULL, pixs, sel)) == NULL)
438 return (PIX *)ERROR_PTR("pixt not made", procName, pixd);
439 pixDilate(pixd, pixt, sel);
440 pixDestroy(&pixt);
441
442 return pixd;
443}
444
445
472PIX *
474 PIX *pixs,
475 SEL *sel)
476{
477PIX *pixt;
478
479 PROCNAME("pixClose");
480
481 if ((pixd = processMorphArgs2(pixd, pixs, sel)) == NULL)
482 return (PIX *)ERROR_PTR("pixd not returned", procName, pixd);
483
484 if ((pixt = pixDilate(NULL, pixs, sel)) == NULL)
485 return (PIX *)ERROR_PTR("pixt not made", procName, pixd);
486 pixErode(pixd, pixt, sel);
487 pixDestroy(&pixt);
488
489 return pixd;
490}
491
492
523PIX *
525 PIX *pixs,
526 SEL *sel)
527{
528l_int32 xp, yp, xn, yn, xmax, xbord;
529PIX *pixt1, *pixt2;
530
531 PROCNAME("pixCloseSafe");
532
533 if (!pixs)
534 return (PIX *)ERROR_PTR("pixs not defined", procName, pixd);
535 if (!sel)
536 return (PIX *)ERROR_PTR("sel not defined", procName, pixd);
537 if (pixGetDepth(pixs) != 1)
538 return (PIX *)ERROR_PTR("pixs not 1 bpp", procName, pixd);
539
540 /* Symmetric b.c. handles correctly without added pixels */
541 if (MORPH_BC == SYMMETRIC_MORPH_BC)
542 return pixClose(pixd, pixs, sel);
543
544 selFindMaxTranslations(sel, &xp, &yp, &xn, &yn);
545 xmax = L_MAX(xp, xn);
546 xbord = 32 * ((xmax + 31) / 32); /* full 32 bit words */
547
548 if ((pixt1 = pixAddBorderGeneral(pixs, xbord, xbord, yp, yn, 0)) == NULL)
549 return (PIX *)ERROR_PTR("pixt1 not made", procName, pixd);
550 pixClose(pixt1, pixt1, sel);
551 if ((pixt2 = pixRemoveBorderGeneral(pixt1, xbord, xbord, yp, yn)) == NULL)
552 return (PIX *)ERROR_PTR("pixt2 not made", procName, pixd);
553 pixDestroy(&pixt1);
554
555 if (!pixd)
556 return pixt2;
557
558 pixCopy(pixd, pixt2);
559 pixDestroy(&pixt2);
560 return pixd;
561}
562
563
590PIX *
592 PIX *pixs,
593 SEL *sel)
594{
595PIX *pixt;
596
597 PROCNAME("pixOpenGeneralized");
598
599 if ((pixd = processMorphArgs2(pixd, pixs, sel)) == NULL)
600 return (PIX *)ERROR_PTR("pixd not returned", procName, pixd);
601
602 if ((pixt = pixHMT(NULL, pixs, sel)) == NULL)
603 return (PIX *)ERROR_PTR("pixt not made", procName, pixd);
604 pixDilate(pixd, pixt, sel);
605 pixDestroy(&pixt);
606 return pixd;
607}
608
609
637PIX *
639 PIX *pixs,
640 SEL *sel)
641{
642PIX *pixt;
643
644 PROCNAME("pixCloseGeneralized");
645
646 if ((pixd = processMorphArgs2(pixd, pixs, sel)) == NULL)
647 return (PIX *)ERROR_PTR("pixd not returned", procName, pixd);
648
649 if ((pixt = pixDilate(NULL, pixs, sel)) == NULL)
650 return (PIX *)ERROR_PTR("pixt not made", procName, pixd);
651 pixHMT(pixd, pixt, sel);
652 pixDestroy(&pixt);
653
654 return pixd;
655}
656
657
658/*-----------------------------------------------------------------*
659 * Binary morphological (raster) ops with brick Sels *
660 *-----------------------------------------------------------------*/
687PIX *
689 PIX *pixs,
690 l_int32 hsize,
691 l_int32 vsize)
692{
693PIX *pixt;
694SEL *sel, *selh, *selv;
695
696 PROCNAME("pixDilateBrick");
697
698 if (!pixs)
699 return (PIX *)ERROR_PTR("pixs not defined", procName, pixd);
700 if (pixGetDepth(pixs) != 1)
701 return (PIX *)ERROR_PTR("pixs not 1 bpp", procName, pixd);
702 if (hsize < 1 || vsize < 1)
703 return (PIX *)ERROR_PTR("hsize and vsize not >= 1", procName, pixd);
704
705 if (hsize == 1 && vsize == 1)
706 return pixCopy(pixd, pixs);
707 if (hsize == 1 || vsize == 1) { /* no intermediate result */
708 sel = selCreateBrick(vsize, hsize, vsize / 2, hsize / 2, SEL_HIT);
709 if (!sel)
710 return (PIX *)ERROR_PTR("sel not made", procName, pixd);
711 pixd = pixDilate(pixd, pixs, sel);
712 selDestroy(&sel);
713 } else {
714 if ((selh = selCreateBrick(1, hsize, 0, hsize / 2, SEL_HIT)) == NULL)
715 return (PIX *)ERROR_PTR("selh not made", procName, pixd);
716 if ((selv = selCreateBrick(vsize, 1, vsize / 2, 0, SEL_HIT)) == NULL) {
717 selDestroy(&selh);
718 return (PIX *)ERROR_PTR("selv not made", procName, pixd);
719 }
720 pixt = pixDilate(NULL, pixs, selh);
721 pixd = pixDilate(pixd, pixt, selv);
722 pixDestroy(&pixt);
723 selDestroy(&selh);
724 selDestroy(&selv);
725 }
726
727 return pixd;
728}
729
730
757PIX *
759 PIX *pixs,
760 l_int32 hsize,
761 l_int32 vsize)
762{
763PIX *pixt;
764SEL *sel, *selh, *selv;
765
766 PROCNAME("pixErodeBrick");
767
768 if (!pixs)
769 return (PIX *)ERROR_PTR("pixs not defined", procName, pixd);
770 if (pixGetDepth(pixs) != 1)
771 return (PIX *)ERROR_PTR("pixs not 1 bpp", procName, pixd);
772 if (hsize < 1 || vsize < 1)
773 return (PIX *)ERROR_PTR("hsize and vsize not >= 1", procName, pixd);
774
775 if (hsize == 1 && vsize == 1)
776 return pixCopy(pixd, pixs);
777 if (hsize == 1 || vsize == 1) { /* no intermediate result */
778 sel = selCreateBrick(vsize, hsize, vsize / 2, hsize / 2, SEL_HIT);
779 if (!sel)
780 return (PIX *)ERROR_PTR("sel not made", procName, pixd);
781 pixd = pixErode(pixd, pixs, sel);
782 selDestroy(&sel);
783 } else {
784 if ((selh = selCreateBrick(1, hsize, 0, hsize / 2, SEL_HIT)) == NULL)
785 return (PIX *)ERROR_PTR("selh not made", procName, pixd);
786 if ((selv = selCreateBrick(vsize, 1, vsize / 2, 0, SEL_HIT)) == NULL) {
787 selDestroy(&selh);
788 return (PIX *)ERROR_PTR("selv not made", procName, pixd);
789 }
790 pixt = pixErode(NULL, pixs, selh);
791 pixd = pixErode(pixd, pixt, selv);
792 pixDestroy(&pixt);
793 selDestroy(&selh);
794 selDestroy(&selv);
795 }
796
797 return pixd;
798}
799
800
827PIX *
829 PIX *pixs,
830 l_int32 hsize,
831 l_int32 vsize)
832{
833PIX *pixt;
834SEL *sel, *selh, *selv;
835
836 PROCNAME("pixOpenBrick");
837
838 if (!pixs)
839 return (PIX *)ERROR_PTR("pixs not defined", procName, pixd);
840 if (pixGetDepth(pixs) != 1)
841 return (PIX *)ERROR_PTR("pixs not 1 bpp", procName, pixd);
842 if (hsize < 1 || vsize < 1)
843 return (PIX *)ERROR_PTR("hsize and vsize not >= 1", procName, pixd);
844
845 if (hsize == 1 && vsize == 1)
846 return pixCopy(pixd, pixs);
847 if (hsize == 1 || vsize == 1) { /* no intermediate result */
848 sel = selCreateBrick(vsize, hsize, vsize / 2, hsize / 2, SEL_HIT);
849 if (!sel)
850 return (PIX *)ERROR_PTR("sel not made", procName, pixd);
851 pixd = pixOpen(pixd, pixs, sel);
852 selDestroy(&sel);
853 } else { /* do separably */
854 if ((selh = selCreateBrick(1, hsize, 0, hsize / 2, SEL_HIT)) == NULL)
855 return (PIX *)ERROR_PTR("selh not made", procName, pixd);
856 if ((selv = selCreateBrick(vsize, 1, vsize / 2, 0, SEL_HIT)) == NULL) {
857 selDestroy(&selh);
858 return (PIX *)ERROR_PTR("selv not made", procName, pixd);
859 }
860 pixt = pixErode(NULL, pixs, selh);
861 pixd = pixErode(pixd, pixt, selv);
862 pixDilate(pixt, pixd, selh);
863 pixDilate(pixd, pixt, selv);
864 pixDestroy(&pixt);
865 selDestroy(&selh);
866 selDestroy(&selv);
867 }
868
869 return pixd;
870}
871
872
899PIX *
901 PIX *pixs,
902 l_int32 hsize,
903 l_int32 vsize)
904{
905PIX *pixt;
906SEL *sel, *selh, *selv;
907
908 PROCNAME("pixCloseBrick");
909
910 if (!pixs)
911 return (PIX *)ERROR_PTR("pixs not defined", procName, pixd);
912 if (pixGetDepth(pixs) != 1)
913 return (PIX *)ERROR_PTR("pixs not 1 bpp", procName, pixd);
914 if (hsize < 1 || vsize < 1)
915 return (PIX *)ERROR_PTR("hsize and vsize not >= 1", procName, pixd);
916
917 if (hsize == 1 && vsize == 1)
918 return pixCopy(pixd, pixs);
919 if (hsize == 1 || vsize == 1) { /* no intermediate result */
920 sel = selCreateBrick(vsize, hsize, vsize / 2, hsize / 2, SEL_HIT);
921 if (!sel)
922 return (PIX *)ERROR_PTR("sel not made", procName, pixd);
923 pixd = pixClose(pixd, pixs, sel);
924 selDestroy(&sel);
925 } else { /* do separably */
926 if ((selh = selCreateBrick(1, hsize, 0, hsize / 2, SEL_HIT)) == NULL)
927 return (PIX *)ERROR_PTR("selh not made", procName, pixd);
928 if ((selv = selCreateBrick(vsize, 1, vsize / 2, 0, SEL_HIT)) == NULL) {
929 selDestroy(&selh);
930 return (PIX *)ERROR_PTR("selv not made", procName, pixd);
931 }
932 pixt = pixDilate(NULL, pixs, selh);
933 pixd = pixDilate(pixd, pixt, selv);
934 pixErode(pixt, pixd, selh);
935 pixErode(pixd, pixt, selv);
936 pixDestroy(&pixt);
937 selDestroy(&selh);
938 selDestroy(&selv);
939 }
940
941 return pixd;
942}
943
944
976PIX *
978 PIX *pixs,
979 l_int32 hsize,
980 l_int32 vsize)
981{
982l_int32 maxtrans, bordsize;
983PIX *pixsb, *pixt, *pixdb;
984SEL *sel, *selh, *selv;
985
986 PROCNAME("pixCloseSafeBrick");
987
988 if (!pixs)
989 return (PIX *)ERROR_PTR("pixs not defined", procName, pixd);
990 if (pixGetDepth(pixs) != 1)
991 return (PIX *)ERROR_PTR("pixs not 1 bpp", procName, pixd);
992 if (hsize < 1 || vsize < 1)
993 return (PIX *)ERROR_PTR("hsize and vsize not >= 1", procName, pixd);
994
995 if (hsize == 1 && vsize == 1)
996 return pixCopy(pixd, pixs);
997
998 /* Symmetric b.c. handles correctly without added pixels */
999 if (MORPH_BC == SYMMETRIC_MORPH_BC)
1000 return pixCloseBrick(pixd, pixs, hsize, vsize);
1001
1002 maxtrans = L_MAX(hsize / 2, vsize / 2);
1003 bordsize = 32 * ((maxtrans + 31) / 32); /* full 32 bit words */
1004 pixsb = pixAddBorder(pixs, bordsize, 0);
1005
1006 if (hsize == 1 || vsize == 1) { /* no intermediate result */
1007 sel = selCreateBrick(vsize, hsize, vsize / 2, hsize / 2, SEL_HIT);
1008 if (!sel) {
1009 pixDestroy(&pixsb);
1010 return (PIX *)ERROR_PTR("sel not made", procName, pixd);
1011 }
1012 pixdb = pixClose(NULL, pixsb, sel);
1013 selDestroy(&sel);
1014 } else { /* do separably */
1015 selh = selCreateBrick(1, hsize, 0, hsize / 2, SEL_HIT);
1016 selv = selCreateBrick(vsize, 1, vsize / 2, 0, SEL_HIT);
1017 if (!selh || !selv) {
1018 selDestroy(&selh);
1019 selDestroy(&selv);
1020 pixDestroy(&pixsb);
1021 return (PIX *)ERROR_PTR("selh and selv not both made",
1022 procName, pixd);
1023 }
1024 pixt = pixDilate(NULL, pixsb, selh);
1025 pixdb = pixDilate(NULL, pixt, selv);
1026 pixErode(pixt, pixdb, selh);
1027 pixErode(pixdb, pixt, selv);
1028 pixDestroy(&pixt);
1029 selDestroy(&selh);
1030 selDestroy(&selv);
1031 }
1032
1033 pixt = pixRemoveBorder(pixdb, bordsize);
1034 pixDestroy(&pixsb);
1035 pixDestroy(&pixdb);
1036
1037 if (!pixd) {
1038 pixd = pixt;
1039 } else {
1040 pixCopy(pixd, pixt);
1041 pixDestroy(&pixt);
1042 }
1043 return pixd;
1044}
1045
1046
1047/*-----------------------------------------------------------------*
1048 * Binary composed morphological (raster) ops with brick Sels *
1049 *-----------------------------------------------------------------*/
1050/* \brief selectComposableSels()
1051 *
1052 * \param[in] size of composed sel
1053 * \param[in] direction L_HORIZ, L_VERT
1054 * \param[out] psel1 [optional] contiguous sel; can be null
1055 * \param[out] psel2 [optional] comb sel; can be null
1056 * \return 0 if OK, 1 on error
1057 *
1058 * <pre>
1059 * Notes:
1060 * (1) When using composable Sels, where the original Sel is
1061 * decomposed into two, the best you can do in terms
1062 * of reducing the computation is by a factor:
1063 *
1064 * 2 * sqrt(size) / size
1065 *
1066 * In practice, you get quite close to this. E.g.,
1067 *
1068 * Sel size | Optimum reduction factor
1069 * -------- ------------------------
1070 * 36 | 1/3
1071 * 64 | 1/4
1072 * 144 | 1/6
1073 * 256 | 1/8
1074 * </pre>
1075 */
1076l_int32
1077selectComposableSels(l_int32 size,
1078 l_int32 direction,
1079 SEL **psel1,
1080 SEL **psel2)
1081{
1082l_int32 factor1, factor2;
1083
1084 PROCNAME("selectComposableSels");
1085
1086 if (!psel1 && !psel2)
1087 return ERROR_INT("neither &sel1 nor &sel2 are defined", procName, 1);
1088 if (psel1) *psel1 = NULL;
1089 if (psel2) *psel2 = NULL;
1090 if (size < 1 || size > 10000)
1091 return ERROR_INT("size < 1 or size > 10000", procName, 1);
1092 if (direction != L_HORIZ && direction != L_VERT)
1093 return ERROR_INT("invalid direction", procName, 1);
1094
1095 if (selectComposableSizes(size, &factor1, &factor2))
1096 return ERROR_INT("factors not found", procName, 1);
1097
1098 if (psel1) {
1099 if (direction == L_HORIZ)
1100 *psel1 = selCreateBrick(1, factor1, 0, factor1 / 2, SEL_HIT);
1101 else
1102 *psel1 = selCreateBrick(factor1, 1, factor1 / 2 , 0, SEL_HIT);
1103 }
1104 if (psel2)
1105 *psel2 = selCreateComb(factor1, factor2, direction);
1106 return 0;
1107}
1108
1109
1131l_ok
1133 l_int32 *pfactor1,
1134 l_int32 *pfactor2)
1135{
1136l_int32 i, midval, val1, val2m, val2p;
1137l_int32 index, prodm, prodp;
1138l_int32 mincost, totcost, rastcostm, rastcostp, diffm, diffp;
1139l_int32 lowval[256];
1140l_int32 hival[256];
1141l_int32 rastcost[256]; /* excess in sum of sizes (extra rasterops) */
1142l_int32 diff[256]; /* diff between product (sel size) and input size */
1143
1144 PROCNAME("selectComposableSizes");
1145
1146 if (size < 1 || size > 10000)
1147 return ERROR_INT("size < 1 or size > 10000", procName, 1);
1148 if (!pfactor1 || !pfactor2)
1149 return ERROR_INT("&factor1 or &factor2 not defined", procName, 1);
1150
1151 midval = (l_int32)(sqrt((l_float64)size) + 0.001);
1152 if (midval * midval == size) {
1153 *pfactor1 = *pfactor2 = midval;
1154 return 0;
1155 }
1156
1157 /* Set up arrays. For each val1, optimize for lowest diff,
1158 * and save the rastcost, the diff, and the two factors. */
1159 for (val1 = midval + 1, i = 0; val1 > 0; val1--, i++) {
1160 val2m = size / val1;
1161 val2p = val2m + 1;
1162 prodm = val1 * val2m;
1163 prodp = val1 * val2p;
1164 rastcostm = val1 + val2m - 2 * midval;
1165 rastcostp = val1 + val2p - 2 * midval;
1166 diffm = L_ABS(size - prodm);
1167 diffp = L_ABS(size - prodp);
1168 if (diffm <= diffp) {
1169 lowval[i] = L_MIN(val1, val2m);
1170 hival[i] = L_MAX(val1, val2m);
1171 rastcost[i] = rastcostm;
1172 diff[i] = diffm;
1173 } else {
1174 lowval[i] = L_MIN(val1, val2p);
1175 hival[i] = L_MAX(val1, val2p);
1176 rastcost[i] = rastcostp;
1177 diff[i] = diffp;
1178 }
1179 }
1180
1181 /* Choose the optimum factors; use cost ratio 4 on diff */
1182 mincost = 10000;
1183 index = 1; /* unimportant initial value */
1184 for (i = 0; i < midval + 1; i++) {
1185 if (diff[i] == 0 && rastcost[i] < ACCEPTABLE_COST) {
1186 *pfactor1 = hival[i];
1187 *pfactor2 = lowval[i];
1188 return 0;
1189 }
1190 totcost = 4 * diff[i] + rastcost[i];
1191 if (totcost < mincost) {
1192 mincost = totcost;
1193 index = i;
1194 }
1195 }
1196 *pfactor1 = hival[index];
1197 *pfactor2 = lowval[index];
1198
1199 return 0;
1200}
1201
1202
1243PIX *
1245 PIX *pixs,
1246 l_int32 hsize,
1247 l_int32 vsize)
1248{
1249PIX *pix1, *pix2, *pix3;
1250SEL *selh1 = NULL;
1251SEL *selh2 = NULL;
1252SEL *selv1 = NULL;
1253SEL *selv2 = NULL;
1254
1255 PROCNAME("pixDilateCompBrick");
1256
1257 if (!pixs)
1258 return (PIX *)ERROR_PTR("pixs not defined", procName, pixd);
1259 if (pixGetDepth(pixs) != 1)
1260 return (PIX *)ERROR_PTR("pixs not 1 bpp", procName, pixd);
1261 if (hsize < 1 || vsize < 1)
1262 return (PIX *)ERROR_PTR("hsize and vsize not >= 1", procName, pixd);
1263
1264 if (hsize == 1 && vsize == 1)
1265 return pixCopy(pixd, pixs);
1266 if (hsize > 1) {
1267 if (selectComposableSels(hsize, L_HORIZ, &selh1, &selh2)) {
1268 selDestroy(&selh1);
1269 selDestroy(&selh2);
1270 return (PIX *)ERROR_PTR("horiz sels not made", procName, pixd);
1271 }
1272 }
1273 if (vsize > 1) {
1274 if (selectComposableSels(vsize, L_VERT, &selv1, &selv2)) {
1275 selDestroy(&selh1);
1276 selDestroy(&selh2);
1277 selDestroy(&selv1);
1278 selDestroy(&selv2);
1279 return (PIX *)ERROR_PTR("vert sels not made", procName, pixd);
1280 }
1281 }
1282
1283 pix1 = pixAddBorder(pixs, 32, 0);
1284 if (vsize == 1) {
1285 pix2 = pixDilate(NULL, pix1, selh1);
1286 pix3 = pixDilate(NULL, pix2, selh2);
1287 } else if (hsize == 1) {
1288 pix2 = pixDilate(NULL, pix1, selv1);
1289 pix3 = pixDilate(NULL, pix2, selv2);
1290 } else {
1291 pix2 = pixDilate(NULL, pix1, selh1);
1292 pix3 = pixDilate(NULL, pix2, selh2);
1293 pixDilate(pix2, pix3, selv1);
1294 pixDilate(pix3, pix2, selv2);
1295 }
1296 pixDestroy(&pix1);
1297 pixDestroy(&pix2);
1298
1299 selDestroy(&selh1);
1300 selDestroy(&selh2);
1301 selDestroy(&selv1);
1302 selDestroy(&selv2);
1303
1304 pix1 = pixRemoveBorder(pix3, 32);
1305 pixDestroy(&pix3);
1306 if (!pixd)
1307 return pix1;
1308 pixCopy(pixd, pix1);
1309 pixDestroy(&pix1);
1310 return pixd;
1311}
1312
1313
1354PIX *
1356 PIX *pixs,
1357 l_int32 hsize,
1358 l_int32 vsize)
1359{
1360PIX *pixt;
1361SEL *selh1 = NULL;
1362SEL *selh2 = NULL;
1363SEL *selv1 = NULL;
1364SEL *selv2 = NULL;
1365
1366 PROCNAME("pixErodeCompBrick");
1367
1368 if (!pixs)
1369 return (PIX *)ERROR_PTR("pixs not defined", procName, pixd);
1370 if (pixGetDepth(pixs) != 1)
1371 return (PIX *)ERROR_PTR("pixs not 1 bpp", procName, pixd);
1372 if (hsize < 1 || vsize < 1)
1373 return (PIX *)ERROR_PTR("hsize and vsize not >= 1", procName, pixd);
1374
1375 if (hsize == 1 && vsize == 1)
1376 return pixCopy(pixd, pixs);
1377 if (hsize > 1) {
1378 if (selectComposableSels(hsize, L_HORIZ, &selh1, &selh2)) {
1379 selDestroy(&selh1);
1380 selDestroy(&selh2);
1381 return (PIX *)ERROR_PTR("horiz sels not made", procName, pixd);
1382 }
1383 }
1384 if (vsize > 1) {
1385 if (selectComposableSels(vsize, L_VERT, &selv1, &selv2)) {
1386 selDestroy(&selh1);
1387 selDestroy(&selh2);
1388 selDestroy(&selv1);
1389 selDestroy(&selv2);
1390 return (PIX *)ERROR_PTR("vert sels not made", procName, pixd);
1391 }
1392 }
1393
1394 if (vsize == 1) {
1395 pixt = pixErode(NULL, pixs, selh1);
1396 pixd = pixErode(pixd, pixt, selh2);
1397 } else if (hsize == 1) {
1398 pixt = pixErode(NULL, pixs, selv1);
1399 pixd = pixErode(pixd, pixt, selv2);
1400 } else {
1401 pixt = pixErode(NULL, pixs, selh1);
1402 pixd = pixErode(pixd, pixt, selh2);
1403 pixErode(pixt, pixd, selv1);
1404 pixErode(pixd, pixt, selv2);
1405 }
1406 pixDestroy(&pixt);
1407
1408 selDestroy(&selh1);
1409 selDestroy(&selh2);
1410 selDestroy(&selv1);
1411 selDestroy(&selv2);
1412 return pixd;
1413}
1414
1415
1456PIX *
1458 PIX *pixs,
1459 l_int32 hsize,
1460 l_int32 vsize)
1461{
1462PIX *pixt;
1463SEL *selh1 = NULL;
1464SEL *selh2 = NULL;
1465SEL *selv1 = NULL;
1466SEL *selv2 = NULL;
1467
1468 PROCNAME("pixOpenCompBrick");
1469
1470 if (!pixs)
1471 return (PIX *)ERROR_PTR("pixs not defined", procName, pixd);
1472 if (pixGetDepth(pixs) != 1)
1473 return (PIX *)ERROR_PTR("pixs not 1 bpp", procName, pixd);
1474 if (hsize < 1 || vsize < 1)
1475 return (PIX *)ERROR_PTR("hsize and vsize not >= 1", procName, pixd);
1476
1477 if (hsize == 1 && vsize == 1)
1478 return pixCopy(pixd, pixs);
1479 if (hsize > 1) {
1480 if (selectComposableSels(hsize, L_HORIZ, &selh1, &selh2)) {
1481 selDestroy(&selh1);
1482 selDestroy(&selh2);
1483 return (PIX *)ERROR_PTR("horiz sels not made", procName, pixd);
1484 }
1485 }
1486 if (vsize > 1) {
1487 if (selectComposableSels(vsize, L_VERT, &selv1, &selv2)) {
1488 selDestroy(&selh1);
1489 selDestroy(&selh2);
1490 selDestroy(&selv1);
1491 selDestroy(&selv2);
1492 return (PIX *)ERROR_PTR("vert sels not made", procName, pixd);
1493 }
1494 }
1495
1496 if (vsize == 1) {
1497 pixt = pixErode(NULL, pixs, selh1);
1498 pixd = pixErode(pixd, pixt, selh2);
1499 pixDilate(pixt, pixd, selh1);
1500 pixDilate(pixd, pixt, selh2);
1501 } else if (hsize == 1) {
1502 pixt = pixErode(NULL, pixs, selv1);
1503 pixd = pixErode(pixd, pixt, selv2);
1504 pixDilate(pixt, pixd, selv1);
1505 pixDilate(pixd, pixt, selv2);
1506 } else { /* do separably */
1507 pixt = pixErode(NULL, pixs, selh1);
1508 pixd = pixErode(pixd, pixt, selh2);
1509 pixErode(pixt, pixd, selv1);
1510 pixErode(pixd, pixt, selv2);
1511 pixDilate(pixt, pixd, selh1);
1512 pixDilate(pixd, pixt, selh2);
1513 pixDilate(pixt, pixd, selv1);
1514 pixDilate(pixd, pixt, selv2);
1515 }
1516 pixDestroy(&pixt);
1517
1518 selDestroy(&selh1);
1519 selDestroy(&selh2);
1520 selDestroy(&selv1);
1521 selDestroy(&selv2);
1522 return pixd;
1523}
1524
1525
1566PIX *
1568 PIX *pixs,
1569 l_int32 hsize,
1570 l_int32 vsize)
1571{
1572PIX *pixt;
1573SEL *selh1 = NULL;
1574SEL *selh2 = NULL;
1575SEL *selv1 = NULL;
1576SEL *selv2 = NULL;
1577
1578 PROCNAME("pixCloseCompBrick");
1579
1580 if (!pixs)
1581 return (PIX *)ERROR_PTR("pixs not defined", procName, pixd);
1582 if (pixGetDepth(pixs) != 1)
1583 return (PIX *)ERROR_PTR("pixs not 1 bpp", procName, pixd);
1584 if (hsize < 1 || vsize < 1)
1585 return (PIX *)ERROR_PTR("hsize and vsize not >= 1", procName, pixd);
1586
1587 if (hsize == 1 && vsize == 1)
1588 return pixCopy(pixd, pixs);
1589 if (hsize > 1) {
1590 if (selectComposableSels(hsize, L_HORIZ, &selh1, &selh2)) {
1591 selDestroy(&selh1);
1592 selDestroy(&selh2);
1593 return (PIX *)ERROR_PTR("horiz sels not made", procName, pixd);
1594 }
1595 }
1596 if (vsize > 1) {
1597 if (selectComposableSels(vsize, L_VERT, &selv1, &selv2)) {
1598 selDestroy(&selh1);
1599 selDestroy(&selh2);
1600 selDestroy(&selv1);
1601 selDestroy(&selv2);
1602 return (PIX *)ERROR_PTR("vert sels not made", procName, pixd);
1603 }
1604 }
1605
1606 if (vsize == 1) {
1607 pixt = pixDilate(NULL, pixs, selh1);
1608 pixd = pixDilate(pixd, pixt, selh2);
1609 pixErode(pixt, pixd, selh1);
1610 pixErode(pixd, pixt, selh2);
1611 } else if (hsize == 1) {
1612 pixt = pixDilate(NULL, pixs, selv1);
1613 pixd = pixDilate(pixd, pixt, selv2);
1614 pixErode(pixt, pixd, selv1);
1615 pixErode(pixd, pixt, selv2);
1616 } else { /* do separably */
1617 pixt = pixDilate(NULL, pixs, selh1);
1618 pixd = pixDilate(pixd, pixt, selh2);
1619 pixDilate(pixt, pixd, selv1);
1620 pixDilate(pixd, pixt, selv2);
1621 pixErode(pixt, pixd, selh1);
1622 pixErode(pixd, pixt, selh2);
1623 pixErode(pixt, pixd, selv1);
1624 pixErode(pixd, pixt, selv2);
1625 }
1626 pixDestroy(&pixt);
1627
1628 selDestroy(&selh1);
1629 selDestroy(&selh2);
1630 selDestroy(&selv1);
1631 selDestroy(&selv2);
1632 return pixd;
1633}
1634
1635
1681PIX *
1683 PIX *pixs,
1684 l_int32 hsize,
1685 l_int32 vsize)
1686{
1687l_int32 maxtrans, bordsize;
1688PIX *pixsb, *pixt, *pixdb;
1689SEL *selh1 = NULL;
1690SEL *selh2 = NULL;
1691SEL *selv1 = NULL;
1692SEL *selv2 = NULL;
1693
1694 PROCNAME("pixCloseSafeCompBrick");
1695
1696 if (!pixs)
1697 return (PIX *)ERROR_PTR("pixs not defined", procName, pixd);
1698 if (pixGetDepth(pixs) != 1)
1699 return (PIX *)ERROR_PTR("pixs not 1 bpp", procName, pixd);
1700 if (hsize < 1 || vsize < 1)
1701 return (PIX *)ERROR_PTR("hsize and vsize not >= 1", procName, pixd);
1702
1703 if (hsize == 1 && vsize == 1)
1704 return pixCopy(pixd, pixs);
1705
1706 /* Symmetric b.c. handles correctly without added pixels */
1707 if (MORPH_BC == SYMMETRIC_MORPH_BC)
1708 return pixCloseCompBrick(pixd, pixs, hsize, vsize);
1709
1710 if (hsize > 1) {
1711 if (selectComposableSels(hsize, L_HORIZ, &selh1, &selh2)) {
1712 selDestroy(&selh1);
1713 selDestroy(&selh2);
1714 return (PIX *)ERROR_PTR("horiz sels not made", procName, pixd);
1715 }
1716 }
1717 if (vsize > 1) {
1718 if (selectComposableSels(vsize, L_VERT, &selv1, &selv2)) {
1719 selDestroy(&selh1);
1720 selDestroy(&selh2);
1721 selDestroy(&selv1);
1722 selDestroy(&selv2);
1723 return (PIX *)ERROR_PTR("vert sels not made", procName, pixd);
1724 }
1725 }
1726
1727 maxtrans = L_MAX(hsize / 2, vsize / 2);
1728 bordsize = 32 * ((maxtrans + 31) / 32); /* full 32 bit words */
1729 pixsb = pixAddBorder(pixs, bordsize, 0);
1730
1731 if (vsize == 1) {
1732 pixt = pixDilate(NULL, pixsb, selh1);
1733 pixdb = pixDilate(NULL, pixt, selh2);
1734 pixErode(pixt, pixdb, selh1);
1735 pixErode(pixdb, pixt, selh2);
1736 } else if (hsize == 1) {
1737 pixt = pixDilate(NULL, pixsb, selv1);
1738 pixdb = pixDilate(NULL, pixt, selv2);
1739 pixErode(pixt, pixdb, selv1);
1740 pixErode(pixdb, pixt, selv2);
1741 } else { /* do separably */
1742 pixt = pixDilate(NULL, pixsb, selh1);
1743 pixdb = pixDilate(NULL, pixt, selh2);
1744 pixDilate(pixt, pixdb, selv1);
1745 pixDilate(pixdb, pixt, selv2);
1746 pixErode(pixt, pixdb, selh1);
1747 pixErode(pixdb, pixt, selh2);
1748 pixErode(pixt, pixdb, selv1);
1749 pixErode(pixdb, pixt, selv2);
1750 }
1751 pixDestroy(&pixt);
1752
1753 pixt = pixRemoveBorder(pixdb, bordsize);
1754 pixDestroy(&pixsb);
1755 pixDestroy(&pixdb);
1756
1757 if (!pixd) {
1758 pixd = pixt;
1759 } else {
1760 pixCopy(pixd, pixt);
1761 pixDestroy(&pixt);
1762 }
1763
1764 selDestroy(&selh1);
1765 selDestroy(&selh2);
1766 selDestroy(&selv1);
1767 selDestroy(&selv2);
1768 return pixd;
1769}
1770
1771
1772/*-----------------------------------------------------------------*
1773 * Functions associated with boundary conditions *
1774 *-----------------------------------------------------------------*/
1781void
1783{
1784 PROCNAME("resetMorphBoundaryCondition");
1785
1786 if (bc != SYMMETRIC_MORPH_BC && bc != ASYMMETRIC_MORPH_BC) {
1787 L_WARNING("invalid bc; using asymmetric\n", procName);
1788 bc = ASYMMETRIC_MORPH_BC;
1789 }
1790 MORPH_BC = bc;
1791 return;
1792}
1793
1794
1802l_uint32
1804 l_int32 depth)
1805{
1806 PROCNAME("getMorphBorderPixelColor");
1807
1808 if (type != L_MORPH_DILATE && type != L_MORPH_ERODE)
1809 return ERROR_INT("invalid type", procName, 0);
1810 if (depth != 1 && depth != 2 && depth != 4 && depth != 8 &&
1811 depth != 16 && depth != 32)
1812 return ERROR_INT("invalid depth", procName, 0);
1813
1814 if (MORPH_BC == ASYMMETRIC_MORPH_BC || type == L_MORPH_DILATE)
1815 return 0;
1816
1817 /* Symmetric & erosion */
1818 if (depth < 32)
1819 return ((1 << depth) - 1);
1820 else /* depth == 32 */
1821 return 0xffffff00;
1822}
1823
1824
1825/*-----------------------------------------------------------------*
1826 * Static helpers for arg processing *
1827 *-----------------------------------------------------------------*/
1843static PIX *
1845 PIX *pixs,
1846 SEL *sel,
1847 PIX **ppixt)
1848{
1849l_int32 sx, sy;
1850
1851 PROCNAME("processMorphArgs1");
1852
1853 if (!ppixt)
1854 return (PIX *)ERROR_PTR("&pixt not defined", procName, pixd);
1855 *ppixt = NULL;
1856 if (!pixs)
1857 return (PIX *)ERROR_PTR("pixs not defined", procName, pixd);
1858 if (!sel)
1859 return (PIX *)ERROR_PTR("sel not defined", procName, pixd);
1860 if (pixGetDepth(pixs) != 1)
1861 return (PIX *)ERROR_PTR("pixs not 1 bpp", procName, pixd);
1862
1863 selGetParameters(sel, &sx, &sy, NULL, NULL);
1864 if (sx == 0 || sy == 0)
1865 return (PIX *)ERROR_PTR("sel of size 0", procName, pixd);
1866
1867 /* We require pixd to exist and to be the same size as pixs.
1868 * Further, pixt must be a copy (or clone) of pixs. */
1869 if (!pixd) {
1870 if ((pixd = pixCreateTemplate(pixs)) == NULL)
1871 return (PIX *)ERROR_PTR("pixd not made", procName, NULL);
1872 *ppixt = pixClone(pixs);
1873 } else {
1874 pixResizeImageData(pixd, pixs);
1875 if (pixd == pixs) { /* in-place; must make a copy of pixs */
1876 if ((*ppixt = pixCopy(NULL, pixs)) == NULL)
1877 return (PIX *)ERROR_PTR("pixt not made", procName, pixd);
1878 } else {
1879 *ppixt = pixClone(pixs);
1880 }
1881 }
1882 return pixd;
1883}
1884
1885
1891static PIX *
1893 PIX *pixs,
1894 SEL *sel)
1895{
1896l_int32 sx, sy;
1897
1898 PROCNAME("processMorphArgs2");
1899
1900 if (!pixs)
1901 return (PIX *)ERROR_PTR("pixs not defined", procName, pixd);
1902 if (!sel)
1903 return (PIX *)ERROR_PTR("sel not defined", procName, pixd);
1904 if (pixGetDepth(pixs) != 1)
1905 return (PIX *)ERROR_PTR("pixs not 1 bpp", procName, pixd);
1906
1907 selGetParameters(sel, &sx, &sy, NULL, NULL);
1908 if (sx == 0 || sy == 0)
1909 return (PIX *)ERROR_PTR("sel of size 0", procName, pixd);
1910
1911 if (!pixd)
1912 return pixCreateTemplate(pixs);
1913 pixResizeImageData(pixd, pixs);
1914 return pixd;
1915}
PIX * pixOpenGeneralized(PIX *pixd, PIX *pixs, SEL *sel)
pixOpenGeneralized()
Definition: morph.c:591
PIX * pixErodeCompBrick(PIX *pixd, PIX *pixs, l_int32 hsize, l_int32 vsize)
pixErodeCompBrick()
Definition: morph.c:1355
PIX * pixDilateBrick(PIX *pixd, PIX *pixs, l_int32 hsize, l_int32 vsize)
pixDilateBrick()
Definition: morph.c:688
void resetMorphBoundaryCondition(l_int32 bc)
resetMorphBoundaryCondition()
Definition: morph.c:1782
PIX * pixCloseBrick(PIX *pixd, PIX *pixs, l_int32 hsize, l_int32 vsize)
pixCloseBrick()
Definition: morph.c:900
PIX * pixDilateCompBrick(PIX *pixd, PIX *pixs, l_int32 hsize, l_int32 vsize)
pixDilateCompBrick()
Definition: morph.c:1244
PIX * pixCloseCompBrick(PIX *pixd, PIX *pixs, l_int32 hsize, l_int32 vsize)
pixCloseCompBrick()
Definition: morph.c:1567
l_ok selectComposableSizes(l_int32 size, l_int32 *pfactor1, l_int32 *pfactor2)
selectComposableSizes()
Definition: morph.c:1132
PIX * pixCloseSafeBrick(PIX *pixd, PIX *pixs, l_int32 hsize, l_int32 vsize)
pixCloseSafeBrick()
Definition: morph.c:977
PIX * pixOpen(PIX *pixd, PIX *pixs, SEL *sel)
pixOpen()
Definition: morph.c:426
PIX * pixOpenBrick(PIX *pixd, PIX *pixs, l_int32 hsize, l_int32 vsize)
pixOpenBrick()
Definition: morph.c:828
PIX * pixDilate(PIX *pixd, PIX *pixs, SEL *sel)
pixDilate()
Definition: morph.c:213
PIX * pixCloseGeneralized(PIX *pixd, PIX *pixs, SEL *sel)
pixCloseGeneralized()
Definition: morph.c:638
PIX * pixOpenCompBrick(PIX *pixd, PIX *pixs, l_int32 hsize, l_int32 vsize)
pixOpenCompBrick()
Definition: morph.c:1457
static PIX * processMorphArgs1(PIX *pixd, PIX *pixs, SEL *sel, PIX **ppixt)
processMorphArgs1()
Definition: morph.c:1844
PIX * pixClose(PIX *pixd, PIX *pixs, SEL *sel)
pixClose()
Definition: morph.c:473
PIX * pixHMT(PIX *pixd, PIX *pixs, SEL *sel)
pixHMT()
Definition: morph.c:342
PIX * pixCloseSafe(PIX *pixd, PIX *pixs, SEL *sel)
pixCloseSafe()
Definition: morph.c:524
PIX * pixErode(PIX *pixd, PIX *pixs, SEL *sel)
pixErode()
Definition: morph.c:267
static PIX * processMorphArgs2(PIX *pixd, PIX *pixs, SEL *sel)
processMorphArgs2()
Definition: morph.c:1892
PIX * pixCloseSafeCompBrick(PIX *pixd, PIX *pixs, l_int32 hsize, l_int32 vsize)
pixCloseSafeCompBrick()
Definition: morph.c:1682
l_uint32 getMorphBorderPixelColor(l_int32 type, l_int32 depth)
getMorphBorderPixelColor()
Definition: morph.c:1803
PIX * pixErodeBrick(PIX *pixd, PIX *pixs, l_int32 hsize, l_int32 vsize)
pixErodeBrick()
Definition: morph.c:758
l_ok pixResizeImageData(PIX *pixd, const PIX *pixs)
pixResizeImageData()
Definition: pix1.c:768
void pixDestroy(PIX **ppix)
pixDestroy()
Definition: pix1.c:621
l_ok pixGetDimensions(const PIX *pix, l_int32 *pw, l_int32 *ph, l_int32 *pd)
pixGetDimensions()
Definition: pix1.c:1113
PIX * pixClone(PIX *pixs)
pixClone()
Definition: pix1.c:593
PIX * pixCreateTemplate(const PIX *pixs)
pixCreateTemplate()
Definition: pix1.c:383
PIX * pixCopy(PIX *pixd, const PIX *pixs)
pixCopy()
Definition: pix1.c:705
l_ok pixClearAll(PIX *pix)
pixClearAll()
Definition: pix2.c:789
PIX * pixRemoveBorder(PIX *pixs, l_int32 npix)
pixRemoveBorder()
Definition: pix2.c:1972
PIX * pixRemoveBorderGeneral(PIX *pixs, l_int32 left, l_int32 right, l_int32 top, l_int32 bot)
pixRemoveBorderGeneral()
Definition: pix2.c:1993
l_ok pixSetAll(PIX *pix)
pixSetAll()
Definition: pix2.c:817
PIX * pixAddBorder(PIX *pixs, l_int32 npix, l_uint32 val)
pixAddBorder()
Definition: pix2.c:1823
PIX * pixAddBorderGeneral(PIX *pixs, l_int32 left, l_int32 right, l_int32 top, l_int32 bot, l_uint32 val)
pixAddBorderGeneral()
Definition: pix2.c:1917
#define PIX_DST
Definition: pix.h:331
#define PIX_SRC
Definition: pix.h:330
#define PIX_CLR
Definition: pix.h:333
#define PIX_NOT(op)
Definition: pix.h:332
l_ok pixRasterop(PIX *pixd, l_int32 dx, l_int32 dy, l_int32 dw, l_int32 dh, l_int32 op, PIX *pixs, l_int32 sx, l_int32 sy)
pixRasterop()
Definition: rop.c:204
l_ok selGetParameters(SEL *sel, l_int32 *psy, l_int32 *psx, l_int32 *pcy, l_int32 *pcx)
selGetParameters()
Definition: sel1.c:848
l_ok selFindMaxTranslations(SEL *sel, l_int32 *pxp, l_int32 *pyp, l_int32 *pxn, l_int32 *pyn)
selFindMaxTranslations()
Definition: sel1.c:1190
void selDestroy(SEL **psel)
selDestroy()
Definition: sel1.c:340
SEL * selCreateComb(l_int32 factor1, l_int32 factor2, l_int32 direction)
selCreateComb()
Definition: sel1.c:462
SEL * selCreateBrick(l_int32 h, l_int32 w, l_int32 cy, l_int32 cx, l_int32 type)
selCreateBrick()
Definition: sel1.c:418
Definition: pix.h:139
l_int32 ** data
Definition: morph.h:67