예제 #1
0
int main(int    argc,
         char **argv)
{
char        *fname, *filename;
const char  *str;
char         buffer[512];
l_int32      i, npages;
size_t       length;
FILE        *fp;
NUMA        *naflags, *nasizes;
PIX         *pix, *pix1, *pix2, *pixd;
PIXA        *pixa;
PIXCMAP     *cmap;
SARRAY      *savals, *satypes, *sa;
static char  mainName[] = "mtifftest";

    if (argc != 1)
        return ERROR_INT(" Syntax:  mtifftest", mainName, 1);

    lept_mkdir("tiff");

#if 1   /* ------------------  Test multipage I/O  -------------------*/
        /* This puts every image file in the directory with a string
         * match to "weasel" into a multipage tiff file.
         * Images with 1 bpp are coded as g4; the others as zip.
         * It then reads back into a pix and displays.  */
    writeMultipageTiff(".", "weasel8.", "/tmp/tiff/weasel8.tif");
    pixa = pixaReadMultipageTiff("/tmp/tiff/weasel8.tif");
    pixd = pixaDisplayTiledInRows(pixa, 1, 1200, 0.5, 0, 15, 4);
    pixDisplay(pixd, 100, 0);
    pixDestroy(&pixd);
    pixd = pixaDisplayTiledInRows(pixa, 8, 1200, 0.8, 0, 15, 4);
    pixDisplay(pixd, 100, 200);
    pixDestroy(&pixd);
    pixd = pixaDisplayTiledInRows(pixa, 32, 1200, 1.2, 0, 15, 4);
    pixDisplay(pixd, 100, 400);
    pixDestroy(&pixd);
    pixaDestroy(&pixa);
#endif

#if 1   /* ------------ Test single-to-multipage I/O  -------------------*/
        /* Read the files and generate a multipage tiff file of G4 images.
         * Then convert that to a G4 compressed and ascii85 encoded PS file. */
    sa = getSortedPathnamesInDirectory(".", "weasel4.", 0, 4);
    sarrayWriteStream(stderr, sa);
    sarraySort(sa, sa, L_SORT_INCREASING);
    sarrayWriteStream(stderr, sa);
    npages = sarrayGetCount(sa);
    for (i = 0; i < npages; i++) {
        fname = sarrayGetString(sa, i, 0);
        filename = genPathname(".", fname);
        pix1 = pixRead(filename);
        if (!pix1) continue;
        pix2 = pixConvertTo1(pix1, 128);
        if (i == 0)
            pixWriteTiff("/tmp/tiff/weasel4", pix2, IFF_TIFF_G4, "w+");
        else
            pixWriteTiff("/tmp/tiff/weasel4", pix2, IFF_TIFF_G4, "a");
        pixDestroy(&pix1);
        pixDestroy(&pix2);
        lept_free(filename);
    }

        /* Write it out as a PS file */
    convertTiffMultipageToPS("/tmp/tiff/weasel4", "/tmp/tiff/weasel4.ps",
                             NULL, 0.95);
    sarrayDestroy(&sa);
#endif

#if 1   /* ------------------  Test multipage I/O  -------------------*/
        /* Read count of pages in tiff multipage  file */
    writeMultipageTiff(".", "weasel2", weasel_orig);
    fp = lept_fopen(weasel_orig, "rb");
    if (fileFormatIsTiff(fp)) {
        tiffGetCount(fp, &npages);
        fprintf(stderr, " Tiff: %d page\n", npages);
    }
    else
        return ERROR_INT(" file not tiff", mainName, 1);
    lept_fclose(fp);

        /* Split into separate page files */
    for (i = 0; i < npages + 1; i++) {   /* read one beyond to catch error */
        if (i == npages)
            L_INFO("Errors in next 2 lines are intentional!\n", mainName);
        pix = pixReadTiff(weasel_orig, i);
        if (!pix) continue;
        sprintf(buffer, "/tmp/tiff/%03d.tif", i);
        pixWrite(buffer, pix, IFF_TIFF_ZIP);
        pixDestroy(&pix);
    }

        /* Read separate page files and write reversed file */
    for (i = npages - 1; i >= 0; i--) {
        sprintf(buffer, "/tmp/tiff/%03d.tif", i);
        pix = pixRead(buffer);
        if (!pix) continue;
        if (i == npages - 1)
            pixWriteTiff(weasel_rev, pix, IFF_TIFF_ZIP, "w+");
        else
            pixWriteTiff(weasel_rev, pix, IFF_TIFF_ZIP, "a");
        pixDestroy(&pix);
    }

        /* Read reversed file and reverse again */
    pixa = pixaCreate(npages);
    for (i = 0; i < npages; i++) {
        pix = pixReadTiff(weasel_rev, i);
        pixaAddPix(pixa, pix, L_INSERT);
    }
    for (i = npages - 1; i >= 0; i--) {
        pix = pixaGetPix(pixa, i, L_CLONE);
        if (i == npages - 1)
            pixWriteTiff(weasel_rev_rev, pix, IFF_TIFF_ZIP, "w+");
        else
            pixWriteTiff(weasel_rev_rev, pix, IFF_TIFF_ZIP, "a");
        pixDestroy(&pix);
    }
    pixaDestroy(&pixa);
#endif


#if 0    /* -----   test adding custom public tags to a tiff header ----- */
    pix = pixRead("feyn.tif");
    naflags = numaCreate(10);
    savals = sarrayCreate(10);
    satypes = sarrayCreate(10);
    nasizes = numaCreate(10);

/*    numaAddNumber(naflags, TIFFTAG_XMLPACKET);  */ /* XMP:  700 */
    numaAddNumber(naflags, 700);
    str = "<xmp>This is a Fake XMP packet</xmp>\n<text>Guess what ...?</text>";
    length = strlen(str);
    sarrayAddString(savals, (char *)str, 1);
    sarrayAddString(satypes, (char *)"char*", 1);
    numaAddNumber(nasizes, length);  /* get it all */

    numaAddNumber(naflags, 269);  /* DOCUMENTNAME */
    sarrayAddString(savals, (char *)"One silly title", 1);
    sarrayAddString(satypes, (char *)"const char*", 1);
    numaAddNumber(naflags, 270);  /* IMAGEDESCRIPTION */
    sarrayAddString(savals, (char *)"One page of text", 1);
    sarrayAddString(satypes, (char *)"const char*", 1);
        /* the max sample is used by rendering programs
         * to scale the dynamic range */
    numaAddNumber(naflags, 281);  /* MAXSAMPLEVALUE */
    sarrayAddString(savals, (char *)"4", 1);
    sarrayAddString(satypes, (char *)"l_uint16", 1);
        /* note that date is required to be a 20 byte string */
    numaAddNumber(naflags, 306);  /* DATETIME */
    sarrayAddString(savals, (char *)"2004:10:11 09:35:15", 1);
    sarrayAddString(satypes, (char *)"const char*", 1);
        /* note that page number requires 2 l_uint16 input */
    numaAddNumber(naflags, 297);  /* PAGENUMBER */
    sarrayAddString(savals, (char *)"1-412", 1);
    sarrayAddString(satypes, (char *)"l_uint16-l_uint16", 1);
    pixWriteTiffCustom("/tmp/tiff/tags.tif", pix, IFF_TIFF_G4, "w", naflags,
                       savals, satypes, nasizes);
    fprintTiffInfo(stderr, (char *)"/tmp/tiff/tags.tif");
    fprintf(stderr, "num flags = %d\n", numaGetCount(naflags));
    fprintf(stderr, "num sizes = %d\n", numaGetCount(nasizes));
    fprintf(stderr, "num vals = %d\n", sarrayGetCount(savals));
    fprintf(stderr, "num types = %d\n", sarrayGetCount(satypes));
    numaDestroy(&naflags);
    numaDestroy(&nasizes);
    sarrayDestroy(&savals);
    sarrayDestroy(&satypes);
    pixDestroy(&pix);
#endif

    return 0;
}
예제 #2
0
l_int32 main(int    argc,
             char **argv)
{
char         *dir, *path;
char         *str1 = NULL;
char         *chara, *chara2;
char          buf[256];
l_uint8      *data1, *data2, *data3, *data4;
l_int32       w, h, i, n, bx, by, bw, bh, nchar, nbytes, ret;
l_int32      *rtable64;
l_uint32      pixval;
size_t        nbytes1, nbytes2, nout, nout2, nout3;
L_BMF        *bmf;
BOX          *box1, *box2;
BOXA         *boxa;
PIX          *pix, *pixs, *pixm, *pixg, *pixd;
PIX          *pix0, *pix1, *pix2, *pix3, *pix4, *pix5, *pix6;
PIXA         *pixas, *pixa1, *pixa2, *pixa3;
L_RECOG      *recog;
L_STRCODE    *strc;

    if (argc != 1) {
        fprintf(stderr, " Syntax: recog_bootnum\n");
        return 1;
    }

    lept_mkdir("lept/recog/digits");

    /* ----------------------- Bootnum 1 --------------------- */
        /* Make the bootnum pixa from the images */
    pixa1 = MakeBootnum1();
    pixaWrite("/tmp/lept/recog/digits/bootnum1.pa", pixa1);
    pix1 = pixaDisplayTiledWithText(pixa1, 1500, 1.0, 10, 2, 6, 0xff000000);
    pixDisplay(pix1, 100, 0);
    pixDestroy(&pix1);
    pixaDestroy(&pixa1);

        /* Generate the code to make the bootnum1 pixa.
         * Note: the actual code we use is in bootnumgen1.c, and
         * has already been compiled into the library. */
    strc = strcodeCreate(101);  /* arbitrary integer */
    strcodeGenerate(strc, "/tmp/lept/recog/digits/bootnum1.pa", "PIXA");
    strcodeFinalize(&strc, "/tmp/lept/auto");
    lept_free(strc);

        /* Generate the bootnum1 pixa from the generated code */
    pixa1 = (PIXA *)l_bootnum_gen1();
    pix1 = pixaDisplayTiledWithText(pixa1, 1500, 1.0, 10, 2, 6, 0xff000000);
/*    pix1 = pixaDisplayTiled(pixa1, 1500, 0, 30); */
    pixDisplay(pix1, 100, 0);
    pixDestroy(&pix1);

        /* Extend the bootnum1 pixa by erosion */
    pixa3 = pixaExtendIterative(pixa1, L_MORPH_ERODE, 2, NULL, 1);
    pix1 = pixaDisplayTiledWithText(pixa3, 1500, 1.0, 10, 2, 6, 0xff000000);
    pixDisplay(pix1, 100, 0);
    pixDestroy(&pix1);
    pixaDestroy(&pixa1);
    pixaDestroy(&pixa3);

    /* ----------------------- Bootnum 2 --------------------- */
        /* Make the bootnum pixa from the images */
    L_INFO("the 4 errors below are due to bad input\n", "recog_bootnum");
    pixa2 = MakeBootnum2();
    pix1 = pixaDisplayTiledWithText(pixa2, 1500, 1.0, 10, 2, 6, 0xff000000);
    pixDisplay(pix1, 100, 700);
    pixDestroy(&pix1);
    pixaDestroy(&pixa2);

        /* Generate the code to make the bootnum2 pixa.
         * Note: the actual code we use is in bootnumgen2.c. */
    strc = strcodeCreate(102);  /* another arbitrary integer */
    strcodeGenerate(strc, "/tmp/lept/recog/digits/bootnum2.pa", "PIXA");
    strcodeFinalize(&strc, "/tmp/lept/auto");
    lept_free(strc);

        /* Generate the bootnum2 pixa from the generated code */
    pixa2 = (PIXA *)l_bootnum_gen2();
/*    pix1 = pixaDisplayTiled(pixa2, 1500, 0, 30);  */
    pix1 = pixaDisplayTiledWithText(pixa2, 1500, 1.0, 10, 2, 6, 0xff000000);
    pixDisplay(pix1, 100, 700);
    pixDestroy(&pix1);
    pixaDestroy(&pixa2);


#if 0
    pixas = (PIXA *)l_bootnum_gen1();
/*    pixas = pixaRead("recog/digits/bootnum1.pa"); */
    pixaWrite("/tmp/junk.pa", pixas);
    pixa1 = pixaRead("/tmp/junk.pa");
    pixaWrite("/tmp/junk1.pa", pixa1);
    pixa = pixaRead("/tmp/junk1.pa");
    n = pixaGetCount(pixa);
    for (i = 0; i < n; i++) {
        pix = pixaGetPix(pixa, i, L_CLONE);
        fprintf(stderr, "i = %d, text = %s\n", i, pixGetText(pix));
        pixDestroy(&pix);
    }
#endif

    return 0;
}
예제 #3
0
int main(int    argc,
         char **argv)
{
l_int32      i, j, w, h, empty;
l_uint32     redval, greenval;
l_float32    f;
L_WSHED     *wshed;
PIX         *pixs, *pixc, *pixd;
PIX         *pixt0, *pixt1, *pixt2, *pixt3, *pixt4, *pixt5;
PIX         *pixt6, *pixt7, *pixt8;
PIXA        *pixac;
PTA         *pta;
static char  mainName[] = "watershedtest";

    if (argc != 1)
        return ERROR_INT(" Syntax:  watershedtest", mainName, 1);

    pixac = pixaCreate(0);
    pixs = pixCreate(500, 500, 8);
    pixGetDimensions(pixs, &w, &h, NULL);
    for (i = 0; i < 500; i++) {
        for (j = 0; j < 500; j++) {
#if 1
            f = 128.0 + 26.3 * sin(0.0438 * (l_float32)i);
            f += 33.4 * cos(0.0712 * (l_float32)i);
            f += 18.6 * sin(0.0561 * (l_float32)j);
            f += 23.6 * cos(0.0327 * (l_float32)j);
#else
            f = 128.0 + 26.3 * sin(0.0238 * (l_float32)i);
            f += 33.4 * cos(0.0312 * (l_float32)i);
            f += 18.6 * sin(0.0261 * (l_float32)j);
            f += 23.6 * cos(0.0207 * (l_float32)j);
#endif
            pixSetPixel(pixs, j, i, (l_int32)f);
        }
    }
    pixSaveTiled(pixs, pixac, 1.0, 1, 10, 32);
    pixWrite("/tmp/pattern.png", pixs, IFF_PNG);
    startTimer();
    pixLocalExtrema(pixs, 0, 0, &pixt1, &pixt2);
    fprintf(stderr, "Time for extrema: %7.3f\n", stopTimer());
    pixSetOrClearBorder(pixt1, 2, 2, 2, 2, PIX_CLR);
    composeRGBPixel(255, 0, 0, &redval);
    composeRGBPixel(0, 255, 0, &greenval);
    pixc = pixConvertTo32(pixs);
    pixPaintThroughMask(pixc, pixt2, 0, 0, greenval);
    pixPaintThroughMask(pixc, pixt1, 0, 0, redval);
    pixSaveTiled(pixc, pixac, 1.0, 0, 10, 32);
    pixWrite("/tmp/pixc.png", pixc, IFF_PNG);
    pixSaveTiled(pixt1, pixac, 1.0, 0, 10, 32);
    pixSelectMinInConnComp(pixs, pixt1, &pta, NULL);
/*    ptaWriteStream(stderr, pta, 1); */
    pixt3 = pixGenerateFromPta(pta, w, h);
    pixSaveTiled(pixt3, pixac, 1.0, 1, 10, 32);

    pixt4 = pixConvertTo32(pixs);
    pixPaintThroughMask(pixt4, pixt3, 0, 0, greenval);
    pixSaveTiled(pixt4, pixac, 1.0, 0, 10, 32);
    pixt5 = pixRemoveSeededComponents(NULL, pixt3, pixt1, 8, 2);
    pixSaveTiled(pixt5, pixac, 1.0, 0, 10, 32);
    pixZero(pixt5, &empty);
    fprintf(stderr, "Is empty?  %d\n", empty);
    pixDestroy(&pixt4);
    pixDestroy(&pixt5);

    wshed = wshedCreate(pixs, pixt3, 10, 0);
    startTimer();
    wshedApply(wshed);
    fprintf(stderr, "Time for wshed: %7.3f\n", stopTimer());
    pixt6 = pixaDisplayRandomCmap(wshed->pixad, w, h);
    pixSaveTiled(pixt6, pixac, 1.0, 1, 10, 32);
    numaWriteStream(stderr, wshed->nalevels);
    pixt7 = wshedRenderFill(wshed);
    pixSaveTiled(pixt7, pixac, 1.0, 0, 10, 32);
    pixt8 = wshedRenderColors(wshed);
    pixSaveTiled(pixt8, pixac, 1.0, 0, 10, 32);
    wshedDestroy(&wshed);

    pixd = pixaDisplay(pixac, 0, 0);
    pixDisplay(pixd, 100, 100);
    pixWrite("/tmp/wshed.png", pixd, IFF_PNG);
    pixDestroy(&pixd);
    pixaDestroy(&pixac);

    pixDestroy(&pixt1);
    pixDestroy(&pixt2);
    pixDestroy(&pixt3);
    pixDestroy(&pixt6);
    pixDestroy(&pixt7);
    pixDestroy(&pixt8);
    pixDestroy(&pixs);
    pixDestroy(&pixc);
    ptaDestroy(&pta);
    return 0;
}
예제 #4
0
main(int    argc,
     char **argv)
{
char       textstr[256];
l_int32    i, thresh, fgval, bgval;
l_float32  scorefract;
L_BMF     *bmf;
PIX       *pixs, *pixb, *pixb2, *pixb3, *pixg, *pixp, *pixt1, *pixt2;
PIXA      *pixa;

    pixs = pixRead("1555-7.jpg");
    pixg = pixConvertTo8(pixs, 0);
    bmf = bmfCreate("fonts", 8);
    for (i = 0; i < 3; i++) {
        pixa = pixaCreate(3);
        scorefract = 0.1 * i;
        pixOtsuAdaptiveThreshold(pixg, 2000, 2000, 0, 0, scorefract,
                                 NULL, &pixb);
        pixSaveTiledOutline(pixb, pixa, 2, 1, 20, 2, 32);
        pixSplitDistributionFgBg(pixg, scorefract, 1, &thresh, &fgval, &bgval, 1);
        fprintf(stderr, "thresh = %d, fgval = %d, bgval = %d\n", thresh, fgval,
                 bgval);

        /* Give gnuplot time to write out the plot */
#ifndef  _WIN32
    sleep(1);
#else
    Sleep(1000);
#endif  /* _WIN32 */

        pixp = pixRead("/tmp/histplot.png");
        pixSaveTiled(pixp, pixa, 1, 0, 20, 1);
        pixt1 = pixaDisplay(pixa, 0, 0);
        snprintf(textstr, sizeof(textstr),
             "Scorefract = %3.1f ........... Thresh = %d", scorefract, thresh);
        pixt2 = pixAddSingleTextblock(pixt1, bmf, textstr, 0x00ff0000,
                                      L_ADD_BELOW, NULL);
        pixDisplay(pixt2, 100, 100);
        snprintf(textstr, sizeof(textstr), "/tmp/otsu.%d.png", i);
        pixWrite(textstr, pixt2, IFF_PNG);
        pixDestroy(&pixb);
        pixDestroy(&pixp);
        pixDestroy(&pixt1);
        pixDestroy(&pixt2);
        pixaDestroy(&pixa);
    }

    pixa = pixaCreate(2);
    for (i = 0; i < 2; i++) {
        scorefract = 0.1 * i;
        pixOtsuAdaptiveThreshold(pixg, 300, 300, 0, 0, scorefract,
                                 NULL, &pixb);
        pixb2 = pixAddBlackBorder(pixb, 2);
        snprintf(textstr, sizeof(textstr),
             "Scorefract = %3.1f", scorefract);
        pixb3 = pixAddSingleTextblock(pixb2, bmf, textstr, 1,
                                      L_ADD_BELOW, NULL);
        pixSaveTiled(pixb3, pixa, 2, (i + 1) % 1, 20, 32);
        pixDestroy(&pixb);
        pixDestroy(&pixb2);
    }
    pixb = pixaDisplay(pixa, 0, 0);
    pixWrite("/tmp/otsu-tiled.jpg", pixb, IFF_PNG);
    pixDestroy(&pixb);
    pixaDestroy(&pixa);

    bmfDestroy(&bmf);
    pixDestroy(&pixs);
    pixDestroy(&pixg);
    return 0;
}
예제 #5
0
int main(int    argc,
         char **argv)
{
PIX         *pixs, *pixc, *pixd;
PIXA        *pixa;
static char  mainName[] = "snapcolortest";

    if (argc != 1)
        return ERROR_INT(" Syntax:  snapcolortest", mainName, 1);

    if ((pixs = pixRead("Leptonica.jpg")) == NULL)
        return ERROR_INT("pixs not made", mainName, 1);
    pixa = pixaCreate(0);

        /* First, snap the color directly on the input rgb image. */
    pixSaveTiledOutline(pixs, pixa, 1.0, 1, 25, 2, 32);
    pixd = pixSnapColor(NULL, pixs, 0xffffff00, LEPTONICA_YELLOW, 30);
    pixSaveTiledOutline(pixd, pixa, 1.0, 0, 25, 2, 32);
    pixWrite("/tmp/logo1.jpg", pixd, IFF_JFIF_JPEG);
    pixDestroy(&pixd);

        /* Then make a colormapped version and snap the color */
    pixd = pixOctreeQuantNumColors(pixs, 250, 0);
    pixSaveTiledOutline(pixd, pixa, 1.0, 1, 25, 2, 32);
    pixSnapColor(pixd, pixd, 0xffffff00, LEPTONICA_YELLOW, 30);
    pixSaveTiledOutline(pixd, pixa, 1.0, 0, 25, 2, 32);
    pixWrite("/tmp/logo2.png", pixd, IFF_PNG);
    pixDestroy(&pixd);
    pixDestroy(&pixs);


        /* Set the background of the google searchbox to yellow.
         * The input image is colormapped with all 256 colors used. */
    if ((pixs = pixRead("google-searchbox.png")) == NULL)
        return ERROR_INT("pixs not made", mainName, 1);
    pixSaveTiledOutline(pixs, pixa, 1.0, 1, 25, 2, 32);
    pixd = pixSnapColor(NULL, pixs, 0xffffff00, LEPTONICA_YELLOW, 30);
    pixSaveTiledOutline(pixd, pixa, 1.0, 0, 25, 2, 32);
    pixWrite("/tmp/logo3.png", pixd, IFF_PNG);
    pixDestroy(&pixd);
    pixDestroy(&pixs);

        /* A couple of more, setting pixels near white to strange colors */
    pixs = pixRead("weasel4.11c.png");
    pixSaveTiledOutline(pixs, pixa, 1.0, 1, 25, 2, 32);
    pixd = pixSnapColor(NULL, pixs, 0xfefefe00, 0x80800000, 50);
    pixSaveTiledOutline(pixd, pixa, 1.0, 0, 25, 2, 32);
    pixDestroy(&pixs);
    pixDestroy(&pixd);

    pixs = pixRead("wyom.jpg");
    pixc = pixFixedOctcubeQuant256(pixs, 0);
    pixSaveTiledOutline(pixc, pixa, 1.0, 1, 25, 2, 32);
    pixd = pixSnapColor(NULL, pixc, 0xf0f0f000, 0x80008000, 100);
    pixSaveTiledOutline(pixd, pixa, 1.0, 0, 25, 2, 32);
    pixDestroy(&pixs);
    pixDestroy(&pixc);
    pixDestroy(&pixd);

        /* --- Display results --- */
    pixd = pixaDisplay(pixa, 0, 0);
    pixDisplay(pixd, 100, 100);
    pixWrite("/tmp/snap.jpg", pixd, IFF_PNG);
    pixDestroy(&pixd);
    pixaDestroy(&pixa);
    return 0;
}
예제 #6
0
파일: cctest1.c 프로젝트: vkbrad/AndroidOCR
int main(int    argc,
         char **argv)
{
char        *filein;
l_int32      i, n, count;
BOX         *box;
BOXA        *boxa;
PIX         *pixs, *pixd;
PIXA        *pixa;
PIXCMAP     *cmap;
static char  mainName[] = "cctest1";

    if (argc != 2)
        return ERROR_INT(" Syntax:  cctest1 filein", mainName, 1);

    filein = argv[1];

    if ((pixs = pixRead(filein)) == NULL)
        return ERROR_INT("pixs not made", mainName, 1);
    if (pixGetDepth(pixs) != 1)
        exit(ERROR_INT("pixs not 1 bpp", mainName, 1));

        /* Test speed of pixCountConnComp() */
    startTimer();
    for (i = 0; i < NTIMES; i++)
        pixCountConnComp(pixs, 4, &count);
    fprintf(stderr, "Time to compute 4-cc: %6.3f sec\n", stopTimer()/NTIMES);
    fprintf(stderr, "Number of 4-cc: %d\n", count);
    startTimer();
    for (i = 0; i < NTIMES; i++)
        pixCountConnComp(pixs, 8, &count);
    fprintf(stderr, "Time to compute 8-cc: %6.3f sec\n", stopTimer()/NTIMES);
    fprintf(stderr, "Number of 8-cc: %d\n", count);

        /* Test speed of pixConnComp(), with only boxa output  */
    startTimer();
    for (i = 0; i < NTIMES; i++) {
        boxa = pixConnComp(pixs, NULL, 4);
        boxaDestroy(&boxa);
    }
    fprintf(stderr, "Time to compute 4-cc: %6.3f sec\n", stopTimer()/NTIMES);
    startTimer();
    for (i = 0; i < NTIMES; i++) {
        boxa = pixConnComp(pixs, NULL, 8);
        boxaDestroy(&boxa);
    }
    fprintf(stderr, "Time to compute 8-cc: %6.3f sec\n", stopTimer()/NTIMES);

        /* Draw outline of each c.c. box */
    boxa = pixConnComp(pixs, NULL, 4);
    n = boxaGetCount(boxa);
    fprintf(stderr, "Num 4-cc boxes: %d\n", n);
    for (i = 0; i < n; i++) {
        box = boxaGetBox(boxa, i, L_CLONE);
        pixRenderBox(pixs, box, 3, L_FLIP_PIXELS);
        boxDestroy(&box);   /* remember, clones need to be destroyed */
    }
    pixDisplayWrite(pixs, 1);
    boxaDestroy(&boxa);

        /* Display each component as a random color in cmapped 8 bpp.
         * Background is color 0; it is set to white. */
    boxa = pixConnComp(pixs, &pixa, 4);
    pixd = pixaDisplayRandomCmap(pixa, pixGetWidth(pixs), pixGetHeight(pixs));
    cmap = pixGetColormap(pixd);
    pixcmapResetColor(cmap, 0, 255, 255, 255);  /* reset background to white */
    pixDisplay(pixd, 100, 100);
    pixDisplayWrite(pixd, 1);
    boxaDestroy(&boxa);
    pixDestroy(&pixd);
    pixaDestroy(&pixa);

    pixDestroy(&pixs);
    return 0;
}
l_int32 main(int    argc,
             char **argv)
{
l_int32      method, pageno;
L_DEWARP    *dew1;
L_DEWARPA   *dewa;
PIX         *pixs, *pixn, *pixg, *pixb, *pixd;
static char  mainName[] = "dewarptest2";

    if (argc != 2 && argc != 4)
        return ERROR_INT("Syntax: dewarptest2 method [image pageno]",
                         mainName, 1);

    if (argc == 2) {
        pixs = pixRead("cat.035.jpg");
        pageno = 35;
    }
    else {
        pixs = pixRead(argv[2]);
        pageno = atoi(argv[3]);
    }
    if (!pixs)
        return ERROR_INT("image not read", mainName, 1);
    method = atoi(argv[1]);
    lept_mkdir("lept/dewarp");

    if (method == 1) {  /* Use single page dewarp function */
        dewarpSinglePage(pixs, 0, 1, 1, 0, &pixd, NULL, 1);
        pixDisplay(pixd, 100, 100);
    } else {  /* Break down into multiple steps; require min of only 8 lines */
        dewa = dewarpaCreate(40, 30, 1, 8, 50);
        dewarpaUseBothArrays(dewa, 1);
        dewarpaSetCheckColumns(dewa, 0);

#if NORMALIZE
            /* Normalize for varying background and binarize */
        pixn = pixBackgroundNormSimple(pixs, NULL, NULL);
        pixg = pixConvertRGBToGray(pixn, 0.5, 0.3, 0.2);
        pixb = pixThresholdToBinary(pixg, 130);
        pixDestroy(&pixn);
#else
            /* Don't normalize; just threshold and clean edges */
        pixg = pixConvertTo8(pixs, 0);
        pixb = pixThresholdToBinary(pixg, 100);
        pixSetOrClearBorder(pixb, 30, 30, 40, 40, PIX_CLR);
#endif

            /* Run the basic functions */
        dew1 = dewarpCreate(pixb, pageno);
        dewarpaInsertDewarp(dewa, dew1);
        dewarpBuildPageModel(dew1, "/tmp/lept/dewarp/test2_model.pdf");
        dewarpaApplyDisparity(dewa, pageno, pixg, -1, 0, 0, &pixd,
                              "/tmp/lept/dewarp/test2_apply.pdf");

        dewarpaInfo(stderr, dewa);
        dewarpaDestroy(&dewa);
        pixDestroy(&pixg);
        pixDestroy(&pixb);
    }

    pixDestroy(&pixs);
    pixDestroy(&pixd);
    return 0;
}
예제 #8
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;
}
예제 #9
0
파일: bmf.c 프로젝트: ansgri/rsdt-students
/*!
 *  pixaGenerateFont()
 *
 *      Input:  dir (directory holding image of character set)
 *              size (4, 6, 8, ... , 20, in pts at 300 ppi)
 *              &bl1 (<return> baseline of row 1)
 *              &bl2 (<return> baseline of row 2)
 *              &bl3 (<return> baseline of row 3)
 *      Return: pixa of font bitmaps for 95 characters, or null on error
 *
 *  These font generation functions use 9 sets, each with bitmaps
 *  of 94 ascii characters, all in Palatino-Roman font.
 *  Each input bitmap has 3 rows of characters.  The range of
 *  ascii values in each row is as follows:
 *    row 0:  32-57   (32 is a space)
 *    row 1:  58-91   (92, '\', is not represented in this font)
 *    row 2:  93-126 
 *  We LR flip the '/' char to generate a bitmap for the missing
 *  '\' character, so that we have representations of all 95
 *  printable chars.
 *
 *  Computation of the bitmaps and baselines for a single
 *  font takes from 40 to 200 msec on a 2 GHz processor,
 *  depending on the size.  Use pixaGetFont() to read the
 *  generated character set directly from files that were
 *  produced in prog/genfonts.c using this function.
 */
PIXA *
pixaGenerateFont(const char  *dir,
                 l_int32      size,
                 l_int32     *pbl0,
                 l_int32     *pbl1,
                 l_int32     *pbl2)
{
char     *pathname;
l_int32   fileno;
l_int32   i, j, nrows, nrowchars, nchars, h, yval;
l_int32   width, height;
l_int32   baseline[3];
l_int32  *tab;
BOX      *box, *box1, *box2;
BOXA     *boxar, *boxac, *boxacs;
PIX      *pixs, *pixt1, *pixt2, *pixt3;
PIX      *pixr, *pixrc, *pixc;
PIXA     *pixa;

    PROCNAME("pixaGenerateFont");

    if (!pbl0 || !pbl1 || !pbl2)
        return (PIXA *)ERROR_PTR("&bl not all defined", procName, NULL);
    *pbl0 = *pbl1 = *pbl2 = 0;

    fileno = (size / 2) - 2;
    if (fileno < 0 || fileno > NFONTS)
        return (PIXA *)ERROR_PTR("font size invalid", procName, NULL);
    tab = makePixelSumTab8();
    pathname = genPathname(dir, inputfonts[fileno]);
    if ((pixs = pixRead(pathname)) == NULL)
        return (PIXA *)ERROR_PTR("pixs not all defined", procName, NULL);
    FREE(pathname);

    pixa = pixaCreate(95);
    pixt1 = pixMorphSequence(pixs, "c1.35 + c101.1", 0);
    boxar = pixConnComp(pixt1, NULL, 8);  /* one box for each row */
    pixDestroy(&pixt1);
    nrows = boxaGetCount(boxar);
#if  DEBUG_FONT_GEN
    fprintf(stderr, "For font %s, number of rows is %d\n",
            inputfonts[fileno], nrows);
#endif  /* DEBUG_FONT_GEN */
    if (nrows != 3) {
        L_INFO_INT2("nrows = %d; skipping font %d", procName, nrows, fileno);
        return (PIXA *)ERROR_PTR("3 rows not generated", procName, NULL);
    }
    for (i = 0; i < nrows; i++) {
        box = boxaGetBox(boxar, i, L_CLONE);
        pixr = pixClipRectangle(pixs, box, NULL);  /* row of chars */
        pixGetTextBaseline(pixr, tab, &yval);
        baseline[i] = yval;

#if DEBUG_BASELINE
      { PIX *pixbl;
        fprintf(stderr, "row %d, yval = %d, h = %d\n",
                i, yval, pixGetHeight(pixr));
        pixbl = pixCopy(NULL, pixr);
        pixRenderLine(pixbl, 0, yval, pixGetWidth(pixbl), yval, 1,
                      L_FLIP_PIXELS);
        if (i == 0 )
            pixWrite("junktl0", pixbl, IFF_PNG);
        else if (i == 1)
            pixWrite("junktl1", pixbl, IFF_PNG);
        else
            pixWrite("junktl2", pixbl, IFF_PNG);
        pixDestroy(&pixbl);
      }
#endif  /* DEBUG_BASELINE */

        boxDestroy(&box);
        pixrc = pixCloseSafeBrick(NULL, pixr, 1, 35);
        boxac = pixConnComp(pixrc, NULL, 8);
        boxacs = boxaSort(boxac, L_SORT_BY_X, L_SORT_INCREASING, NULL);
        if (i == 0) {  /* consolidate the two components of '"' */
            box1 = boxaGetBox(boxacs, 1, L_CLONE);
            box2 = boxaGetBox(boxacs, 2, L_CLONE);
            box1->w = box2->x + box2->w - box1->x;  /* increase width */
            boxDestroy(&box1);
            boxDestroy(&box2);
            boxaRemoveBox(boxacs, 2);
        }
        h = pixGetHeight(pixr);
        nrowchars = boxaGetCount(boxacs);
        for (j = 0; j < nrowchars; j++) {
            box = boxaGetBox(boxacs, j, L_COPY);
            if (box->w <= 2 && box->h == 1) {  /* skip 1x1, 2x1 components */
                boxDestroy(&box);
                continue;
            }
            box->y = 0;
            box->h = h - 1;
            pixc = pixClipRectangle(pixr, box, NULL);
            boxDestroy(&box);
            if (i == 0 && j == 0)  /* add a pix for the space; change later */
                pixaAddPix(pixa, pixc, L_COPY);
            if (i == 2 && j == 0)  /* add a pix for the '\'; change later */
                pixaAddPix(pixa, pixc, L_COPY);
            pixaAddPix(pixa, pixc, L_INSERT);
        }
        pixDestroy(&pixr);
        pixDestroy(&pixrc);
        boxaDestroy(&boxac);
        boxaDestroy(&boxacs);
    }

    nchars = pixaGetCount(pixa);
    if (nchars != 95)
        return (PIXA *)ERROR_PTR("95 chars not generated", procName, NULL);

    *pbl0 = baseline[0];
    *pbl1 = baseline[1];
    *pbl2 = baseline[2];
        
        /* Fix the space character up; it should have no ON pixels,
         * and be about twice as wide as the '!' character.    */
    pixt2 = pixaGetPix(pixa, 0, L_CLONE);
    width = 2 * pixGetWidth(pixt2);
    height = pixGetHeight(pixt2);
    pixDestroy(&pixt2);
    pixt2 = pixCreate(width, height, 1);
    pixaReplacePix(pixa, 0, pixt2, NULL);

        /* Fix up the '\' character; use a LR flip of the '/' char */
    pixt2 = pixaGetPix(pixa, 15, L_CLONE);
    pixt3 = pixFlipLR(NULL, pixt2);
    pixDestroy(&pixt2);
    pixaReplacePix(pixa, 60, pixt3, NULL);
    
#if DEBUG_CHARS
  { PIX *pixd;
    pixd = pixaDisplayTiled(pixa, 1500, 0, 10);
    pixDisplay(pixd, 100 * i, 200);
    pixDestroy(&pixd);
  }
#endif  /* DEBUG_CHARS */

    pixDestroy(&pixs);
    boxaDestroy(&boxar);
    FREE(tab);

    return pixa;
}
예제 #10
0
/*!
 *  pixFindPageForeground()
 *
 *      Input:  pixs (full resolution (any type or depth)
 *              threshold (for binarization; typically about 128)
 *              mindist (min distance of text from border to allow
 *                       cleaning near border; at 2x reduction, this
 *                       should be larger than 50; typically about 70)
 *              erasedist (when conditions are satisfied, erase anything
 *                         within this distance of the edge;
 *                         typically 30 at 2x reduction)
 *              pagenum (use for debugging when called repeatedly; labels
 *                       debug images that are assembled into pdfdir)
 *              showmorph (set to a negative integer to show steps in
 *                         generating masks; this is typically used
 *                         for debugging region extraction)
 *              display (set to 1  to display mask and selected region
 *                       for debugging a single page)
 *              pdfdir (subdirectory of /tmp where images showing the
 *                      result are placed when called repeatedly; use
 *                      null if no output requested)
 *      Return: box (region including foreground, with some pixel noise
 *                   removed), or null if not found
 *
 *  Notes:
 *      (1) This doesn't simply crop to the fg.  It attempts to remove
 *          pixel noise and junk at the edge of the image before cropping.
 *          The input @threshold is used if pixs is not 1 bpp.
 *      (2) There are several debugging options, determined by the
 *          last 4 arguments.
 *      (3) If you want pdf output of results when called repeatedly,
 *          the pagenum arg labels the images written, which go into
 *          /tmp/<pdfdir>/<pagenum>.png.  In that case,
 *          you would clean out the /tmp directory before calling this
 *          function on each page:
 *              lept_rmdir(pdfdir);
 *              lept_mkdir(pdfdir);
 */
BOX *
pixFindPageForeground(PIX         *pixs,
                      l_int32      threshold,
                      l_int32      mindist,
                      l_int32      erasedist,
                      l_int32      pagenum,
                      l_int32      showmorph,
                      l_int32      display,
                      const char  *pdfdir)
{
char     buf[64];
l_int32  flag, nbox, intersects;
l_int32  w, h, bx, by, bw, bh, left, right, top, bottom;
PIX     *pixb, *pixb2, *pixseed, *pixsf, *pixm, *pix1, *pixg2;
BOX     *box, *boxfg, *boxin, *boxd;
BOXA    *ba1, *ba2;

    PROCNAME("pixFindPageForeground");

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

        /* Binarize, downscale by 0.5, remove the noise to generate a seed,
         * and do a seedfill back from the seed into those 8-connected
         * components of the binarized image for which there was at least
         * one seed pixel.  Also clear out any components that are within
         * 10 pixels of the edge at 2x reduction. */
    flag = (showmorph) ? -1 : 0;  /* if showmorph == -1, write intermediate
                                   * images to /tmp/seq_output_1.pdf */
    pixb = pixConvertTo1(pixs, threshold);
    pixb2 = pixScale(pixb, 0.5, 0.5);
    pixseed = pixMorphSequence(pixb2, "o1.2 + c9.9 + o3.5", flag);
    pixsf = pixSeedfillBinary(NULL, pixseed, pixb2, 8);
    pixSetOrClearBorder(pixsf, 10, 10, 10, 10, PIX_SET);
    pixm = pixRemoveBorderConnComps(pixsf, 8);
    if (display) pixDisplay(pixm, 100, 100);

        /* Now, where is the main block of text?  We want to remove noise near
         * the edge of the image, but to do that, we have to be convinced that
         * (1) there is noise and (2) it is far enough from the text block
         * and close enough to the edge.  For each edge, if the block
         * is more than mindist from that edge, then clean 'erasedist'
         * pixels from the edge. */
    pix1 = pixMorphSequence(pixm, "c50.50", flag - 1);
    ba1 = pixConnComp(pix1, NULL, 8);
    ba2 = boxaSort(ba1, L_SORT_BY_AREA, L_SORT_DECREASING, NULL);
    pixGetDimensions(pix1, &w, &h, NULL);
    nbox = boxaGetCount(ba2);
    if (nbox > 1) {
        box = boxaGetBox(ba2, 0, L_CLONE);
        boxGetGeometry(box, &bx, &by, &bw, &bh);
        left = (bx > mindist) ? erasedist : 0;
        right = (w - bx - bw > mindist) ? erasedist : 0;
        top = (by > mindist) ? erasedist : 0;
        bottom = (h - by - bh > mindist) ? erasedist : 0;
        pixSetOrClearBorder(pixm, left, right, top, bottom, PIX_CLR);
        boxDestroy(&box);
    }
    pixDestroy(&pix1);
    boxaDestroy(&ba1);
    boxaDestroy(&ba2);

        /* Locate the foreground region; don't bother cropping */
    pixClipToForeground(pixm, NULL, &boxfg);

        /* Sanity check the fg region.  Make sure it's not confined
         * to a thin boundary on the left and right sides of the image,
         * in which case it is likely to be noise. */
    if (boxfg) {
        boxin = boxCreate(0.1 * w, 0, 0.8 * w, h);
        boxIntersects(boxfg, boxin, &intersects);
        if (!intersects) {
            L_INFO("found only noise on page %d\n", procName, pagenum);
            boxDestroy(&boxfg);
        }
        boxDestroy(&boxin);
    }

    boxd = NULL;
    if (!boxfg) {
        L_INFO("no fg region found for page %d\n", procName, pagenum);
    } else {
        boxAdjustSides(boxfg, boxfg, -2, 2, -2, 2);  /* tiny expansion */
        boxd = boxTransform(boxfg, 0, 0, 2.0, 2.0);

            /* Write image showing box for this page.  This is to be
             * bundled up into a pdf of all the pages, which can be
             * generated by convertFilesToPdf()  */
        if (pdfdir) {
            pixg2 = pixConvert1To4Cmap(pixb);
            pixRenderBoxArb(pixg2, boxd, 3, 255, 0, 0);
            snprintf(buf, sizeof(buf), "/tmp/%s/%05d.png", pdfdir, pagenum);
            if (display) pixDisplay(pixg2, 700, 100);
            pixWrite(buf, pixg2, IFF_PNG);
            pixDestroy(&pixg2);
        }
    }

    pixDestroy(&pixb);
    pixDestroy(&pixb2);
    pixDestroy(&pixseed);
    pixDestroy(&pixsf);
    pixDestroy(&pixm);
    boxDestroy(&boxfg);
    return boxd;
}
예제 #11
0
l_int32 main(int    argc,
             char **argv)
{
L_DEWARP   *dew1, *dew2, *dew3;
L_DEWARPA  *dewa1, *dewa2, *dewa3;
PIX        *pixs, *pixn, *pixg, *pixb, *pixd;
PIX        *pixs2, *pixn2, *pixg2, *pixb2, *pixd2;
PIX        *pixd3, *pixc1, *pixc2;

/*    pixs = pixRead("1555-7.jpg"); */
    pixs = pixRead("cat-35.jpg");
    dewa1 = dewarpaCreate(40, 30, 1, 15, 10);
    dewarpaUseBothArrays(dewa1, 1);

        /* Normalize for varying background and binarize */
    pixn = pixBackgroundNormSimple(pixs, NULL, NULL);
    pixg = pixConvertRGBToGray(pixn, 0.5, 0.3, 0.2);
    pixb = pixThresholdToBinary(pixg, 130);

        /* Run the basic functions */
    dew1 = dewarpCreate(pixb, 35);
    dewarpaInsertDewarp(dewa1, dew1);
    dewarpBuildPageModel(dew1, "/tmp/dewarp_junk35.pdf");  /* debug output */
    dewarpPopulateFullRes(dew1, pixg, 0, 0);
    dewarpaApplyDisparity(dewa1, 35, pixg, 200, 0, 0, &pixd,
                          "/tmp/dewarp_debug_35.pdf");

        /* Normalize another image. */
/*    pixs2 = pixRead("1555-3.jpg"); */
    pixs2 = pixRead("cat-7.jpg");
    pixn2 = pixBackgroundNormSimple(pixs2, NULL, NULL);
    pixg2 = pixConvertRGBToGray(pixn2, 0.5, 0.3, 0.2);
    pixb2 = pixThresholdToBinary(pixg2, 130);

        /* Run the basic functions */
    dew2 = dewarpCreate(pixb2, 7);
    dewarpaInsertDewarp(dewa1, dew2);
    dewarpBuildPageModel(dew2, "/tmp/dewarp_junk7.pdf");
    dewarpaApplyDisparity(dewa1, 7, pixg, 200, 0, 0, &pixd2,
                          "/tmp/dewarp_debug_7.pdf");

        /* Serialize and deserialize dewarpa */
    dewarpaWrite("/tmp/dewarpa1.dewa", dewa1);
    dewa2 = dewarpaRead("/tmp/dewarpa1.dewa");
    dewarpaWrite("/tmp/dewarpa2.dewa", dewa2);
    dewa3 = dewarpaRead("/tmp/dewarpa2.dewa");
    dewarpDebug(dewa3->dewarp[7], "dew1", 7);
    dewarpaWrite("/tmp/dewarpa3.dewa", dewa3);

        /* Repopulate and show the vertical disparity arrays */
    dewarpPopulateFullRes(dew1, NULL, 0, 0);
    pixc1 = fpixRenderContours(dew1->fullvdispar, 2.0, 0.2);
    pixDisplay(pixc1, 1400, 900);
    dew3 = dewarpaGetDewarp(dewa2, 35);
    dewarpPopulateFullRes(dew3, pixs, 0, 0);
    pixc2 = fpixRenderContours(dew3->fullvdispar, 2.0, 0.2);
    pixDisplay(pixc2, 1400, 900);
    dewarpaApplyDisparity(dewa2, 35, pixb, 200, 0, 0, &pixd3,
                          "/tmp/dewarp_debug_35b.pdf");
    pixDisplay(pixd, 0, 1000);
    pixDisplay(pixd2, 600, 1000);
    pixDisplay(pixd3, 1200, 1000);
    pixDestroy(&pixd3);

    dewarpaDestroy(&dewa1);
    dewarpaDestroy(&dewa2);
    dewarpaDestroy(&dewa3);
    pixDestroy(&pixs);
    pixDestroy(&pixn);
    pixDestroy(&pixg);
    pixDestroy(&pixb);
    pixDestroy(&pixd);
    pixDestroy(&pixs2);
    pixDestroy(&pixn2);
    pixDestroy(&pixg2);
    pixDestroy(&pixb2);
    pixDestroy(&pixd2);
    pixDestroy(&pixc1);
    pixDestroy(&pixc2);
    return 0;
}
예제 #12
0
main(int    argc,
     char **argv)
{
l_int32      i, j;
l_float32    f;
l_uint32     redval, greenval;
PIX         *pixs, *pixd, *pixt0, *pixt1, *pixt2, *pixt3;
static char  mainName[] = "locminmax_reg";

    if (argc != 1)
        exit(ERROR_INT("syntax: locminmax_reg", mainName, 1));

    pixs = pixCreate(500, 500, 8);
    for (i = 0; i < 500; i++) {
        for (j = 0; j < 500; j++) {
            f = 128.0 + 26.3 * sin(0.0438 * (l_float32)i);
            f += 33.4 * cos(0.0712 * (l_float32)i);
            f += 18.6 * sin(0.0561 * (l_float32)j);
            f += 23.6 * cos(0.0327 * (l_float32)j);
            pixSetPixel(pixs, j, i, (l_int32)f);
        }
    }
    pixDisplay(pixs, 0, 0);
    pixWrite("/tmp/junkpattern.png", pixs, IFF_PNG);

    startTimer();
/*    pixSelectedLocalExtrema(pixs, 1, &pixt1, &pixt2); */
    pixLocalExtrema(pixs, 0, 0, &pixt1, &pixt2);
    fprintf(stderr, "Time for extrema: %7.3f\n", stopTimer());
    composeRGBPixel(255, 0, 0, &redval);
    composeRGBPixel(0, 255, 0, &greenval);
    pixd = pixConvertTo32(pixs);
    pixPaintThroughMask(pixd, pixt2, 0, 0, greenval);
    pixPaintThroughMask(pixd, pixt1, 0, 0, redval);
    pixDisplay(pixd, 510, 0);
    pixWrite("/tmp/junkpixd.png", pixd, IFF_PNG);
    pixDestroy(&pixt1);
    pixDestroy(&pixt2);
    pixDestroy(&pixs);
    pixDestroy(&pixd);

    pixt0 = pixRead("karen8.jpg");
    pixs = pixBlockconv(pixt0, 10, 10);
    pixDisplay(pixs, 0, 400);
    pixWrite("/tmp/junkconv.png", pixs, IFF_PNG);
    startTimer();
/*    pixSelectedLocalExtrema(pixs, 1, &pixt1, &pixt2); */
    pixLocalExtrema(pixs, 50, 100, &pixt1, &pixt2);
    fprintf(stderr, "Time for extrema: %7.3f\n", stopTimer());
    composeRGBPixel(255, 0, 0, &redval);
    composeRGBPixel(0, 255, 0, &greenval);
    pixd = pixConvertTo32(pixs);
    pixPaintThroughMask(pixd, pixt2, 0, 0, greenval);
    pixPaintThroughMask(pixd, pixt1, 0, 0, redval);
    pixDisplay(pixd, 350, 400);
    pixWrite("/tmp/junkpixd2.png", pixd, IFF_PNG);
    pixDestroy(&pixt0);
    pixDestroy(&pixt1);
    pixDestroy(&pixt2);
    pixDestroy(&pixs);
    pixDestroy(&pixd);

    return 0;
}
예제 #13
0
파일: sel2.c 프로젝트: pnordhus/leptonica
/*!
 * \brief   selaAddTJunctions()
 *
 * \param[in]    sela [optional]
 * \param[in]    hlsize length of each line of hits from origin
 * \param[in]    mdist distance of misses from the origin
 * \param[in]    norient number of orientations; max of 8
 * \param[in]    debugflag 1 for debug output
 * \return  sela with additional sels, or NULL on error
 *
 * <pre>
 * Notes:
 *      (1) Adds hitmiss Sels for the T-junction of two lines.
 *          If the lines are very thin, they must be nearly orthogonal
 *          to register.
 *      (2) The number of Sels generated is 4 * %norient.
 *      (3) It is suggested that %hlsize be chosen at least 1 greater
 *          than %mdist.  Try values of (%hlsize, %mdist) such as
 *          (6,5), (7,6), (8,7), (9,7), etc.
 * </pre>
 */
SELA *
selaAddTJunctions(SELA      *sela,
                  l_float32  hlsize,
                  l_float32  mdist,
                  l_int32    norient,
                  l_int32    debugflag)
{
char       name[L_BUF_SIZE];
l_int32    i, j, k, w, xc, yc;
l_float64  pi, halfpi, radincr, jang, radang;
l_float64  angle[3], dist[3];
PIX       *pixc, *pixm, *pixt;
PIXA      *pixa;
PTA       *pta1, *pta2, *pta3;
SEL       *sel;

    PROCNAME("selaAddTJunctions");

    if (hlsize <= 2)
        return (SELA *)ERROR_PTR("hlsizel not > 1", procName, NULL);
    if (norient < 1 || norient > 8)
        return (SELA *)ERROR_PTR("norient not in [1, ... 8]", procName, NULL);

    if (!sela) {
        if ((sela = selaCreate(0)) == NULL)
            return (SELA *)ERROR_PTR("sela not made", procName, NULL);
    }

    pi = 3.1415926535;
    halfpi = 3.1415926535 / 2.0;
    radincr = halfpi / (l_float32)norient;
    w = (l_int32)(2.4 * (L_MAX(hlsize, mdist) + 0.5));
    if (w % 2 == 0)
        w++;
    xc = w / 2;
    yc = w / 2;

    pixa = pixaCreate(4 * norient);
    for (i = 0; i < norient; i++) {
        for (j = 0; j < 4; j++) {  /* 4 orthogonal orientations */
            jang = (l_float32)j * halfpi;

                /* Set the don't cares */
            pixc = pixCreate(w, w, 32);
            pixSetAll(pixc);

                /* Add the green lines of hits */
            pixm = pixCreate(w, w, 1);
            radang = (l_float32)i * radincr;
            pta1 = generatePtaLineFromPt(xc, yc, hlsize + 1, jang + radang);
            pta2 = generatePtaLineFromPt(xc, yc, hlsize + 1,
                                         jang + radang + halfpi);
            pta3 = generatePtaLineFromPt(xc, yc, hlsize + 1,
                                         jang + radang + pi);
            ptaJoin(pta1, pta2, 0, -1);
            ptaJoin(pta1, pta3, 0, -1);
            pixRenderPta(pixm, pta1, L_SET_PIXELS);
            pixPaintThroughMask(pixc, pixm, 0, 0, 0x00ff0000);
            ptaDestroy(&pta1);
            ptaDestroy(&pta2);
            ptaDestroy(&pta3);

                /* Add red misses between the lines */
            angle[0] = radang + jang - halfpi;
            angle[1] = radang + jang + 0.5 * halfpi;
            angle[2] = radang + jang + 1.5 * halfpi;
            dist[0] = 0.8 * mdist;
            dist[1] = dist[2] = mdist;
            for (k = 0; k < 3; k++) {
                pixSetPixel(pixc, xc + (l_int32)(dist[k] * cos(angle[k])),
                            yc + (l_int32)(dist[k] * sin(angle[k])),
                            0xff000000);
            }

                /* Add dark green for origin */
            pixSetPixel(pixc, xc, yc, 0x00550000);

                /* Generate the sel */
            sel = selCreateFromColorPix(pixc, NULL);
            sprintf(name, "sel_cross_%d", 4 * i + j);
            selaAddSel(sela, sel, name, 0);

            if (debugflag) {
                pixt = pixScaleBySampling(pixc, 10.0, 10.0);
                pixaAddPix(pixa, pixt, L_INSERT);
            }
            pixDestroy(&pixm);
            pixDestroy(&pixc);
        }
    }

    if (debugflag) {
        l_int32  w;
        lept_mkdir("lept/sel");
        pixaGetPixDimensions(pixa, 0, &w, NULL, NULL);
        pixt = pixaDisplayTiledAndScaled(pixa, 32, w, 4, 0, 10, 2);
        pixWrite("/tmp/lept/sel/tsel1.png", pixt, IFF_PNG);
        pixDisplay(pixt, 0, 100);
        pixDestroy(&pixt);
        pixt = selaDisplayInPix(sela, 15, 2, 20, 4);
        pixWrite("/tmp/lept/sel/tsel2.png", pixt, IFF_PNG);
        pixDisplay(pixt, 500, 100);
        pixDestroy(&pixt);
        selaWriteStream(stderr, sela);
    }
    pixaDestroy(&pixa);

    return sela;
}
예제 #14
0
파일: croptest.c 프로젝트: chewi/leptonica
int main(int    argc,
         char **argv)
{
l_int32      i, pageno, w, h, left, right;
NUMA        *na1, *nar, *naro, *narl, *nart, *nai, *naio, *nait;
PIX         *pixs, *pixr, *pixg, *pixgi, *pixd, *pix1, *pix2;
PIXA        *pixa1, *pixa2;
static char  mainName[] = "croptest";

    if (argc != 1)
        return ERROR_INT("syntax: croptest", mainName, 1);

    setLeptDebugOK(1);
    lept_mkdir("lept/crop");

    pixa1 = pixaCreate(2);
    for (i = 0; i < 2; i++) {
        pageno = extractNumberFromFilename(fnames[i], 5, 0);
        fprintf(stderr, "Page %d\n", pageno);
        pixs = pixRead(fnames[i]);
        pixr = pixRotate90(pixs, (pageno % 2) ? 1 : -1);
        pixg = pixConvertTo8(pixr, 0);
        pixGetDimensions(pixg, &w, &h, NULL);

            /* Get info on vertical reversal profile */
        nar = pixReversalProfile(pixg, 0.8, L_VERTICAL_LINE,
                                 0, h - 1, mindif, 1, 1);
        naro = numaOpen(nar, 11);
        gplotSimple1(naro, GPLOT_PNG, "/tmp/lept/crop/reversals",
                     "Reversals Opened");
        narl = numaLowPassIntervals(naro, 0.1, 0.0);
        fprintf(stderr, "narl:");
        numaWriteStream(stderr, narl);
        nart = numaThresholdEdges(naro, 0.1, 0.5, 0.0);
        fprintf(stderr, "nart:");
        numaWriteStream(stderr, nart);
        numaDestroy(&nar);
        numaDestroy(&naro);

            /* Get info on vertical intensity profile */
        pixgi = pixInvert(NULL, pixg);
        nai = pixAverageIntensityProfile(pixgi, 0.8, L_VERTICAL_LINE,
                                         0, h - 1, 1, 1);
        naio = numaOpen(nai, 11);
        gplotSimple1(naio, GPLOT_PNG, "/tmp/lept/crop/intensities",
                     "Intensities Opened");
        nait = numaThresholdEdges(naio, 0.4, 0.6, 0.0);
        fprintf(stderr, "nait:");
        numaWriteStream(stderr, nait);
        numaDestroy(&nai);
        numaDestroy(&naio);

            /* Analyze profiles for left/right edges  */
        GetLeftCut(narl, nart, nait, w, &left);
        GetRightCut(narl, nart, nait, w, &right);
        fprintf(stderr, "left = %d, right = %d\n", left, right);

            /* Output visuals */
        pixa2 = pixaCreate(3);
        pixSaveTiled(pixr, pixa2, 1.0, 1, 25, 32);
        pix1 = pixRead("/tmp/lept/crop/reversals.png");
        pix2 = pixRead("/tmp/lept/crop/intensities.png");
        pixSaveTiled(pix1, pixa2, 1.0, 1, 25, 32);
        pixSaveTiled(pix2, pixa2, 1.0, 0, 25, 32);
        pixd = pixaDisplay(pixa2, 0, 0);
        pixaDestroy(&pixa2);
        pixaAddPix(pixa1, pixd, L_INSERT);
        pixDisplay(pixd, 100, 100);
        pixDestroy(&pixs);
        pixDestroy(&pixr);
        pixDestroy(&pixg);
        pixDestroy(&pixgi);
        pixDestroy(&pix1);
        pixDestroy(&pix2);
        numaDestroy(&narl);
        numaDestroy(&nart);
        numaDestroy(&nait);
    }

    fprintf(stderr, "Writing profiles to /tmp/lept/crop/croptest.pdf\n");
    pixaConvertToPdf(pixa1, 75, 1.0, L_JPEG_ENCODE, 0, "Profiles",
                     "/tmp/lept/crop/croptest.pdf");
    pixaDestroy(&pixa1);

        /* Now plot the profiles from text lines */
    pixs = pixRead("1555.007.jpg");
    pixGetDimensions(pixs, &w, &h, NULL);
    na1 = pixReversalProfile(pixs, 0.98, L_HORIZONTAL_LINE,
                                  0, h - 1, 40, 3, 3);
    gplotSimple1(na1, GPLOT_PNG, "/tmp/lept/crop/rev", "Reversals");
    numaDestroy(&na1);

    na1 = pixAverageIntensityProfile(pixs, 0.98, L_HORIZONTAL_LINE,
                                    0, h - 1, 1, 1);
    gplotSimple1(na1, GPLOT_PNG, "/tmp/lept/crop/inten", "Intensities");
    numaDestroy(&na1);
    pixa1 = pixaCreate(3);
    pixaAddPix(pixa1, pixScale(pixs, 0.5, 0.5), L_INSERT);
    pix1 = pixRead("/tmp/lept/crop/rev.png");
    pixaAddPix(pixa1, pix1, L_INSERT);
    pix1 = pixRead("/tmp/lept/crop/inten.png");
    pixaAddPix(pixa1, pix1, L_INSERT);
    pixd = pixaDisplayTiledInRows(pixa1, 32, 1000, 1.0, 0, 30, 2);
    pixWrite("/tmp/lept/crop/profiles.png", pixd, IFF_PNG);
    pixDisplay(pixd, 100, 100);
    pixDestroy(&pixs);
    pixDestroy(&pixd);
    pixaDestroy(&pixa1);
    return 0;
}
예제 #15
0
/*!
 *  pixFindBaselines()
 *
 *      Input:  pixs (1 bpp)
 *              &pta (<optional return> pairs of pts corresponding to
 *                    approx. ends of each text line)
 *              debug (usually 0; set to 1 for debugging output)
 *      Return: na (of baseline y values), or null on error
 *
 *  Notes:
 *      (1) Input binary image must have text lines already aligned
 *          horizontally.  This can be done by either rotating the
 *          image with pixDeskew(), or, if a projective transform
 *          is required, by doing pixDeskewLocal() first.
 *      (2) Input null for &pta if you don't want this returned.
 *          The pta will come in pairs of points (left and right end
 *          of each baseline).
 *      (3) Caution: this will not work properly on text with multiple
 *          columns, where the lines are not aligned between columns.
 *          If there are multiple columns, they should be extracted
 *          separately before finding the baselines.
 *      (4) This function constructs different types of output
 *          for baselines; namely, a set of raster line values and
 *          a set of end points of each baseline.
 *      (5) This function was designed to handle short and long text lines
 *          without using dangerous thresholds on the peak heights.  It does
 *          this by combining the differential signal with a morphological
 *          analysis of the locations of the text lines.  One can also
 *          combine this data to normalize the peak heights, by weighting
 *          the differential signal in the region of each baseline
 *          by the inverse of the width of the text line found there.
 *      (6) There are various debug sections that can be turned on
 *          with the debug flag.
 */
NUMA *
pixFindBaselines(PIX     *pixs,
                 PTA    **ppta,
                 l_int32  debug)
{
l_int32    w, h, i, j, nbox, val1, val2, ndiff, bx, by, bw, bh;
l_int32    imaxloc, peakthresh, zerothresh, inpeak;
l_int32    mintosearch, max, maxloc, nloc, locval;
l_int32   *array;
l_float32  maxval;
BOXA      *boxa1, *boxa2, *boxa3;
GPLOT     *gplot;
NUMA      *nasum, *nadiff, *naloc, *naval;
PIX       *pixt1, *pixt2;
PTA       *pta;

    PROCNAME("pixFindBaselines");

    if (!pixs)
        return (NUMA *)ERROR_PTR("pixs not defined", procName, NULL);
    pta = NULL;
    if (ppta) {
        pta = ptaCreate(0);
        *ppta = pta;
    }

        /* Close up the text characters, removing noise */
    pixt1 = pixMorphSequence(pixs, "c25.1 + e3.1", 0);

        /* Save the difference of adjacent row sums.
         * The high positive-going peaks are the baselines */
    if ((nasum = pixCountPixelsByRow(pixt1, NULL)) == NULL)
        return (NUMA *)ERROR_PTR("nasum not made", procName, NULL);
    w = pixGetWidth(pixs);
    h = pixGetHeight(pixs);
    nadiff = numaCreate(h);
    numaGetIValue(nasum, 0, &val2);
    for (i = 0; i < h - 1; i++) {
        val1 = val2;
        numaGetIValue(nasum, i + 1, &val2);
        numaAddNumber(nadiff, val1 - val2);
    }

    if (debug)  /* show the difference signal */
        gplotSimple1(nadiff, GPLOT_X11, "junkdiff", "difference");

        /* Use the zeroes of the profile to locate each baseline. */
    array = numaGetIArray(nadiff);
    ndiff = numaGetCount(nadiff);
    numaGetMax(nadiff, &maxval, &imaxloc);
        /* Use this to begin locating a new peak: */
    peakthresh = (l_int32)maxval / PEAK_THRESHOLD_RATIO;
        /* Use this to begin a region between peaks: */
    zerothresh = (l_int32)maxval / ZERO_THRESHOLD_RATIO;
    naloc = numaCreate(0);
    naval = numaCreate(0);
    inpeak = FALSE;
    for (i = 0; i < ndiff; i++) {
        if (inpeak == FALSE) {
            if (array[i] > peakthresh) {  /* transition to in-peak */
                inpeak = TRUE;
                mintosearch = i + MIN_DIST_IN_PEAK; /* accept no zeros
                                               * between i and mintosearch */
                max = array[i];
                maxloc = i;
            }
        }
        else {  /* inpeak == TRUE; look for max */
            if (array[i] > max) {
                max = array[i];
                maxloc = i;
                mintosearch = i + MIN_DIST_IN_PEAK;
            }
            else if (i > mintosearch && array[i] <= zerothresh) {  /* leave */
                inpeak = FALSE;
                numaAddNumber(naval, max);
                numaAddNumber(naloc, maxloc);
            }
        }
    }

        /* If array[ndiff-1] is max, eg. no descenders, baseline at bottom */
    if (inpeak) {
        numaAddNumber(naval, max);
        numaAddNumber(naloc, maxloc);
    }
    FREE(array);

    if (debug) {  /* show the raster locations for the peaks */
        gplot = gplotCreate("junkloc", GPLOT_X11, "Peak locations",
                            "rasterline", "height");
        gplotAddPlot(gplot, naloc, naval, GPLOT_POINTS, "locs");
        gplotMakeOutput(gplot);
        gplotDestroy(&gplot);
    }
                
        /* Generate an approximate profile of text line width.
         * First, filter the boxes of text, where there may be
         * more than one box for a given textline. */
    pixt2 = pixMorphSequence(pixt1, "r11 + c25.1 + o7.1 +c1.3", 0);
    boxa1 = pixConnComp(pixt2, NULL, 4);
    boxa2 = boxaTransform(boxa1, 0, 0, 4., 4.);
    boxa3 = boxaSort(boxa2, L_SORT_BY_Y, L_SORT_INCREASING, NULL);
    
        /* Then find the baseline segments */
    if (pta) {
      nloc = numaGetCount(naloc);
      nbox = boxaGetCount(boxa3);
      for (i = 0; i < nbox; i++) {
          boxaGetBoxGeometry(boxa3, i, &bx, &by, &bw, &bh);
          for (j = 0; j < nloc; j++) {
              numaGetIValue(naloc, j, &locval);
              if (L_ABS(locval - (by + bh)) > 25)
                  continue;
              ptaAddPt(pta, bx, locval);
              ptaAddPt(pta, bx + bw, locval);
              break;
          }
      }
    }

    if (debug) {  /* display baselines */
        PIX     *pixd; 
        l_int32  npts, x1, y1, x2, y2;
        if (pta) {
            pixd = pixConvertTo32(pixs);
            npts = ptaGetCount(pta);
            for (i = 0; i < npts; i += 2) {
                ptaGetIPt(pta, i, &x1, &y1);
                ptaGetIPt(pta, i + 1, &x2, &y2);
                pixRenderLineArb(pixd, x1, y1, x2, y2, 1, 255, 0, 0);
            }
            pixDisplay(pixd, 200, 200);
            pixWrite("junkbaselines", pixd, IFF_PNG);
            pixDestroy(&pixd);
        }
    }
            
    boxaDestroy(&boxa1);
    boxaDestroy(&boxa2);
    boxaDestroy(&boxa3);
    pixDestroy(&pixt1);
    pixDestroy(&pixt2);
    numaDestroy(&nasum);
    numaDestroy(&nadiff);
    numaDestroy(&naval);
    return naloc;
}
main(int    argc,
     char **argv)
{
l_uint8     *array1, *array2;
l_int32      i, n, np, same, diff, nbytes1, nbytes2;
FILE        *fp;
BOX         *box;
BOXA        *boxa, *boxa2;
PIX         *pixs, *pixd;
PIXA        *pixa;
PIXCMAP     *cmap;
static char  mainName[] = "conncomp_reg";

    if (argc != 1)
	exit(ERROR_INT(" Syntax: conncomp_reg", mainName, 1));

    if ((pixs = pixRead("feyn.tif")) == NULL)
	exit(ERROR_INT("pixs not made", mainName, 1));
	    
	/* Test pixConnComp() with output to both boxa and pixa */
	/* First, test with 4-cc */
    boxa = pixConnComp(pixs, &pixa, 4);
    n = boxaGetCount(boxa);
    fprintf(stderr, "Number of 4 c.c. b.b: %d\n", n);
    np = pixaGetCount(pixa);
    fprintf(stderr, "Number of 4 c.c. pix: %d\n", np);
    pixd = pixaDisplay(pixa, pixGetWidth(pixs), pixGetHeight(pixs));
    pixWrite("/tmp/junkout1.png", pixd, IFF_PNG);
    pixEqual(pixs, pixd, &same);
    if (same == 1)
	fprintf(stderr, "Source and reconstructed pix are the same.\n");
    else
	fprintf(stderr, "Error: source and reconstructed pix differ!\n");
    pixaDestroy(&pixa);
    boxaDestroy(&boxa);
    pixDestroy(&pixd);

	/* Test with 8-cc */
    boxa = pixConnComp(pixs, &pixa, 8);
    n = boxaGetCount(boxa);
    fprintf(stderr, "Number of 8 c.c. b.b: %d\n", n);
    np = pixaGetCount(pixa);
    fprintf(stderr, "Number of 8 c.c. pix: %d\n", np);
    pixd = pixaDisplay(pixa, pixGetWidth(pixs), pixGetHeight(pixs));
    pixWrite("/tmp/junkout2.png", pixd, IFF_PNG);
    pixEqual(pixs, pixd, &same);
    if (same == 1)
	fprintf(stderr, "Source and reconstructed pix are the same.\n");
    else
	fprintf(stderr, "Error: source and reconstructed pix differ!\n");
    pixaDestroy(&pixa);
    boxaDestroy(&boxa);
    pixDestroy(&pixd);

	/* Test i/o */
    boxa = pixConnComp(pixs, NULL, 4);
    fp = fopen("/tmp/junk1.ba", "wb+");
    boxaWriteStream(fp, boxa);
    fclose(fp);
    fp = fopen("/tmp/junk1.ba", "r");
    boxa2 = boxaReadStream(fp);
    fclose(fp);
    fp = fopen("/tmp/junk2.ba", "wb+");
    boxaWriteStream(fp, boxa2);
    fclose(fp);
    array1 = arrayRead("/tmp/junk1.ba", &nbytes1);
    array2 = arrayRead("/tmp/junk2.ba", &nbytes2);
    diff = strcmp((char *)array1, (char *)array2);
    if (nbytes1 != nbytes2 || diff)
	fprintf(stderr, "I/O error for boxes.\n");
    else
	fprintf(stderr, "I/O valid for boxes.\n");
    FREE(array1);
    FREE(array2);
    boxaDestroy(&boxa);
    boxaDestroy(&boxa2);

        /* Just for fun, display each component as a random color
	 * in cmapped 8 bpp.  Background is color 0; it is set to white. */
    boxa = pixConnComp(pixs, &pixa, 4);
    pixd = pixaDisplayRandomCmap(pixa, pixGetWidth(pixs), pixGetHeight(pixs));
    cmap = pixGetColormap(pixd);
    pixcmapResetColor(cmap, 0, 255, 255, 255);  /* reset background to white */
    pixDisplay(pixd, 100, 100);
    boxaDestroy(&boxa);
    pixDestroy(&pixd);
    pixaDestroy(&pixa);

    pixDestroy(&pixs);

    exit(0);
}
예제 #17
0
main(int    argc,
     char **argv)
{
l_int32      index, maxiters, type;
BOX         *box;
PIX         *pix, *pixs, *pixd, *pixt;
PIXA        *pixa;
static char  mainName[] = "ccthin2_reg";

    if (argc != 1 && argc != 3)
	exit(ERROR_INT(" Syntax: ccthin2_reg [index maxiters]", mainName, 1));

    pixDisplayWrite(NULL, 0);
    if ((pix = pixRead("feyn.tif")) == NULL)
	exit(ERROR_INT("pix not made", mainName, 1));
    box = boxCreate(683, 799, 970, 479);
    pixs = pixClipRectangle(pix, box, NULL);
    pixDisplayWrite(pixs, 1);

        /* Just do one of the examples */
    if (argc == 3) {
        index = atoi(argv[1]);
        maxiters = atoi(argv[2]);
        if (index <= 7)
            type = L_THIN_FG;
        else
            type = L_THIN_BG;
        pixt = pixThinExamples(pixs, type, index, maxiters,
                               "/tmp/junksels.png");
        pixDisplay(pixt, 100, 100);
        pixDisplayWrite(pixt, 1);
        pixDestroy(&pixt);
        pixDisplayMultiple("/tmp/junk_write_display*");
        return 0;
    }

        /* Do all the examples */
    pixt = pixThinExamples(pixs, L_THIN_FG, 1, 0, "/tmp/junksel_example1.png");
    pixDisplayWrite(pixt, 1);
    pixDestroy(&pixt);
    pixt = pixThinExamples(pixs, L_THIN_FG, 2, 0, "/tmp/junksel_example2.png");
    pixDisplayWrite(pixt, 1);
    pixDestroy(&pixt);
    pixt = pixThinExamples(pixs, L_THIN_FG, 3, 0, "/tmp/junksel_example3.png");
    pixDisplayWrite(pixt, 1);
    pixDestroy(&pixt);
    pixt = pixThinExamples(pixs, L_THIN_FG, 4, 0, "/tmp/junksel_example4.png");
    pixDisplayWrite(pixt, 1);
    pixDestroy(&pixt);
    pixt = pixThinExamples(pixs, L_THIN_FG, 5, 0, "/tmp/junksel_example5.png");
    pixDisplayWrite(pixt, 1);
    pixDestroy(&pixt);
    pixt = pixThinExamples(pixs, L_THIN_FG, 6, 0, "/tmp/junksel_example6.png");
    pixDisplayWrite(pixt, 1);
    pixDestroy(&pixt);
    pixt = pixThinExamples(pixs, L_THIN_FG, 7, 0, "/tmp/junksel_example7.png");
    pixDisplayWrite(pixt, 1);
    pixDestroy(&pixt);
    pixt = pixThinExamples(pixs, L_THIN_BG, 8, 5, "/tmp/junksel_example8.png");
    pixDisplayWrite(pixt, 1);
    pixDestroy(&pixt);
    pixt = pixThinExamples(pixs, L_THIN_BG, 9, 5, "/tmp/junksel_example9.png");
    pixDisplayWrite(pixt, 1);
    pixDestroy(&pixt);

        /* Display the thinning results */
    pixa = pixaReadFiles("/tmp", "junk_write_display");
    pixd = pixaDisplayTiledAndScaled(pixa, 8, 500, 1, 0, 25, 2);
    pixWrite("/tmp/junktiles.jpg", pixd, IFF_JFIF_JPEG);
    pixDestroy(&pixd);
    pixaDestroy(&pixa);

        /* Display the sels used in the examples */
    pixa = pixaReadFiles("/tmp", "junksel_example");
    pixd = pixaDisplayTiledInRows(pixa, 1, 500, 1.0, 0, 50, 2);
    pixWrite("/tmp/junksels.png", pixd, IFF_PNG);
    pixDestroy(&pixd);
    pixaDestroy(&pixa);

    pixDestroy(&pix);
    pixDestroy(&pixs);
    boxDestroy(&box);

    pixDisplayMultiple("/tmp/junk_write_display*");
    return 0;
}
예제 #18
0
/*!
 *  dewarpBuildModel()
 *
 *      Input:  dew
 *              debugflag (1 for debugging output)
 *      Return: 0 if OK, 1 on error
 *
 *  Notes:
 *      (1) This is the basic function that builds the vertical
 *          disparity array, which allows determination of the
 *          src pixel in the input image corresponding to each
 *          dest pixel in the dewarped image.
 *      (2) The method is as follows:
 *          * Estimate the centers of all the long textlines and
 *            fit a LS quadratic to each one.  This smooths the curves.
 *          * Sample each curve at a regular interval, find the y-value
 *            of the flat point on each curve, and subtract the sampled
 *            curve value from this value.  This is the vertical
 *            disparity.
 *          * Fit a LS quadratic to each set of vertically aligned
 *            disparity samples.  This smooths the disparity values
 *            in the vertical direction.  Then resample at the same
 *            regular interval,  We now have a regular grid of smoothed
 *            vertical disparity valuels.
 *          * Interpolate this grid to get a full resolution disparity
 *            map.  This can be applied directly to the src image
 *            pixels to dewarp the image in the vertical direction,
 *            making all textlines horizontal.
 */
l_int32
dewarpBuildModel(L_DEWARP  *dew,
                 l_int32    debugflag)
{
char       *tempname;
l_int32     i, j, nlines, nx, ny, sampling;
l_float32   c0, c1, c2, x, y, flaty, val;
l_float32  *faflats;
NUMA       *nax, *nafit, *nacurve, *nacurves, *naflat, *naflats, *naflatsi;
PIX        *pixs, *pixt1, *pixt2;
PTA        *pta, *ptad;
PTAA       *ptaa1, *ptaa2, *ptaa3, *ptaa4, *ptaa5, *ptaa6, *ptaa7;
FPIX       *fpix1, *fpix2, *fpix3;

    PROCNAME("dewarpBuildModel");

    if (!dew)
        return ERROR_INT("dew not defined", procName, 1);

    pixs = dew->pixs;
    if (debugflag) {
        pixDisplayWithTitle(pixs, 0, 0, "pixs", 1);
        pixWriteTempfile("/tmp", "pixs.png", pixs, IFF_PNG, NULL);
    }

        /* Make initial estimate of centers of textlines */
    ptaa1 = pixGetTextlineCenters(pixs, DEBUG_TEXTLINE_CENTERS);
    if (debugflag) {
        pixt1 = pixConvertTo32(pixs);
        pixt2 = pixDisplayPtaa(pixt1, ptaa1);
        pixWriteTempfile("/tmp", "lines1.png", pixt2, IFF_PNG, NULL);
        pixDestroy(&pixt1);
        pixDestroy(&pixt2);
    }

        /* Remove all lines that are not near the length
         * of the longest line. */
    ptaa2 = ptaaRemoveShortLines(pixs, ptaa1, 0.8, DEBUG_SHORT_LINES);
    if (debugflag) {
        pixt1 = pixConvertTo32(pixs);
        pixt2 = pixDisplayPtaa(pixt1, ptaa2);
        pixWriteTempfile("/tmp", "lines2.png", pixt2, IFF_PNG, NULL);
        pixDestroy(&pixt1);
        pixDestroy(&pixt2);
    }
    nlines = ptaaGetCount(ptaa2);
    if (nlines < dew->minlines)
        return ERROR_INT("insufficient lines to build model", procName, 1);

        /* Do quadratic fit to smooth each line.  A single quadratic
         * over the entire width of the line appears to be sufficient.
         * Quartics tend to overfit to noise.  Each line is thus
         * represented by three coefficients: c2 * x^2 + c1 * x + c0.
         * Using the coefficients, sample each fitted curve uniformly
         * across the full width of the image.  */
    sampling = dew->sampling;
    nx = dew->nx;
    ny = dew->ny;
    ptaa3 = ptaaCreate(nlines);
    nacurve = numaCreate(nlines);  /* stores curvature coeff c2 */
    for (i = 0; i < nlines; i++) {  /* for each line */
        pta = ptaaGetPta(ptaa2, i, L_CLONE);
        ptaGetQuadraticLSF(pta, &c2, &c1, &c0, NULL);
        numaAddNumber(nacurve, c2);
        ptad = ptaCreate(nx);
        for (j = 0; j < nx; j++) {  /* uniformly sampled in x */
             x = j * sampling;
             applyQuadraticFit(c2, c1, c0, x, &y);
             ptaAddPt(ptad, x, y);
        }
        ptaaAddPta(ptaa3, ptad, L_INSERT);
        ptaDestroy(&pta);
    }
    if (debugflag) {
        ptaa4 = ptaaCreate(nlines);
        for (i = 0; i < nlines; i++) {
            pta = ptaaGetPta(ptaa2, i, L_CLONE);
            ptaGetArrays(pta, &nax, NULL);
            ptaGetQuadraticLSF(pta, NULL, NULL, NULL, &nafit);
            ptad = ptaCreateFromNuma(nax, nafit);
            ptaaAddPta(ptaa4, ptad, L_INSERT);
            ptaDestroy(&pta);
            numaDestroy(&nax);
            numaDestroy(&nafit);
        }
        pixt1 = pixConvertTo32(pixs);
        pixt2 = pixDisplayPtaa(pixt1, ptaa4);
        pixWriteTempfile("/tmp", "lines3.png", pixt2, IFF_PNG, NULL);
        pixDestroy(&pixt1);
        pixDestroy(&pixt2);
        ptaaDestroy(&ptaa4);
    }

        /* Find and save the flat points in each curve. */
    naflat = numaCreate(nlines);
    for (i = 0; i < nlines; i++) {
        pta = ptaaGetPta(ptaa3, i, L_CLONE);
        numaGetFValue(nacurve, i, &c2);
        if (c2 <= 0)  /* flat point at bottom; max value of y in curve */
            ptaGetRange(pta, NULL, NULL, NULL, &flaty);
        else  /* flat point at top; min value of y in curve */
            ptaGetRange(pta, NULL, NULL, &flaty, NULL);
        numaAddNumber(naflat, flaty);
        ptaDestroy(&pta);
    }

        /* Sort the lines in ptaa3 by their position */
    naflatsi = numaGetSortIndex(naflat, L_SORT_INCREASING);
    naflats = numaSortByIndex(naflat, naflatsi);
    nacurves = numaSortByIndex(nacurve, naflatsi);
    dew->naflats = naflats;
    dew->nacurves = nacurves;
    ptaa4 = ptaaSortByIndex(ptaa3, naflatsi);
    numaDestroy(&naflat);
    numaDestroy(&nacurve);
    numaDestroy(&naflatsi);
    if (debugflag) {
        tempname = genTempFilename("/tmp", "naflats.na", 0);
        numaWrite(tempname, naflats);
        FREE(tempname);
    }

        /* Convert the sampled points in ptaa3 to a sampled disparity with
         * with respect to the flat point in the curve. */
    ptaa5 = ptaaCreate(nlines);
    for (i = 0; i < nlines; i++) {
        pta = ptaaGetPta(ptaa4, i, L_CLONE);
        numaGetFValue(naflats, i, &flaty);
        ptad = ptaCreate(nx);
        for (j = 0; j < nx; j++) {
            ptaGetPt(pta, j, &x, &y);
            ptaAddPt(ptad, x, flaty - y);
        }
        ptaaAddPta(ptaa5, ptad, L_INSERT);
        ptaDestroy(&pta);
    }
    if (debugflag) {
        tempname = genTempFilename("/tmp", "ptaa5.ptaa", 0);
        ptaaWrite(tempname, ptaa5, 0);
        FREE(tempname);
    }

        /* Generate a ptaa taking vertical 'columns' from ptaa5.
         * We want to fit the vertical disparity on the column to the
         * vertical position of the line, which we call 'y' here and
         * obtain from naflats. */
    ptaa6 = ptaaCreate(nx);
    faflats = numaGetFArray(naflats, L_NOCOPY);
    for (j = 0; j < nx; j++) {
        pta = ptaCreate(nlines);
        for (i = 0; i < nlines; i++) {
            y = faflats[i];
            ptaaGetPt(ptaa5, i, j, NULL, &val);  /* disparity value */
            ptaAddPt(pta, y, val);
        }
        ptaaAddPta(ptaa6, pta, L_INSERT);
    }
    if (debugflag) {
        tempname = genTempFilename("/tmp", "ptaa6.ptaa", 0);
        ptaaWrite(tempname, ptaa6, 0);
        FREE(tempname);
    }

        /* Do quadratic fit vertically on a subset of pixel columns
         * for the vertical displacement, which identifies the
         * src pixel(s) for each dest pixel.  Sample the displacement
         * on a regular grid in the vertical direction.   */
    ptaa7 = ptaaCreate(nx);  /* uniformly sampled across full height of image */
    for (j = 0; j < nx; j++) {  /* for each column */
        pta = ptaaGetPta(ptaa6, j, L_CLONE);
        ptaGetQuadraticLSF(pta, &c2, &c1, &c0, NULL);
        ptad = ptaCreate(ny);
        for (i = 0; i < ny; i++) {  /* uniformly sampled in y */
             y = i * sampling;
             applyQuadraticFit(c2, c1, c0, y, &val);
             ptaAddPt(ptad, y, val);
        }
        ptaaAddPta(ptaa7, ptad, L_INSERT);
        ptaDestroy(&pta);
    }
    if (debugflag) {
        tempname = genTempFilename("/tmp", "ptaa7.ptaa", 0);
        ptaaWrite(tempname, ptaa7, 0);
        FREE(tempname);
    }

        /* Save the result in a fpix at the specified subsampling  */
    fpix1 = fpixCreate(nx, ny);
    for (i = 0; i < ny; i++) {
        for (j = 0; j < nx; j++) {
            ptaaGetPt(ptaa7, j, i, NULL, &val);
            fpixSetPixel(fpix1, j, i, val);
        }
    }
    dew->sampvdispar = fpix1;

        /* Generate a full res fpix for vertical dewarping.  We require that
         * the size of this fpix is at least as big as the input image. */
    fpix2 = fpixScaleByInteger(fpix1, sampling);
    dew->fullvdispar = fpix2;
    if (debugflag) {
        pixt1 = fpixRenderContours(fpix2, -2., 2.0, 0.2);
        pixWriteTempfile("/tmp", "vert-contours.png", pixt1, IFF_PNG, NULL);
        pixDisplay(pixt1, 1000, 0);
        pixDestroy(&pixt1);
    }

        /* Generate full res and sampled fpix for horizontal dewarping.  This
         * works to the extent that the line curvature is due to bending
         * out of the plane normal to the camera, and not wide-angle
         * "fishbowl" distortion.  Also generate the sampled horizontal
         * disparity array. */
    if (dew->applyhoriz) {
        fpix3 = fpixBuildHorizontalDisparity(fpix2, 0, &dew->extraw);
        dew->fullhdispar = fpix3;
        dew->samphdispar = fpixSampledDisparity(fpix3, dew->sampling);
        if (debugflag) {
            pixt1 = fpixRenderContours(fpix3, -2., 2.0, 0.2);
            pixWriteTempfile("/tmp", "horiz-contours.png", pixt1,
                             IFF_PNG, NULL);
            pixDisplay(pixt1, 1000, 0);
            pixDestroy(&pixt1);
        }
    }

    dew->success = 1;

    ptaaDestroy(&ptaa1);
    ptaaDestroy(&ptaa2);
    ptaaDestroy(&ptaa3);
    ptaaDestroy(&ptaa4);
    ptaaDestroy(&ptaa5);
    ptaaDestroy(&ptaa6);
    ptaaDestroy(&ptaa7);
    return 0;
}
예제 #19
0
main(int    argc,
     char **argv)
{
char         buf[8];
l_int32      i, n, h;
l_float32    scalefact;
BOXA        *boxa;
PIX         *pixs, *pix, *pixt1, *pixt2;
PIXA        *pixa, *pixas, *pixad;
PIXAA       *pixaa;
static char  mainName[] = "digitprep1";

    if (argc != 1) {
        ERROR_INT(" Syntax: digitprep1", mainName, 1);
        return 1;
    }

    if ((pixs = pixRead("barcode-digits.png")) == NULL)
        return ERROR_INT("pixs not read", mainName, 1);

        /* Extract the digits and scale to HEIGHT */
    boxa = pixConnComp(pixs, &pixa, 8);
    pixas = pixaSort(pixa, L_SORT_BY_X, L_SORT_INCREASING, NULL, L_CLONE);
    n = pixaGetCount(pixas);

        /* Move the last ("0") to the first position */
    pixt1 = pixaGetPix(pixas, n - 1, L_CLONE);
    pixaInsertPix(pixas, 0, pixt1, NULL);
    pixaRemovePix(pixas, n);

        /* Make the output scaled pixa */
    pixad = pixaCreate(n);
    for (i = 0; i < n; i++) {
        pixt1 = pixaGetPix(pixas, i, L_CLONE);
        pixGetDimensions(pixt1, NULL, &h, NULL);
        scalefact = HEIGHT / (l_float32)h;
        pixt2 = pixScale(pixt1, scalefact, scalefact);
        if (pixGetHeight(pixt2) != 32)
            return ERROR_INT("height not 32!", mainName, 1);
        sprintf(buf, "%d", i);
        pixSetText(pixt2, buf);
        pixaAddPix(pixad, pixt2, L_INSERT);
        pixDestroy(&pixt1);
    }

        /* Save in a pixaa, with 1 pix in each pixa */
    pixaa = pixaaCreateFromPixa(pixad, 1, L_CHOOSE_CONSECUTIVE, L_CLONE);
    pixaaWrite("junkdigits.pixaa", pixaa);

        /* Show result */
    pixt1 = pixaaDisplayByPixa(pixaa, 20, 20, 1000);
    pixDisplay(pixt1, 100, 100);
    pixDestroy(&pixt1);

    boxaDestroy(&boxa);
    pixaDestroy(&pixa);
    pixaDestroy(&pixas);
    pixaDestroy(&pixad);
    pixaaDestroy(&pixaa);
    return 0;
}
예제 #20
0
main(int    argc,
     char **argv)
{
PIX         *pixs, *pixg, *pixc, *pixt, *pixd;
PIXA        *pixa;
static char  mainName[] = "blend_reg";

    pixg = pixRead("blender8.png");
    pixt = pixRead("weasel4.11c.png");
    pixc = pixRemoveColormap(pixt, REMOVE_CMAP_TO_FULL_COLOR);
    pixDisplayWrite(NULL, -1);
    pixa = pixaCreate(0);

#if 1
        /* Gray blend (straight) */
    pixs = pixRead("test24.jpg");
    GrayBlend(pixs, pixg, L_BLEND_GRAY, 0.3);
    pixSaveTiled(pixs, pixa, 1, 1, 20, 32);
    pixDisplayWithTitle(pixs, 100, 100, NULL, DISPLAY);
    pixDestroy(&pixs);
    pixs = pixRead("marge.jpg");
    GrayBlend(pixs, pixg, L_BLEND_GRAY, 0.2);
    pixSaveTiled(pixs, pixa, 1, 1, 20, 32);
    pixDisplayWithTitle(pixs, 100, 100, NULL, DISPLAY);
    pixDestroy(&pixs);
    pixs = pixRead("marge.jpg");
    pixt = pixConvertRGBToLuminance(pixs);
    GrayBlend(pixt, pixg, L_BLEND_GRAY, 0.2);
    pixSaveTiled(pixt, pixa, 1, 0, 20, 32);
    pixDisplayWithTitle(pixt, 100, 100, NULL, DISPLAY);
    pixDestroy(&pixs);
    pixDestroy(&pixt);
#endif

#if 1
        /* Gray blend (inverse) */
    pixs = pixRead("test24.jpg");
    GrayBlend(pixs, pixg, L_BLEND_GRAY_WITH_INVERSE, 0.6);
    pixSaveTiled(pixs, pixa, 1, 1, 20, 32);
    pixDisplayWithTitle(pixs, 100, 100, NULL, DISPLAY);
    pixDestroy(&pixs);
    pixs = pixRead("marge.jpg");
    GrayBlend(pixs, pixg, L_BLEND_GRAY_WITH_INVERSE, 0.6);
    pixSaveTiled(pixs, pixa, 1, 1, 20, 32);
    pixDisplayWithTitle(pixs, 100, 100, NULL, DISPLAY);
    pixDestroy(&pixs);
    pixs = pixRead("marge.jpg");
    pixt = pixConvertRGBToLuminance(pixs);
    GrayBlend(pixt, pixg, L_BLEND_GRAY_WITH_INVERSE, 0.6);
    pixSaveTiled(pixt, pixa, 1, 0, 20, 32);
    pixDisplayWithTitle(pixt, 100, 100, NULL, DISPLAY);
    pixDestroy(&pixs);
    pixDestroy(&pixt);
    pixs = MakeGrayWash(1000, 120);
    GrayBlend(pixs, pixg, L_BLEND_GRAY_WITH_INVERSE, 0.3);
    pixSaveTiled(pixs, pixa, 1, 1, 20, 32);
    pixDisplayWithTitle(pixs, 200, 100, NULL, DISPLAY);
    pixDestroy(&pixs);
    pixs = MakeColorWash(1000, 120, COLOR_RED);
    GrayBlend(pixs, pixg, L_BLEND_GRAY_WITH_INVERSE, 1.0);
    pixSaveTiled(pixs, pixa, 1, 1, 20, 32);
    pixDisplayWithTitle(pixs, 200, 100, NULL, DISPLAY);
    pixDestroy(&pixs);
#endif

#if 1
        /* Adaptive gray blend */
    pixs = pixRead("test24.jpg");
    AdaptiveGrayBlend(pixs, pixg, 0.8);
    pixSaveTiled(pixs, pixa, 1, 1, 20, 32);
    pixDisplayWithTitle(pixs, 200, 100, NULL, DISPLAY);
    pixDestroy(&pixs);
    pixs = pixRead("marge.jpg");
    AdaptiveGrayBlend(pixs, pixg, 0.8);
    pixSaveTiled(pixs, pixa, 1, 1, 20, 32);
    pixDisplayWithTitle(pixs, 200, 100, NULL, DISPLAY);
    pixt = pixConvertRGBToLuminance(pixs);
    AdaptiveGrayBlend(pixt, pixg, 0.1);
    pixSaveTiled(pixt, pixa, 1, 0, 20, 32);
    pixDisplayWithTitle(pixt, 200, 100, NULL, DISPLAY);
    pixDestroy(&pixs);
    pixDestroy(&pixt);
    pixs = MakeGrayWash(1000, 120);
    AdaptiveGrayBlend(pixs, pixg, 0.3);
    pixSaveTiled(pixs, pixa, 1, 1, 20, 32);
    pixDisplayWithTitle(pixs, 200, 100, NULL, DISPLAY);
    pixDestroy(&pixs);
    pixs = MakeColorWash(1000, 120, COLOR_RED);
    AdaptiveGrayBlend(pixs, pixg, 0.5);
    pixSaveTiled(pixs, pixa, 1, 1, 20, 32);
    pixDisplayWithTitle(pixs, 200, 100, NULL, DISPLAY);
    pixDestroy(&pixs);
#endif

#if 1
        /* Color blend */
    pixs = pixRead("test24.jpg");
    ColorBlend(pixs, pixc, 0.3);
    pixSaveTiled(pixs, pixa, 1, 1, 20, 32);
    pixDisplayWithTitle(pixs, 300, 100, NULL, DISPLAY);
    pixDestroy(&pixs);
    pixs = pixRead("marge.jpg");
    ColorBlend(pixs, pixc, 0.30);
    pixSaveTiled(pixs, pixa, 1, 1, 20, 32);
    pixDisplayWithTitle(pixs, 300, 100, NULL, DISPLAY);
    pixDestroy(&pixs);
    pixs = pixRead("marge.jpg");
    ColorBlend(pixs, pixc, 0.15);
    pixSaveTiled(pixs, pixa, 1, 0, 20, 32);
    pixDisplayWithTitle(pixs, 300, 100, NULL, DISPLAY);
    pixDestroy(&pixs);
#endif

        /* Display results */
    pixd = pixaDisplay(pixa, 0, 0);
    pixDisplay(pixd, 100, 100);
    pixWrite("/tmp/junkblend.jpg", pixd, IFF_JFIF_JPEG);
    pixDestroy(&pixd);
    pixaDestroy(&pixa);

    pixDisplayMultiple("/tmp/junk_write_display*");

    pixDestroy(&pixg);
    pixDestroy(&pixt);
    pixDestroy(&pixc);
    return 0;
}
예제 #21
0
main(int    argc,
     char **argv)
{
l_int32      i, j, wc, hc, d;
L_KERNEL    *kel1, *kel2;
PIX         *pixs, *pixg, *pixacc, *pixd, *pixt;
char        *filein, *fileout;
static char  mainName[] = "convolvetest";

    if (argc != 5)
	exit(ERROR_INT(" Syntax:  convolvetest filein wc hc fileout", mainName, 1));

    filein = argv[1];
    wc = atoi(argv[2]);
    hc = atoi(argv[3]);
    fileout = argv[4];

    if ((pixs = pixRead(filein)) == NULL)
	exit(ERROR_INT("pix not made", mainName, 1));

#if 0  /* Measure speed */
    pixacc = pixBlockconvAccum(pixs);
    for (i = 0; i < NTIMES; i++) {
	pixd = pixBlockconvGray(pixs, pixacc, wc, hc);
	if ((i+1) % 10 == 0)
	    fprintf(stderr, "%d iters\n", i + 1);
	pixDestroy(&pixd);
    }
    pixd = pixBlockconvGray(pixs, pixacc, wc, hc);
    pixWrite(fileout, pixd, IFF_JFIF_JPEG);
    pixDestroy(&pixacc);
#endif

#if 0  /* Test pixBlockconvGray() */
    pixacc = pixBlockconvAccum(pixs);
    pixd = pixBlockconvGray(pixs, pixacc, wc, hc);
    pixWrite(fileout, pixd, IFF_JFIF_JPEG);
    pixDestroy(&pixacc);
#endif

#if 0  /* Test pixBlockconv() */
    pixd = pixBlockconv(pixs, wc, hc);
    pixWrite(fileout, pixd, IFF_JFIF_JPEG);
#endif

#if 0  /* Test pixBlockrank() */
    pixacc = pixBlockconvAccum(pixs);
    pixd = pixBlockrank(pixs, pixacc, wc, hc, 0.5);
    pixWrite(fileout, pixd, IFF_TIFF_G4);
    pixDestroy(&pixacc);
#endif

#if 0  /* Test pixBlocksum() */
    pixacc = pixBlockconvAccum(pixs);
    pixd = pixBlocksum(pixs, pixacc, wc, hc);
    pixInvert(pixd, pixd);
    pixWrite(fileout, pixd, IFF_JFIF_JPEG);
    pixDestroy(&pixacc);
#endif

#if 0  /* Test pixCensusTransform() */
    d = pixGetDepth(pixs);
    if (d == 32)
        pixt = pixConvertRGBToLuminance(pixs);
    else
        pixt = pixClone(pixs);
    pixacc = pixBlockconvAccum(pixt);
    pixd = pixCensusTransform(pixt, wc, NULL);
    pixDestroy(&pixt);
    pixDestroy(&pixacc);
    pixWrite(fileout, pixd, IFF_PNG);
#endif

#if 1   /* Test generic convolution with kel1 */
    if (pixGetDepth(pixs) == 32)
        pixg = pixScaleRGBToGrayFast(pixs, 2, COLOR_GREEN);
    else
        pixg = pixScale(pixs, 0.5, 0.5);
    pixDisplay(pixg, 0, 600);
    kel1 = kernelCreateFromString(5, 5, 2, 2, kdatastr);
    pixd = pixConvolve(pixg, kel1, 8, 1);
    pixDisplay(pixd, 700, 0);
    pixWrite("/tmp/junkpixd4.bmp", pixd, IFF_BMP);
    pixDestroy(&pixd);
    kernelDestroy(&kel1);

        /* Test convolution with flat rectangular kel */
    kel2 = kernelCreate(11, 11);
    kernelSetOrigin(kel2, 5, 5);
    for (i = 0; i < 11; i++) {
        for (j = 0; j < 11; j++)
            kernelSetElement(kel2, i, j, 1);
    }
    startTimer();
    pixd = pixConvolve(pixg, kel2, 8, 1);
    fprintf(stderr, "Generic convolution: %7.3f sec\n", stopTimer());
    pixDisplay(pixd, 1200, 0);
    pixWrite("/tmp/junkpixd5.bmp", pixd, IFF_BMP);
    startTimer();
    pixt = pixBlockconv(pixg, 5, 5);
    fprintf(stderr, "Block convolution: %7.3f sec\n", stopTimer());
    pixDisplay(pixd, 1200, 600);
    pixWrite("/tmp/junkpixd6.bmp", pixt, IFF_BMP);
    pixCompareGray(pixd, pixt, L_COMPARE_ABS_DIFF, GPLOT_X11, NULL,
                   NULL, NULL, NULL);
    pixDestroy(&pixg);
    pixDestroy(&pixt);
    kernelDestroy(&kel2);
#endif

    pixDestroy(&pixs);
    pixDestroy(&pixd);
    return 0;
}
예제 #22
0
main(int    argc,
     char **argv)
{
l_int32      i, j, w, h, error;
l_float32    val1, val2;
l_float32    val00, val10, val01, val11, valc00, valc10, valc01, valc11;
PIX         *pixs, *pixg, *pixt1, *pixt2, *pixt3, *pixt4, *pixt5;
FPIXA       *fpixam, *fpixav, *fpixarv;
BOXAA       *baa;
static char  mainName[] = "quadtreetest";

    if (argc != 1)
	return ERROR_INT(" Syntax:  quadtreetest", mainName, 1);

        /* Test generation of quadtree regions. */
    baa = boxaaQuadtreeRegions(1000, 500, 3);
    boxaaWriteStream(stderr, baa);
    boxaaDestroy(&baa);
    baa = boxaaQuadtreeRegions(1001, 501, 3);
    boxaaWriteStream(stderr, baa);
    boxaaDestroy(&baa);

        /* Test quadtree stats generation */
#if 1
    pixs = pixRead("rabi.png");
    pixg = pixScaleToGray4(pixs);
#else
    pixs = pixRead("test24.jpg");
    pixg = pixConvertTo8(pixs, 0);
#endif
    pixQuadtreeMean(pixg, 8, NULL, &fpixam);
    pixt1 = fpixaDisplayQuadtree(fpixam, 4);
    pixDisplay(pixt1, 100, 0);
    pixWrite("/tmp/quadtree1.png", pixt1, IFF_PNG);
    pixQuadtreeVariance(pixg, 8, NULL, NULL, &fpixav, &fpixarv);
    pixt2 = fpixaDisplayQuadtree(fpixav, 4);
    pixDisplay(pixt2, 100, 200);
    pixWrite("/tmp/quadtree2.png", pixt2, IFF_PNG);
    pixt3 = fpixaDisplayQuadtree(fpixarv, 4);
    pixDisplay(pixt3, 100, 400);
    pixWrite("/tmp/quadtree3.png", pixt3, IFF_PNG);

        /* Compare with fixed-size tiling at a resolution corresponding
         * to the deepest level of the quadtree above */
    pixt4 = pixGetAverageTiled(pixg, 5, 6, L_MEAN_ABSVAL);
    pixt5 = pixExpandReplicate(pixt4, 4);
    pixWrite("/tmp/quadtree4.png", pixt5, IFF_PNG);
    pixDisplay(pixt5, 800, 0);
    pixDestroy(&pixt4);
    pixDestroy(&pixt5);
    pixt4 = pixGetAverageTiled(pixg, 5, 6, L_STANDARD_DEVIATION);
    pixt5 = pixExpandReplicate(pixt4, 4);
    pixWrite("/tmp/quadtree5.png", pixt5, IFF_PNG);
    pixDisplay(pixt5, 800, 400);

        /* Test quadtree parent/child access */
    error = FALSE;
    fpixaGetFPixDimensions(fpixam, 4, &w, &h);
    for (i = 0; i < w; i += 2) {
        for (j = 0; j < h; j += 2) {
            quadtreeGetParent(fpixam, 4, j, i, &val1);
            fpixaGetPixel(fpixam, 3, j / 2, i / 2, &val2);
            if (val1 != val2) error = TRUE;
        }
    }
    if (error)
        fprintf(stderr, "\n======================\nError: parent access\n");
    else
        fprintf(stderr, "\n======================\nSuccess: parent access\n");
    error = FALSE;
    for (i = 0; i < w; i++) {
        for (j = 0; j < h; j++) {
            quadtreeGetChildren(fpixam, 4, j, i,
                                &val00, &val10, &val01, &val11);
            fpixaGetPixel(fpixam, 5, 2 * j, 2 * i, &valc00);
            fpixaGetPixel(fpixam, 5, 2 * j + 1, 2 * i, &valc10);
            fpixaGetPixel(fpixam, 5, 2 * j, 2 * i + 1, &valc01);
            fpixaGetPixel(fpixam, 5, 2 * j + 1, 2 * i + 1, &valc11);
            if ((val00 != valc00) || (val10 != valc10) ||
                (val01 != valc01) || (val11 != valc11))
                error = TRUE;
        }
    }
    if (error)
        fprintf(stderr, "Error: child access\n======================\n");
    else
        fprintf(stderr, "Success: child access\n======================\n");

    pixDestroy(&pixs);
    pixDestroy(&pixg);
    pixDestroy(&pixt1);
    pixDestroy(&pixt2);
    pixDestroy(&pixt3);
    pixDestroy(&pixt4);
    pixDestroy(&pixt5);
    fpixaDestroy(&fpixam);
    fpixaDestroy(&fpixav);
    fpixaDestroy(&fpixarv);
    return 0;
}
예제 #23
0
/*!
 *  pixGetRegionsBinary()
 *
 *      Input:  pixs (1 bpp, assumed to be 300 to 400 ppi)
 *              &pixhm (<optional return> halftone mask)
 *              &pixtm (<optional return> textline mask)
 *              &pixtb (<optional return> textblock mask)
 *              debug (flag: set to 1 for debug output)
 *      Return: 0 if OK, 1 on error
 *
 *  Notes:
 *      (1) It is best to deskew the image before segmenting.
 *      (2) The debug flag enables a number of outputs.  These
 *          are included to show how to generate and save/display
 *          these results.
 */
l_int32
pixGetRegionsBinary(PIX     *pixs,
                    PIX    **ppixhm,
                    PIX    **ppixtm,
                    PIX    **ppixtb,
                    l_int32  debug)
{
char    *tempname;
l_int32  htfound, tlfound;
PIX     *pixr, *pixt1, *pixt2;
PIX     *pixtext;  /* text pixels only */
PIX     *pixhm2;   /* halftone mask; 2x reduction */
PIX     *pixhm;    /* halftone mask;  */
PIX     *pixtm2;   /* textline mask; 2x reduction */
PIX     *pixtm;    /* textline mask */
PIX     *pixvws;   /* vertical white space mask */
PIX     *pixtb2;   /* textblock mask; 2x reduction */
PIX     *pixtbf2;  /* textblock mask; 2x reduction; small comps filtered */
PIX     *pixtb;    /* textblock mask */

    PROCNAME("pixGetRegionsBinary");

    if (ppixhm) *ppixhm = NULL;
    if (ppixtm) *ppixtm = NULL;
    if (ppixtb) *ppixtb = NULL;
    if (!pixs)
        return ERROR_INT("pixs not defined", procName, 1);
    if (pixGetDepth(pixs) != 1)
        return ERROR_INT("pixs not 1 bpp", procName, 1);

        /* 2x reduce, to 150 -200 ppi */
    pixr = pixReduceRankBinaryCascade(pixs, 1, 0, 0, 0);
    pixDisplayWrite(pixr, debug);

        /* Get the halftone mask */
    pixhm2 = pixGenHalftoneMask(pixr, &pixtext, &htfound, debug);

        /* Get the textline mask from the text pixels */
    pixtm2 = pixGenTextlineMask(pixtext, &pixvws, &tlfound, debug);

        /* Get the textblock mask from the textline mask */
    pixtb2 = pixGenTextblockMask(pixtm2, pixvws, debug);
    pixDestroy(&pixr);
    pixDestroy(&pixtext);
    pixDestroy(&pixvws);

        /* Remove small components from the mask, where a small
         * component is defined as one with both width and height < 60 */
    pixtbf2 = pixSelectBySize(pixtb2, 60, 60, 4, L_SELECT_IF_EITHER,
                              L_SELECT_IF_GTE, NULL);
    pixDestroy(&pixtb2);
    pixDisplayWriteFormat(pixtbf2, debug, IFF_PNG);

        /* Expand all masks to full resolution, and do filling or
         * small dilations for better coverage. */
    pixhm = pixExpandReplicate(pixhm2, 2);
    pixt1 = pixSeedfillBinary(NULL, pixhm, pixs, 8);
    pixOr(pixhm, pixhm, pixt1);
    pixDestroy(&pixt1);
    pixDisplayWriteFormat(pixhm, debug, IFF_PNG);

    pixt1 = pixExpandReplicate(pixtm2, 2);
    pixtm = pixDilateBrick(NULL, pixt1, 3, 3);
    pixDestroy(&pixt1);
    pixDisplayWriteFormat(pixtm, debug, IFF_PNG);

    pixt1 = pixExpandReplicate(pixtbf2, 2);
    pixtb = pixDilateBrick(NULL, pixt1, 3, 3);
    pixDestroy(&pixt1);
    pixDisplayWriteFormat(pixtb, debug, IFF_PNG);

    pixDestroy(&pixhm2);
    pixDestroy(&pixtm2);
    pixDestroy(&pixtbf2);

        /* Debug: identify objects that are neither text nor halftone image */
    if (debug) {
        pixt1 = pixSubtract(NULL, pixs, pixtm);  /* remove text pixels */
        pixt2 = pixSubtract(NULL, pixt1, pixhm);  /* remove halftone pixels */
        pixDisplayWriteFormat(pixt2, 1, IFF_PNG);
        pixDestroy(&pixt1);
        pixDestroy(&pixt2);
    }

        /* Debug: display textline components with random colors */
    if (debug) {
        l_int32  w, h;
        BOXA    *boxa;
        PIXA    *pixa;
        boxa = pixConnComp(pixtm, &pixa, 8);
        pixGetDimensions(pixtm, &w, &h, NULL);
        pixt1 = pixaDisplayRandomCmap(pixa, w, h);
        pixcmapResetColor(pixGetColormap(pixt1), 0, 255, 255, 255);
        pixDisplay(pixt1, 100, 100);
        pixDisplayWriteFormat(pixt1, 1, IFF_PNG);
        pixaDestroy(&pixa);
        boxaDestroy(&boxa);
        pixDestroy(&pixt1);
    }

        /* Debug: identify the outlines of each textblock */
    if (debug) {
        PIXCMAP  *cmap;
        PTAA     *ptaa;
        ptaa = pixGetOuterBordersPtaa(pixtb);
        tempname = genTempFilename("/tmp", "tb_outlines.ptaa", 0);
	ptaaWrite(tempname, ptaa, 1);
        FREE(tempname);
        pixt1 = pixRenderRandomCmapPtaa(pixtb, ptaa, 1, 16, 1);
        cmap = pixGetColormap(pixt1);
        pixcmapResetColor(cmap, 0, 130, 130, 130);
        pixDisplay(pixt1, 500, 100);
        pixDisplayWriteFormat(pixt1, 1, IFF_PNG);
        pixDestroy(&pixt1);
        ptaaDestroy(&ptaa);
    }

        /* Debug: get b.b. for all mask components */
    if (debug) {
        BOXA  *bahm, *batm, *batb;
        bahm = pixConnComp(pixhm, NULL, 4);
        batm = pixConnComp(pixtm, NULL, 4);
        batb = pixConnComp(pixtb, NULL, 4);
        tempname = genTempFilename("/tmp", "htmask.boxa", 0);
        boxaWrite(tempname, bahm);
        FREE(tempname);
        tempname = genTempFilename("/tmp", "textmask.boxa", 0);
        boxaWrite(tempname, batm);
        FREE(tempname);
        tempname = genTempFilename("/tmp", "textblock.boxa", 0);
        boxaWrite(tempname, batb);
        FREE(tempname);
	boxaDestroy(&bahm);
	boxaDestroy(&batm);
	boxaDestroy(&batb);
    }

    if (ppixhm)
        *ppixhm = pixhm;
    else
        pixDestroy(&pixhm);
    if (ppixtm)
        *ppixtm = pixtm;
    else
        pixDestroy(&pixtm);
    if (ppixtb)
        *ppixtb = pixtb;
    else
        pixDestroy(&pixtb);

    return 0;
}
예제 #24
0
main(int    argc,
     char **argv)
{
char         bufname[256];
l_int32      i, j, w, h, d, x, y, wpls;
l_uint32    *datas, *lines;
l_float32   *vc;
PIX         *pixs, *pixsc, *pixb, *pixg, *pixc, *pixcs, *pixd;
PIX         *pixt1, *pixt2, *pixt3;
PIXA        *pixa;
PTA         *ptas, *ptad;
static char  mainName[] = "projective_reg";

    if (argc != 1)
	exit(ERROR_INT(" Syntax:  projective_reg", mainName, 1));
    if ((pixs = pixRead("feyn.tif")) == NULL)
	exit(ERROR_INT("pixs not made", mainName, 1));
    pixsc = pixScale(pixs, 0.5, 0.5);

#if ALL
        /* Test invertability of sampling */
    pixa = pixaCreate(0);
    for (i = 0; i < 3; i++) {
        pixb = pixAddBorder(pixsc, ADDED_BORDER_PIXELS, 0);
        MakePtas(i, &ptas, &ptad);
        pixt1 = pixProjectiveSampledPta(pixb, ptad, ptas, L_BRING_IN_WHITE);
        pixSaveTiled(pixt1, pixa, 1, 1, 20, 8);
        pixt2 = pixProjectiveSampledPta(pixt1, ptas, ptad, L_BRING_IN_WHITE);
        pixSaveTiled(pixt2, pixa, 1, 0, 20, 0);
        pixd = pixRemoveBorder(pixt2, ADDED_BORDER_PIXELS);
        pixXor(pixd, pixd, pixsc);
        pixSaveTiled(pixd, pixa, 1, 0, 20, 0);
        if (i == 0) pixWrite("/tmp/junksamp.png", pixt1, IFF_PNG);
        pixDestroy(&pixb);
        pixDestroy(&pixt1);
        pixDestroy(&pixt2);
        pixDestroy(&pixd);
        ptaDestroy(&ptas);
        ptaDestroy(&ptad);
    }

    pixt1 = pixaDisplay(pixa, 0, 0);
    pixWrite("/tmp/junkproj1.png", pixt1, IFF_PNG);
    pixDisplay(pixt1, 100, 300);
    pixDestroy(&pixt1);
    pixaDestroy(&pixa);
#endif

#if ALL
        /* Test invertability of interpolation on grayscale */
    pixa = pixaCreate(0);
    pixg = pixScaleToGray3(pixs);
    for (i = 0; i < 3; i++) {
        pixb = pixAddBorder(pixg, ADDED_BORDER_PIXELS / 2, 255);
        MakePtas(i, &ptas, &ptad);
        pixt1 = pixProjectivePta(pixb, ptad, ptas, L_BRING_IN_WHITE);
        pixSaveTiled(pixt1, pixa, 1, 1, 20, 8);
        pixt2 = pixProjectivePta(pixt1, ptas, ptad, L_BRING_IN_WHITE);
        pixSaveTiled(pixt2, pixa, 1, 0, 20, 0);
        pixd = pixRemoveBorder(pixt2, ADDED_BORDER_PIXELS / 2);
        pixXor(pixd, pixd, pixg);
        pixSaveTiled(pixd, pixa, 1, 0, 20, 0);
        if (i == 0) pixWrite("/tmp/junkinterp.png", pixt1, IFF_PNG);
        pixDestroy(&pixb);
        pixDestroy(&pixt1);
        pixDestroy(&pixt2);
        pixDestroy(&pixd);
        ptaDestroy(&ptas);
        ptaDestroy(&ptad);
    }

    pixt1 = pixaDisplay(pixa, 0, 0);
    pixWrite("/tmp/junkproj2.png", pixt1, IFF_PNG);
    pixDisplay(pixt1, 100, 500);
    pixDestroy(&pixt1);
    pixaDestroy(&pixa);
    pixDestroy(&pixg);
#endif

#if ALL
        /* Test invertability of interpolation on color */
    pixa = pixaCreate(0);
    pixc = pixRead("test24.jpg");
    pixcs = pixScale(pixc, 0.3, 0.3);
    for (i = 0; i < 5; i++) {
        pixb = pixAddBorder(pixcs, ADDED_BORDER_PIXELS, 0xffffff00);
        MakePtas(i, &ptas, &ptad);
        pixt1 = pixProjectivePta(pixb, ptad, ptas, L_BRING_IN_WHITE);
        pixSaveTiled(pixt1, pixa, 1, 1, 20, 32);
        pixt2 = pixProjectivePta(pixt1, ptas, ptad, L_BRING_IN_WHITE);
        pixSaveTiled(pixt2, pixa, 1, 0, 20, 0);
        pixd = pixRemoveBorder(pixt2, ADDED_BORDER_PIXELS);
        pixXor(pixd, pixd, pixcs);
        pixSaveTiled(pixd, pixa, 1, 0, 20, 0);
        pixDestroy(&pixb);
        pixDestroy(&pixt1);
        pixDestroy(&pixt2);
        pixDestroy(&pixd);
        ptaDestroy(&ptas);
        ptaDestroy(&ptad);
    }

    pixt1 = pixaDisplay(pixa, 0, 0);
    pixWrite("/tmp/junkproj3.png", pixt1, IFF_PNG);
    pixDisplay(pixt1, 100, 500);
    pixDestroy(&pixt1);
    pixaDestroy(&pixa);
    pixDestroy(&pixc);
    pixDestroy(&pixcs);
#endif

#if ALL 
       /* Comparison between sampling and interpolated */
    MakePtas(3, &ptas, &ptad);
    pixa = pixaCreate(0);

	/* Use sampled transform */
    pixt1 = pixProjectiveSampledPta(pixs, ptas, ptad, L_BRING_IN_WHITE);
    pixSaveTiled(pixt1, pixa, 2, 1, 20, 8);

	/* Use interpolated transforms */
    pixt2 = pixProjectivePta(pixs, ptas, ptad, L_BRING_IN_WHITE);
    pixSaveTiled(pixt2, pixa, 2, 0, 20, 8);

        /* Compare the results */
    pixXor(pixt2, pixt2, pixt1);
    pixSaveTiled(pixt2, pixa, 2, 0, 20, 8);

    pixd = pixaDisplay(pixa, 0, 0);
    pixWrite("/tmp/junkproj4.png", pixd, IFF_PNG);
    pixDisplay(pixd, 100, 700);
    pixDestroy(&pixt1);
    pixDestroy(&pixt2);
    pixDestroy(&pixd);
    pixaDestroy(&pixa);
    ptaDestroy(&ptas);
    ptaDestroy(&ptad);
#endif

#if ALL
       /* Get timings */
    MakePtas(4, &ptas, &ptad);
    pixa = pixaCreate(0);
    pixg = pixScaleToGray3(pixs);

    startTimer();
    pixt1 = pixProjectiveSampledPta(pixg, ptas, ptad, L_BRING_IN_WHITE);
    fprintf(stderr, " Time for pixProjectiveSampledPta(): %6.2f sec\n", stopTimer());
    pixSaveTiled(pixt1, pixa, 1, 1, 20, 8);

    startTimer();
    pixt2 = pixProjectivePta(pixg, ptas, ptad, L_BRING_IN_WHITE);
    fprintf(stderr, " Time for pixProjectivePta(): %6.2f sec\n", stopTimer());
    pixSaveTiled(pixt2, pixa, 1, 0, 20, 8);

    pixXor(pixt1, pixt1, pixt2);
    pixSaveTiled(pixt1, pixa, 1, 0, 20, 8);
    pixDestroy(&pixt1);
    pixDestroy(&pixt2);

    pixd = pixaDisplay(pixa, 0, 0);
    pixWrite("/tmp/junkproj5.png", pixd, IFF_PNG);
    pixDisplay(pixd, 100, 900);
    pixDestroy(&pixd);
    pixDestroy(&pixg);
    pixaDestroy(&pixa);
    ptaDestroy(&ptas);
    ptaDestroy(&ptad);
#endif

    pixDestroy(&pixs);
    pixDestroy(&pixsc);
    return 0;
}
예제 #25
0
/*!
 *  pixMorphCompSequenceDwa()
 *
 *      Input:  pixs
 *              sequence (string specifying sequence)
 *              dispsep (controls debug display of each result in the sequence:
 *                       0: no output
 *                       > 0: gives horizontal separation in pixels between
 *                            successive displays
 *                       < 0: pdf output; abs(dispsep) is used for naming)
 *      Return: pixd, or null on error
 *
 *  Notes:
 *      (1) This does dwa morphology on binary images, using brick Sels.
 *      (2) This runs a pipeline of operations; no branching is allowed.
 *      (3) It implements all brick Sels that have dimensions up to 63
 *          on each side, using a composite (linear + comb) when useful.
 *      (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) See pixMorphSequence() for further information about usage.
 */
PIX *
pixMorphCompSequenceDwa(PIX         *pixs,
                        const char  *sequence,
                        l_int32      dispsep)
{
char    *rawop, *op, *fname;
char     buf[256];
l_int32  nops, i, j, nred, fact, w, h, x, y, border, pdfout;
l_int32  level[4];
PIX     *pixt1, *pixt2;
PIXA    *pixa;
SARRAY  *sa;

    PROCNAME("pixMorphCompSequenceDwa");

    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);
    pdfout = (dispsep < 0) ? 1 : 0;

    if (!morphSequenceVerify(sa)) {
        sarrayDestroy(&sa);
        return (PIX *)ERROR_PTR("sequence not valid", procName, NULL);
    }

        /* Parse and operate */
    pixa = NULL;
    if (pdfout) {
        pixa = pixaCreate(0);
        pixaAddPix(pixa, pixs, L_CLONE);
        snprintf(buf, sizeof(buf), "/tmp/seq_output_%d.pdf", L_ABS(dispsep));
        fname = genPathname(buf, NULL);
    }
    border = 0;
    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);
            pixt2 = pixDilateCompBrickDwa(NULL, pixt1, w, h);
            pixSwapAndDestroy(&pixt1, &pixt2);
            break;
        case 'e':
        case 'E':
            sscanf(&op[1], "%d.%d", &w, &h);
            pixt2 = pixErodeCompBrickDwa(NULL, pixt1, w, h);
            pixSwapAndDestroy(&pixt1, &pixt2);
            break;
        case 'o':
        case 'O':
            sscanf(&op[1], "%d.%d", &w, &h);
            pixOpenCompBrickDwa(pixt1, pixt1, w, h);
            break;
        case 'c':
        case 'C':
            sscanf(&op[1], "%d.%d", &w, &h);
            pixCloseCompBrickDwa(pixt1, pixt1, w, h);
            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]);
            pixSwapAndDestroy(&pixt1, &pixt2);
            break;
        case 'x':
        case 'X':
            sscanf(&op[1], "%d", &fact);
            pixt2 = pixExpandReplicate(pixt1, fact);
            pixSwapAndDestroy(&pixt1, &pixt2);
            break;
        case 'b':
        case 'B':
            sscanf(&op[1], "%d", &border);
            pixt2 = pixAddBorder(pixt1, border, 0);
            pixSwapAndDestroy(&pixt1, &pixt2);
            break;
        default:
            /* All invalid ops are caught in the first pass */
            break;
        }
        FREE(op);

            /* Debug output */
        if (dispsep > 0) {
            pixDisplay(pixt1, x, y);
            x += dispsep;
        }
        if (pdfout)
            pixaAddPix(pixa, pixt1, L_COPY);
    }
    if (border > 0) {
        pixt2 = pixRemoveBorder(pixt1, border);
        pixSwapAndDestroy(&pixt1, &pixt2);
    }

    if (pdfout) {
        pixaConvertToPdf(pixa, 0, 1.0, L_FLATE_ENCODE, 0, fname, fname);
        FREE(fname);
        pixaDestroy(&pixa);
    }

    sarrayDestroy(&sa);
    return pixt1;
}
예제 #26
0
std::vector<Figure> extractFigures(PIX *original, PageRegions &pageRegions,
                                   DocumentStatistics &docStats, bool verbose,
                                   bool showSteps,
                                   std::vector<Figure> &errors) {
  BOXA *bodytext = pageRegions.bodytext;
  BOXA *graphics = pageRegions.graphics;
  BOXA *captions = pageRegions.getCaptionsBoxa();
  std::vector<Caption> unassigned_captions = pageRegions.captions;
  int total_captions = captions->n;

  PIXA *steps = showSteps ? pixaCreate(4) : NULL;

  // Add bodyText boxes to fill up the margin
  BOX *margin;
  BOX *foreground;
  pixClipToForeground(original, NULL, &foreground);
  BOX *extent;
  boxaGetExtent(graphics, NULL, NULL, &extent);
  margin = boxBoundingRegion(extent, foreground);
  boxDestroy(&extent);
  boxaGetExtent(bodytext, NULL, NULL, &extent);
  margin = boxBoundingRegion(margin, extent);
  boxDestroy(&extent);
  boxaGetExtent(pageRegions.other, NULL, NULL, &extent);
  margin = boxBoundingRegion(margin, extent);
  int x = margin->x - 2, y = margin->y - 2, h = margin->h + 4,
      w = margin->w + 4;
  x = std::max(x, 0);
  y = std::max(y, 0);
  h = std::min((int)original->h, h);
  w = std::min((int)original->w, w);
  boxDestroy(&margin);
  boxaAddBox(bodytext, boxCreate(0, 0, original->w, y), L_CLONE);
  boxaAddBox(bodytext, boxCreate(0, y + h, original->w, original->h - y - h),
             L_CLONE);
  boxaAddBox(bodytext, boxCreate(0, 0, x, original->h), L_CLONE);
  boxaAddBox(bodytext, boxCreate(x + w, 0, original->w - x - w, original->h),
             L_CLONE);

  // Add captions to body text
  boxaJoin(bodytext, captions, 0, captions->n);

  if (showSteps)
    pixaAddPix(steps, original, L_CLONE);

  // Generate proposed regions for each caption box
  double center = original->w / 2.0;
  BOXAA *allProposals = boxaaCreate(captions->n);
  BOXA *claimedImages = boxaCreate(captions->n);
  for (int i = 0; i < captions->n; i++) {
    BOX *captBox = boxaGetBox(captions, i, L_CLONE);
    BOXA *proposals = boxaCreate(4);
    for (int j = 0; j < bodytext->n; j++) {
      BOX *txtBox = boxaGetBox(bodytext, j, L_CLONE);
      BOX *proposal = NULL;
      int tolerance = 2;
      int horizontal = 0;
      int vertical = 0;

      boxAlignment(captBox, txtBox, tolerance, &horizontal, &vertical);
      if (vertical * horizontal != 0 or (vertical == 0 and horizontal == 0)) {
        continue;
      }

      if (vertical == 0) {
        if (horizontal == 1) {
          proposal = boxRelocateOneSide(NULL, captBox,
                                        txtBox->x + txtBox->w + 2, L_FROM_LEFT);
        } else if (horizontal == -1) {
          proposal =
              boxRelocateOneSide(NULL, captBox, txtBox->x - 2, L_FROM_RIGHT);
        }
        boxExpandUD(proposal, bodytext);
        if (horizontal == -1) {
          proposal->w -= captBox->w + 1;
          proposal->x = captBox->x + captBox->w + 1;
        } else if (horizontal == 1) {
          proposal->w -= captBox->w + 1;
        }
      } else {
        if (vertical == 1) {
          proposal = boxRelocateOneSide(NULL, captBox,
                                        txtBox->y + txtBox->h + 3, L_FROM_TOP);
        } else if (vertical == -1) {
          proposal =
              boxRelocateOneSide(NULL, captBox, txtBox->y - 3, L_FROM_BOT);
        }
        boxExpandLR(proposal, bodytext);
        if (vertical == -1) {
          proposal->h -= captBox->h + 1;
          proposal->y = captBox->y + captBox->h + 1;
        } else if (vertical == 1) {
          proposal->h -= captBox->h + 1;
        }
      }

      // For two columns document, captions that do not
      // cross the center should not have regions pass the center
      if (docStats.documentIsTwoColumn()) {
        if (captBox->x + captBox->w <= center and
            proposal->x + proposal->w > center) {
          boxRelocateOneSide(proposal, proposal, center - 1, L_FROM_RIGHT);
        } else if (captBox->x >= center and proposal->x < center) {
          boxRelocateOneSide(proposal, proposal, center + 1, L_FROM_LEFT);
        }
      }

      BOX *clippedProposal;
      pixClipBoxToForeground(original, proposal, NULL, &clippedProposal);
      if (clippedProposal != NULL and
          scoreBox(clippedProposal, pageRegions.captions.at(i).type, bodytext,
                   graphics, claimedImages, original) > 0) {
        boxaAddBox(proposals, clippedProposal, L_CLONE);
      }
    }

    if (proposals->n > 0) {
      boxaaAddBoxa(allProposals, proposals, L_CLONE);
    } else {
      // Give up on this caption
      int on_caption = i - (total_captions - unassigned_captions.size());
      errors.push_back(Figure(unassigned_captions.at(on_caption), NULL));
      unassigned_captions.erase(unassigned_captions.begin() + on_caption);
    }
  }
  std::vector<Figure> figures = std::vector<Figure>();
  if (unassigned_captions.size() == 0) {
    return figures;
  }

  // Now go through every possible assignment of captions
  // to proposals pick the highest scorign one
  int numConfigurations = 1;
  for (int i = 0; i < allProposals->n; ++i) {
    numConfigurations *= allProposals->boxa[i]->n;
  }

  if (verbose)
    printf("Found %d possible configurations\n", numConfigurations);

  BOXA *bestProposals = NULL;
  std::vector<bool> bestKeep;
  int bestFound = -1;
  double bestScore = -1;
  for (int onConfig = 0; onConfig < numConfigurations; ++onConfig) {

    // Gather the proposed regions based on the configuration number
    int configNum = onConfig;
    BOXA *proposals = boxaCreate(allProposals->n);
    std::vector<bool> keep;
    for (int i = 0; i < allProposals->n; ++i) {
      int numProposals = allProposals->boxa[i]->n;
      int selected = configNum % numProposals;
      configNum = configNum / numProposals;
      boxaAddBox(proposals, allProposals->boxa[i]->box[selected], L_COPY);
    }

    // Attempt to split any overlapping regions
    for (int i = 0; i < proposals->n; ++i) {
      for (int j = i; j < proposals->n; ++j) {
        BOX *p1 = proposals->box[i];
        BOX *p2 = proposals->box[j];
        int eq;
        boxEqual(p1, p2, &eq);
        if (not eq)
          continue;
        int vertical, horizontal;
        boxAlignment(unassigned_captions.at(i).boundingBox,
                     unassigned_captions.at(j).boundingBox, 2, &horizontal,
                     &vertical);
        if (vertical == 0 or horizontal != 0)
          continue;

        double split = splitBoxVertical(original, p1);
        if (split > 0) {
          BOX *topClipped;
          BOX *botClipped;
          BOX *top = boxRelocateOneSide(NULL, p1, split - 1, L_FROM_BOT);
          pixClipBoxToForeground(original, top, NULL, &topClipped);
          BOX *bot = boxRelocateOneSide(NULL, p1, split + 1, L_FROM_TOP);
          pixClipBoxToForeground(original, bot, NULL, &botClipped);
          if (vertical == -1) {
            proposals->box[i] = topClipped;
            proposals->box[j] = botClipped;
          } else {
            proposals->box[i] = botClipped;
            proposals->box[j] = topClipped;
          }
          if (verbose)
            printf("Split a region vertically\n");
        }
      }
    }

    if (showSteps) {
      pixaAddPix(steps, pixDrawBoxa(original, proposals, 4, 0xff000000),
                 L_CLONE);
    }

    // Score the proposals
    int numFound = 0;
    double totalScore = 0;
    for (int i = 0; i < proposals->n; ++i) {
      double score =
          scoreBox(proposals->box[i], pageRegions.captions.at(i).type, bodytext,
                   graphics, proposals, original);
      totalScore += score;
      if (score > 0) {
        numFound += 1;
        keep.push_back(true);
      } else {
        keep.push_back(false);
      }
    }

    // Switch in for the current best needed
    if (numFound > bestFound or
        (numFound == bestFound and totalScore > bestScore)) {
      bestFound = numFound;
      bestScore = totalScore;
      bestProposals = proposals;
      bestKeep = keep;
    }
  }

  if (showSteps) {
    BOX *clip;
    PIXA *show = pixaCreate(4);
    pixClipBoxToForeground(original, NULL, NULL, &clip);
    int pad = 10;
    clip->x -= 10;
    clip->y -= 10;
    clip->w += pad * 2;
    clip->h += pad * 2;
    for (int i = 0; i < steps->n; ++i) {
      pixaAddPix(show, pixClipRectangle(steps->pix[i], clip, NULL), L_CLONE);
    }
    pixDisplay(pixaDisplayTiled(pixaConvertTo32(show), 4000, 1, 30), 0, 0);
  }

  for (int i = 0; i < bestProposals->n; ++i) {
    if (bestKeep.at(i)) {
      BOX *imageBox = bestProposals->box[i];
      int pad = 2;
      imageBox->x -= pad;
      imageBox->y -= pad;
      imageBox->w += pad * 2;
      imageBox->h += pad * 2;
      figures.push_back(Figure(unassigned_captions.at(i), imageBox));
    } else {
      errors.push_back(Figure(unassigned_captions.at(i), NULL));
    }
  }
  return figures;
}
예제 #27
0
/*!
 *  pixGrayMorphSequence()
 *
 *      Input:  pixs
 *              sequence (string specifying sequence)
 *              dispsep (controls debug display of each result in the sequence:
 *                       0: no output
 *                       > 0: gives horizontal separation in pixels between
 *                            successive displays
 *                       < 0: pdf output; abs(dispsep) is used for naming)
 *              dispy (if dispsep > 0, this gives the y-value of the
 *                     UL corner for display; otherwise it is ignored)
 *      Return: pixd, or null on error
 *
 *  Notes:
 *      (1) This works on 8 bpp grayscale images.
 *      (2) This runs a pipeline of operations; no branching is allowed.
 *      (3) This only uses brick SELs.
 *      (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, the composite
 *          morph/subtract tophat can be performed.
 *      (8) Sel sizes (width, height) must each be odd numbers.
 *      (9) Intermediate results can optionally be displayed
 *      (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)
 *                 t or T  (tophat)
 *            - 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. (each must be an odd number)
 *            - The args to the tophat are w or W (for white tophat)
 *              or b or B (for black tophat), followed by a.b as for
 *              the dilation, erosion, opening and closing.
 *           Example valid sequences are:
 *             "c5.3 + o7.5"
 *             "c9.9 + tw9.9"
 */
PIX *
pixGrayMorphSequence(PIX         *pixs,
                     const char  *sequence,
                     l_int32      dispsep,
                     l_int32      dispy)
{
char    *rawop, *op, *fname;
char     buf[256];
l_int32  nops, i, valid, w, h, x, pdfout;
PIX     *pixt1, *pixt2;
PIXA    *pixa;
SARRAY  *sa;

    PROCNAME("pixGrayMorphSequence");

    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);
    pdfout = (dispsep < 0) ? 1 : 0;

        /* 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 < 1 || (w & 1) == 0 || h < 1 || (h & 1) == 0 ) {
                fprintf(stderr,
                        "*** op: %s; w = %d, h = %d; must both be odd\n",
                        op, w, h);
                valid = FALSE;
                break;
            }
/*            fprintf(stderr, "op = %s; w = %d, h = %d\n", op, w, h); */
            break;
        case 't':
        case 'T':
            if (op[1] != 'w' && op[1] != 'W' &&
                op[1] != 'b' && op[1] != 'B') {
                fprintf(stderr,
                        "*** op = %s; arg %c must be 'w' or 'b'\n", op, op[1]);
                valid = FALSE;
                break;
            }
            sscanf(&op[2], "%d.%d", &w, &h);
            if (w < 1 || (w & 1) == 0 || h < 1 || (h & 1) == 0 ) {
                fprintf(stderr,
                        "*** op: %s; w = %d, h = %d; must both be odd\n",
                        op, w, h);
                valid = FALSE;
                break;
            }
/*            fprintf(stderr, "op = %s", op); */
            break;
        default:
            fprintf(stderr, "*** nonexistent op = %s\n", op);
            valid = FALSE;
        }
        FREE(op);
    }
    if (!valid) {
        sarrayDestroy(&sa);
        return (PIX *)ERROR_PTR("sequence invalid", procName, NULL);
    }

        /* Parse and operate */
    pixa = NULL;
    if (pdfout) {
        pixa = pixaCreate(0);
        pixaAddPix(pixa, pixs, L_CLONE);
        snprintf(buf, sizeof(buf), "/tmp/seq_output_%d.pdf", L_ABS(dispsep));
        fname = genPathname(buf, NULL);
    }
    pixt1 = pixCopy(NULL, pixs);
    pixt2 = NULL;
    x = 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);
            pixt2 = pixDilateGray(pixt1, w, h);
            pixSwapAndDestroy(&pixt1, &pixt2);
            break;
        case 'e':
        case 'E':
            sscanf(&op[1], "%d.%d", &w, &h);
            pixt2 = pixErodeGray(pixt1, w, h);
            pixSwapAndDestroy(&pixt1, &pixt2);
            break;
        case 'o':
        case 'O':
            sscanf(&op[1], "%d.%d", &w, &h);
            pixt2 = pixOpenGray(pixt1, w, h);
            pixSwapAndDestroy(&pixt1, &pixt2);
            break;
        case 'c':
        case 'C':
            sscanf(&op[1], "%d.%d", &w, &h);
            pixt2 = pixCloseGray(pixt1, w, h);
            pixSwapAndDestroy(&pixt1, &pixt2);
            break;
        case 't':
        case 'T':
            sscanf(&op[2], "%d.%d", &w, &h);
            if (op[1] == 'w' || op[1] == 'W')
                pixt2 = pixTophat(pixt1, w, h, L_TOPHAT_WHITE);
            else   /* 'b' or 'B' */
                pixt2 = pixTophat(pixt1, w, h, L_TOPHAT_BLACK);
            pixSwapAndDestroy(&pixt1, &pixt2);
            break;
        default:
            /* All invalid ops are caught in the first pass */
            break;
        }
        FREE(op);

            /* Debug output */
        if (dispsep > 0) {
            pixDisplay(pixt1, x, dispy);
            x += dispsep;
        }
        if (pdfout)
            pixaAddPix(pixa, pixt1, L_COPY);
    }

    if (pdfout) {
        pixaConvertToPdf(pixa, 0, 1.0, L_FLATE_ENCODE, 0, fname, fname);
        FREE(fname);
        pixaDestroy(&pixa);
    }

    sarrayDestroy(&sa);
    return pixt1;
}
예제 #28
0
int main(int argc,
         char **argv) {
    l_int32 i, j;
    l_int32 w, h, bw, bh, wpls, rval, gval, bval, same;
    l_uint32 pixel;
    l_uint32 *lines, *datas;
    l_float32 sum1, sum2, ave1, ave2, ave3, ave4, diff1, diff2;
    l_float32 var1, var2, var3;
    BOX *box1, *box2;
    NUMA *na, *na1, *na2, *na3, *na4;
    PIX *pix, *pixs, *pix1, *pix2, *pix3, *pix4, *pix5, *pixg, *pixd;
    PIXA *pixa;
    static char mainName[] = "numa2_reg";

    if (argc != 1)
        return ERROR_INT(" Syntax:  numa2_reg", mainName, 1);

    lept_mkdir("lept");

    /* -------------------------------------------------------------------*
     *                         Numa-windowed stats                        *
     * -------------------------------------------------------------------*/
#if  DO_ALL
    na = numaRead("lyra.5.na");
    numaWindowedStats(na, 5, &na1, &na2, &na3, &na4);
    gplotSimple1(na, GPLOT_PNG, "/tmp/lept/numa_lyra6", "Original");
    gplotSimple1(na1, GPLOT_PNG, "/tmp/lept/numa_lyra7", "Mean");
    gplotSimple1(na2, GPLOT_PNG, "/tmp/lept/numa_lyra8", "Mean Square");
    gplotSimple1(na3, GPLOT_PNG, "/tmp/lept/numa_lyra9", "Variance");
    gplotSimple1(na4, GPLOT_PNG, "/tmp/lept/numa_lyra10", "RMS Difference");
#ifndef  _WIN32
    sleep(1);
#else
    Sleep(1000);
#endif  /* _WIN32 */
    pixa = pixaCreate(5);
    pix1 = pixRead("/tmp/lept/numa_lyra6.png");
    pix2 = pixRead("/tmp/lept/numa_lyra7.png");
    pix3 = pixRead("/tmp/lept/numa_lyra8.png");
    pix4 = pixRead("/tmp/lept/numa_lyra9.png");
    pix5 = pixRead("/tmp/lept/numa_lyra10.png");
    pixSaveTiled(pix1, pixa, 1.0, 1, 25, 32);
    pixSaveTiled(pix2, pixa, 1.0, 1, 25, 32);
    pixSaveTiled(pix3, pixa, 1.0, 0, 25, 32);
    pixSaveTiled(pix4, pixa, 1.0, 1, 25, 32);
    pixSaveTiled(pix5, pixa, 1.0, 0, 25, 32);
    pixd = pixaDisplay(pixa, 0, 0);
    pixDisplay(pixd, 100, 100);
    pixWrite("/tmp/lept/numa_window.png", pixd, IFF_PNG);
    numaDestroy(&na);
    numaDestroy(&na1);
    numaDestroy(&na2);
    numaDestroy(&na3);
    numaDestroy(&na4);
    pixaDestroy(&pixa);
    pixDestroy(&pix1);
    pixDestroy(&pix2);
    pixDestroy(&pix3);
    pixDestroy(&pix4);
    pixDestroy(&pix5);
    pixDestroy(&pixd);
#endif

    /* -------------------------------------------------------------------*
     *                        Extraction on a line                        *
     * -------------------------------------------------------------------*/
#if  DO_ALL
    /* First, make a pretty image */
    w = h = 200;
    pixs = pixCreate(w, h, 32);
    wpls = pixGetWpl(pixs);
    datas = pixGetData(pixs);
    for (i = 0; i < 200; i++) {
        lines = datas + i * wpls;
        for (j = 0; j < 200; j++) {
            rval = (l_int32)((255. * j) / w + (255. * i) / h);
            gval = (l_int32)((255. * 2 * j) / w + (255. * 2 * i) / h) % 255;
            bval = (l_int32)((255. * 4 * j) / w + (255. * 4 * i) / h) % 255;
            composeRGBPixel(rval, gval, bval, &pixel);
            lines[j] = pixel;
        }
    }
    pixg = pixConvertTo8(pixs, 0);  /* and a grayscale version */
    pixWrite("/tmp/lept/numa_pixg.png", pixg, IFF_PNG);
    pixDisplay(pixg, 450, 100);

    na1 = pixExtractOnLine(pixg, 20, 20, 180, 20, 1);
    na2 = pixExtractOnLine(pixg, 40, 30, 40, 170, 1);
    na3 = pixExtractOnLine(pixg, 20, 170, 180, 30, 1);
    na4 = pixExtractOnLine(pixg, 20, 190, 180, 10, 1);
    gplotSimple1(na1, GPLOT_PNG, "/tmp/lept/numa_ext1", "Horizontal");
    gplotSimple1(na2, GPLOT_PNG, "/tmp/lept/numa_ext2", "Vertical");
    gplotSimple1(na3, GPLOT_PNG, "/tmp/lept/numa_ext3",
                 "Slightly more horizontal than vertical");
    gplotSimple1(na4, GPLOT_PNG, "/tmp/lept/numa_ext4",
                 "Slightly more vertical than horizontal");
#ifndef  _WIN32
    sleep(1);
#else
    Sleep(1000);
#endif  /* _WIN32 */
    pixa = pixaCreate(4);
    pix1 = pixRead("/tmp/lept/numa_ext1.png");
    pix2 = pixRead("/tmp/lept/numa_ext2.png");
    pix3 = pixRead("/tmp/lept/numa_ext3.png");
    pix4 = pixRead("/tmp/lept/numa_ext4.png");
    pixSaveTiled(pix1, pixa, 1.0, 1, 25, 32);
    pixSaveTiled(pix2, pixa, 1.0, 0, 25, 32);
    pixSaveTiled(pix3, pixa, 1.0, 1, 25, 32);
    pixSaveTiled(pix4, pixa, 1.0, 0, 25, 32);
    pixd = pixaDisplay(pixa, 0, 0);
    pixDisplay(pixd, 100, 500);
    pixWrite("/tmp/lept/numa_extract.png", pixd, IFF_PNG);
    numaDestroy(&na1);
    numaDestroy(&na2);
    numaDestroy(&na3);
    numaDestroy(&na4);
    pixaDestroy(&pixa);
    pixDestroy(&pix1);
    pixDestroy(&pix2);
    pixDestroy(&pix3);
    pixDestroy(&pix4);
    pixDestroy(&pix5);
    pixDestroy(&pixs);
    pixDestroy(&pixg);
    pixDestroy(&pixd);
#endif

    /* -------------------------------------------------------------------*
     *                     Row and column pixel sums                      *
     * -------------------------------------------------------------------*/
#if  DO_ALL
    /* Sum by columns in two halves (left and right) */
    pixs = pixRead("test8.jpg");
    pixGetDimensions(pixs, &w, &h, NULL);
    box1 = boxCreate(0, 0, w / 2, h);
    box2 = boxCreate(w / 2, 0, w - 2 / 2, h);
    na1 = pixAverageByColumn(pixs, box1, L_BLACK_IS_MAX);
    na2 = pixAverageByColumn(pixs, box2, L_BLACK_IS_MAX);
    numaJoin(na1, na2, 0, -1);
    na3 = pixAverageByColumn(pixs, NULL, L_BLACK_IS_MAX);
    numaSimilar(na1, na3, 0.0, &same);
    if (same)
        fprintf(stderr, "Same for columns\n");
    else
        fprintf(stderr, "Error for columns\n");
    pix = pixConvertTo32(pixs);
    pixRenderPlotFromNumaGen(&pix, na3, L_HORIZONTAL_LINE, 3, h / 2, 80, 1,
                             0xff000000);
    pixRenderPlotFromNuma(&pix, na3, L_PLOT_AT_BOT, 3, 80, 0xff000000);
    boxDestroy(&box1);
    boxDestroy(&box2);
    numaDestroy(&na1);
    numaDestroy(&na2);
    numaDestroy(&na3);

    /* Sum by rows in two halves (top and bottom) */
    box1 = boxCreate(0, 0, w, h / 2);
    box2 = boxCreate(0, h / 2, w, h - h / 2);
    na1 = pixAverageByRow(pixs, box1, L_WHITE_IS_MAX);
    na2 = pixAverageByRow(pixs, box2, L_WHITE_IS_MAX);
    numaJoin(na1, na2, 0, -1);
    na3 = pixAverageByRow(pixs, NULL, L_WHITE_IS_MAX);
    numaSimilar(na1, na3, 0.0, &same);
    if (same)
        fprintf(stderr, "Same for rows\n");
    else
        fprintf(stderr, "Error for rows\n");
    pixRenderPlotFromNumaGen(&pix, na3, L_VERTICAL_LINE, 3, w / 2, 80, 1,
                             0x00ff0000);
    pixRenderPlotFromNuma(&pix, na3, L_PLOT_AT_RIGHT, 3, 80, 0x00ff0000);
    pixDisplay(pix, 500, 200);
    boxDestroy(&box1);
    boxDestroy(&box2);
    numaDestroy(&na1);
    numaDestroy(&na2);
    numaDestroy(&na3);
    pixDestroy(&pix);

    /* Average left by rows; right by columns; compare totals */
    box1 = boxCreate(0, 0, w / 2, h);
    box2 = boxCreate(w / 2, 0, w - 2 / 2, h);
    na1 = pixAverageByRow(pixs, box1, L_WHITE_IS_MAX);
    na2 = pixAverageByColumn(pixs, box2, L_WHITE_IS_MAX);
    numaGetSum(na1, &sum1);  /* sum of averages of left box */
    numaGetSum(na2, &sum2);  /* sum of averages of right box */
    ave1 = sum1 / h;
    ave2 = 2.0 * sum2 / w;
    ave3 = 0.5 * (ave1 + ave2);  /* average over both halves */
    fprintf(stderr, "ave1 = %8.4f\n", sum1 / h);
    fprintf(stderr, "ave2 = %8.4f\n", 2.0 * sum2 / w);
    pixAverageInRect(pixs, NULL, &ave4);  /* entire image */
    diff1 = ave4 - ave3;
    diff2 = w * h * ave4 - (0.5 * w * sum1 + h * sum2);
    if (diff1 < 0.001)
        fprintf(stderr, "Average diffs are correct\n");
    else
        fprintf(stderr, "Average diffs are wrong: diff1 = %7.5f\n", diff1);
    if (diff2 < 20)  /* float-to-integer roundoff */
        fprintf(stderr, "Pixel sums are correct\n");
    else
        fprintf(stderr, "Pixel sums are in error: diff = %7.0f\n", diff2);

    /* Variance left and right halves.  Variance doesn't average
     * in a simple way, unlike pixel sums. */
    pixVarianceInRect(pixs, box1, &var1);  /* entire image */
    pixVarianceInRect(pixs, box2, &var2);  /* entire image */
    pixVarianceInRect(pixs, NULL, &var3);  /* entire image */
    fprintf(stderr, "0.5 * (var1 + var2) = %7.3f, var3 = %7.3f\n",
            0.5 * (var1 + var2), var3);
    boxDestroy(&box1);
    boxDestroy(&box2);
    numaDestroy(&na1);
    numaDestroy(&na2);
#endif

    /* -------------------------------------------------------------------*
     *                     Row and column variances                       *
     * -------------------------------------------------------------------*/
#if  DO_ALL

    /* Display variance by rows and columns */
    box1 = boxCreate(415, 0, 130, 425);
    boxGetGeometry(box1, NULL, NULL, &bw, &bh);
    na1 = pixVarianceByRow(pixs, box1);
    na2 = pixVarianceByColumn(pixs, box1);
    pix = pixConvertTo32(pixs);
    pix1 = pixCopy(NULL, pix);
    pixRenderPlotFromNumaGen(&pix, na1, L_VERTICAL_LINE, 3, 415, 100, 1,
                             0xff000000);
    pixRenderPlotFromNumaGen(&pix, na2, L_HORIZONTAL_LINE, 3, bh / 2, 100, 1,
                             0x00ff0000);
    pixRenderPlotFromNuma(&pix1, na1, L_PLOT_AT_LEFT, 3, 60, 0x00ff0000);
    pixRenderPlotFromNuma(&pix1, na1, L_PLOT_AT_MID_VERT, 3, 60, 0x0000ff00);
    pixRenderPlotFromNuma(&pix1, na1, L_PLOT_AT_RIGHT, 3, 60, 0xff000000);
    pixRenderPlotFromNuma(&pix1, na2, L_PLOT_AT_TOP, 3, 60, 0x0000ff00);
    pixRenderPlotFromNuma(&pix1, na2, L_PLOT_AT_MID_HORIZ, 3, 60, 0xff000000);
    pixRenderPlotFromNuma(&pix1, na2, L_PLOT_AT_BOT, 3, 60, 0x00ff0000);
    pixDisplay(pix, 500, 900);
    pixDisplay(pix1, 500, 1000);
    boxDestroy(&box1);
    numaDestroy(&na1);
    numaDestroy(&na2);
    pixDestroy(&pix);
    pixDestroy(&pix1);
    pixDestroy(&pixs);

    /* Again on a different image */
    pix1 = pixRead("boxedpage.jpg");
    pix2 = pixConvertTo8(pix1, 0);
    pixGetDimensions(pix2, &w, &h, NULL);
    na1 = pixVarianceByRow(pix2, NULL);
    pix3 = pixConvertTo32(pix1);
    pixRenderPlotFromNumaGen(&pix3, na1, L_VERTICAL_LINE, 3, 0, 70, 1,
                             0xff000000);
    na2 = pixVarianceByColumn(pix2, NULL);
    pixRenderPlotFromNumaGen(&pix3, na2, L_HORIZONTAL_LINE, 3, bh - 1, 70, 1,
                             0x00ff0000);
    pixDisplay(pix3, 1000, 0);
    numaDestroy(&na1);
    numaDestroy(&na2);
    pixDestroy(&pix3);

    /* Again, with an erosion */
    pix3 = pixErodeGray(pix2, 3, 21);
    pixDisplay(pix3, 1400, 0);
    na1 = pixVarianceByRow(pix3, NULL);
    pix4 = pixConvertTo32(pix1);
    pixRenderPlotFromNumaGen(&pix4, na1, L_VERTICAL_LINE, 3, 30, 70, 1,
                             0xff000000);
    na2 = pixVarianceByColumn(pix3, NULL);
    pixRenderPlotFromNumaGen(&pix4, na2, L_HORIZONTAL_LINE, 3, bh - 1, 70, 1,
                             0x00ff0000);
    pixDisplay(pix4, 1000, 550);
    numaDestroy(&na1);
    numaDestroy(&na2);
    pixDestroy(&pix1);
    pixDestroy(&pix2);
    pixDestroy(&pix3);
    pixDestroy(&pix4);
#endif

    /* -------------------------------------------------------------------*
     *                    Windowed variance along a line                  *
     * -------------------------------------------------------------------*/
#if  DO_ALL
    pix1 = pixRead("boxedpage.jpg");
    pix2 = pixConvertTo8(pix1, 0);
    pixGetDimensions(pix2, &w, &h, NULL);
    pix3 = pixCopy(NULL, pix1);

    /* Plot along horizontal line */
    pixWindowedVarianceOnLine(pix2, L_HORIZONTAL_LINE, h / 2 - 30, 0,
                              w, 5, &na1);
    pixRenderPlotFromNumaGen(&pix1, na1, L_HORIZONTAL_LINE, 3, h / 2 - 30,
                             80, 1, 0xff000000);
    pixRenderPlotFromNuma(&pix3, na1, L_PLOT_AT_TOP, 3, 60, 0x00ff0000);
    pixRenderPlotFromNuma(&pix3, na1, L_PLOT_AT_BOT, 3, 60, 0x0000ff00);

    /* Plot along vertical line */
    pixWindowedVarianceOnLine(pix2, L_VERTICAL_LINE, 0.78 * w, 0,
                              h, 5, &na2);
    pixRenderPlotFromNumaGen(&pix1, na2, L_VERTICAL_LINE, 3, 0.78 * w, 60,
                             1, 0x00ff0000);
    pixRenderPlotFromNuma(&pix3, na2, L_PLOT_AT_LEFT, 3, 60, 0xff000000);
    pixRenderPlotFromNuma(&pix3, na2, L_PLOT_AT_RIGHT, 3, 60, 0x00ff0000);
    pixDisplay(pix1, 1000, 1000);
    pixDisplay(pix3, 1500, 1000);
    pixDestroy(&pix1);
    pixDestroy(&pix2);
    pixDestroy(&pix3);
    numaDestroy(&na1);
    numaDestroy(&na2);
#endif
    return 0;
}
예제 #29
0
int main(int    argc,
         char **argv)
{
l_int32      i, j, wc, hc, d, bias;
L_KERNEL    *kel1, *kel2, *kel3x, *kel3y;
PIX         *pix, *pixs, *pixg, *pixacc, *pixd, *pixt;
char        *filein, *fileout;
static char  mainName[] = "convolvetest";

    if (argc != 5)
        return ERROR_INT(" Syntax:  convolvetest filein wc hc fileout",
                         mainName, 1);

    filein = argv[1];
    wc = atoi(argv[2]);
    hc = atoi(argv[3]);
    fileout = argv[4];
    if ((pix = pixRead(filein)) == NULL)
        return ERROR_INT("pix not made", mainName, 1);
    d = pixGetDepth(pix);
    if (d != 1 && d != 8 && d != 32)
        pixs = pixConvertTo8(pix, 0);
    else
        pixs = pixClone(pix);
    pixDestroy(&pix);
    d = pixGetDepth(pixs);

    if (d == 8 && (ALL || 0)) {
            /* Measure speed */
        pixacc = pixBlockconvAccum(pixs);
        for (i = 0; i < NTIMES; i++) {
            pixd = pixBlockconvGray(pixs, pixacc, wc, hc);
            if ((i+1) % 10 == 0)
                fprintf(stderr, "%d iters\n", i + 1);
            pixDestroy(&pixd);
        }
        pixd = pixBlockconvGray(pixs, pixacc, wc, hc);
        pixWrite(fileout, pixd, IFF_JFIF_JPEG);
        pixDestroy(&pixacc);
    }
    if (d == 8 && (ALL || 0)) {
            /* Test pixBlockconvGray() */
        pixacc = pixBlockconvAccum(pixs);
        pixd = pixBlockconvGray(pixs, pixacc, wc, hc);
        pixWrite(fileout, pixd, IFF_JFIF_JPEG);
        pixDestroy(&pixacc);
    }
    if (ALL || 0) {
            /* Test pixBlockconv() */
        pixd = pixBlockconv(pixs, wc, hc);
        pixWrite(fileout, pixd, IFF_JFIF_JPEG);
    }
    if (d == 1 && (ALL || 0)) {
            /* Test pixBlockrank() */
        pixacc = pixBlockconvAccum(pixs);
        pixd = pixBlockrank(pixs, pixacc, wc, hc, 0.5);
        pixWrite(fileout, pixd, IFF_TIFF_G4);
        pixDestroy(&pixacc);
    }
    if (d == 1 && (ALL || 0)) {
            /* Test pixBlocksum() */
        pixacc = pixBlockconvAccum(pixs);
        pixd = pixBlocksum(pixs, pixacc, wc, hc);
        pixInvert(pixd, pixd);
        pixWrite(fileout, pixd, IFF_JFIF_JPEG);
        pixDestroy(&pixacc);
    }
    if (ALL || 0) {
            /* Test pixCensusTransform() */
        d = pixGetDepth(pixs);
        if (d == 32)
            pixt = pixConvertRGBToLuminance(pixs);
        else
            pixt = pixClone(pixs);
        pixacc = pixBlockconvAccum(pixt);
        pixd = pixCensusTransform(pixt, wc, NULL);
        pixDestroy(&pixt);
        pixDestroy(&pixacc);
        pixWrite(fileout, pixd, IFF_PNG);
    }
    if (ALL || 0) {
            /* Test generic convolution with kel1 */
        lept_mkdir("lept");
        if (pixGetDepth(pixs) == 32)
            pixg = pixScaleRGBToGrayFast(pixs, 2, COLOR_GREEN);
        else
            pixg = pixScale(pixs, 0.5, 0.5);
        pixDisplay(pixg, 0, 600);
        kel1 = kernelCreateFromString(5, 5, 2, 2, kel1str);
        pixd = pixConvolve(pixg, kel1, 8, 1);
        pixDisplay(pixd, 700, 0);
        pixWrite("/tmp/lept/convol_d4.bmp", pixd, IFF_BMP);
        pixDestroy(&pixd);
        kernelDestroy(&kel1);

            /* Test convolution with flat rectangular kel */
        kel2 = kernelCreate(11, 11);
        kernelSetOrigin(kel2, 5, 5);
        for (i = 0; i < 11; i++) {
            for (j = 0; j < 11; j++)
                kernelSetElement(kel2, i, j, 1);
        }
        startTimer();
        pixd = pixConvolve(pixg, kel2, 8, 1);
        fprintf(stderr, "Generic convolution: %7.3f sec\n", stopTimer());
        pixDisplay(pixd, 1200, 0);
        pixWrite("/tmp/lept/convol_d5.bmp", pixd, IFF_BMP);
        startTimer();
        pixt = pixBlockconv(pixg, 5, 5);
        fprintf(stderr, "Block convolution: %7.3f sec\n", stopTimer());
        pixDisplay(pixd, 1200, 600);
        pixWrite("/tmp/lept/convol_d6.bmp", pixt, IFF_BMP);
        pixCompareGray(pixd, pixt, L_COMPARE_ABS_DIFF, GPLOT_X11, NULL,
                       NULL, NULL, NULL);
        pixDestroy(&pixg);
        pixDestroy(&pixt);
        kernelDestroy(&kel2);
    }
    if (ALL || 0) {
            /* Test bias convolution with kel2 */
        if (pixGetDepth(pixs) == 32)
            pixg = pixScaleRGBToGrayFast(pixs, 2, COLOR_GREEN);
        else
            pixg = pixScale(pixs, 0.5, 0.5);
        pixDisplay(pixg, 0, 600);
        kel2 = kernelCreateFromString(5, 5, 2, 2, kel2str);
        pixd = pixConvolveWithBias(pixg, kel2, NULL, TRUE, &bias);
        pixDisplay(pixd, 700, 0);
        fprintf(stderr, "bias = %d\n", bias);
        pixWrite("/tmp/lept/convol_d6.png", pixd, IFF_PNG);
        pixDestroy(&pixg);
        kernelDestroy(&kel2);
        pixDestroy(&pixd);
    }
    if (ALL || 1) {
            /* Test separable bias convolution with kel3x, kel3y */
        if (pixGetDepth(pixs) == 32)
            pixg = pixScaleRGBToGrayFast(pixs, 2, COLOR_GREEN);
        else
            pixg = pixScale(pixs, 0.5, 0.5);
        pixDisplay(pixg, 0, 600);
        kel3x = kernelCreateFromString(1, 5, 0, 2, kel3xstr);
        kel3y = kernelCreateFromString(7, 1, 3, 0, kel3ystr);
        pixd = pixConvolveWithBias(pixg, kel3x, kel3y, TRUE, &bias);
        pixDisplay(pixd, 700, 0);
        fprintf(stderr, "bias = %d\n", bias);
        pixWrite("/tmp/lept/convol_d7.png", pixd, IFF_PNG);
        pixDestroy(&pixg);
        kernelDestroy(&kel3x);
        kernelDestroy(&kel3y);
        pixDestroy(&pixd);
    }

    pixDestroy(&pixs);
    return 0;
}