Leptonica  1.83.1
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(). */
176 LEPT_DLL l_int32 MORPH_BC = ASYMMETRIC_MORPH_BC;
177 
178  /* We accept this cost in extra rasterops for decomposing exactly. */
179 static const l_int32 ACCEPTABLE_COST = 5;
180 
181  /* Static helpers for arg processing */
182 static PIX * processMorphArgs1(PIX *pixd, PIX *pixs, SEL *sel, PIX **ppixt);
183 static PIX * processMorphArgs2(PIX *pixd, PIX *pixs, SEL *sel);
184 
185 
186 /*-----------------------------------------------------------------*
187  * Generic binary morphological ops implemented with rasterop *
188  *-----------------------------------------------------------------*/
212 PIX *
214  PIX *pixs,
215  SEL *sel)
216 {
217 l_int32 i, j, w, h, sx, sy, cx, cy, seldata;
218 PIX *pixt;
219 
220  if ((pixd = processMorphArgs1(pixd, pixs, sel, &pixt)) == NULL)
221  return (PIX *)ERROR_PTR("processMorphArgs1 failed", __func__, pixd);
222 
223  pixGetDimensions(pixs, &w, &h, NULL);
224  selGetParameters(sel, &sy, &sx, &cy, &cx);
225  pixClearAll(pixd);
226  for (i = 0; i < sy; i++) {
227  for (j = 0; j < sx; j++) {
228  seldata = sel->data[i][j];
229  if (seldata == 1) { /* src | dst */
230  pixRasterop(pixd, j - cx, i - cy, w, h, PIX_SRC | PIX_DST,
231  pixt, 0, 0);
232  }
233  }
234  }
235 
236  pixDestroy(&pixt);
237  return pixd;
238 }
239 
240 
264 PIX *
265 pixErode(PIX *pixd,
266  PIX *pixs,
267  SEL *sel)
268 {
269 l_int32 i, j, w, h, sx, sy, cx, cy, seldata;
270 l_int32 xp, yp, xn, yn;
271 PIX *pixt;
272 
273  if ((pixd = processMorphArgs1(pixd, pixs, sel, &pixt)) == NULL)
274  return (PIX *)ERROR_PTR("processMorphArgs1 failed", __func__, pixd);
275 
276  pixGetDimensions(pixs, &w, &h, NULL);
277  selGetParameters(sel, &sy, &sx, &cy, &cx);
278  pixSetAll(pixd);
279  for (i = 0; i < sy; i++) {
280  for (j = 0; j < sx; j++) {
281  seldata = sel->data[i][j];
282  if (seldata == 1) { /* src & dst */
283  pixRasterop(pixd, cx - j, cy - i, w, h, PIX_SRC & PIX_DST,
284  pixt, 0, 0);
285  }
286  }
287  }
288 
289  /* Clear near edges. We do this for the asymmetric boundary
290  * condition convention that implements erosion assuming all
291  * pixels surrounding the image are OFF. If you use a
292  * use a symmetric b.c. convention, where the erosion is
293  * implemented assuming pixels surrounding the image
294  * are ON, these operations are omitted. */
295  if (MORPH_BC == ASYMMETRIC_MORPH_BC) {
296  selFindMaxTranslations(sel, &xp, &yp, &xn, &yn);
297  if (xp > 0)
298  pixRasterop(pixd, 0, 0, xp, h, PIX_CLR, NULL, 0, 0);
299  if (xn > 0)
300  pixRasterop(pixd, w - xn, 0, xn, h, PIX_CLR, NULL, 0, 0);
301  if (yp > 0)
302  pixRasterop(pixd, 0, 0, w, yp, PIX_CLR, NULL, 0, 0);
303  if (yn > 0)
304  pixRasterop(pixd, 0, h - yn, w, yn, PIX_CLR, NULL, 0, 0);
305  }
306 
307  pixDestroy(&pixt);
308  return pixd;
309 }
310 
311 
337 PIX *
338 pixHMT(PIX *pixd,
339  PIX *pixs,
340  SEL *sel)
341 {
342 l_int32 i, j, w, h, sx, sy, cx, cy, firstrasterop, seldata;
343 l_int32 xp, yp, xn, yn;
344 PIX *pixt;
345 
346  if ((pixd = processMorphArgs1(pixd, pixs, sel, &pixt)) == NULL)
347  return (PIX *)ERROR_PTR("processMorphArgs1 failed", __func__, pixd);
348 
349  pixGetDimensions(pixs, &w, &h, NULL);
350  selGetParameters(sel, &sy, &sx, &cy, &cx);
351  firstrasterop = TRUE;
352  for (i = 0; i < sy; i++) {
353  for (j = 0; j < sx; j++) {
354  seldata = sel->data[i][j];
355  if (seldata == 1) { /* hit */
356  if (firstrasterop == TRUE) { /* src only */
357  pixClearAll(pixd);
358  pixRasterop(pixd, cx - j, cy - i, w, h, PIX_SRC,
359  pixt, 0, 0);
360  firstrasterop = FALSE;
361  } else { /* src & dst */
362  pixRasterop(pixd, cx - j, cy - i, w, h, PIX_SRC & PIX_DST,
363  pixt, 0, 0);
364  }
365  } else if (seldata == 2) { /* miss */
366  if (firstrasterop == TRUE) { /* ~src only */
367  pixSetAll(pixd);
368  pixRasterop(pixd, cx - j, cy - i, w, h, PIX_NOT(PIX_SRC),
369  pixt, 0, 0);
370  firstrasterop = FALSE;
371  } else { /* ~src & dst */
372  pixRasterop(pixd, cx - j, cy - i, w, h,
374  pixt, 0, 0);
375  }
376  }
377  }
378  }
379 
380  /* Clear near edges */
381  selFindMaxTranslations(sel, &xp, &yp, &xn, &yn);
382  if (xp > 0)
383  pixRasterop(pixd, 0, 0, xp, h, PIX_CLR, NULL, 0, 0);
384  if (xn > 0)
385  pixRasterop(pixd, w - xn, 0, xn, h, PIX_CLR, NULL, 0, 0);
386  if (yp > 0)
387  pixRasterop(pixd, 0, 0, w, yp, PIX_CLR, NULL, 0, 0);
388  if (yn > 0)
389  pixRasterop(pixd, 0, h - yn, w, yn, PIX_CLR, NULL, 0, 0);
390 
391  pixDestroy(&pixt);
392  return pixd;
393 }
394 
395 
419 PIX *
420 pixOpen(PIX *pixd,
421  PIX *pixs,
422  SEL *sel)
423 {
424 PIX *pixt;
425 
426  if ((pixd = processMorphArgs2(pixd, pixs, sel)) == NULL)
427  return (PIX *)ERROR_PTR("pixd not returned", __func__, pixd);
428 
429  if ((pixt = pixErode(NULL, pixs, sel)) == NULL)
430  return (PIX *)ERROR_PTR("pixt not made", __func__, pixd);
431  pixDilate(pixd, pixt, sel);
432  pixDestroy(&pixt);
433 
434  return pixd;
435 }
436 
437 
464 PIX *
465 pixClose(PIX *pixd,
466  PIX *pixs,
467  SEL *sel)
468 {
469 PIX *pixt;
470 
471  if ((pixd = processMorphArgs2(pixd, pixs, sel)) == NULL)
472  return (PIX *)ERROR_PTR("pixd not returned", __func__, pixd);
473 
474  if ((pixt = pixDilate(NULL, pixs, sel)) == NULL)
475  return (PIX *)ERROR_PTR("pixt not made", __func__, pixd);
476  pixErode(pixd, pixt, sel);
477  pixDestroy(&pixt);
478 
479  return pixd;
480 }
481 
482 
513 PIX *
515  PIX *pixs,
516  SEL *sel)
517 {
518 l_int32 xp, yp, xn, yn, xmax, xbord;
519 PIX *pixt1, *pixt2;
520 
521  if (!pixs)
522  return (PIX *)ERROR_PTR("pixs not defined", __func__, pixd);
523  if (!sel)
524  return (PIX *)ERROR_PTR("sel not defined", __func__, pixd);
525  if (pixGetDepth(pixs) != 1)
526  return (PIX *)ERROR_PTR("pixs not 1 bpp", __func__, pixd);
527 
528  /* Symmetric b.c. handles correctly without added pixels */
529  if (MORPH_BC == SYMMETRIC_MORPH_BC)
530  return pixClose(pixd, pixs, sel);
531 
532  selFindMaxTranslations(sel, &xp, &yp, &xn, &yn);
533  xmax = L_MAX(xp, xn);
534  xbord = 32 * ((xmax + 31) / 32); /* full 32 bit words */
535 
536  if ((pixt1 = pixAddBorderGeneral(pixs, xbord, xbord, yp, yn, 0)) == NULL)
537  return (PIX *)ERROR_PTR("pixt1 not made", __func__, pixd);
538  pixClose(pixt1, pixt1, sel);
539  if ((pixt2 = pixRemoveBorderGeneral(pixt1, xbord, xbord, yp, yn)) == NULL)
540  return (PIX *)ERROR_PTR("pixt2 not made", __func__, pixd);
541  pixDestroy(&pixt1);
542 
543  if (!pixd)
544  return pixt2;
545 
546  pixCopy(pixd, pixt2);
547  pixDestroy(&pixt2);
548  return pixd;
549 }
550 
551 
578 PIX *
580  PIX *pixs,
581  SEL *sel)
582 {
583 PIX *pixt;
584 
585  if ((pixd = processMorphArgs2(pixd, pixs, sel)) == NULL)
586  return (PIX *)ERROR_PTR("pixd not returned", __func__, pixd);
587 
588  if ((pixt = pixHMT(NULL, pixs, sel)) == NULL)
589  return (PIX *)ERROR_PTR("pixt not made", __func__, pixd);
590  pixDilate(pixd, pixt, sel);
591  pixDestroy(&pixt);
592  return pixd;
593 }
594 
595 
623 PIX *
625  PIX *pixs,
626  SEL *sel)
627 {
628 PIX *pixt;
629 
630  if ((pixd = processMorphArgs2(pixd, pixs, sel)) == NULL)
631  return (PIX *)ERROR_PTR("pixd not returned", __func__, pixd);
632 
633  if ((pixt = pixDilate(NULL, pixs, sel)) == NULL)
634  return (PIX *)ERROR_PTR("pixt not made", __func__, pixd);
635  pixHMT(pixd, pixt, sel);
636  pixDestroy(&pixt);
637 
638  return pixd;
639 }
640 
641 
642 /*-----------------------------------------------------------------*
643  * Binary morphological (raster) ops with brick Sels *
644  *-----------------------------------------------------------------*/
671 PIX *
673  PIX *pixs,
674  l_int32 hsize,
675  l_int32 vsize)
676 {
677 PIX *pixt;
678 SEL *sel, *selh, *selv;
679 
680  if (!pixs)
681  return (PIX *)ERROR_PTR("pixs not defined", __func__, pixd);
682  if (pixGetDepth(pixs) != 1)
683  return (PIX *)ERROR_PTR("pixs not 1 bpp", __func__, pixd);
684  if (hsize < 1 || vsize < 1)
685  return (PIX *)ERROR_PTR("hsize and vsize not >= 1", __func__, pixd);
686 
687  if (hsize == 1 && vsize == 1)
688  return pixCopy(pixd, pixs);
689  if (hsize == 1 || vsize == 1) { /* no intermediate result */
690  sel = selCreateBrick(vsize, hsize, vsize / 2, hsize / 2, SEL_HIT);
691  if (!sel)
692  return (PIX *)ERROR_PTR("sel not made", __func__, pixd);
693  pixd = pixDilate(pixd, pixs, sel);
694  selDestroy(&sel);
695  } else {
696  if ((selh = selCreateBrick(1, hsize, 0, hsize / 2, SEL_HIT)) == NULL)
697  return (PIX *)ERROR_PTR("selh not made", __func__, pixd);
698  if ((selv = selCreateBrick(vsize, 1, vsize / 2, 0, SEL_HIT)) == NULL) {
699  selDestroy(&selh);
700  return (PIX *)ERROR_PTR("selv not made", __func__, pixd);
701  }
702  pixt = pixDilate(NULL, pixs, selh);
703  pixd = pixDilate(pixd, pixt, selv);
704  pixDestroy(&pixt);
705  selDestroy(&selh);
706  selDestroy(&selv);
707  }
708 
709  return pixd;
710 }
711 
712 
739 PIX *
741  PIX *pixs,
742  l_int32 hsize,
743  l_int32 vsize)
744 {
745 PIX *pixt;
746 SEL *sel, *selh, *selv;
747 
748  if (!pixs)
749  return (PIX *)ERROR_PTR("pixs not defined", __func__, pixd);
750  if (pixGetDepth(pixs) != 1)
751  return (PIX *)ERROR_PTR("pixs not 1 bpp", __func__, pixd);
752  if (hsize < 1 || vsize < 1)
753  return (PIX *)ERROR_PTR("hsize and vsize not >= 1", __func__, pixd);
754 
755  if (hsize == 1 && vsize == 1)
756  return pixCopy(pixd, pixs);
757  if (hsize == 1 || vsize == 1) { /* no intermediate result */
758  sel = selCreateBrick(vsize, hsize, vsize / 2, hsize / 2, SEL_HIT);
759  if (!sel)
760  return (PIX *)ERROR_PTR("sel not made", __func__, pixd);
761  pixd = pixErode(pixd, pixs, sel);
762  selDestroy(&sel);
763  } else {
764  if ((selh = selCreateBrick(1, hsize, 0, hsize / 2, SEL_HIT)) == NULL)
765  return (PIX *)ERROR_PTR("selh not made", __func__, pixd);
766  if ((selv = selCreateBrick(vsize, 1, vsize / 2, 0, SEL_HIT)) == NULL) {
767  selDestroy(&selh);
768  return (PIX *)ERROR_PTR("selv not made", __func__, pixd);
769  }
770  pixt = pixErode(NULL, pixs, selh);
771  pixd = pixErode(pixd, pixt, selv);
772  pixDestroy(&pixt);
773  selDestroy(&selh);
774  selDestroy(&selv);
775  }
776 
777  return pixd;
778 }
779 
780 
807 PIX *
809  PIX *pixs,
810  l_int32 hsize,
811  l_int32 vsize)
812 {
813 PIX *pixt;
814 SEL *sel, *selh, *selv;
815 
816  if (!pixs)
817  return (PIX *)ERROR_PTR("pixs not defined", __func__, pixd);
818  if (pixGetDepth(pixs) != 1)
819  return (PIX *)ERROR_PTR("pixs not 1 bpp", __func__, pixd);
820  if (hsize < 1 || vsize < 1)
821  return (PIX *)ERROR_PTR("hsize and vsize not >= 1", __func__, pixd);
822 
823  if (hsize == 1 && vsize == 1)
824  return pixCopy(pixd, pixs);
825  if (hsize == 1 || vsize == 1) { /* no intermediate result */
826  sel = selCreateBrick(vsize, hsize, vsize / 2, hsize / 2, SEL_HIT);
827  if (!sel)
828  return (PIX *)ERROR_PTR("sel not made", __func__, pixd);
829  pixd = pixOpen(pixd, pixs, sel);
830  selDestroy(&sel);
831  } else { /* do separably */
832  if ((selh = selCreateBrick(1, hsize, 0, hsize / 2, SEL_HIT)) == NULL)
833  return (PIX *)ERROR_PTR("selh not made", __func__, pixd);
834  if ((selv = selCreateBrick(vsize, 1, vsize / 2, 0, SEL_HIT)) == NULL) {
835  selDestroy(&selh);
836  return (PIX *)ERROR_PTR("selv not made", __func__, pixd);
837  }
838  pixt = pixErode(NULL, pixs, selh);
839  pixd = pixErode(pixd, pixt, selv);
840  pixDilate(pixt, pixd, selh);
841  pixDilate(pixd, pixt, selv);
842  pixDestroy(&pixt);
843  selDestroy(&selh);
844  selDestroy(&selv);
845  }
846 
847  return pixd;
848 }
849 
850 
877 PIX *
879  PIX *pixs,
880  l_int32 hsize,
881  l_int32 vsize)
882 {
883 PIX *pixt;
884 SEL *sel, *selh, *selv;
885 
886  if (!pixs)
887  return (PIX *)ERROR_PTR("pixs not defined", __func__, pixd);
888  if (pixGetDepth(pixs) != 1)
889  return (PIX *)ERROR_PTR("pixs not 1 bpp", __func__, pixd);
890  if (hsize < 1 || vsize < 1)
891  return (PIX *)ERROR_PTR("hsize and vsize not >= 1", __func__, pixd);
892 
893  if (hsize == 1 && vsize == 1)
894  return pixCopy(pixd, pixs);
895  if (hsize == 1 || vsize == 1) { /* no intermediate result */
896  sel = selCreateBrick(vsize, hsize, vsize / 2, hsize / 2, SEL_HIT);
897  if (!sel)
898  return (PIX *)ERROR_PTR("sel not made", __func__, pixd);
899  pixd = pixClose(pixd, pixs, sel);
900  selDestroy(&sel);
901  } else { /* do separably */
902  if ((selh = selCreateBrick(1, hsize, 0, hsize / 2, SEL_HIT)) == NULL)
903  return (PIX *)ERROR_PTR("selh not made", __func__, pixd);
904  if ((selv = selCreateBrick(vsize, 1, vsize / 2, 0, SEL_HIT)) == NULL) {
905  selDestroy(&selh);
906  return (PIX *)ERROR_PTR("selv not made", __func__, pixd);
907  }
908  pixt = pixDilate(NULL, pixs, selh);
909  pixd = pixDilate(pixd, pixt, selv);
910  pixErode(pixt, pixd, selh);
911  pixErode(pixd, pixt, selv);
912  pixDestroy(&pixt);
913  selDestroy(&selh);
914  selDestroy(&selv);
915  }
916 
917  return pixd;
918 }
919 
920 
952 PIX *
954  PIX *pixs,
955  l_int32 hsize,
956  l_int32 vsize)
957 {
958 l_int32 maxtrans, bordsize;
959 PIX *pixsb, *pixt, *pixdb;
960 SEL *sel, *selh, *selv;
961 
962  if (!pixs)
963  return (PIX *)ERROR_PTR("pixs not defined", __func__, pixd);
964  if (pixGetDepth(pixs) != 1)
965  return (PIX *)ERROR_PTR("pixs not 1 bpp", __func__, pixd);
966  if (hsize < 1 || vsize < 1)
967  return (PIX *)ERROR_PTR("hsize and vsize not >= 1", __func__, pixd);
968 
969  if (hsize == 1 && vsize == 1)
970  return pixCopy(pixd, pixs);
971 
972  /* Symmetric b.c. handles correctly without added pixels */
973  if (MORPH_BC == SYMMETRIC_MORPH_BC)
974  return pixCloseBrick(pixd, pixs, hsize, vsize);
975 
976  maxtrans = L_MAX(hsize / 2, vsize / 2);
977  bordsize = 32 * ((maxtrans + 31) / 32); /* full 32 bit words */
978  pixsb = pixAddBorder(pixs, bordsize, 0);
979 
980  if (hsize == 1 || vsize == 1) { /* no intermediate result */
981  sel = selCreateBrick(vsize, hsize, vsize / 2, hsize / 2, SEL_HIT);
982  if (!sel) {
983  pixDestroy(&pixsb);
984  return (PIX *)ERROR_PTR("sel not made", __func__, pixd);
985  }
986  pixdb = pixClose(NULL, pixsb, sel);
987  selDestroy(&sel);
988  } else { /* do separably */
989  selh = selCreateBrick(1, hsize, 0, hsize / 2, SEL_HIT);
990  selv = selCreateBrick(vsize, 1, vsize / 2, 0, SEL_HIT);
991  if (!selh || !selv) {
992  selDestroy(&selh);
993  selDestroy(&selv);
994  pixDestroy(&pixsb);
995  return (PIX *)ERROR_PTR("selh and selv not both made",
996  __func__, pixd);
997  }
998  pixt = pixDilate(NULL, pixsb, selh);
999  pixdb = pixDilate(NULL, pixt, selv);
1000  pixErode(pixt, pixdb, selh);
1001  pixErode(pixdb, pixt, selv);
1002  pixDestroy(&pixt);
1003  selDestroy(&selh);
1004  selDestroy(&selv);
1005  }
1006 
1007  pixt = pixRemoveBorder(pixdb, bordsize);
1008  pixDestroy(&pixsb);
1009  pixDestroy(&pixdb);
1010 
1011  if (!pixd) {
1012  pixd = pixt;
1013  } else {
1014  pixCopy(pixd, pixt);
1015  pixDestroy(&pixt);
1016  }
1017  return pixd;
1018 }
1019 
1020 
1021 /*-----------------------------------------------------------------*
1022  * Binary composed morphological (raster) ops with brick Sels *
1023  *-----------------------------------------------------------------*/
1024 /* \brief selectComposableSels()
1025  *
1026  * \param[in] size of composed sel
1027  * \param[in] direction L_HORIZ, L_VERT
1028  * \param[out] psel1 [optional] contiguous sel; can be null
1029  * \param[out] psel2 [optional] comb sel; can be null
1030  * \return 0 if OK, 1 on error
1031  *
1032  * <pre>
1033  * Notes:
1034  * (1) When using composable Sels, where the original Sel is
1035  * decomposed into two, the best you can do in terms
1036  * of reducing the computation is by a factor:
1037  *
1038  * 2 * sqrt(size) / size
1039  *
1040  * In practice, you get quite close to this. E.g.,
1041  *
1042  * Sel size | Optimum reduction factor
1043  * -------- ------------------------
1044  * 36 | 1/3
1045  * 64 | 1/4
1046  * 144 | 1/6
1047  * 256 | 1/8
1048  * </pre>
1049  */
1050 l_int32
1051 selectComposableSels(l_int32 size,
1052  l_int32 direction,
1053  SEL **psel1,
1054  SEL **psel2)
1055 {
1056 l_int32 factor1, factor2;
1057 
1058  if (!psel1 && !psel2)
1059  return ERROR_INT("neither &sel1 nor &sel2 are defined", __func__, 1);
1060  if (psel1) *psel1 = NULL;
1061  if (psel2) *psel2 = NULL;
1062  if (size < 1 || size > 10000)
1063  return ERROR_INT("size < 1 or size > 10000", __func__, 1);
1064  if (direction != L_HORIZ && direction != L_VERT)
1065  return ERROR_INT("invalid direction", __func__, 1);
1066 
1067  if (selectComposableSizes(size, &factor1, &factor2))
1068  return ERROR_INT("factors not found", __func__, 1);
1069 
1070  if (psel1) {
1071  if (direction == L_HORIZ)
1072  *psel1 = selCreateBrick(1, factor1, 0, factor1 / 2, SEL_HIT);
1073  else
1074  *psel1 = selCreateBrick(factor1, 1, factor1 / 2 , 0, SEL_HIT);
1075  }
1076  if (psel2)
1077  *psel2 = selCreateComb(factor1, factor2, direction);
1078  return 0;
1079 }
1080 
1081 
1103 l_ok
1105  l_int32 *pfactor1,
1106  l_int32 *pfactor2)
1107 {
1108 l_int32 i, midval, val1, val2m, val2p;
1109 l_int32 index, prodm, prodp;
1110 l_int32 mincost, totcost, rastcostm, rastcostp, diffm, diffp;
1111 l_int32 lowval[256];
1112 l_int32 hival[256];
1113 l_int32 rastcost[256]; /* excess in sum of sizes (extra rasterops) */
1114 l_int32 diff[256]; /* diff between product (sel size) and input size */
1115 
1116  if (size < 1 || size > 10000)
1117  return ERROR_INT("size < 1 or size > 10000", __func__, 1);
1118  if (!pfactor1 || !pfactor2)
1119  return ERROR_INT("&factor1 or &factor2 not defined", __func__, 1);
1120 
1121  midval = (l_int32)(sqrt((l_float64)size) + 0.001);
1122  if (midval * midval == size) {
1123  *pfactor1 = *pfactor2 = midval;
1124  return 0;
1125  }
1126 
1127  /* Set up arrays. For each val1, optimize for lowest diff,
1128  * and save the rastcost, the diff, and the two factors. */
1129  for (val1 = midval + 1, i = 0; val1 > 0; val1--, i++) {
1130  val2m = size / val1;
1131  val2p = val2m + 1;
1132  prodm = val1 * val2m;
1133  prodp = val1 * val2p;
1134  rastcostm = val1 + val2m - 2 * midval;
1135  rastcostp = val1 + val2p - 2 * midval;
1136  diffm = L_ABS(size - prodm);
1137  diffp = L_ABS(size - prodp);
1138  if (diffm <= diffp) {
1139  lowval[i] = L_MIN(val1, val2m);
1140  hival[i] = L_MAX(val1, val2m);
1141  rastcost[i] = rastcostm;
1142  diff[i] = diffm;
1143  } else {
1144  lowval[i] = L_MIN(val1, val2p);
1145  hival[i] = L_MAX(val1, val2p);
1146  rastcost[i] = rastcostp;
1147  diff[i] = diffp;
1148  }
1149  }
1150 
1151  /* Choose the optimum factors; use cost ratio 4 on diff */
1152  mincost = 10000;
1153  index = 1; /* unimportant initial value */
1154  for (i = 0; i < midval + 1; i++) {
1155  if (diff[i] == 0 && rastcost[i] < ACCEPTABLE_COST) {
1156  *pfactor1 = hival[i];
1157  *pfactor2 = lowval[i];
1158  return 0;
1159  }
1160  totcost = 4 * diff[i] + rastcost[i];
1161  if (totcost < mincost) {
1162  mincost = totcost;
1163  index = i;
1164  }
1165  }
1166  *pfactor1 = hival[index];
1167  *pfactor2 = lowval[index];
1168 
1169  return 0;
1170 }
1171 
1172 
1213 PIX *
1215  PIX *pixs,
1216  l_int32 hsize,
1217  l_int32 vsize)
1218 {
1219 PIX *pix1, *pix2, *pix3;
1220 SEL *selh1 = NULL;
1221 SEL *selh2 = NULL;
1222 SEL *selv1 = NULL;
1223 SEL *selv2 = NULL;
1224 
1225  if (!pixs)
1226  return (PIX *)ERROR_PTR("pixs not defined", __func__, pixd);
1227  if (pixGetDepth(pixs) != 1)
1228  return (PIX *)ERROR_PTR("pixs not 1 bpp", __func__, pixd);
1229  if (hsize < 1 || vsize < 1)
1230  return (PIX *)ERROR_PTR("hsize and vsize not >= 1", __func__, pixd);
1231 
1232  if (hsize == 1 && vsize == 1)
1233  return pixCopy(pixd, pixs);
1234  if (hsize > 1) {
1235  if (selectComposableSels(hsize, L_HORIZ, &selh1, &selh2)) {
1236  selDestroy(&selh1);
1237  selDestroy(&selh2);
1238  return (PIX *)ERROR_PTR("horiz sels not made", __func__, pixd);
1239  }
1240  }
1241  if (vsize > 1) {
1242  if (selectComposableSels(vsize, L_VERT, &selv1, &selv2)) {
1243  selDestroy(&selh1);
1244  selDestroy(&selh2);
1245  selDestroy(&selv1);
1246  selDestroy(&selv2);
1247  return (PIX *)ERROR_PTR("vert sels not made", __func__, pixd);
1248  }
1249  }
1250 
1251  pix1 = pixAddBorder(pixs, 32, 0);
1252  if (vsize == 1) {
1253  pix2 = pixDilate(NULL, pix1, selh1);
1254  pix3 = pixDilate(NULL, pix2, selh2);
1255  } else if (hsize == 1) {
1256  pix2 = pixDilate(NULL, pix1, selv1);
1257  pix3 = pixDilate(NULL, pix2, selv2);
1258  } else {
1259  pix2 = pixDilate(NULL, pix1, selh1);
1260  pix3 = pixDilate(NULL, pix2, selh2);
1261  pixDilate(pix2, pix3, selv1);
1262  pixDilate(pix3, pix2, selv2);
1263  }
1264  pixDestroy(&pix1);
1265  pixDestroy(&pix2);
1266 
1267  selDestroy(&selh1);
1268  selDestroy(&selh2);
1269  selDestroy(&selv1);
1270  selDestroy(&selv2);
1271 
1272  pix1 = pixRemoveBorder(pix3, 32);
1273  pixDestroy(&pix3);
1274  if (!pixd)
1275  return pix1;
1276  pixCopy(pixd, pix1);
1277  pixDestroy(&pix1);
1278  return pixd;
1279 }
1280 
1281 
1322 PIX *
1324  PIX *pixs,
1325  l_int32 hsize,
1326  l_int32 vsize)
1327 {
1328 PIX *pixt;
1329 SEL *selh1 = NULL;
1330 SEL *selh2 = NULL;
1331 SEL *selv1 = NULL;
1332 SEL *selv2 = NULL;
1333 
1334  if (!pixs)
1335  return (PIX *)ERROR_PTR("pixs not defined", __func__, pixd);
1336  if (pixGetDepth(pixs) != 1)
1337  return (PIX *)ERROR_PTR("pixs not 1 bpp", __func__, pixd);
1338  if (hsize < 1 || vsize < 1)
1339  return (PIX *)ERROR_PTR("hsize and vsize not >= 1", __func__, pixd);
1340 
1341  if (hsize == 1 && vsize == 1)
1342  return pixCopy(pixd, pixs);
1343  if (hsize > 1) {
1344  if (selectComposableSels(hsize, L_HORIZ, &selh1, &selh2)) {
1345  selDestroy(&selh1);
1346  selDestroy(&selh2);
1347  return (PIX *)ERROR_PTR("horiz sels not made", __func__, pixd);
1348  }
1349  }
1350  if (vsize > 1) {
1351  if (selectComposableSels(vsize, L_VERT, &selv1, &selv2)) {
1352  selDestroy(&selh1);
1353  selDestroy(&selh2);
1354  selDestroy(&selv1);
1355  selDestroy(&selv2);
1356  return (PIX *)ERROR_PTR("vert sels not made", __func__, pixd);
1357  }
1358  }
1359 
1360  if (vsize == 1) {
1361  pixt = pixErode(NULL, pixs, selh1);
1362  pixd = pixErode(pixd, pixt, selh2);
1363  } else if (hsize == 1) {
1364  pixt = pixErode(NULL, pixs, selv1);
1365  pixd = pixErode(pixd, pixt, selv2);
1366  } else {
1367  pixt = pixErode(NULL, pixs, selh1);
1368  pixd = pixErode(pixd, pixt, selh2);
1369  pixErode(pixt, pixd, selv1);
1370  pixErode(pixd, pixt, selv2);
1371  }
1372  pixDestroy(&pixt);
1373 
1374  selDestroy(&selh1);
1375  selDestroy(&selh2);
1376  selDestroy(&selv1);
1377  selDestroy(&selv2);
1378  return pixd;
1379 }
1380 
1381 
1422 PIX *
1424  PIX *pixs,
1425  l_int32 hsize,
1426  l_int32 vsize)
1427 {
1428 PIX *pixt;
1429 SEL *selh1 = NULL;
1430 SEL *selh2 = NULL;
1431 SEL *selv1 = NULL;
1432 SEL *selv2 = NULL;
1433 
1434  if (!pixs)
1435  return (PIX *)ERROR_PTR("pixs not defined", __func__, pixd);
1436  if (pixGetDepth(pixs) != 1)
1437  return (PIX *)ERROR_PTR("pixs not 1 bpp", __func__, pixd);
1438  if (hsize < 1 || vsize < 1)
1439  return (PIX *)ERROR_PTR("hsize and vsize not >= 1", __func__, pixd);
1440 
1441  if (hsize == 1 && vsize == 1)
1442  return pixCopy(pixd, pixs);
1443  if (hsize > 1) {
1444  if (selectComposableSels(hsize, L_HORIZ, &selh1, &selh2)) {
1445  selDestroy(&selh1);
1446  selDestroy(&selh2);
1447  return (PIX *)ERROR_PTR("horiz sels not made", __func__, pixd);
1448  }
1449  }
1450  if (vsize > 1) {
1451  if (selectComposableSels(vsize, L_VERT, &selv1, &selv2)) {
1452  selDestroy(&selh1);
1453  selDestroy(&selh2);
1454  selDestroy(&selv1);
1455  selDestroy(&selv2);
1456  return (PIX *)ERROR_PTR("vert sels not made", __func__, pixd);
1457  }
1458  }
1459 
1460  if (vsize == 1) {
1461  pixt = pixErode(NULL, pixs, selh1);
1462  pixd = pixErode(pixd, pixt, selh2);
1463  pixDilate(pixt, pixd, selh1);
1464  pixDilate(pixd, pixt, selh2);
1465  } else if (hsize == 1) {
1466  pixt = pixErode(NULL, pixs, selv1);
1467  pixd = pixErode(pixd, pixt, selv2);
1468  pixDilate(pixt, pixd, selv1);
1469  pixDilate(pixd, pixt, selv2);
1470  } else { /* do separably */
1471  pixt = pixErode(NULL, pixs, selh1);
1472  pixd = pixErode(pixd, pixt, selh2);
1473  pixErode(pixt, pixd, selv1);
1474  pixErode(pixd, pixt, selv2);
1475  pixDilate(pixt, pixd, selh1);
1476  pixDilate(pixd, pixt, selh2);
1477  pixDilate(pixt, pixd, selv1);
1478  pixDilate(pixd, pixt, selv2);
1479  }
1480  pixDestroy(&pixt);
1481 
1482  selDestroy(&selh1);
1483  selDestroy(&selh2);
1484  selDestroy(&selv1);
1485  selDestroy(&selv2);
1486  return pixd;
1487 }
1488 
1489 
1530 PIX *
1532  PIX *pixs,
1533  l_int32 hsize,
1534  l_int32 vsize)
1535 {
1536 PIX *pixt;
1537 SEL *selh1 = NULL;
1538 SEL *selh2 = NULL;
1539 SEL *selv1 = NULL;
1540 SEL *selv2 = NULL;
1541 
1542  if (!pixs)
1543  return (PIX *)ERROR_PTR("pixs not defined", __func__, pixd);
1544  if (pixGetDepth(pixs) != 1)
1545  return (PIX *)ERROR_PTR("pixs not 1 bpp", __func__, pixd);
1546  if (hsize < 1 || vsize < 1)
1547  return (PIX *)ERROR_PTR("hsize and vsize not >= 1", __func__, pixd);
1548 
1549  if (hsize == 1 && vsize == 1)
1550  return pixCopy(pixd, pixs);
1551  if (hsize > 1) {
1552  if (selectComposableSels(hsize, L_HORIZ, &selh1, &selh2)) {
1553  selDestroy(&selh1);
1554  selDestroy(&selh2);
1555  return (PIX *)ERROR_PTR("horiz sels not made", __func__, pixd);
1556  }
1557  }
1558  if (vsize > 1) {
1559  if (selectComposableSels(vsize, L_VERT, &selv1, &selv2)) {
1560  selDestroy(&selh1);
1561  selDestroy(&selh2);
1562  selDestroy(&selv1);
1563  selDestroy(&selv2);
1564  return (PIX *)ERROR_PTR("vert sels not made", __func__, pixd);
1565  }
1566  }
1567 
1568  if (vsize == 1) {
1569  pixt = pixDilate(NULL, pixs, selh1);
1570  pixd = pixDilate(pixd, pixt, selh2);
1571  pixErode(pixt, pixd, selh1);
1572  pixErode(pixd, pixt, selh2);
1573  } else if (hsize == 1) {
1574  pixt = pixDilate(NULL, pixs, selv1);
1575  pixd = pixDilate(pixd, pixt, selv2);
1576  pixErode(pixt, pixd, selv1);
1577  pixErode(pixd, pixt, selv2);
1578  } else { /* do separably */
1579  pixt = pixDilate(NULL, pixs, selh1);
1580  pixd = pixDilate(pixd, pixt, selh2);
1581  pixDilate(pixt, pixd, selv1);
1582  pixDilate(pixd, pixt, selv2);
1583  pixErode(pixt, pixd, selh1);
1584  pixErode(pixd, pixt, selh2);
1585  pixErode(pixt, pixd, selv1);
1586  pixErode(pixd, pixt, selv2);
1587  }
1588  pixDestroy(&pixt);
1589 
1590  selDestroy(&selh1);
1591  selDestroy(&selh2);
1592  selDestroy(&selv1);
1593  selDestroy(&selv2);
1594  return pixd;
1595 }
1596 
1597 
1643 PIX *
1645  PIX *pixs,
1646  l_int32 hsize,
1647  l_int32 vsize)
1648 {
1649 l_int32 maxtrans, bordsize;
1650 PIX *pixsb, *pixt, *pixdb;
1651 SEL *selh1 = NULL;
1652 SEL *selh2 = NULL;
1653 SEL *selv1 = NULL;
1654 SEL *selv2 = NULL;
1655 
1656  if (!pixs)
1657  return (PIX *)ERROR_PTR("pixs not defined", __func__, pixd);
1658  if (pixGetDepth(pixs) != 1)
1659  return (PIX *)ERROR_PTR("pixs not 1 bpp", __func__, pixd);
1660  if (hsize < 1 || vsize < 1)
1661  return (PIX *)ERROR_PTR("hsize and vsize not >= 1", __func__, pixd);
1662 
1663  if (hsize == 1 && vsize == 1)
1664  return pixCopy(pixd, pixs);
1665 
1666  /* Symmetric b.c. handles correctly without added pixels */
1667  if (MORPH_BC == SYMMETRIC_MORPH_BC)
1668  return pixCloseCompBrick(pixd, pixs, hsize, vsize);
1669 
1670  if (hsize > 1) {
1671  if (selectComposableSels(hsize, L_HORIZ, &selh1, &selh2)) {
1672  selDestroy(&selh1);
1673  selDestroy(&selh2);
1674  return (PIX *)ERROR_PTR("horiz sels not made", __func__, pixd);
1675  }
1676  }
1677  if (vsize > 1) {
1678  if (selectComposableSels(vsize, L_VERT, &selv1, &selv2)) {
1679  selDestroy(&selh1);
1680  selDestroy(&selh2);
1681  selDestroy(&selv1);
1682  selDestroy(&selv2);
1683  return (PIX *)ERROR_PTR("vert sels not made", __func__, pixd);
1684  }
1685  }
1686 
1687  maxtrans = L_MAX(hsize / 2, vsize / 2);
1688  bordsize = 32 * ((maxtrans + 31) / 32); /* full 32 bit words */
1689  pixsb = pixAddBorder(pixs, bordsize, 0);
1690 
1691  if (vsize == 1) {
1692  pixt = pixDilate(NULL, pixsb, selh1);
1693  pixdb = pixDilate(NULL, pixt, selh2);
1694  pixErode(pixt, pixdb, selh1);
1695  pixErode(pixdb, pixt, selh2);
1696  } else if (hsize == 1) {
1697  pixt = pixDilate(NULL, pixsb, selv1);
1698  pixdb = pixDilate(NULL, pixt, selv2);
1699  pixErode(pixt, pixdb, selv1);
1700  pixErode(pixdb, pixt, selv2);
1701  } else { /* do separably */
1702  pixt = pixDilate(NULL, pixsb, selh1);
1703  pixdb = pixDilate(NULL, pixt, selh2);
1704  pixDilate(pixt, pixdb, selv1);
1705  pixDilate(pixdb, pixt, selv2);
1706  pixErode(pixt, pixdb, selh1);
1707  pixErode(pixdb, pixt, selh2);
1708  pixErode(pixt, pixdb, selv1);
1709  pixErode(pixdb, pixt, selv2);
1710  }
1711  pixDestroy(&pixt);
1712 
1713  pixt = pixRemoveBorder(pixdb, bordsize);
1714  pixDestroy(&pixsb);
1715  pixDestroy(&pixdb);
1716 
1717  if (!pixd) {
1718  pixd = pixt;
1719  } else {
1720  pixCopy(pixd, pixt);
1721  pixDestroy(&pixt);
1722  }
1723 
1724  selDestroy(&selh1);
1725  selDestroy(&selh2);
1726  selDestroy(&selv1);
1727  selDestroy(&selv2);
1728  return pixd;
1729 }
1730 
1731 
1732 /*-----------------------------------------------------------------*
1733  * Functions associated with boundary conditions *
1734  *-----------------------------------------------------------------*/
1741 void
1743 {
1744  if (bc != SYMMETRIC_MORPH_BC && bc != ASYMMETRIC_MORPH_BC) {
1745  L_WARNING("invalid bc; using asymmetric\n", __func__);
1746  bc = ASYMMETRIC_MORPH_BC;
1747  }
1748  MORPH_BC = bc;
1749  return;
1750 }
1751 
1752 
1760 l_uint32
1762  l_int32 depth)
1763 {
1764  if (type != L_MORPH_DILATE && type != L_MORPH_ERODE)
1765  return ERROR_INT("invalid type", __func__, 0);
1766  if (depth != 1 && depth != 2 && depth != 4 && depth != 8 &&
1767  depth != 16 && depth != 32)
1768  return ERROR_INT("invalid depth", __func__, 0);
1769 
1770  if (MORPH_BC == ASYMMETRIC_MORPH_BC || type == L_MORPH_DILATE)
1771  return 0;
1772 
1773  /* Symmetric & erosion */
1774  if (depth < 32)
1775  return ((1 << depth) - 1);
1776  else /* depth == 32 */
1777  return 0xffffff00;
1778 }
1779 
1780 
1781 /*-----------------------------------------------------------------*
1782  * Static helpers for arg processing *
1783  *-----------------------------------------------------------------*/
1799 static PIX *
1801  PIX *pixs,
1802  SEL *sel,
1803  PIX **ppixt)
1804 {
1805 l_int32 sx, sy;
1806 
1807  if (!ppixt)
1808  return (PIX *)ERROR_PTR("&pixt not defined", __func__, pixd);
1809  *ppixt = NULL;
1810  if (!pixs)
1811  return (PIX *)ERROR_PTR("pixs not defined", __func__, pixd);
1812  if (!sel)
1813  return (PIX *)ERROR_PTR("sel not defined", __func__, pixd);
1814  if (pixGetDepth(pixs) != 1)
1815  return (PIX *)ERROR_PTR("pixs not 1 bpp", __func__, pixd);
1816 
1817  selGetParameters(sel, &sx, &sy, NULL, NULL);
1818  if (sx == 0 || sy == 0)
1819  return (PIX *)ERROR_PTR("sel of size 0", __func__, pixd);
1820 
1821  /* We require pixd to exist and to be the same size as pixs.
1822  * Further, pixt must be a copy (or clone) of pixs. */
1823  if (!pixd) {
1824  if ((pixd = pixCreateTemplate(pixs)) == NULL)
1825  return (PIX *)ERROR_PTR("pixd not made", __func__, NULL);
1826  *ppixt = pixClone(pixs);
1827  } else {
1828  pixResizeImageData(pixd, pixs);
1829  if (pixd == pixs) { /* in-place; must make a copy of pixs */
1830  if ((*ppixt = pixCopy(NULL, pixs)) == NULL)
1831  return (PIX *)ERROR_PTR("pixt not made", __func__, pixd);
1832  } else {
1833  *ppixt = pixClone(pixs);
1834  }
1835  }
1836  return pixd;
1837 }
1838 
1839 
1845 static PIX *
1847  PIX *pixs,
1848  SEL *sel)
1849 {
1850 l_int32 sx, sy;
1851 
1852  if (!pixs)
1853  return (PIX *)ERROR_PTR("pixs not defined", __func__, pixd);
1854  if (!sel)
1855  return (PIX *)ERROR_PTR("sel not defined", __func__, pixd);
1856  if (pixGetDepth(pixs) != 1)
1857  return (PIX *)ERROR_PTR("pixs not 1 bpp", __func__, pixd);
1858 
1859  selGetParameters(sel, &sx, &sy, NULL, NULL);
1860  if (sx == 0 || sy == 0)
1861  return (PIX *)ERROR_PTR("sel of size 0", __func__, pixd);
1862 
1863  if (!pixd)
1864  return pixCreateTemplate(pixs);
1865  pixResizeImageData(pixd, pixs);
1866  return pixd;
1867 }
PIX * pixCloseSafe(PIX *pixd, PIX *pixs, SEL *sel)
pixCloseSafe()
Definition: morph.c:514
PIX * pixOpenBrick(PIX *pixd, PIX *pixs, l_int32 hsize, l_int32 vsize)
pixOpenBrick()
Definition: morph.c:808
void resetMorphBoundaryCondition(l_int32 bc)
resetMorphBoundaryCondition()
Definition: morph.c:1742
PIX * pixOpen(PIX *pixd, PIX *pixs, SEL *sel)
pixOpen()
Definition: morph.c:420
PIX * pixErode(PIX *pixd, PIX *pixs, SEL *sel)
pixErode()
Definition: morph.c:265
l_ok selectComposableSizes(l_int32 size, l_int32 *pfactor1, l_int32 *pfactor2)
selectComposableSizes()
Definition: morph.c:1104
PIX * pixOpenCompBrick(PIX *pixd, PIX *pixs, l_int32 hsize, l_int32 vsize)
pixOpenCompBrick()
Definition: morph.c:1423
PIX * pixOpenGeneralized(PIX *pixd, PIX *pixs, SEL *sel)
pixOpenGeneralized()
Definition: morph.c:579
PIX * pixClose(PIX *pixd, PIX *pixs, SEL *sel)
pixClose()
Definition: morph.c:465
static PIX * processMorphArgs1(PIX *pixd, PIX *pixs, SEL *sel, PIX **ppixt)
processMorphArgs1()
Definition: morph.c:1800
PIX * pixCloseSafeCompBrick(PIX *pixd, PIX *pixs, l_int32 hsize, l_int32 vsize)
pixCloseSafeCompBrick()
Definition: morph.c:1644
PIX * pixCloseSafeBrick(PIX *pixd, PIX *pixs, l_int32 hsize, l_int32 vsize)
pixCloseSafeBrick()
Definition: morph.c:953
PIX * pixErodeBrick(PIX *pixd, PIX *pixs, l_int32 hsize, l_int32 vsize)
pixErodeBrick()
Definition: morph.c:740
PIX * pixCloseCompBrick(PIX *pixd, PIX *pixs, l_int32 hsize, l_int32 vsize)
pixCloseCompBrick()
Definition: morph.c:1531
PIX * pixDilate(PIX *pixd, PIX *pixs, SEL *sel)
pixDilate()
Definition: morph.c:213
PIX * pixHMT(PIX *pixd, PIX *pixs, SEL *sel)
pixHMT()
Definition: morph.c:338
static PIX * processMorphArgs2(PIX *pixd, PIX *pixs, SEL *sel)
processMorphArgs2()
Definition: morph.c:1846
l_uint32 getMorphBorderPixelColor(l_int32 type, l_int32 depth)
getMorphBorderPixelColor()
Definition: morph.c:1761
PIX * pixDilateBrick(PIX *pixd, PIX *pixs, l_int32 hsize, l_int32 vsize)
pixDilateBrick()
Definition: morph.c:672
PIX * pixCloseBrick(PIX *pixd, PIX *pixs, l_int32 hsize, l_int32 vsize)
pixCloseBrick()
Definition: morph.c:878
PIX * pixCloseGeneralized(PIX *pixd, PIX *pixs, SEL *sel)
pixCloseGeneralized()
Definition: morph.c:624
PIX * pixDilateCompBrick(PIX *pixd, PIX *pixs, l_int32 hsize, l_int32 vsize)
pixDilateCompBrick()
Definition: morph.c:1214
PIX * pixErodeCompBrick(PIX *pixd, PIX *pixs, l_int32 hsize, l_int32 vsize)
pixErodeCompBrick()
Definition: morph.c:1323
l_ok pixResizeImageData(PIX *pixd, const PIX *pixs)
pixResizeImageData()
Definition: pix1.c:750
void pixDestroy(PIX **ppix)
pixDestroy()
Definition: pix1.c:608
l_ok pixGetDimensions(const PIX *pix, l_int32 *pw, l_int32 *ph, l_int32 *pd)
pixGetDimensions()
Definition: pix1.c:1074
PIX * pixCopy(PIX *pixd, const PIX *pixs)
pixCopy()
Definition: pix1.c:689
PIX * pixCreateTemplate(const PIX *pixs)
pixCreateTemplate()
Definition: pix1.c:380
PIX * pixClone(PIX *pixs)
pixClone()
Definition: pix1.c:582
l_ok pixClearAll(PIX *pix)
pixClearAll()
Definition: pix2.c:773
PIX * pixRemoveBorderGeneral(PIX *pixs, l_int32 left, l_int32 right, l_int32 top, l_int32 bot)
pixRemoveBorderGeneral()
Definition: pix2.c:1996
PIX * pixAddBorder(PIX *pixs, l_int32 npix, l_uint32 val)
pixAddBorder()
Definition: pix2.c:1773
PIX * pixAddBorderGeneral(PIX *pixs, l_int32 left, l_int32 right, l_int32 top, l_int32 bot, l_uint32 val)
pixAddBorderGeneral()
Definition: pix2.c:1863
PIX * pixRemoveBorder(PIX *pixs, l_int32 npix)
pixRemoveBorder()
Definition: pix2.c:1977
l_ok pixSetAll(PIX *pix)
pixSetAll()
Definition: pix2.c:799
#define PIX_DST
Definition: pix.h:445
#define PIX_SRC
Definition: pix.h:444
#define PIX_CLR
Definition: pix.h:447
#define PIX_NOT(op)
Definition: pix.h:446
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:816
l_ok selFindMaxTranslations(SEL *sel, l_int32 *pxp, l_int32 *pyp, l_int32 *pxn, l_int32 *pyn)
selFindMaxTranslations()
Definition: sel1.c:1144
SEL * selCreateComb(l_int32 factor1, l_int32 factor2, l_int32 direction)
selCreateComb()
Definition: sel1.c:452
void selDestroy(SEL **psel)
selDestroy()
Definition: sel1.c:336
SEL * selCreateBrick(l_int32 h, l_int32 w, l_int32 cy, l_int32 cx, l_int32 type)
selCreateBrick()
Definition: sel1.c:410
l_int32 ** data
Definition: morph.h:67