Logo Search packages:      
Sourcecode: leptonlib version File versions  Download package

morphseq.c

/*====================================================================*
 -  Copyright (C) 2001 Leptonica.  All rights reserved.
 -  This software is distributed in the hope that it will be
 -  useful, but with NO WARRANTY OF ANY KIND.
 -  No author or distributor accepts responsibility to anyone for the
 -  consequences of using this software, or for whether it serves any
 -  particular purpose or works at all, unless he or she says so in
 -  writing.  Everyone is granted permission to copy, modify and
 -  redistribute this source code, for commercial or non-commercial
 -  purposes, with the following restrictions: (1) the origin of this
 -  source code must not be misrepresented; (2) modified versions must
 -  be plainly marked as such; and (3) this notice may not be removed
 -  or altered from any source or modified source distribution.
 *====================================================================*/


/*
 *  morphseq.c
 *
 *      Run a sequence of morphological operations
 *            PIX     *pixMorphSequence()
 *
 */

#include <stdio.h>
#include <stdlib.h>
#include "allheaders.h"


/*-----------------------------------------------------------------*
 *            Run a sequence of morphological operations           *
 *-----------------------------------------------------------------*/
/*!
 *  pixMorphSequence()
 *
 *      Input:  pixs
 *              sequence (string specifying sequence)
 *              dispsep (horizontal separation in pixels between
 *                       successive displays; use zero to suppress display)
 *      Return: pixd, or null on error
 *
 *  Notes:
 *      (1) This works on binary images.
 *      (2) This runs a pipeline of operations; no branching is allowed.
 *      (3) This only uses brick SELs, which are created on the fly.
 *          In the future this will be generalized to extract SELs from
 *          a SELA by name.
 *      (4) A new image is always produced; the input image is not changed.
 *      (5) This contains an interpreter, allowing sequences to be
 *          generated and run.
 *      (6) The format of the sequence string is defined below.
 *      (7) In addition to morphological operations, rank order reduction
 *          and replicated expansion allow operations to take place
 *          downscaled by a power of 2.
 *      (8) Intermediate results can be written to file.
 *      (9) Thanks to Dar-Shyang Lee, who had the idea for this and
 *          built the first implementation.
 *      (10) The sequence string is formatted as follows:
 *            - An arbitrary number of operations,  each separated
 *              by a '+' character.  White space is ignored.
 *            - Each operation begins with a case-independent character
 *              specifying the operation:
 *                 d or D  (dilation)
 *                 e or E  (erosion)
 *                 o or O  (opening)
 *                 c or C  (closing)
 *                 r or R  (rank binary reduction)
 *                 x or X  (replicative binary expansion)
 *            - The args to the morphological operations are bricks of hits,
 *              and are formatted as a.b, where a and b are horizontal and
 *              vertical dimensions, rsp.
 *            - The args to the reduction are a sequence of up to 4 integers,
 *              each from 1 to 4.
 *            - The arg to the expansion is a power of two, in the set
 *              {2, 4, 8, 16}.
 *           An example valid sequence is:
 *             "o1.3 + C3.1 + r22 + e2.2 + D3.2 + X4"
 */
PIX *
pixMorphSequence(PIX         *pixs,
                 const char  *sequence,
             l_int32      dispsep)
{
char    *rawop, *op;
l_int32  nops, i, j, nred, fact, valid, w, h, x, y;
l_int32  level[4];
PIX     *pixt1, *pixt2;
SARRAY  *sa;
SEL     *sel;

    PROCNAME("pixMorphSequence");

    if (!pixs)
      return (PIX *)ERROR_PTR("pixs not defined", procName, NULL);
    if (!sequence)
      return (PIX *)ERROR_PTR("sequence not defined", procName, NULL);

        /* Split sequence into individual operations */
    sa = sarrayCreate(0);
    sarraySplitString(sa, sequence, "+");
    nops = sarrayGetCount(sa);

      /* Verify that the operation sequence is valid */
    valid = TRUE;
    for (i = 0; i < nops; i++) {
        rawop = sarrayGetString(sa, i, 0);
      op = stringRemoveChars(rawop, " \n\t");
      switch (op[0])
      {
      case 'd':
      case 'D':
      case 'e':
      case 'E':
      case 'o':
      case 'O':
      case 'c':
      case 'C':
          if (sscanf(&op[1], "%d.%d", &w, &h) != 2) {
              fprintf(stderr, "*** op: %s invalid\n", op);
            valid = FALSE;
            break;
          }
            if (w <= 0 || h <= 0) {
              fprintf(stderr,
                        "*** op: %s; w = %d, h = %d; must both be > 0\n",
                        op, w, h);
            valid = FALSE;
            break;
          }
/*        fprintf(stderr, "op = %s; w = %d, h = %d\n", op, w, h); */
          break;
      case 'r':
      case 'R':
          nred = strlen(op) - 1;
          if (nred < 1 || nred > 4) {
            fprintf(stderr,
                        "*** op = %s; num reduct = %d; must be in {1,2,3,4}\n",
                        op, nred);
            valid = FALSE;
            break;
          }
          for (j = 0; j < nred; j++) {
              level[j] = op[j + 1] - '0';
            if (level[j] < 1 || level[j] > 4) {
                fprintf(stderr, "*** op = %s; level[%d] = %d is invalid\n",
                            op, j, level[j]);
                valid = FALSE;
                    break;
            }
          }
            if (!valid)
                break;
/*        fprintf(stderr, "op = %s", op); */
          for (j = 0; j < nred; j++) {
              level[j] = op[j + 1] - '0';
/*          fprintf(stderr, ", level[%d] = %d", j, level[j]); */
            }
/*        fprintf(stderr, "\n"); */
          break;
      case 'x':
      case 'X':
            if (sscanf(&op[1], "%d", &fact) != 1) {
              fprintf(stderr, "*** op: %s; fact invalid\n", op);
            valid = FALSE;
            break;
          }
          if (fact != 2 && fact != 4 && fact != 8 && fact != 16) {
              fprintf(stderr, "*** op = %s; invalid fact = %d\n", op, fact);
            valid = FALSE;
            break;
          }
/*        fprintf(stderr, "op = %s; fact = %d\n", op, fact); */
          break;
      default:
          fprintf(stderr, "*** nonexistent op = %s\n", op);
          valid = FALSE;
      }
      FREE((void *)op);
    }
    if (!valid) {
        sarrayDestroy(&sa);
      return (PIX *)ERROR_PTR("sequence invalid", procName, NULL);
    }

        /* Parse and operate */
    pixt1 = pixCopy(NULL, pixs);
    pixt2 = NULL;
    x = y = 0;
    for (i = 0; i < nops; i++) {
        rawop = sarrayGetString(sa, i, 0);
      op = stringRemoveChars(rawop, " \n\t");
      switch (op[0])
      {
      case 'd':
      case 'D':
          sscanf(&op[1], "%d.%d", &w, &h);
          sel = selCreateBrick(h, w, h / 2, w / 2, SEL_HIT);
            pixt2 = pixDilate(NULL, pixt1, sel);
          pixDestroy(&pixt1);
            pixt1 = pixClone(pixt2);
            pixDestroy(&pixt2);
          selDestroy(&sel);
            if (dispsep > 0) {
                pixDisplay(pixt1, x, y);
                x += dispsep;
            }
          break;
      case 'e':
      case 'E':
          sscanf(&op[1], "%d.%d", &w, &h);
          sel = selCreateBrick(h, w, h / 2, w / 2, SEL_HIT);
            pixt2 = pixErode(NULL, pixt1, sel);
            pixDestroy(&pixt1);
            pixt1 = pixClone(pixt2);
            pixDestroy(&pixt2);
          selDestroy(&sel);
            if (dispsep > 0) {
                pixDisplay(pixt1, x, y);
                x += dispsep;
            }
          break;
      case 'o':
      case 'O':
          sscanf(&op[1], "%d.%d", &w, &h);
          sel = selCreateBrick(h, w, h / 2, w / 2, SEL_HIT);
            pixOpen(pixt1, pixt1, sel);
          selDestroy(&sel);
            if (dispsep > 0) {
                pixDisplay(pixt1, x, y);
                x += dispsep;
            }
          break;
      case 'c':
      case 'C':
          sscanf(&op[1], "%d.%d", &w, &h);
          sel = selCreateBrick(h, w, h / 2, w / 2, SEL_HIT);
            pixCloseSafe(pixt1, pixt1, sel);
          selDestroy(&sel);
            if (dispsep > 0) {
                pixDisplay(pixt1, x, y);
                x += dispsep;
            }
          break;
      case 'r':
      case 'R':
          nred = strlen(op) - 1;
          for (j = 0; j < nred; j++)
              level[j] = op[j + 1] - '0';
            for (j = nred; j < 4; j++)
              level[j] = 0;
            pixt2 = pixReduceRankBinaryCascade(pixt1, level[0], level[1],
                                               level[2], level[3]);
            pixDestroy(&pixt1);
            pixt1 = pixClone(pixt2);
            pixDestroy(&pixt2);
            if (dispsep > 0) {
                pixDisplay(pixt1, x, y);
                x += dispsep;
            }
          break;
      case 'x':
      case 'X':
            sscanf(&op[1], "%d", &fact);
            pixt2 = pixExpandBinary(pixt1, fact);
            pixDestroy(&pixt1);
            pixt1 = pixClone(pixt2);
            pixDestroy(&pixt2);
            if (dispsep > 0) {
                pixDisplay(pixt1, x, y);
                x += dispsep;
            }
          break;
        default:
          /* All invalid ops are caught in the first pass */
          break;
      }
      FREE((void *)op);
    }

    sarrayDestroy(&sa);
    return pixt1;
}



Generated by  Doxygen 1.6.0   Back to index