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