Leptonica  1.77.0
Image processing and image analysis suite
morphseq.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 
54 #include <string.h>
55 #include "allheaders.h"
56 
57 /*-------------------------------------------------------------------------*
58  * Run a sequence of binary rasterop morphological operations *
59  *-------------------------------------------------------------------------*/
132 PIX *
134  const char *sequence,
135  l_int32 dispsep)
136 {
137 char *rawop, *op;
138 char fname[256];
139 l_int32 nops, i, j, nred, fact, w, h, x, border, pdfout;
140 l_int32 level[4];
141 PIX *pix1, *pix2;
142 PIXA *pixa;
143 SARRAY *sa;
144 
145  PROCNAME("pixMorphSequence");
146 
147  if (!pixs)
148  return (PIX *)ERROR_PTR("pixs not defined", procName, NULL);
149  if (!sequence)
150  return (PIX *)ERROR_PTR("sequence not defined", procName, NULL);
151 
152  /* Split sequence into individual operations */
153  sa = sarrayCreate(0);
154  sarraySplitString(sa, sequence, "+");
155  nops = sarrayGetCount(sa);
156  pdfout = (dispsep < 0) ? 1 : 0;
157  if (!morphSequenceVerify(sa)) {
158  sarrayDestroy(&sa);
159  return (PIX *)ERROR_PTR("sequence not valid", procName, NULL);
160  }
161 
162  /* Parse and operate */
163  pixa = NULL;
164  if (pdfout) {
165  pixa = pixaCreate(0);
166  pixaAddPix(pixa, pixs, L_CLONE);
167  }
168  border = 0;
169  pix1 = pixCopy(NULL, pixs);
170  pix2 = NULL;
171  x = 0;
172  for (i = 0; i < nops; i++) {
173  rawop = sarrayGetString(sa, i, L_NOCOPY);
174  op = stringRemoveChars(rawop, " \n\t");
175  switch (op[0])
176  {
177  case 'd':
178  case 'D':
179  sscanf(&op[1], "%d.%d", &w, &h);
180  pix2 = pixDilateBrick(NULL, pix1, w, h);
181  pixSwapAndDestroy(&pix1, &pix2);
182  break;
183  case 'e':
184  case 'E':
185  sscanf(&op[1], "%d.%d", &w, &h);
186  pix2 = pixErodeBrick(NULL, pix1, w, h);
187  pixSwapAndDestroy(&pix1, &pix2);
188  break;
189  case 'o':
190  case 'O':
191  sscanf(&op[1], "%d.%d", &w, &h);
192  pixOpenBrick(pix1, pix1, w, h);
193  break;
194  case 'c':
195  case 'C':
196  sscanf(&op[1], "%d.%d", &w, &h);
197  pixCloseSafeBrick(pix1, pix1, w, h);
198  break;
199  case 'r':
200  case 'R':
201  nred = strlen(op) - 1;
202  for (j = 0; j < nred; j++)
203  level[j] = op[j + 1] - '0';
204  for (j = nred; j < 4; j++)
205  level[j] = 0;
206  pix2 = pixReduceRankBinaryCascade(pix1, level[0], level[1],
207  level[2], level[3]);
208  pixSwapAndDestroy(&pix1, &pix2);
209  break;
210  case 'x':
211  case 'X':
212  sscanf(&op[1], "%d", &fact);
213  pix2 = pixExpandReplicate(pix1, fact);
214  pixSwapAndDestroy(&pix1, &pix2);
215  break;
216  case 'b':
217  case 'B':
218  sscanf(&op[1], "%d", &border);
219  pix2 = pixAddBorder(pix1, border, 0);
220  pixSwapAndDestroy(&pix1, &pix2);
221  break;
222  default:
223  /* All invalid ops are caught in the first pass */
224  break;
225  }
226  LEPT_FREE(op);
227 
228  /* Debug output */
229  if (dispsep > 0) {
230  pixDisplay(pix1, x, 0);
231  x += dispsep;
232  }
233  if (pdfout)
234  pixaAddPix(pixa, pix1, L_COPY);
235  }
236  if (border > 0) {
237  pix2 = pixRemoveBorder(pix1, border);
238  pixSwapAndDestroy(&pix1, &pix2);
239  }
240 
241  if (pdfout) {
242  snprintf(fname, sizeof(fname), "/tmp/lept/seq_output_%d.pdf",
243  L_ABS(dispsep));
244  pixaConvertToPdf(pixa, 0, 1.0, L_FLATE_ENCODE, 0, fname, fname);
245  pixaDestroy(&pixa);
246  }
247 
248  sarrayDestroy(&sa);
249  return pix1;
250 }
251 
252 
253 /*-------------------------------------------------------------------------*
254  * Run a sequence of binary composite rasterop morphological operations *
255  *-------------------------------------------------------------------------*/
299 PIX *
301  const char *sequence,
302  l_int32 dispsep)
303 {
304 char *rawop, *op;
305 char fname[256];
306 l_int32 nops, i, j, nred, fact, w, h, x, border, pdfout;
307 l_int32 level[4];
308 PIX *pix1, *pix2;
309 PIXA *pixa;
310 SARRAY *sa;
311 
312  PROCNAME("pixMorphCompSequence");
313 
314  if (!pixs)
315  return (PIX *)ERROR_PTR("pixs not defined", procName, NULL);
316  if (!sequence)
317  return (PIX *)ERROR_PTR("sequence not defined", procName, NULL);
318 
319  /* Split sequence into individual operations */
320  sa = sarrayCreate(0);
321  sarraySplitString(sa, sequence, "+");
322  nops = sarrayGetCount(sa);
323  pdfout = (dispsep < 0) ? 1 : 0;
324 
325  if (!morphSequenceVerify(sa)) {
326  sarrayDestroy(&sa);
327  return (PIX *)ERROR_PTR("sequence not valid", procName, NULL);
328  }
329 
330  /* Parse and operate */
331  pixa = NULL;
332  if (pdfout) {
333  pixa = pixaCreate(0);
334  pixaAddPix(pixa, pixs, L_CLONE);
335  }
336  border = 0;
337  pix1 = pixCopy(NULL, pixs);
338  pix2 = NULL;
339  x = 0;
340  for (i = 0; i < nops; i++) {
341  rawop = sarrayGetString(sa, i, L_NOCOPY);
342  op = stringRemoveChars(rawop, " \n\t");
343  switch (op[0])
344  {
345  case 'd':
346  case 'D':
347  sscanf(&op[1], "%d.%d", &w, &h);
348  pix2 = pixDilateCompBrick(NULL, pix1, w, h);
349  pixSwapAndDestroy(&pix1, &pix2);
350  break;
351  case 'e':
352  case 'E':
353  sscanf(&op[1], "%d.%d", &w, &h);
354  pix2 = pixErodeCompBrick(NULL, pix1, w, h);
355  pixSwapAndDestroy(&pix1, &pix2);
356  break;
357  case 'o':
358  case 'O':
359  sscanf(&op[1], "%d.%d", &w, &h);
360  pixOpenCompBrick(pix1, pix1, w, h);
361  break;
362  case 'c':
363  case 'C':
364  sscanf(&op[1], "%d.%d", &w, &h);
365  pixCloseSafeCompBrick(pix1, pix1, w, h);
366  break;
367  case 'r':
368  case 'R':
369  nred = strlen(op) - 1;
370  for (j = 0; j < nred; j++)
371  level[j] = op[j + 1] - '0';
372  for (j = nred; j < 4; j++)
373  level[j] = 0;
374  pix2 = pixReduceRankBinaryCascade(pix1, level[0], level[1],
375  level[2], level[3]);
376  pixSwapAndDestroy(&pix1, &pix2);
377  break;
378  case 'x':
379  case 'X':
380  sscanf(&op[1], "%d", &fact);
381  pix2 = pixExpandReplicate(pix1, fact);
382  pixSwapAndDestroy(&pix1, &pix2);
383  break;
384  case 'b':
385  case 'B':
386  sscanf(&op[1], "%d", &border);
387  pix2 = pixAddBorder(pix1, border, 0);
388  pixSwapAndDestroy(&pix1, &pix2);
389  break;
390  default:
391  /* All invalid ops are caught in the first pass */
392  break;
393  }
394  LEPT_FREE(op);
395 
396  /* Debug output */
397  if (dispsep > 0) {
398  pixDisplay(pix1, x, 0);
399  x += dispsep;
400  }
401  if (pdfout)
402  pixaAddPix(pixa, pix1, L_COPY);
403  }
404  if (border > 0) {
405  pix2 = pixRemoveBorder(pix1, border);
406  pixSwapAndDestroy(&pix1, &pix2);
407  }
408 
409  if (pdfout) {
410  snprintf(fname, sizeof(fname), "/tmp/lept/seq_output_%d.pdf",
411  L_ABS(dispsep));
412  pixaConvertToPdf(pixa, 0, 1.0, L_FLATE_ENCODE, 0, fname, fname);
413  pixaDestroy(&pixa);
414  }
415 
416  sarrayDestroy(&sa);
417  return pix1;
418 }
419 
420 
421 /*-------------------------------------------------------------------------*
422  * Run a sequence of binary dwa morphological operations *
423  *-------------------------------------------------------------------------*/
448 PIX *
450  const char *sequence,
451  l_int32 dispsep)
452 {
453 char *rawop, *op;
454 char fname[256];
455 l_int32 nops, i, j, nred, fact, w, h, x, border, pdfout;
456 l_int32 level[4];
457 PIX *pix1, *pix2;
458 PIXA *pixa;
459 SARRAY *sa;
460 
461  PROCNAME("pixMorphSequenceDwa");
462 
463  if (!pixs)
464  return (PIX *)ERROR_PTR("pixs not defined", procName, NULL);
465  if (!sequence)
466  return (PIX *)ERROR_PTR("sequence not defined", procName, NULL);
467 
468  /* Split sequence into individual operations */
469  sa = sarrayCreate(0);
470  sarraySplitString(sa, sequence, "+");
471  nops = sarrayGetCount(sa);
472  pdfout = (dispsep < 0) ? 1 : 0;
473 
474  if (!morphSequenceVerify(sa)) {
475  sarrayDestroy(&sa);
476  return (PIX *)ERROR_PTR("sequence not valid", procName, NULL);
477  }
478 
479  /* Parse and operate */
480  pixa = NULL;
481  if (pdfout) {
482  pixa = pixaCreate(0);
483  pixaAddPix(pixa, pixs, L_CLONE);
484  }
485  border = 0;
486  pix1 = pixCopy(NULL, pixs);
487  pix2 = NULL;
488  x = 0;
489  for (i = 0; i < nops; i++) {
490  rawop = sarrayGetString(sa, i, L_NOCOPY);
491  op = stringRemoveChars(rawop, " \n\t");
492  switch (op[0])
493  {
494  case 'd':
495  case 'D':
496  sscanf(&op[1], "%d.%d", &w, &h);
497  pix2 = pixDilateBrickDwa(NULL, pix1, w, h);
498  pixSwapAndDestroy(&pix1, &pix2);
499  break;
500  case 'e':
501  case 'E':
502  sscanf(&op[1], "%d.%d", &w, &h);
503  pix2 = pixErodeBrickDwa(NULL, pix1, w, h);
504  pixSwapAndDestroy(&pix1, &pix2);
505  break;
506  case 'o':
507  case 'O':
508  sscanf(&op[1], "%d.%d", &w, &h);
509  pixOpenBrickDwa(pix1, pix1, w, h);
510  break;
511  case 'c':
512  case 'C':
513  sscanf(&op[1], "%d.%d", &w, &h);
514  pixCloseBrickDwa(pix1, pix1, w, h);
515  break;
516  case 'r':
517  case 'R':
518  nred = strlen(op) - 1;
519  for (j = 0; j < nred; j++)
520  level[j] = op[j + 1] - '0';
521  for (j = nred; j < 4; j++)
522  level[j] = 0;
523  pix2 = pixReduceRankBinaryCascade(pix1, level[0], level[1],
524  level[2], level[3]);
525  pixSwapAndDestroy(&pix1, &pix2);
526  break;
527  case 'x':
528  case 'X':
529  sscanf(&op[1], "%d", &fact);
530  pix2 = pixExpandReplicate(pix1, fact);
531  pixSwapAndDestroy(&pix1, &pix2);
532  break;
533  case 'b':
534  case 'B':
535  sscanf(&op[1], "%d", &border);
536  pix2 = pixAddBorder(pix1, border, 0);
537  pixSwapAndDestroy(&pix1, &pix2);
538  break;
539  default:
540  /* All invalid ops are caught in the first pass */
541  break;
542  }
543  LEPT_FREE(op);
544 
545  /* Debug output */
546  if (dispsep > 0) {
547  pixDisplay(pix1, x, 0);
548  x += dispsep;
549  }
550  if (pdfout)
551  pixaAddPix(pixa, pix1, L_COPY);
552  }
553  if (border > 0) {
554  pix2 = pixRemoveBorder(pix1, border);
555  pixSwapAndDestroy(&pix1, &pix2);
556  }
557 
558  if (pdfout) {
559  snprintf(fname, sizeof(fname), "/tmp/lept/seq_output_%d.pdf",
560  L_ABS(dispsep));
561  pixaConvertToPdf(pixa, 0, 1.0, L_FLATE_ENCODE, 0, fname, fname);
562  pixaDestroy(&pixa);
563  }
564 
565  sarrayDestroy(&sa);
566  return pix1;
567 }
568 
569 
570 /*-------------------------------------------------------------------------*
571  * Run a sequence of binary composite dwa morphological operations *
572  *-------------------------------------------------------------------------*/
597 PIX *
599  const char *sequence,
600  l_int32 dispsep)
601 {
602 char *rawop, *op;
603 char fname[256];
604 l_int32 nops, i, j, nred, fact, w, h, x, border, pdfout;
605 l_int32 level[4];
606 PIX *pix1, *pix2;
607 PIXA *pixa;
608 SARRAY *sa;
609 
610  PROCNAME("pixMorphCompSequenceDwa");
611 
612  if (!pixs)
613  return (PIX *)ERROR_PTR("pixs not defined", procName, NULL);
614  if (!sequence)
615  return (PIX *)ERROR_PTR("sequence not defined", procName, NULL);
616 
617  /* Split sequence into individual operations */
618  sa = sarrayCreate(0);
619  sarraySplitString(sa, sequence, "+");
620  nops = sarrayGetCount(sa);
621  pdfout = (dispsep < 0) ? 1 : 0;
622 
623  if (!morphSequenceVerify(sa)) {
624  sarrayDestroy(&sa);
625  return (PIX *)ERROR_PTR("sequence not valid", procName, NULL);
626  }
627 
628  /* Parse and operate */
629  pixa = NULL;
630  if (pdfout) {
631  pixa = pixaCreate(0);
632  pixaAddPix(pixa, pixs, L_CLONE);
633  }
634  border = 0;
635  pix1 = pixCopy(NULL, pixs);
636  pix2 = NULL;
637  x = 0;
638  for (i = 0; i < nops; i++) {
639  rawop = sarrayGetString(sa, i, L_NOCOPY);
640  op = stringRemoveChars(rawop, " \n\t");
641  switch (op[0])
642  {
643  case 'd':
644  case 'D':
645  sscanf(&op[1], "%d.%d", &w, &h);
646  pix2 = pixDilateCompBrickDwa(NULL, pix1, w, h);
647  pixSwapAndDestroy(&pix1, &pix2);
648  break;
649  case 'e':
650  case 'E':
651  sscanf(&op[1], "%d.%d", &w, &h);
652  pix2 = pixErodeCompBrickDwa(NULL, pix1, w, h);
653  pixSwapAndDestroy(&pix1, &pix2);
654  break;
655  case 'o':
656  case 'O':
657  sscanf(&op[1], "%d.%d", &w, &h);
658  pixOpenCompBrickDwa(pix1, pix1, w, h);
659  break;
660  case 'c':
661  case 'C':
662  sscanf(&op[1], "%d.%d", &w, &h);
663  pixCloseCompBrickDwa(pix1, pix1, w, h);
664  break;
665  case 'r':
666  case 'R':
667  nred = strlen(op) - 1;
668  for (j = 0; j < nred; j++)
669  level[j] = op[j + 1] - '0';
670  for (j = nred; j < 4; j++)
671  level[j] = 0;
672  pix2 = pixReduceRankBinaryCascade(pix1, level[0], level[1],
673  level[2], level[3]);
674  pixSwapAndDestroy(&pix1, &pix2);
675  break;
676  case 'x':
677  case 'X':
678  sscanf(&op[1], "%d", &fact);
679  pix2 = pixExpandReplicate(pix1, fact);
680  pixSwapAndDestroy(&pix1, &pix2);
681  break;
682  case 'b':
683  case 'B':
684  sscanf(&op[1], "%d", &border);
685  pix2 = pixAddBorder(pix1, border, 0);
686  pixSwapAndDestroy(&pix1, &pix2);
687  break;
688  default:
689  /* All invalid ops are caught in the first pass */
690  break;
691  }
692  LEPT_FREE(op);
693 
694  /* Debug output */
695  if (dispsep > 0) {
696  pixDisplay(pix1, x, 0);
697  x += dispsep;
698  }
699  if (pdfout)
700  pixaAddPix(pixa, pix1, L_COPY);
701  }
702  if (border > 0) {
703  pix2 = pixRemoveBorder(pix1, border);
704  pixSwapAndDestroy(&pix1, &pix2);
705  }
706 
707  if (pdfout) {
708  snprintf(fname, sizeof(fname), "/tmp/lept/seq_output_%d.pdf",
709  L_ABS(dispsep));
710  pixaConvertToPdf(pixa, 0, 1.0, L_FLATE_ENCODE, 0, fname, fname);
711  pixaDestroy(&pixa);
712  }
713 
714  sarrayDestroy(&sa);
715  return pix1;
716 }
717 
718 
719 /*-------------------------------------------------------------------------*
720  * Parser verifier for binary morphological operations *
721  *-------------------------------------------------------------------------*/
736 l_int32
738 {
739 char *rawop, *op;
740 l_int32 nops, i, j, nred, fact, valid, w, h, netred, border;
741 l_int32 level[4];
742 l_int32 intlogbase2[5] = {1, 2, 3, 0, 4}; /* of arg/4 */
743 
744  PROCNAME("morphSequenceVerify");
745 
746  if (!sa)
747  return ERROR_INT("sa not defined", procName, FALSE);
748 
749  nops = sarrayGetCount(sa);
750  valid = TRUE;
751  netred = 0;
752  border = 0;
753  for (i = 0; i < nops; i++) {
754  rawop = sarrayGetString(sa, i, L_NOCOPY);
755  op = stringRemoveChars(rawop, " \n\t");
756  switch (op[0])
757  {
758  case 'd':
759  case 'D':
760  case 'e':
761  case 'E':
762  case 'o':
763  case 'O':
764  case 'c':
765  case 'C':
766  if (sscanf(&op[1], "%d.%d", &w, &h) != 2) {
767  fprintf(stderr, "*** op: %s invalid\n", op);
768  valid = FALSE;
769  break;
770  }
771  if (w <= 0 || h <= 0) {
772  fprintf(stderr,
773  "*** op: %s; w = %d, h = %d; must both be > 0\n",
774  op, w, h);
775  valid = FALSE;
776  break;
777  }
778 /* fprintf(stderr, "op = %s; w = %d, h = %d\n", op, w, h); */
779  break;
780  case 'r':
781  case 'R':
782  nred = strlen(op) - 1;
783  netred += nred;
784  if (nred < 1 || nred > 4) {
785  fprintf(stderr,
786  "*** op = %s; num reduct = %d; must be in {1,2,3,4}\n",
787  op, nred);
788  valid = FALSE;
789  break;
790  }
791  for (j = 0; j < nred; j++) {
792  level[j] = op[j + 1] - '0';
793  if (level[j] < 1 || level[j] > 4) {
794  fprintf(stderr, "*** op = %s; level[%d] = %d is invalid\n",
795  op, j, level[j]);
796  valid = FALSE;
797  break;
798  }
799  }
800  if (!valid)
801  break;
802 /* fprintf(stderr, "op = %s", op); */
803  for (j = 0; j < nred; j++) {
804  level[j] = op[j + 1] - '0';
805 /* fprintf(stderr, ", level[%d] = %d", j, level[j]); */
806  }
807 /* fprintf(stderr, "\n"); */
808  break;
809  case 'x':
810  case 'X':
811  if (sscanf(&op[1], "%d", &fact) != 1) {
812  fprintf(stderr, "*** op: %s; fact invalid\n", op);
813  valid = FALSE;
814  break;
815  }
816  if (fact != 2 && fact != 4 && fact != 8 && fact != 16) {
817  fprintf(stderr, "*** op = %s; invalid fact = %d\n", op, fact);
818  valid = FALSE;
819  break;
820  }
821  netred -= intlogbase2[fact / 4];
822 /* fprintf(stderr, "op = %s; fact = %d\n", op, fact); */
823  break;
824  case 'b':
825  case 'B':
826  if (sscanf(&op[1], "%d", &fact) != 1) {
827  fprintf(stderr, "*** op: %s; fact invalid\n", op);
828  valid = FALSE;
829  break;
830  }
831  if (i > 0) {
832  fprintf(stderr, "*** op = %s; must be first op\n", op);
833  valid = FALSE;
834  break;
835  }
836  if (fact < 1) {
837  fprintf(stderr, "*** op = %s; invalid fact = %d\n", op, fact);
838  valid = FALSE;
839  break;
840  }
841  border = fact;
842 /* fprintf(stderr, "op = %s; fact = %d\n", op, fact); */
843  break;
844  default:
845  fprintf(stderr, "*** nonexistent op = %s\n", op);
846  valid = FALSE;
847  }
848  LEPT_FREE(op);
849  }
850 
851  if (border != 0 && netred != 0) {
852  fprintf(stderr,
853  "*** op = %s; border added but net reduction not 0\n", op);
854  valid = FALSE;
855  }
856  return valid;
857 }
858 
859 
860 /*-----------------------------------------------------------------*
861  * Run a sequence of grayscale morphological operations *
862  *-----------------------------------------------------------------*/
911 PIX *
913  const char *sequence,
914  l_int32 dispsep,
915  l_int32 dispy)
916 {
917 char *rawop, *op;
918 char fname[256];
919 l_int32 nops, i, valid, w, h, x, pdfout;
920 PIX *pix1, *pix2;
921 PIXA *pixa;
922 SARRAY *sa;
923 
924  PROCNAME("pixGrayMorphSequence");
925 
926  if (!pixs)
927  return (PIX *)ERROR_PTR("pixs not defined", procName, NULL);
928  if (!sequence)
929  return (PIX *)ERROR_PTR("sequence not defined", procName, NULL);
930 
931  /* Split sequence into individual operations */
932  sa = sarrayCreate(0);
933  sarraySplitString(sa, sequence, "+");
934  nops = sarrayGetCount(sa);
935  pdfout = (dispsep < 0) ? 1 : 0;
936 
937  /* Verify that the operation sequence is valid */
938  valid = TRUE;
939  for (i = 0; i < nops; i++) {
940  rawop = sarrayGetString(sa, i, L_NOCOPY);
941  op = stringRemoveChars(rawop, " \n\t");
942  switch (op[0])
943  {
944  case 'd':
945  case 'D':
946  case 'e':
947  case 'E':
948  case 'o':
949  case 'O':
950  case 'c':
951  case 'C':
952  if (sscanf(&op[1], "%d.%d", &w, &h) != 2) {
953  fprintf(stderr, "*** op: %s invalid\n", op);
954  valid = FALSE;
955  break;
956  }
957  if (w < 1 || (w & 1) == 0 || h < 1 || (h & 1) == 0 ) {
958  fprintf(stderr,
959  "*** op: %s; w = %d, h = %d; must both be odd\n",
960  op, w, h);
961  valid = FALSE;
962  break;
963  }
964 /* fprintf(stderr, "op = %s; w = %d, h = %d\n", op, w, h); */
965  break;
966  case 't':
967  case 'T':
968  if (op[1] != 'w' && op[1] != 'W' &&
969  op[1] != 'b' && op[1] != 'B') {
970  fprintf(stderr,
971  "*** op = %s; arg %c must be 'w' or 'b'\n", op, op[1]);
972  valid = FALSE;
973  break;
974  }
975  sscanf(&op[2], "%d.%d", &w, &h);
976  if (w < 1 || (w & 1) == 0 || h < 1 || (h & 1) == 0 ) {
977  fprintf(stderr,
978  "*** op: %s; w = %d, h = %d; must both be odd\n",
979  op, w, h);
980  valid = FALSE;
981  break;
982  }
983 /* fprintf(stderr, "op = %s", op); */
984  break;
985  default:
986  fprintf(stderr, "*** nonexistent op = %s\n", op);
987  valid = FALSE;
988  }
989  LEPT_FREE(op);
990  }
991  if (!valid) {
992  sarrayDestroy(&sa);
993  return (PIX *)ERROR_PTR("sequence invalid", procName, NULL);
994  }
995 
996  /* Parse and operate */
997  pixa = NULL;
998  if (pdfout) {
999  pixa = pixaCreate(0);
1000  pixaAddPix(pixa, pixs, L_CLONE);
1001  }
1002  pix1 = pixCopy(NULL, pixs);
1003  pix2 = NULL;
1004  x = 0;
1005  for (i = 0; i < nops; i++) {
1006  rawop = sarrayGetString(sa, i, L_NOCOPY);
1007  op = stringRemoveChars(rawop, " \n\t");
1008  switch (op[0])
1009  {
1010  case 'd':
1011  case 'D':
1012  sscanf(&op[1], "%d.%d", &w, &h);
1013  pix2 = pixDilateGray(pix1, w, h);
1014  pixSwapAndDestroy(&pix1, &pix2);
1015  break;
1016  case 'e':
1017  case 'E':
1018  sscanf(&op[1], "%d.%d", &w, &h);
1019  pix2 = pixErodeGray(pix1, w, h);
1020  pixSwapAndDestroy(&pix1, &pix2);
1021  break;
1022  case 'o':
1023  case 'O':
1024  sscanf(&op[1], "%d.%d", &w, &h);
1025  pix2 = pixOpenGray(pix1, w, h);
1026  pixSwapAndDestroy(&pix1, &pix2);
1027  break;
1028  case 'c':
1029  case 'C':
1030  sscanf(&op[1], "%d.%d", &w, &h);
1031  pix2 = pixCloseGray(pix1, w, h);
1032  pixSwapAndDestroy(&pix1, &pix2);
1033  break;
1034  case 't':
1035  case 'T':
1036  sscanf(&op[2], "%d.%d", &w, &h);
1037  if (op[1] == 'w' || op[1] == 'W')
1038  pix2 = pixTophat(pix1, w, h, L_TOPHAT_WHITE);
1039  else /* 'b' or 'B' */
1040  pix2 = pixTophat(pix1, w, h, L_TOPHAT_BLACK);
1041  pixSwapAndDestroy(&pix1, &pix2);
1042  break;
1043  default:
1044  /* All invalid ops are caught in the first pass */
1045  break;
1046  }
1047  LEPT_FREE(op);
1048 
1049  /* Debug output */
1050  if (dispsep > 0) {
1051  pixDisplay(pix1, x, dispy);
1052  x += dispsep;
1053  }
1054  if (pdfout)
1055  pixaAddPix(pixa, pix1, L_COPY);
1056  }
1057 
1058  if (pdfout) {
1059  snprintf(fname, sizeof(fname), "/tmp/lept/seq_output_%d.pdf",
1060  L_ABS(dispsep));
1061  pixaConvertToPdf(pixa, 0, 1.0, L_FLATE_ENCODE, 0, fname, fname);
1062  pixaDestroy(&pixa);
1063  }
1064 
1065  sarrayDestroy(&sa);
1066  return pix1;
1067 }
1068 
1069 
1070 /*-----------------------------------------------------------------*
1071  * Run a sequence of color morphological operations *
1072  *-----------------------------------------------------------------*/
1116 PIX *
1118  const char *sequence,
1119  l_int32 dispsep,
1120  l_int32 dispy)
1121 {
1122 char *rawop, *op;
1123 char fname[256];
1124 l_int32 nops, i, valid, w, h, x, pdfout;
1125 PIX *pix1, *pix2;
1126 PIXA *pixa;
1127 SARRAY *sa;
1128 
1129  PROCNAME("pixColorMorphSequence");
1130 
1131  if (!pixs)
1132  return (PIX *)ERROR_PTR("pixs not defined", procName, NULL);
1133  if (!sequence)
1134  return (PIX *)ERROR_PTR("sequence not defined", procName, NULL);
1135 
1136  /* Split sequence into individual operations */
1137  sa = sarrayCreate(0);
1138  sarraySplitString(sa, sequence, "+");
1139  nops = sarrayGetCount(sa);
1140  pdfout = (dispsep < 0) ? 1 : 0;
1141 
1142  /* Verify that the operation sequence is valid */
1143  valid = TRUE;
1144  for (i = 0; i < nops; i++) {
1145  rawop = sarrayGetString(sa, i, L_NOCOPY);
1146  op = stringRemoveChars(rawop, " \n\t");
1147  switch (op[0])
1148  {
1149  case 'd':
1150  case 'D':
1151  case 'e':
1152  case 'E':
1153  case 'o':
1154  case 'O':
1155  case 'c':
1156  case 'C':
1157  if (sscanf(&op[1], "%d.%d", &w, &h) != 2) {
1158  fprintf(stderr, "*** op: %s invalid\n", op);
1159  valid = FALSE;
1160  break;
1161  }
1162  if (w < 1 || (w & 1) == 0 || h < 1 || (h & 1) == 0 ) {
1163  fprintf(stderr,
1164  "*** op: %s; w = %d, h = %d; must both be odd\n",
1165  op, w, h);
1166  valid = FALSE;
1167  break;
1168  }
1169 /* fprintf(stderr, "op = %s; w = %d, h = %d\n", op, w, h); */
1170  break;
1171  default:
1172  fprintf(stderr, "*** nonexistent op = %s\n", op);
1173  valid = FALSE;
1174  }
1175  LEPT_FREE(op);
1176  }
1177  if (!valid) {
1178  sarrayDestroy(&sa);
1179  return (PIX *)ERROR_PTR("sequence invalid", procName, NULL);
1180  }
1181 
1182  /* Parse and operate */
1183  pixa = NULL;
1184  if (pdfout) {
1185  pixa = pixaCreate(0);
1186  pixaAddPix(pixa, pixs, L_CLONE);
1187  }
1188  pix1 = pixCopy(NULL, pixs);
1189  pix2 = NULL;
1190  x = 0;
1191  for (i = 0; i < nops; i++) {
1192  rawop = sarrayGetString(sa, i, L_NOCOPY);
1193  op = stringRemoveChars(rawop, " \n\t");
1194  switch (op[0])
1195  {
1196  case 'd':
1197  case 'D':
1198  sscanf(&op[1], "%d.%d", &w, &h);
1199  pix2 = pixColorMorph(pix1, L_MORPH_DILATE, w, h);
1200  pixSwapAndDestroy(&pix1, &pix2);
1201  break;
1202  case 'e':
1203  case 'E':
1204  sscanf(&op[1], "%d.%d", &w, &h);
1205  pix2 = pixColorMorph(pix1, L_MORPH_ERODE, w, h);
1206  pixSwapAndDestroy(&pix1, &pix2);
1207  break;
1208  case 'o':
1209  case 'O':
1210  sscanf(&op[1], "%d.%d", &w, &h);
1211  pix2 = pixColorMorph(pix1, L_MORPH_OPEN, w, h);
1212  pixSwapAndDestroy(&pix1, &pix2);
1213  break;
1214  case 'c':
1215  case 'C':
1216  sscanf(&op[1], "%d.%d", &w, &h);
1217  pix2 = pixColorMorph(pix1, L_MORPH_CLOSE, w, h);
1218  pixSwapAndDestroy(&pix1, &pix2);
1219  break;
1220  default:
1221  /* All invalid ops are caught in the first pass */
1222  break;
1223  }
1224  LEPT_FREE(op);
1225 
1226  /* Debug output */
1227  if (dispsep > 0) {
1228  pixDisplay(pix1, x, dispy);
1229  x += dispsep;
1230  }
1231  if (pdfout)
1232  pixaAddPix(pixa, pix1, L_COPY);
1233  }
1234 
1235  if (pdfout) {
1236  snprintf(fname, sizeof(fname), "/tmp/lept/seq_output_%d.pdf",
1237  L_ABS(dispsep));
1238  pixaConvertToPdf(pixa, 0, 1.0, L_FLATE_ENCODE, 0, fname, fname);
1239  pixaDestroy(&pixa);
1240  }
1241 
1242  sarrayDestroy(&sa);
1243  return pix1;
1244 }
PIX * pixCloseCompBrickDwa(PIX *pixd, PIX *pixs, l_int32 hsize, l_int32 vsize)
pixCloseCompBrickDwa()
Definition: morphdwa.c:1042
PIX * pixDilateGray(PIX *pixs, l_int32 hsize, l_int32 vsize)
pixDilateGray()
Definition: graymorph.c:274
PIXA * pixaCreate(l_int32 n)
pixaCreate()
Definition: pixabasic.c:163
Definition: pix.h:716
PIX * pixCloseGray(PIX *pixs, l_int32 hsize, l_int32 vsize)
pixCloseGray()
Definition: graymorph.c:522
PIX * pixCloseSafeCompBrick(PIX *pixd, PIX *pixs, l_int32 hsize, l_int32 vsize)
pixCloseSafeCompBrick()
Definition: morph.c:1598
PIX * pixMorphCompSequenceDwa(PIX *pixs, const char *sequence, l_int32 dispsep)
pixMorphCompSequenceDwa()
Definition: morphseq.c:598
PIX * pixDilateBrick(PIX *pixd, PIX *pixs, l_int32 hsize, l_int32 vsize)
pixDilateBrick()
Definition: morph.c:684
PIX * pixTophat(PIX *pixs, l_int32 hsize, l_int32 vsize, l_int32 type)
pixTophat()
Definition: morphapp.c:1203
char * stringRemoveChars(const char *src, const char *remchars)
stringRemoveChars()
Definition: utils2.c:813
SARRAY * sarrayCreate(l_int32 n)
sarrayCreate()
Definition: sarray1.c:163
PIX * pixDilateBrickDwa(PIX *pixd, PIX *pixs, l_int32 hsize, l_int32 vsize)
pixDilateBrickDwa()
Definition: morphdwa.c:175
l_int32 morphSequenceVerify(SARRAY *sa)
morphSequenceVerify()
Definition: morphseq.c:737
Definition: array.h:116
PIX * pixAddBorder(PIX *pixs, l_int32 npix, l_uint32 val)
pixAddBorder()
Definition: pix2.c:1748
PIX * pixRemoveBorder(PIX *pixs, l_int32 npix)
pixRemoveBorder()
Definition: pix2.c:1897
l_ok pixaAddPix(PIXA *pixa, PIX *pix, l_int32 copyflag)
pixaAddPix()
Definition: pixabasic.c:503
PIX * pixCloseSafeBrick(PIX *pixd, PIX *pixs, l_int32 hsize, l_int32 vsize)
pixCloseSafeBrick()
Definition: morph.c:949
PIX * pixCloseBrickDwa(PIX *pixd, PIX *pixs, l_int32 hsize, l_int32 vsize)
pixCloseBrickDwa()
Definition: morphdwa.c:486
PIX * pixMorphSequence(PIX *pixs, const char *sequence, l_int32 dispsep)
pixMorphSequence()
Definition: morphseq.c:133
PIX * pixErodeBrickDwa(PIX *pixd, PIX *pixs, l_int32 hsize, l_int32 vsize)
pixErodeBrickDwa()
Definition: morphdwa.c:277
char * sarrayGetString(SARRAY *sa, l_int32 index, l_int32 copyflag)
sarrayGetString()
Definition: sarray1.c:681
PIX * pixDilateCompBrick(PIX *pixd, PIX *pixs, l_int32 hsize, l_int32 vsize)
pixDilateCompBrick()
Definition: morph.c:1204
PIX * pixColorMorphSequence(PIX *pixs, const char *sequence, l_int32 dispsep, l_int32 dispy)
pixColorMorphSequence()
Definition: morphseq.c:1117
Definition: pix.h:454
PIX * pixOpenCompBrickDwa(PIX *pixd, PIX *pixs, l_int32 hsize, l_int32 vsize)
pixOpenCompBrickDwa()
Definition: morphdwa.c:875
PIX * pixOpenBrick(PIX *pixd, PIX *pixs, l_int32 hsize, l_int32 vsize)
pixOpenBrick()
Definition: morph.c:812
l_ok pixSwapAndDestroy(PIX **ppixd, PIX **ppixs)
pixSwapAndDestroy()
Definition: pix1.c:945
l_int32 sarrayGetCount(SARRAY *sa)
sarrayGetCount()
Definition: sarray1.c:621
PIX * pixGrayMorphSequence(PIX *pixs, const char *sequence, l_int32 dispsep, l_int32 dispy)
pixGrayMorphSequence()
Definition: morphseq.c:912
PIX * pixExpandReplicate(PIX *pixs, l_int32 factor)
pixExpandReplicate()
Definition: scale2.c:867
l_ok pixaConvertToPdf(PIXA *pixa, l_int32 res, l_float32 scalefactor, l_int32 type, l_int32 quality, const char *title, const char *fileout)
pixaConvertToPdf()
Definition: pdfio1.c:752
PIX * pixOpenBrickDwa(PIX *pixd, PIX *pixs, l_int32 hsize, l_int32 vsize)
pixOpenBrickDwa()
Definition: morphdwa.c:379
Definition: pix.h:718
PIX * pixErodeCompBrick(PIX *pixd, PIX *pixs, l_int32 hsize, l_int32 vsize)
pixErodeCompBrick()
Definition: morph.c:1304
Definition: pix.h:134
Definition: pix.h:719
PIX * pixCopy(PIX *pixd, PIX *pixs)
pixCopy()
Definition: pix1.c:628
PIX * pixMorphSequenceDwa(PIX *pixs, const char *sequence, l_int32 dispsep)
pixMorphSequenceDwa()
Definition: morphseq.c:449
PIX * pixErodeBrick(PIX *pixd, PIX *pixs, l_int32 hsize, l_int32 vsize)
pixErodeBrick()
Definition: morph.c:748
PIX * pixDilateCompBrickDwa(PIX *pixd, PIX *pixs, l_int32 hsize, l_int32 vsize)
pixDilateCompBrickDwa()
Definition: morphdwa.c:613
PIX * pixErodeCompBrickDwa(PIX *pixd, PIX *pixs, l_int32 hsize, l_int32 vsize)
pixErodeCompBrickDwa()
Definition: morphdwa.c:746
PIX * pixReduceRankBinaryCascade(PIX *pixs, l_int32 level1, l_int32 level2, l_int32 level3, l_int32 level4)
pixReduceRankBinaryCascade()
Definition: binreduce.c:148
void pixaDestroy(PIXA **ppixa)
pixaDestroy()
Definition: pixabasic.c:408
PIX * pixOpenGray(PIX *pixs, l_int32 hsize, l_int32 vsize)
pixOpenGray()
Definition: graymorph.c:390
PIX * pixErodeGray(PIX *pixs, l_int32 hsize, l_int32 vsize)
pixErodeGray()
Definition: graymorph.c:158
PIX * pixOpenCompBrick(PIX *pixd, PIX *pixs, l_int32 hsize, l_int32 vsize)
pixOpenCompBrick()
Definition: morph.c:1395
void sarrayDestroy(SARRAY **psa)
sarrayDestroy()
Definition: sarray1.c:355
PIX * pixColorMorph(PIX *pixs, l_int32 type, l_int32 hsize, l_int32 vsize)
pixColorMorph()
Definition: colormorph.c:66
PIX * pixMorphCompSequence(PIX *pixs, const char *sequence, l_int32 dispsep)
pixMorphCompSequence()
Definition: morphseq.c:300