示例#1
0
/*!
 *  recogAddAllSamples()
 *
 *      Input:  recog
 *              paa (pixaa from previously trained recog)
 *              debug
 *      Return: 0 if OK, 1 on error
 *
 *  Notes:
 *      (1) This is used with the serialization routine recogRead(),
 *          where each pixa in the pixaa represents a set of characters
 *          in a different class.  Two different pixa may represent
 *          characters with the same label.  Before calling this
 *          function, we verify that the number of character classes,
 *          given by the setsize field in recog, equals the number of
 *          pixa in the paa.  The character labels for each set are
 *          in the sa_text field.
 */
static l_int32
recogAddAllSamples(L_RECOG  *recog,
                   PIXAA    *paa,
                   l_int32   debug)
{
char    *text;
l_int32  i, j, nc, ns;
PIX     *pix;
PIXA    *pixa;

    PROCNAME("recogAddAllSamples");

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

    nc = pixaaGetCount(paa, NULL);
    for (i = 0; i < nc; i++) {
        pixa = pixaaGetPixa(paa, i, L_CLONE);
        ns = pixaGetCount(pixa);
        text = sarrayGetString(recog->sa_text, i, L_NOCOPY);
        for (j = 0; j < ns; j++) {
            pix = pixaGetPix(pixa, j, L_CLONE);
            if (debug) {
                fprintf(stderr, "pix[%d,%d]: text = %s\n", i, j, text);
            }
            pixaaAddPix(recog->pixaa_u, i, pix, NULL, L_INSERT);
        }
        pixaDestroy(&pixa);
    }

    recogTrainingFinished(recog, debug);
    return 0;
}
示例#2
0
/*!
 * \brief   recogAddCharstrLabels()
 *
 * \param[in]    recog
 * \return  0 if OK, 1 on error
 */
static l_int32
recogAddCharstrLabels(L_RECOG  *recog)
{
char    *text;
l_int32  i, j, n1, n2;
PIX     *pix;
PIXA    *pixa;
PIXAA   *paa;

    PROCNAME("recogAddCharstrLabels");

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

        /* Add the labels to each unscaled pix */
    paa = recog->pixaa_u;
    n1 = pixaaGetCount(paa, NULL);
    for (i = 0; i < n1; i++) {
        pixa = pixaaGetPixa(paa, i, L_CLONE);
        text = sarrayGetString(recog->sa_text, i, L_NOCOPY);
        n2 = pixaGetCount(pixa);
        for (j = 0; j < n2; j++) {
             pix = pixaGetPix(pixa, j, L_CLONE);
             pixSetText(pix, text);
             pixDestroy(&pix);
        }
        pixaDestroy(&pixa);
    }

    return 0;
}
/*!
 *  pixaaAddPixa()
 *
 *      Input:  pixaa
 *              pixa  (to be added)
 *              copyflag:
 *                L_INSERT inserts the pixa directly
 *                L_COPY makes a new pixa and copies each pix and each box
 *                L_CLONE gives a new handle to the input pixa
 *                L_COPY_CLONE makes a new pixa and inserts clones of
 *                    all pix and boxes
 *      Return: 0 if OK; 1 on error
 */
l_int32
pixaaAddPixa(PIXAA   *pixaa,
             PIXA    *pixa,
             l_int32  copyflag)
{
l_int32  n;
PIXA    *pixac;

    PROCNAME("pixaaAddPixa");

    if (!pixaa)
        return ERROR_INT("pixaa not defined", procName, 1);
    if (!pixa)
        return ERROR_INT("pixa not defined", procName, 1);
    if (copyflag != L_INSERT && copyflag != L_COPY &&
        copyflag != L_CLONE && copyflag != L_COPY_CLONE)
        return ERROR_INT("invalid copyflag", procName, 1);

    if (copyflag == L_INSERT)
        pixac = pixa;
    else {
        if ((pixac = pixaCopy(pixa, copyflag)) == NULL)
            return ERROR_INT("pixac not made", procName, 1);
    }

    n = pixaaGetCount(pixaa);
    if (n >= pixaa->nalloc)
        pixaaExtendArray(pixaa);
    pixaa->pixa[n] = pixac;
    pixaa->n++;

    return 0;
}
/*!
 *  pixaaWriteStream()
 *
 *      Input:  stream
 *              pixaa
 *      Return: 0 if OK, 1 on error
 */
l_int32
pixaaWriteStream(FILE   *fp,
                 PIXAA  *pixaa)
{
l_int32  n, i;
PIXA    *pixa;

    PROCNAME("pixaaWriteStream");

    if (!fp)
        return ERROR_INT("stream not defined", procName, 1);
    if (!pixaa)
        return ERROR_INT("pixaa not defined", procName, 1);

    n = pixaaGetCount(pixaa);
    fprintf(fp, "\nPixaa Version %d\n", PIXAA_VERSION_NUMBER);
    fprintf(fp, "Number of pixa = %d\n", n);
    boxaWriteStream(fp, pixaa->boxa);
    for (i = 0; i < n; i++) {
        if ((pixa = pixaaGetPixa(pixaa, i, L_CLONE)) == NULL)
            return ERROR_INT("pixa not found", procName, 1);
        fprintf(fp, "\n\n --------------- pixa[%d] ---------------\n", i);
        pixaWriteStream(fp, pixa);
        pixaDestroy(&pixa);
    }
    return 0;
}
/*!
 *  recogaCreateFromPixaa()
 *
 *      Input:  paa (of labelled, 1 bpp images)
 *              scalew  (scale all widths to this; use 0 for no scaling)
 *              scaleh  (scale all heights to this; use 0 for no scaling)
 *              templ_type (L_USE_AVERAGE or L_USE_ALL)
 *              threshold (for binarization; typically ~128)
 *              maxyshift (from nominal centroid alignment; typically 0 or 1)
 *      Return: recoga, or null on error
 *
 *  Notes:
 *      (1) This is a convenience function for training from labelled data.
 *      (2) Each pixa in the paa is a set of labelled data that is used
 *          to train a recognizer (e.g., for a set of characters in a font).
 *          Each image DC in the pixa is put into a class in its
 *          recognizer, defined by its character label.  All examples in
 *          the same class should be similar.
 *      (3) The pixaa can be written by recogaWritePixaa(), and must contain
 *          the unscaled bitmaps used for training.
 */
L_RECOGA *
recogaCreateFromPixaa(PIXAA       *paa,
                      l_int32      scalew,
                      l_int32      scaleh,
                      l_int32      templ_type,
                      l_int32      threshold,
                      l_int32      maxyshift)
{
l_int32    n, i, full;
L_RECOG   *recog;
L_RECOGA  *recoga;
PIXA      *pixa;

    PROCNAME("recogaCreateFromPixaa");

    if (!paa)
        return (L_RECOGA *)ERROR_PTR("paa not defined", procName, NULL);
    if (pixaaVerifyDepth(paa, NULL) != 1)
        return (L_RECOGA *)ERROR_PTR("all pix not 1 bpp", procName, NULL);
    pixaaIsFull(paa, &full);
    if (!full)
        return (L_RECOGA *)ERROR_PTR("all pix not present", procName, NULL);

    n = pixaaGetCount(paa, NULL);
    recoga = recogaCreate(n);
    for (i = 0; i < n; i++) {
        pixa = pixaaGetPixa(paa, i, L_CLONE);
        recog = recogCreateFromPixa(pixa, scalew, scaleh, templ_type,
                                    threshold, maxyshift);
        recogaAddRecog(recoga, recog);
        pixaDestroy(&pixa);
    }

    return recoga;
}
示例#6
0
/*!
 * \brief   recogAddAllSamples()
 *
 * \param[in]    precog  addr of recog
 * \param[in]    paa     pixaa from previously trained recog
 * \param[in]    debug
 * \return  0 if OK, 1 on error
 *
 * <pre>
 * Notes:
 *      (1) On error, the input recog is destroyed.
 *      (2) This is used with the serialization routine recogRead(),
 *          where each pixa in the pixaa represents a set of characters
 *          in a different class.  Before calling this function, we have
 *          verified that the number of character classes, given by the
 *          setsize field in %recog, equals the number of pixa in the paa.
 *          The character labels for each set are in the sa_text field.
 * </pre>
 */
static l_int32
recogAddAllSamples(L_RECOG  **precog,
                   PIXAA     *paa,
                   l_int32    debug)
{
char     *text;
l_int32   i, j, nc, ns;
PIX      *pix;
PIXA     *pixa, *pixa1;
L_RECOG  *recog;

    PROCNAME("recogAddAllSamples");

    if (!precog)
        return ERROR_INT("&recog not defined", procName, 1);
    if ((recog = *precog) == NULL)
        return ERROR_INT("recog not defined", procName, 1);
    if (!paa) {
        recogDestroy(&recog);
        return ERROR_INT("paa not defined", procName, 1);
    }

    nc = pixaaGetCount(paa, NULL);
    for (i = 0; i < nc; i++) {
        pixa = pixaaGetPixa(paa, i, L_CLONE);
        ns = pixaGetCount(pixa);
        text = sarrayGetString(recog->sa_text, i, L_NOCOPY);
        pixa1 = pixaCreate(ns);
        pixaaAddPixa(recog->pixaa_u, pixa1, L_INSERT);
        for (j = 0; j < ns; j++) {
            pix = pixaGetPix(pixa, j, L_CLONE);
            if (debug) fprintf(stderr, "pix[%d,%d]: text = %s\n", i, j, text);
            pixaaAddPix(recog->pixaa_u, i, pix, NULL, L_INSERT);
        }
        pixaDestroy(&pixa);
    }

    recogTrainingFinished(&recog, 0, -1, -1.0);  /* For second parameter,
                                             see comment in recogRead() */
    if (!recog)
        return ERROR_INT("bad templates; recog destroyed", procName, 1);
    return 0;
}
示例#7
0
/*!
 *  pixaaFlattenToPixa()
 *
 *      Input:  pixaa
 *              &naindex  (<optional return> the pixa index in the pixaa)
 *              copyflag  (L_COPY or L_CLONE)
 *      Return: pixa, or null on error
 *
 *  Notes:
 *      (1) This 'flattens' the pixaa to a pixa, taking the pix in
 *          order in the first pixa, then the second, etc.
 *      (2) If &naindex is defined, we generate a Numa that gives, for
 *          each pix in the pixaa, the index of the pixa to which it belongs.
 */
PIXA *
pixaaFlattenToPixa(PIXAA   *pixaa,
                   NUMA   **pnaindex,
                   l_int32  copyflag)
{
l_int32  i, j, m, n;
BOX     *box;
NUMA    *naindex;
PIX     *pix;
PIXA    *pixa, *pixat;

    PROCNAME("pixaaFlattenToPixa");

    if (pnaindex) *pnaindex = NULL;
    if (!pixaa)
        return (PIXA *)ERROR_PTR("pixaa not defined", procName, NULL);
    if (copyflag != L_COPY && copyflag != L_CLONE)
        return (PIXA *)ERROR_PTR("invalid copyflag", procName, NULL);

    if (pnaindex) {
        naindex = numaCreate(0);
        *pnaindex = naindex;
    }

    n = pixaaGetCount(pixaa);
    pixa = pixaCreate(n);
    for (i = 0; i < n; i++) {
        pixat = pixaaGetPixa(pixaa, i, L_CLONE);
        m = pixaGetCount(pixat);
        for (j = 0; j < m; j++) {
            pix = pixaGetPix(pixat, j, copyflag);
            box = pixaGetBox(pixat, j, copyflag);
            pixaAddPix(pixa, pix, L_INSERT);
            pixaAddBox(pixa, box, L_INSERT);
            if (pnaindex)
                numaAddNumber(naindex, i);  /* save 'row' number */
        }
        pixaDestroy(&pixat);
    }

    return pixa;
}
示例#8
0
/*!
 *  pixaaDisplayTiledAndScaled()
 *
 *      Input:  pixaa
 *              outdepth (output depth: 1, 8 or 32 bpp)
 *              tilewidth (each pix is scaled to this width)
 *              ncols (number of tiles in each row)
 *              background (0 for white, 1 for black; this is the color
 *                 of the spacing between the images)
 *              spacing  (between images, and on outside)
 *              border (width of additional black border on each image;
 *                      use 0 for no border)
 *      Return: pixa (of tiled images, one image for each pixa in
 *                    the pixaa), or null on error
 *
 *  Notes:
 *      (1) For each pixa, this generates from all the pix a
 *          tiled/scaled output pix, and puts it in the output pixa.
 *      (2) See comments in pixaDisplayTiledAndScaled().
 */
PIXA *
pixaaDisplayTiledAndScaled(PIXAA   *pixaa,
                           l_int32  outdepth,
                           l_int32  tilewidth,
                           l_int32  ncols,
                           l_int32  background,
                           l_int32  spacing,
                           l_int32  border)
{
l_int32  i, n;
PIX     *pix;
PIXA    *pixa, *pixad;

    PROCNAME("pixaaDisplayTiledAndScaled");

    if (!pixaa)
        return (PIXA *)ERROR_PTR("pixaa not defined", procName, NULL);
    if (outdepth != 1 && outdepth != 8 && outdepth != 32)
        return (PIXA *)ERROR_PTR("outdepth not in {1, 8, 32}", procName, NULL);
    if (border < 0 || border > tilewidth / 5)
        border = 0;
    
    if ((n = pixaaGetCount(pixaa)) == 0)
        return (PIXA *)ERROR_PTR("no components", procName, NULL);

    pixad = pixaCreate(n);
    for (i = 0; i < n; i++) {
        pixa = pixaaGetPixa(pixaa, i, L_CLONE);
        pix = pixaDisplayTiledAndScaled(pixa, outdepth, tilewidth, ncols,
                                        background, spacing, border);
        pixaAddPix(pixad, pix, L_INSERT);
        pixaDestroy(&pixa);
    }

    return pixad;
}
示例#9
0
/*!
 * \brief   recogReadStream()
 *
 * \param[in]    fp file stream
 * \return  recog, or NULL on error
 */
L_RECOG *
recogReadStream(FILE  *fp)
{
l_int32   version, setsize, threshold, scalew, scaleh, linew;
l_int32   maxyshift, nc;
L_DNA    *dna_tochar;
PIXAA    *paa;
L_RECOG  *recog;
SARRAY   *sa_text;

    PROCNAME("recogReadStream");

    if (!fp)
        return (L_RECOG *)ERROR_PTR("stream not defined", procName, NULL);

    if (fscanf(fp, "\nRecog Version %d\n", &version) != 1)
        return (L_RECOG *)ERROR_PTR("not a recog file", procName, NULL);
    if (version != RECOG_VERSION_NUMBER)
        return (L_RECOG *)ERROR_PTR("invalid recog version", procName, NULL);
    if (fscanf(fp, "Size of character set = %d\n", &setsize) != 1)
        return (L_RECOG *)ERROR_PTR("setsize not read", procName, NULL);
    if (fscanf(fp, "Binarization threshold = %d\n", &threshold) != 1)
        return (L_RECOG *)ERROR_PTR("binary thresh not read", procName, NULL);
    if (fscanf(fp, "Maxyshift = %d\n", &maxyshift) != 1)
        return (L_RECOG *)ERROR_PTR("maxyshift not read", procName, NULL);
    if (fscanf(fp, "Scale to width = %d\n", &scalew) != 1)
        return (L_RECOG *)ERROR_PTR("width not read", procName, NULL);
    if (fscanf(fp, "Scale to height = %d\n", &scaleh) != 1)
        return (L_RECOG *)ERROR_PTR("height not read", procName, NULL);
    if (fscanf(fp, "Normalized line width = %d\n", &linew) != 1)
        return (L_RECOG *)ERROR_PTR("line width not read", procName, NULL);
    if ((recog = recogCreate(scalew, scaleh, linew, threshold,
                             maxyshift)) == NULL)
        return (L_RECOG *)ERROR_PTR("recog not made", procName, NULL);

    if (fscanf(fp, "\nLabels for character set:\n") != 0) {
        recogDestroy(&recog);
        return (L_RECOG *)ERROR_PTR("label intro not read", procName, NULL);
    }
    l_dnaDestroy(&recog->dna_tochar);
    if ((dna_tochar = l_dnaReadStream(fp)) == NULL) {
        recogDestroy(&recog);
        return (L_RECOG *)ERROR_PTR("dna_tochar not read", procName, NULL);
    }
    recog->dna_tochar = dna_tochar;
    sarrayDestroy(&recog->sa_text);
    if ((sa_text = sarrayReadStream(fp)) == NULL) {
        recogDestroy(&recog);
        return (L_RECOG *)ERROR_PTR("sa_text not read", procName, NULL);
    }
    recog->sa_text = sa_text;

    if (fscanf(fp, "\nPixaa of all samples in the training set:\n") != 0) {
        recogDestroy(&recog);
        return (L_RECOG *)ERROR_PTR("pixaa intro not read", procName, NULL);
    }
    if ((paa = pixaaReadStream(fp)) == NULL) {
        recogDestroy(&recog);
        return (L_RECOG *)ERROR_PTR("pixaa not read", procName, NULL);
    }
    recog->setsize = setsize;
    nc = pixaaGetCount(paa, NULL);
    if (nc != setsize) {
        recogDestroy(&recog);
        pixaaDestroy(&paa);
        L_ERROR("(setsize = %d) != (paa count = %d)\n", procName,
                     setsize, nc);
        return NULL;
    }

    recogAddAllSamples(&recog, paa, 0);  /* this finishes */
    pixaaDestroy(&paa);
    if (!recog)
        return (L_RECOG *)ERROR_PTR("bad templates", procName, NULL);
    return recog;
}
示例#10
0
/*!
 *  pixaaDisplay()
 *
 *      Input:  pixaa
 *              w, h (if set to 0, determines the size from the
 *                    b.b. of the components in pixaa)
 *      Return: pix, or null on error
 *
 *  Notes:
 *      (1) Each pix of the pixaa is displayed at the location given by
 *          its box, translated by the box of the containing pixa
 *          if it exists.
 */
PIX *
pixaaDisplay(PIXAA   *pixaa,
             l_int32  w,
             l_int32  h)
{
l_int32  i, j, n, nbox, na, d, wmax, hmax, x, y, xb, yb, wb, hb;
BOXA    *boxa1;  /* top-level boxa */
BOXA    *boxa;
PIX     *pixt, *pixd;
PIXA    *pixa;

    PROCNAME("pixaaDisplay");

    if (!pixaa)
        return (PIX *)ERROR_PTR("pixaa not defined", procName, NULL);
    
    n = pixaaGetCount(pixaa);
    if (n == 0)
        return (PIX *)ERROR_PTR("no components", procName, NULL);

        /* If w and h not input, determine the minimum size required
         * to contain the origin and all c.c. */
    boxa1 = pixaaGetBoxa(pixaa, L_CLONE);
    nbox = boxaGetCount(boxa1);
    if (w == 0 || h == 0) {
        if (nbox == n)
            boxaGetExtent(boxa1, &w, &h, NULL);
        else {  /* have to use the lower-level boxa for each pixa */
            wmax = hmax = 0;
            for (i = 0; i < n; i++) {
                pixa = pixaaGetPixa(pixaa, i, L_CLONE);
                boxa = pixaGetBoxa(pixa, L_CLONE);
                boxaGetExtent(boxa, &w, &h, NULL);
                wmax = L_MAX(wmax, w);
                hmax = L_MAX(hmax, h);
                pixaDestroy(&pixa);
                boxaDestroy(&boxa);
            }
            w = wmax;
            h = hmax;
        }
    }

        /* Get depth from first pix */
    pixa = pixaaGetPixa(pixaa, 0, L_CLONE);
    pixt = pixaGetPix(pixa, 0, L_CLONE);
    d = pixGetDepth(pixt);
    pixaDestroy(&pixa);
    pixDestroy(&pixt);

    if ((pixd = pixCreate(w, h, d)) == NULL)
        return (PIX *)ERROR_PTR("pixd not made", procName, NULL);
    
    x = y = 0;
    for (i = 0; i < n; i++) {
        pixa = pixaaGetPixa(pixaa, i, L_CLONE);
        if (nbox == n)
            boxaGetBoxGeometry(boxa1, i, &x, &y, NULL, NULL);
        na = pixaGetCount(pixa);
        for (j = 0; j < na; j++) {
            pixaGetBoxGeometry(pixa, j, &xb, &yb, &wb, &hb);
            pixt = pixaGetPix(pixa, j, L_CLONE);
            pixRasterop(pixd, x + xb, y + yb, wb, hb, PIX_PAINT, pixt, 0, 0);
            pixDestroy(&pixt);
        }
        pixaDestroy(&pixa);
    }
    boxaDestroy(&boxa1);

    return pixd;
}
示例#11
0
/*!
 *  pixaaDisplayByPixa()
 *
 *      Input:  pixaa
 *              xspace between pix in pixa
 *              yspace between pixa
 *              max width of output pix
 *      Return: pix, or null on error
 *
 *  Notes:
 *      (1) Displays each pixa on a line (or set of lines),
 *          in order from top to bottom.  Within each pixa,
 *          the pix are displayed in order from left to right.
 *      (2) The size of each pix in each pixa is assumed to be
 *          approximately equal to the size of the first pix in
 *          the pixa.  If this assumption is not correct, this
 *          function will not work properly.
 *      (3) This ignores the boxa of the pixaa.
 */
PIX *
pixaaDisplayByPixa(PIXAA   *pixaa,
                   l_int32  xspace,
                   l_int32  yspace,
                   l_int32  maxw)
{
l_int32  i, j, npixa, npix;
l_int32  width, height, depth, nlines, lwidth;
l_int32  x, y, w, h, w0, h0;
PIX     *pixt, *pixd;
PIXA    *pixa;

    PROCNAME("pixaaDisplayByPixa");

    if (!pixaa)
        return (PIX *)ERROR_PTR("pixaa not defined", procName, NULL);
    
    if ((npixa = pixaaGetCount(pixaa)) == 0)
        return (PIX *)ERROR_PTR("no components", procName, NULL);

        /* Get size of output pix.  The width is the minimum of the
         * maxw and the largest pixa line width.  The height is whatever
         * it needs to be to accommodate all pixa. */
    height = 2 * yspace;
    width = 0;
    for (i = 0; i < npixa; i++) {
        pixa = pixaaGetPixa(pixaa, i, L_CLONE);
        npix = pixaGetCount(pixa);
        pixt = pixaGetPix(pixa, 0, L_CLONE);
        if (i == 0)
            depth = pixGetDepth(pixt);
        w = pixGetWidth(pixt);
        lwidth = npix * (w + xspace);
        nlines = (lwidth + maxw - 1) / maxw;
        if (nlines > 1)
            width = maxw;
        else
            width = L_MAX(lwidth, width);
        height += nlines * (pixGetHeight(pixt) + yspace);
        pixDestroy(&pixt);
        pixaDestroy(&pixa);
    }

    if ((pixd = pixCreate(width, height, depth)) == NULL)
        return (PIX *)ERROR_PTR("pixd not made", procName, NULL);

        /* Now layout the pix by pixa */
    y = yspace;
    for (i = 0; i < npixa; i++) {
        x = 0;
        pixa = pixaaGetPixa(pixaa, i, L_CLONE);
        npix = pixaGetCount(pixa);
        for (j = 0; j < npix; j++) {
            pixt = pixaGetPix(pixa, j, L_CLONE);
            if (j == 0) {
                w0 = pixGetWidth(pixt);
                h0 = pixGetHeight(pixt);
            }
            w = pixGetWidth(pixt);
            if (width == maxw && x + w >= maxw) {
                x = 0;
                y += h0 + yspace;
            }
            h = pixGetHeight(pixt);
            pixRasterop(pixd, x, y, w, h, PIX_PAINT, pixt, 0, 0);
            pixDestroy(&pixt);
            x += w0 + xspace;
        }
        y += h0 + yspace;
        pixaDestroy(&pixa);
    }

    return pixd;
}