Example #1
0
l_int32 renderTransformedBoxa(PIX *pixt, BOXA *boxa, l_int32 i) {
    l_int32 j, n, rval, gval, bval;
    BOX *box;
    
    n = boxaGetCount(boxa);
    rval = (1413 * i) % 256;
    gval = (4917 * i) % 256;
    bval = (7341 * i) % 256;
    for (j = 0; j < n; j++) {
        box = boxaGetBox(boxa, j, L_CLONE);
        pixRenderHashBoxArb(pixt, box, 10, 3, i % 4, 1, rval, gval, bval);
        boxDestroy(&box);
    }
    return 0;
}
Example #2
0
/*!
 *  pixFindLargestRectangle()
 *
 *      Input:  pixs  (1 bpp)
 *              polarity (0 within background, 1 within foreground)
 *              &box (<return> largest rectangle, either by area or
 *                    by perimeter)
 *              debugflag (1 to output image with rectangle drawn on it)
 *      Return: 0 if OK, 1 on error
 *
 *  Notes:
 *      (1) Why is this here?  This is a simple and elegant solution to
 *          a problem in computational geometry that at first appears
 *          quite difficult: what is the largest rectangle that can
 *          be placed in the image, covering only pixels of one polarity
 *          (bg or fg)?  The solution is O(n), where n is the number
 *          of pixels in the image, and it requires nothing more than
 *          using a simple recursion relation in a single sweep of the image.
 *      (2) In a sweep from UL to LR with left-to-right being the fast
 *          direction, calculate the largest white rectangle at (x, y),
 *          using previously calculated values at pixels #1 and #2:
 *             #1:    (x, y - 1)
 *             #2:    (x - 1, y)
 *          We also need the most recent "black" pixels that were seen
 *          in the current row and column.
 *          Consider the largest area.  There are only two possibilities:
 *             (a)  Min(w(1), horizdist) * (h(1) + 1)
 *             (b)  Min(h(2), vertdist) * (w(2) + 1)
 *          where
 *             horizdist: the distance from the rightmost "black" pixel seen
 *                        in the current row across to the current pixel
 *             vertdist: the distance from the lowest "black" pixel seen
 *                       in the current column down to the current pixel
 *          and we choose the Max of (a) and (b).
 *      (3) To convince yourself that these recursion relations are correct,
 *          it helps to draw the maximum rectangles at #1 and #2.
 *          Then for #1, you try to extend the rectangle down one line,
 *          so that the height is h(1) + 1.  Do you get the full
 *          width of #1, w(1)?  It depends on where the black pixels are
 *          in the current row.  You know the final width is bounded by w(1)
 *          and w(2) + 1, but the actual value depends on the distribution
 *          of black pixels in the current row that are at a distance
 *          from the current pixel that is between these limits.
 *          We call that value "horizdist", and the area is then given
 *          by the expression (a) above.  Using similar reasoning for #2,
 *          where you attempt to extend the rectangle to the right
 *          by 1 pixel, you arrive at (b).  The largest rectangle is
 *          then found by taking the Max.
 */
l_int32
pixFindLargestRectangle(PIX         *pixs,
                        l_int32      polarity,
                        BOX        **pbox,
                        const char  *debugfile)
{
l_int32    i, j, w, h, d, wpls, val;
l_int32    wp, hp, w1, w2, h1, h2, wmin, hmin, area1, area2;
l_int32    xmax, ymax;  /* LR corner of the largest rectangle */
l_int32    maxarea, wmax, hmax, vertdist, horizdist, prevfg;
l_int32   *lowestfg;
l_uint32  *datas, *lines;
l_uint32 **linew, **lineh;
BOX       *box;
PIX       *pixw, *pixh;  /* keeps the width and height for the largest */
                         /* rectangles whose LR corner is located there. */

    PROCNAME("pixFindLargestRectangle");

    if (!pbox)
        return ERROR_INT("&box not defined", procName, 1);
    *pbox = NULL;
    if (!pixs)
        return ERROR_INT("pixs not defined", procName, 1);
    pixGetDimensions(pixs, &w, &h, &d);
    if (d != 1)
        return ERROR_INT("pixs not 1 bpp", procName, 1);
    if (polarity != 0 && polarity != 1)
        return ERROR_INT("invalid polarity", procName, 1);

        /* Initialize lowest "fg" seen so far for each column */
    lowestfg = (l_int32 *)CALLOC(w, sizeof(l_int32));
    for (i = 0; i < w; i++)
        lowestfg[i] = -1;

        /* The combination (val ^ polarity) is the color for which we
         * are searching for the maximum rectangle.  For polarity == 0,
         * we search in the bg (white). */
    pixw = pixCreate(w, h, 32);  /* stores width */
    pixh = pixCreate(w, h, 32);  /* stores height */
    linew = (l_uint32 **)pixGetLinePtrs(pixw, NULL);
    lineh = (l_uint32 **)pixGetLinePtrs(pixh, NULL);
    datas = pixGetData(pixs);
    wpls = pixGetWpl(pixs);
    maxarea = xmax = ymax = wmax = hmax = 0;
    for (i = 0; i < h; i++) {
        lines = datas + i * wpls;
        prevfg = -1;
        for (j = 0; j < w; j++) {
            val = GET_DATA_BIT(lines, j);
            if ((val ^ polarity) == 0) {  /* bg (0) if polarity == 0, etc. */
                if (i == 0 && j == 0) {
                    wp = hp = 1;
                }
                else if (i == 0) {
                    wp = linew[i][j - 1] + 1;
                    hp = 1;
                }
                else if (j == 0) {
                    wp = 1;
                    hp = lineh[i - 1][j] + 1;
                }
                else {
                        /* Expand #1 prev rectangle down */
                    w1 = linew[i - 1][j];
                    h1 = lineh[i - 1][j];
                    horizdist = j - prevfg;
                    wmin = L_MIN(w1, horizdist);  /* width of new rectangle */
                    area1 = wmin * (h1 + 1);

                        /* Expand #2 prev rectangle to right */
                    w2 = linew[i][j - 1];
                    h2 = lineh[i][j - 1];
                    vertdist = i - lowestfg[j];
                    hmin = L_MIN(h2, vertdist);  /* height of new rectangle */
                    area2 = hmin * (w2 + 1);

                    if (area1 > area2) {
                         wp = wmin;
                         hp = h1 + 1;
                    }
                    else {
                         wp = w2 + 1;
                         hp = hmin;
                    }
                }
            }
            else {  /* fg (1) if polarity == 0; bg (0) if polarity == 1 */
                prevfg = j;
                lowestfg[j] = i;
                wp = hp = 0;
            }
            linew[i][j] = wp;
            lineh[i][j] = hp;
            if (wp * hp > maxarea) {
                maxarea = wp * hp;
                xmax = j;
                ymax = i;
                wmax = wp;
                hmax = hp;
            }
        }
    }

        /* Translate from LR corner to Box coords (UL corner, w, h) */
    box = boxCreate(xmax - wmax + 1, ymax - hmax + 1, wmax, hmax);
    *pbox = box;

    if (debugfile) {
        PIX  *pixdb;
        pixdb = pixConvertTo8(pixs, TRUE);
        pixRenderHashBoxArb(pixdb, box, 6, 2, L_NEG_SLOPE_LINE, 1, 255, 0, 0);
        pixWrite(debugfile, pixdb, IFF_PNG);
        pixDestroy(&pixdb);
    }
 
    FREE(linew);
    FREE(lineh);
    FREE(lowestfg);
    pixDestroy(&pixw);
    pixDestroy(&pixh);
    return 0;
}
Example #3
0
main(int    argc,
     char **argv)
{
l_int32      i, n, ws, hs, w, h, rval, gval, bval, order;
l_float32   *mat1, *mat2, *mat3;
l_float32    matd[9];
BOX         *box, *boxt;
BOXA        *boxa, *boxat, *boxa1, *boxa2, *boxa3, *boxa4, *boxa5;
PIX         *pix, *pixs, *pixb, *pixc, *pixt, *pixt1, *pixt2, *pixt3;
PIXA        *pixa;
static char  mainName[] = "xformbox_reg";

    /* ----------------------------------------------------------- *
     *                Test hash rendering in 3 modes               *
     * ----------------------------------------------------------- */
    pixs = pixRead("feyn.tif");
    box = boxCreate(461, 429, 1393, 342);
    pixt1 = pixClipRectangle(pixs, box, NULL);
    boxa = pixConnComp(pixt1, NULL, 8);
    n = boxaGetCount(boxa);
    pixt2 = pixConvertTo8(pixt1, 1);
    pixt3 = pixConvertTo32(pixt1);
    for (i = 0; i < n; i++) {
        boxt = boxaGetBox(boxa, i, L_CLONE);
	rval = (1413 * i) % 256;
	gval = (4917 * i) % 256;
	bval = (7341 * i) % 256;
	pixRenderHashBox(pixt1, boxt, 8, 2, i % 4, 1, L_SET_PIXELS);
	pixRenderHashBoxArb(pixt2, boxt, 7, 2, i % 4, 1, rval, gval, bval);
	pixRenderHashBoxBlend(pixt3, boxt, 7, 2, i % 4, 1, rval, gval, bval,
                              0.5);
	boxDestroy(&boxt);
    }
    pixDisplay(pixt1, 0, 0);
    pixDisplay(pixt2, 0, 300);
    pixDisplay(pixt3, 0, 570);
    pixWrite("/tmp/junkpixt1.png", pixt1, IFF_PNG);
    pixWrite("/tmp/junkpixt2.png", pixt2, IFF_PNG);
    pixWrite("/tmp/junkpixt3.png", pixt3, IFF_PNG);

    boxaDestroy(&boxa);
    boxDestroy(&box);
    pixDestroy(&pixs);
    pixDestroy(&pixt1);
    pixDestroy(&pixt2);
    pixDestroy(&pixt3);


    /* ----------------------------------------------------------- *
     *    Test box transforms with either translation or scaling   *
     *    combined with rotation, using the simple 'ordered'       *
     *    function.  Show that the order of the operations does    *
     *    not matter; different hashing schemes end up in the      *
     *    identical boxes.                                         *
     * ----------------------------------------------------------- */
    pix = pixRead("feyn.tif");
    box = boxCreate(420, 360, 1500, 465);
    pixt = pixClipRectangle(pix, box, NULL);
    pixs = pixAddBorderGeneral(pixt, 0, 200, 0, 0, 0);
    boxDestroy(&box);
    pixDestroy(&pix);
    pixDestroy(&pixt);
    boxa = pixConnComp(pixs, NULL, 8);
    n = boxaGetCount(boxa);
    pixa = pixaCreate(0);

    pixt = pixConvertTo32(pixs);
    for (i = 0; i < 3; i++) {
        if (i == 0)
            order = L_TR_SC_RO;
        else if (i == 1)
            order = L_TR_RO_SC;
        else
            order = L_SC_TR_RO;
        boxat = boxaTransformOrdered(boxa, SHIFTX_2, SHIFTY_2, 1.0, 1.0,
                                     450, 250, ROTATION_2, order);
        RenderTransformedBoxa(pixt, boxat, i);
        boxaDestroy(&boxat);
    }
    pixSaveTiled(pixt, pixa, 1, 1, 30, 32);
    pixDestroy(&pixt);

    pixt = pixConvertTo32(pixs);
    for (i = 0; i < 3; i++) {
        if (i == 0)
            order = L_RO_TR_SC;
        else if (i == 1)
            order = L_RO_SC_TR;
        else
            order = L_SC_RO_TR;
        boxat = boxaTransformOrdered(boxa, SHIFTX_2, SHIFTY_2, 1.0, 1.0,
                                     450, 250, ROTATION_2, order);
        RenderTransformedBoxa(pixt, boxat, i + 4);
        boxaDestroy(&boxat);
    }
    pixSaveTiled(pixt, pixa, 1, 1, 30, 0);
    pixDestroy(&pixt);

    pixt = pixConvertTo32(pixs);
    for (i = 0; i < 3; i++) {
        if (i == 0)
            order = L_TR_SC_RO;
        else if (i == 1)
            order = L_SC_RO_TR;
        else
            order = L_SC_TR_RO;
        boxat = boxaTransformOrdered(boxa, 0, 0, SCALEX_2, SCALEY_2,
                                     450, 250, ROTATION_2, order);
        RenderTransformedBoxa(pixt, boxat, i + 8);
        boxaDestroy(&boxat);
    }
    pixSaveTiled(pixt, pixa, 1, 1, 30, 0);
    pixDestroy(&pixt);

    pixt = pixConvertTo32(pixs);
    for (i = 0; i < 3; i++) {
        if (i == 0)
            order = L_RO_TR_SC;
        else if (i == 1)
            order = L_RO_SC_TR;
        else
            order = L_TR_RO_SC;
        boxat = boxaTransformOrdered(boxa, 0, 0, SCALEX_2, SCALEY_2,
                                     450, 250, ROTATION_2, order);
        RenderTransformedBoxa(pixt, boxat, i + 16);
        boxaDestroy(&boxat);
    }
    pixSaveTiled(pixt, pixa, 1, 1, 30, 0);
    pixDestroy(&pixt);

    pixt = pixaDisplay(pixa, 0, 0);
    pixWrite("/tmp/junkxform1.png", pixt, IFF_PNG);
    pixDisplay(pixt, 1000, 0);
    pixDestroy(&pixt);
    pixDestroy(&pixs);
    boxaDestroy(&boxa);
    pixaDestroy(&pixa);


    /* ----------------------------------------------------------- *
     *    Do more testing of box and pta transforms.  Show that    *
     *    resulting boxes are identical by three methods.          *
     * ----------------------------------------------------------- */
        /* Set up pix and boxa */
    pixa = pixaCreate(0);
    pix = pixRead("lucasta.1.300.tif");
    pixTranslate(pix, pix, 70, 0, L_BRING_IN_WHITE);
    pixt = pixCloseBrick(NULL, pix, 14, 5);
    pixOpenBrick(pixt, pixt, 1, 2);
    boxa = pixConnComp(pixt, NULL, 8);
    pixs = pixConvertTo32(pix);
    pixc = pixCopy(NULL, pixs);
    RenderTransformedBoxa(pixc, boxa, 113);
    pixSaveTiled(pixc, pixa, 2, 1, 30, 32);
    pixDestroy(&pix);
    pixDestroy(&pixc);
    pixDestroy(&pixt);

        /* (a) Do successive discrete operations: shift, scale, rotate */
    pixt1 = pixTranslate(NULL, pixs, SHIFTX_3, SHIFTY_3, L_BRING_IN_WHITE);
    boxa1 = boxaTranslate(boxa, SHIFTX_3, SHIFTY_3);
    pixc = pixCopy(NULL, pixt1);
    RenderTransformedBoxa(pixc, boxa1, 213);
    pixSaveTiled(pixc, pixa, 2, 0, 30, 32);
    pixDestroy(&pixc);

    pixt2 = pixScale(pixt1, SCALEX_3, SCALEY_3);
    boxa2 = boxaScale(boxa1, SCALEX_3, SCALEY_3);
    pixc = pixCopy(NULL, pixt2);
    RenderTransformedBoxa(pixc, boxa2, 313);
    pixSaveTiled(pixc, pixa, 2, 1, 30, 32);
    pixDestroy(&pixc);

    pixGetDimensions(pixt2, &w, &h, NULL);
    pixt3 = pixRotateAM(pixt2, ROTATION_3, L_BRING_IN_WHITE);
    boxa3 = boxaRotate(boxa2, w / 2, h / 2, ROTATION_3);
    pixc = pixCopy(NULL, pixt3);
    RenderTransformedBoxa(pixc, boxa3, 413);
    pixSaveTiled(pixc, pixa, 2, 0, 30, 32);
    pixDestroy(&pixc);

        /* (b) Set up and use the composite transform */
    mat1 = createMatrix2dTranslate(SHIFTX_3, SHIFTY_3);
    mat2 = createMatrix2dScale(SCALEX_3, SCALEY_3);
    mat3 = createMatrix2dRotate(w / 2, h / 2, ROTATION_3);
    l_productMat3(mat3, mat2, mat1, matd, 3);
    boxa4 = boxaAffineTransform(boxa, matd);
    pixc = pixCopy(NULL, pixt3);
    RenderTransformedBoxa(pixc, boxa4, 513);
    pixSaveTiled(pixc, pixa, 2, 1, 30, 32);
    pixDestroy(&pixc);

        /* (c) Use the special 'ordered' function */
    pixGetDimensions(pixs, &ws, &hs, NULL);
    boxa5 = boxaTransformOrdered(boxa, SHIFTX_3, SHIFTY_3,
                                 SCALEX_3, SCALEY_3,
                                 ws / 2, hs / 2, ROTATION_3, L_TR_SC_RO);
    pixc = pixCopy(NULL, pixt3);
    RenderTransformedBoxa(pixc, boxa5, 613);
    pixSaveTiled(pixc, pixa, 2, 0, 30, 32);
    pixDestroy(&pixc);

    pixDestroy(&pixt1);
    pixDestroy(&pixt2);
    pixDestroy(&pixt3);
    boxaDestroy(&boxa1);
    boxaDestroy(&boxa2);
    boxaDestroy(&boxa3);
    boxaDestroy(&boxa4);
    boxaDestroy(&boxa5);
    lept_free(mat1);
    lept_free(mat2);
    lept_free(mat3);

    pixt = pixaDisplay(pixa, 0, 0);
    pixWrite("/tmp/junkxform2.png", pixt, IFF_PNG);
    pixDisplay(pixt, 1000, 300);
    pixDestroy(&pixt);
    pixDestroy(&pixs);
    boxaDestroy(&boxa);
    pixaDestroy(&pixa);
    return 0;
}
Example #4
0
main(int    argc,
     char **argv)
{
l_int32       i, w, h, bx, by, bw, bh, index, rval, gval, bval;
BOX          *box;
BOXA         *boxa;
PIX          *pixm, *pixs, *pixg, *pixt, *pixd;
PIXA         *pixa;
PIXCMAP      *cmap;
PTA          *pta;
PTAA         *ptaa;
L_REGPARAMS  *rp;

    if (regTestSetup(argc, argv, &rp))
	return 1;
    pixa = pixaCreate(0);

    /* ---------------- Shortest path in binary maze ---------------- */
        /* Generate the maze */
    pixm = generateBinaryMaze(200, 200, 20, 20, 0.65, 0.25);
    pixd = pixExpandBinaryReplicate(pixm, 3);
    pixSaveTiledOutline(pixd, pixa, 1, 1, 20, 2, 32);
    pixDestroy(&pixd);

        /* Find the shortest path between two points */
    pta = pixSearchBinaryMaze(pixm, 20, 20, 170, 170, NULL);
    pixt = pixDisplayPta(NULL, pixm, pta);
    pixd = pixScaleBySampling(pixt, 3., 3.);
    pixSaveTiledOutline(pixd, pixa, 1, 0, 20, 2, 32);
    regTestWritePixAndCheck(rp, pixd, IFF_PNG);  /* 0 */
    ptaDestroy(&pta);
    pixDestroy(&pixt);
    pixDestroy(&pixd);
    pixDestroy(&pixm);


    /* ---------------- Shortest path in gray maze ---------------- */
    pixg = pixRead("test8.jpg");
    pixGetDimensions(pixg, &w, &h, NULL);
    ptaa = ptaaCreate(NPATHS);
    for (i = 0; i < NPATHS; i++) {
        if (x0[i] >= w || x1[i] >= w || y0[i] >= h || y1[i] >= h) {
            fprintf(stderr, "path %d extends beyond image; skipping\n", i);
            continue;
        }
        pta = pixSearchGrayMaze(pixg, x0[i], y0[i], x1[i], y1[i], NULL);
        ptaaAddPta(ptaa, pta, L_INSERT);
    }

    pixt = pixDisplayPtaa(pixg, ptaa);
    pixd = pixScaleBySampling(pixt, 2., 2.);
    pixSaveTiledOutline(pixd, pixa, 1, 1, 20, 2, 32);
    regTestWritePixAndCheck(rp, pixd, IFF_PNG);  /* 1 */
    ptaaDestroy(&ptaa);
    pixDestroy(&pixg);
    pixDestroy(&pixt);
    pixDestroy(&pixd);


    /* ---------------- Largest rectangles in image ---------------- */
    pixs = pixRead("test1.png");
    pixd = pixConvertTo8(pixs, FALSE);
    cmap = pixcmapCreateRandom(8, 1, 1);
    pixSetColormap(pixd, cmap);

    boxa = boxaCreate(0);
    for (i = 0; i < NBOXES; i++) {
        pixFindLargestRectangle(pixs, POLARITY, &box, NULL);
        boxGetGeometry(box, &bx, &by, &bw, &bh);
        pixSetInRect(pixs, box);
        fprintf(stderr, "bx = %5d, by = %5d, bw = %5d, bh = %5d, area = %d\n",
                bx, by, bw, bh, bw * bh);
        boxaAddBox(boxa, box, L_INSERT);
    }

    for (i = 0; i < NBOXES; i++) {
        index = 32 + (i & 254);
        pixcmapGetColor(cmap, index, &rval, &gval, &bval);
        box = boxaGetBox(boxa, i, L_CLONE);
        pixRenderHashBoxArb(pixd, box, 6, 2, L_NEG_SLOPE_LINE, 1,
                            rval, gval, bval);
        boxDestroy(&box);
    }
    pixSaveTiledOutline(pixd, pixa, 1, 1, 20, 2, 32);
    regTestWritePixAndCheck(rp, pixd, IFF_PNG);  /* 2 */
    pixDestroy(&pixs);
    pixDestroy(&pixd);
    boxaDestroy(&boxa);

    pixd = pixaDisplay(pixa, 0, 0);
    regTestWritePixAndCheck(rp, pixd, IFF_PNG);  /* 3 */
    pixDisplayWithTitle(pixd, 100, 100, NULL, rp->display);
    pixDestroy(&pixd);
    pixaDestroy(&pixa);

    return regTestCleanup(rp);
}