Пример #1
0
/*
 *  pushWSPixel()
 *
 *      Input:  lh  (priority queue)
 *              stack  (of reusable WSPixels)
 *              val  (pixel value: used for ordering the heap)
 *              x, y  (pixel coordinates)
 *              index  (label for set to which pixel belongs)
 *      Return: void
 *
 *  Notes:
 *      (1) This is a wrapper for adding a WSPixel to a heap.  It
 *          uses the storage stack to retrieve a WSPixel.
 */
static void
pushWSPixel(L_HEAP *lh,
            L_STACK *stack,
            l_int32 val,
            l_int32 x,
            l_int32 y,
            l_int32 index) {
    L_WSPIXEL *wsp;

    PROCNAME("pushWSPixel");

    if (!lh) {
        L_ERROR("heap not defined\n", procName);
        return;
    }
    if (!stack) {
        L_ERROR("stack not defined\n", procName);
        return;
    }

    /* Get a wspixel to use */
    if (lstackGetCount(stack) > 0)
        wsp = (L_WSPIXEL *) lstackRemove(stack);
    else
        wsp = (L_WSPIXEL *) CALLOC(1, sizeof(L_WSPIXEL));

    wsp->val = (l_float32) val;
    wsp->x = x;
    wsp->y = y;
    wsp->index = index;
    lheapAdd(lh, wsp);
    return;
}
Пример #2
0
/*
 *  pushNewPixel()
 *
 *      Input:  lqueue
 *              x, y   (pixel coordinates)
 *              &minx, &maxx, &miny, &maxy  (<return> bounding box update)
 *      Return: void
 *
 *  Notes:
 *      (1) This is a wrapper for adding a NewPixel to a queue, which
 *          updates the bounding box for all pixels on that queue and
 *          uses the storage stack to retrieve a NewPixel.
 */
static void
pushNewPixel(L_QUEUE *lq,
             l_int32 x,
             l_int32 y,
             l_int32 *pminx,
             l_int32 *pmaxx,
             l_int32 *pminy,
             l_int32 *pmaxy) {
    L_NEWPIXEL *np;

    PROCNAME("pushNewPixel");

    if (!lq) {
        L_ERROR("queue not defined\n", procName);
        return;
    }

    /* Adjust bounding box */
    *pminx = L_MIN(*pminx, x);
    *pmaxx = L_MAX(*pmaxx, x);
    *pminy = L_MIN(*pminy, y);
    *pmaxy = L_MAX(*pmaxy, y);

    /* Get a newpixel to use */
    if (lstackGetCount(lq->stack) > 0)
        np = (L_NEWPIXEL *) lstackRemove(lq->stack);
    else
        np = (L_NEWPIXEL *) CALLOC(1, sizeof(L_NEWPIXEL));

    np->x = x;
    np->y = y;
    lqueueAdd(lq, np);
    return;
}
Пример #3
0
/*!
 * \brief   pushFillsegBB()
 *
 * \param[in]    stack
 * \param[in]    xleft, xright
 * \param[in]    y
 * \param[in]    dy
 * \param[in]    ymax
 * \param[out]   pminx minimum x
 * \param[out]   pmaxx maximum x
 * \param[out]   pminy minimum y
 * \param[out]   pmaxy maximum y
 * \return  void
 *
 * <pre>
 * Notes:
 *      (1) This adds a line segment to the stack, and returns its size.
 *      (2) The auxiliary stack is used as a storage area to recycle
 *          fillsegs that are no longer in use.  We only calloc new
 *          fillsegs if the auxiliary stack is empty.
 * </pre>
 */
static void
pushFillsegBB(L_STACK  *stack,
              l_int32   xleft,
              l_int32   xright,
              l_int32   y,
              l_int32   dy,
              l_int32   ymax,
              l_int32  *pminx,
              l_int32  *pmaxx,
              l_int32  *pminy,
              l_int32  *pmaxy)
{
    FILLSEG  *fseg;
    L_STACK  *auxstack;

    PROCNAME("pushFillsegBB");

    if (!stack) {
        L_ERROR("stack not defined\n", procName);
        return;
    }

    *pminx = L_MIN(*pminx, xleft);
    *pmaxx = L_MAX(*pmaxx, xright);
    *pminy = L_MIN(*pminy, y);
    *pmaxy = L_MAX(*pmaxy, y);

    if (y + dy >= 0 && y + dy <= ymax) {
        if ((auxstack = stack->auxstack) == NULL) {
            L_ERROR("auxstack not defined\n", procName);
            return;
        }

        /* Get a fillseg to use */
        if (lstackGetCount(auxstack) > 0) {
            fseg = (FILLSEG *)lstackRemove(auxstack);
        } else {
            if ((fseg = (FILLSEG *)LEPT_CALLOC(1, sizeof(FILLSEG))) == NULL) {
                L_ERROR("fillseg not made\n", procName);
                return;
            }
        }

        fseg->xleft = xleft;
        fseg->xright = xright;
        fseg->y = y;
        fseg->dy = dy;
        lstackAdd(stack, fseg);
    }
    return;
}
Пример #4
0
/*!
 *  pushFillseg()
 *
 *      Input:  lstack
 *              xleft, xright
 *              y
 *              dy
 *              ymax
 *      Return: void
 *
 *  Notes:
 *      (1) This adds a line segment to the stack.
 *      (2) The auxiliary stack is used as a storage area to recycle
 *          fillsegs that are no longer in use.  We only calloc new
 *          fillsegs if the auxiliary stack is empty.
 */
static void
pushFillseg(L_STACK  *lstack,
            l_int32   xleft,
            l_int32   xright,
            l_int32   y,
            l_int32   dy,
            l_int32   ymax)
{
FILLSEG  *fseg;
L_STACK  *auxstack;

    PROCNAME("pushFillseg");

    if (!lstack) {
        L_ERROR(procName, "lstack not defined");
        return;
    }

    if (y + dy >= 0 && y + dy <= ymax) {
        if ((auxstack = lstack->auxstack) == NULL) {
            L_ERROR("auxstack not defined", procName);
            return;
        }

            /* Get a fillseg to use */
        if (lstackGetCount(auxstack) > 0)
            fseg = (FILLSEG *)lstackRemove(auxstack);
        else {
            if ((fseg = (FILLSEG *)CALLOC(1, sizeof(FILLSEG))) == NULL) {
                L_ERROR("fillseg not made", procName);
                return;
            }
        }

        fseg->xleft = xleft;
        fseg->xright = xright;
        fseg->y = y;
        fseg->dy = dy;
        lstackAdd(lstack, fseg);
    }
    return;
}
Пример #5
0
/*!
 * \brief   pixSeedfill8()
 *
 * \param[in]    pixs 1 bpp
 * \param[in]    stack for holding fillsegs
 * \param[in]    x,y   location of seed pixel
 * \return  0 if OK, 1 on error
 *
 * <pre>
 * Notes:
 *      (1) This is Paul Heckbert's stack-based 8-cc seedfill algorithm.
 *      (2) This operates on the input 1 bpp pix to remove the fg seed
 *          pixel, at (x,y), and all pixels that are 8-connected to it.
 *          The seed pixel at (x,y) must initially be ON.
 *      (3) Reference: see pixSeedFill8BB()
 * </pre>
 */
l_int32
pixSeedfill8(PIX      *pixs,
             L_STACK  *stack,
             l_int32   x,
             l_int32   y)
{
    l_int32    w, h, xstart, wpl, x1, x2, dy;
    l_int32    xmax, ymax;
    l_uint32  *data, *line;

    PROCNAME("pixSeedfill8");

    if (!pixs || pixGetDepth(pixs) != 1)
        return ERROR_INT("pixs not defined or not 1 bpp", procName, 1);
    if (!stack)
        return ERROR_INT("stack not defined", procName, 1);
    if (!stack->auxstack)
        stack->auxstack = lstackCreate(0);

    pixGetDimensions(pixs, &w, &h, NULL);
    xmax = w - 1;
    ymax = h - 1;
    data = pixGetData(pixs);
    wpl = pixGetWpl(pixs);
    line = data + y * wpl;

    /* Check pix value of seed; must be ON */
    if (x < 0 || x > xmax || y < 0 || y > ymax || (GET_DATA_BIT(line, x) == 0))
        return 0;

    /* Init stack to seed */
    pushFillseg(stack, x, x, y, 1, ymax);
    pushFillseg(stack, x, x, y + 1, -1, ymax);

    while (lstackGetCount(stack) > 0) {
        /* Pop segment off stack and fill a neighboring scan line */
        popFillseg(stack, &x1, &x2, &y, &dy);
        line = data + y * wpl;

        /* A segment of scanline y - dy for x1 <= x <= x2 was
         * previously filled.  We now explore adjacent pixels
         * in scan line y.  There are three regions: to the
         * left of x1, between x1 and x2, and to the right of x2.
         * These regions are handled differently.  Leaks are
         * possible expansions beyond the previous segment and
         * going back in the -dy direction.  These can happen
         * for x < x1 and for x > x2.  Any "leak" segments
         * are plugged with a push in the -dy (opposite) direction.
         * And any segments found anywhere are always extended
         * in the +dy direction.  */
        for (x = x1 - 1; x >= 0 && (GET_DATA_BIT(line, x) == 1); x--)
            CLEAR_DATA_BIT(line,x);
        if (x >= x1 - 1)  /* pix at x1 - 1 was off and was not cleared */
            goto skip;
        xstart = x + 1;
        if (xstart < x1)   /* leak on left? */
            pushFillseg(stack, xstart, x1 - 1, y, -dy, ymax);

        x = x1;
        do {
            for (; x <= xmax && (GET_DATA_BIT(line, x) == 1); x++)
                CLEAR_DATA_BIT(line, x);
            pushFillseg(stack, xstart, x - 1, y, dy, ymax);
            if (x > x2)   /* leak on right? */
                pushFillseg(stack, x2 + 1, x - 1, y, -dy, ymax);
skip:
            for (x++; x <= x2 + 1 &&
                    x <= xmax &&
                    (GET_DATA_BIT(line, x) == 0); x++)
                ;
            xstart = x;
        } while (x <= x2 + 1 && x <= xmax);
    }

    return 0;
}
Пример #6
0
/*!
 * \brief   pixSeedfill8BB()
 *
 * \param[in]    pixs 1 bpp
 * \param[in]    stack for holding fillsegs
 * \param[in]    x,y   location of seed pixel
 * \return  box or NULL on error.
 *
 * <pre>
 * Notes:
 *      (1) This is Paul Heckbert's stack-based 8-cc seedfill algorithm.
 *      (2) This operates on the input 1 bpp pix to remove the fg seed
 *          pixel, at (x,y), and all pixels that are 8-connected to it.
 *          The seed pixel at (x,y) must initially be ON.
 *      (3) Returns the bounding box of the erased 8-cc component.
 *      (4) Reference: see Paul Heckbert's stack-based seed fill algorithm
 *          in "Graphic Gems", ed. Andrew Glassner, Academic
 *          Press, 1990.  The algorithm description is given
 *          on pp. 275-277; working C code is on pp. 721-722.)
 *          The code here follows Heckbert's closely, except
 *          the leak checks are changed for 8 connectivity.
 *          See comments on pixSeedfill4BB() for more details.
 * </pre>
 */
BOX *
pixSeedfill8BB(PIX      *pixs,
               L_STACK  *stack,
               l_int32   x,
               l_int32   y)
{
    l_int32    w, h, xstart, wpl, x1, x2, dy;
    l_int32    xmax, ymax;
    l_int32    minx, maxx, miny, maxy;  /* for bounding box of this c.c. */
    l_uint32  *data, *line;
    BOX       *box;

    PROCNAME("pixSeedfill8BB");

    if (!pixs || pixGetDepth(pixs) != 1)
        return (BOX *)ERROR_PTR("pixs undefined or not 1 bpp", procName, NULL);
    if (!stack)
        return (BOX *)ERROR_PTR("stack not defined", procName, NULL);
    if (!stack->auxstack)
        stack->auxstack = lstackCreate(0);

    pixGetDimensions(pixs, &w, &h, NULL);
    xmax = w - 1;
    ymax = h - 1;
    data = pixGetData(pixs);
    wpl = pixGetWpl(pixs);
    line = data + y * wpl;

    /* Check pix value of seed; must be ON */
    if (x < 0 || x > xmax || y < 0 || y > ymax || (GET_DATA_BIT(line, x) == 0))
        return NULL;

    /* Init stack to seed:
     * Must first init b.b. values to prevent valgrind from complaining;
     * then init b.b. boundaries correctly to seed.  */
    minx = miny = 100000;
    maxx = maxy = 0;
    pushFillsegBB(stack, x, x, y, 1, ymax, &minx, &maxx, &miny, &maxy);
    pushFillsegBB(stack, x, x, y + 1, -1, ymax, &minx, &maxx, &miny, &maxy);
    minx = maxx = x;
    miny = maxy = y;

    while (lstackGetCount(stack) > 0) {
        /* Pop segment off stack and fill a neighboring scan line */
        popFillseg(stack, &x1, &x2, &y, &dy);
        line = data + y * wpl;

        /* A segment of scanline y - dy for x1 <= x <= x2 was
         * previously filled.  We now explore adjacent pixels
         * in scan line y.  There are three regions: to the
         * left of x1, between x1 and x2, and to the right of x2.
         * These regions are handled differently.  Leaks are
         * possible expansions beyond the previous segment and
         * going back in the -dy direction.  These can happen
         * for x < x1 and for x > x2.  Any "leak" segments
         * are plugged with a push in the -dy (opposite) direction.
         * And any segments found anywhere are always extended
         * in the +dy direction.  */
        for (x = x1 - 1; x >= 0 && (GET_DATA_BIT(line, x) == 1); x--)
            CLEAR_DATA_BIT(line,x);
        if (x >= x1 - 1)  /* pix at x1 - 1 was off and was not cleared */
            goto skip;
        xstart = x + 1;
        if (xstart < x1)   /* leak on left? */
            pushFillsegBB(stack, xstart, x1 - 1, y, -dy,
                          ymax, &minx, &maxx, &miny, &maxy);

        x = x1;
        do {
            for (; x <= xmax && (GET_DATA_BIT(line, x) == 1); x++)
                CLEAR_DATA_BIT(line, x);
            pushFillsegBB(stack, xstart, x - 1, y, dy,
                          ymax, &minx, &maxx, &miny, &maxy);
            if (x > x2)   /* leak on right? */
                pushFillsegBB(stack, x2 + 1, x - 1, y, -dy,
                              ymax, &minx, &maxx, &miny, &maxy);
skip:
            for (x++; x <= x2 + 1 &&
                    x <= xmax &&
                    (GET_DATA_BIT(line, x) == 0); x++)
                ;
            xstart = x;
        } while (x <= x2 + 1 && x <= xmax);
    }

    if ((box = boxCreate(minx, miny, maxx - minx + 1, maxy - miny + 1))
            == NULL)
        return (BOX *)ERROR_PTR("box not made", procName, NULL);
    return box;
}