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