Exemple #1
0
/*!
 *  numaaWriteStream()
 *
 *      Input:  stream, naa
 *      Return: 0 if OK, 1 on error
 */
l_int32
numaaWriteStream(FILE   *fp,
                 NUMAA  *naa)
{
l_int32  i, n;
NUMA    *na;

    PROCNAME("numaaWriteStream");

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

    n = numaaGetCount(naa);
    fprintf(fp, "\nNumaa Version %d\n", NUMA_VERSION_NUMBER);
    fprintf(fp, "Number of numa = %d\n\n", n);
    for (i = 0; i < n; i++) {
        if ((na = numaaGetNuma(naa, i, L_CLONE)) == NULL)
            return ERROR_INT("na not found", procName, 1);
        fprintf(fp, "Numa[%d]:", i);
        numaWriteStream(fp, na);
        numaDestroy(&na);
    }

    return 0;
}
Exemple #2
0
/*!
 *  gplotSimpleXYN()
 *
 *      Input:  nax (<optional>; can be NULL)
 *              naay (numaa of arrays to plot against @nax)
 *              outformat (GPLOT_PNG, GPLOT_PS, GPLOT_EPS, GPLOT_X11,
 *                         GPLOT_LATEX)
 *              outroot (root of output files)
 *              title (<optional>)
 *      Return: 0 if OK, 1 on error
 *
 *  Notes:
 *      (1) This gives line plots of each Numa in @naa against nax,
 *          generated in the specified output format.  The title is optional.
 *      (2) @nax is optional.  If NULL, each Numa array is plotted against
 *          the array index.
 *      (3) When calling these simple plot functions more than once, use
 *          different @outroot to avoid overwriting the output files.
 */
l_int32
gplotSimpleXYN(NUMA        *nax,
               NUMAA       *naay,
               l_int32      outformat,
               const char  *outroot,
               const char  *title)
{
l_int32  i, n;
GPLOT   *gplot;
NUMA    *nay;

    PROCNAME("gplotSimpleXYN");

    if (!naay)
        return ERROR_INT("naay not defined", procName, 1);
    if ((n = numaaGetCount(naay)) == 0)
        return ERROR_INT("no numa in array", procName, 1);
    if (outformat != GPLOT_PNG && outformat != GPLOT_PS &&
        outformat != GPLOT_EPS && outformat != GPLOT_X11 &&
        outformat != GPLOT_LATEX)
        return ERROR_INT("invalid outformat", procName, 1);
    if (!outroot)
        return ERROR_INT("outroot not specified", procName, 1);

    if ((gplot = gplotCreate(outroot, outformat, title, NULL, NULL)) == 0)
        return ERROR_INT("gplot not made", procName, 1);
    for (i = 0; i < n; i++) {
        nay = numaaGetNuma(naay, i, L_CLONE);
        gplotAddPlot(gplot, nax, nay, GPLOT_LINES, NULL);
        numaDestroy(&nay);
    }
    gplotMakeOutput(gplot);
    gplotDestroy(&gplot);
    return 0;
}
Exemple #3
0
/*!
 *  numaaGetValue()
 *
 *      Input:  naa
 *              i (index of numa within numaa)
 *              j (index into numa)
 *              fval (<optional return> float value)
 *              ival (<optional return> int value)
 *      Return: 0 if OK, 1 on error
 */
l_int32
numaaGetValue(NUMAA      *naa,
              l_int32     i,
              l_int32     j,
              l_float32  *pfval,
              l_int32    *pival)
{
l_int32  n;
NUMA    *na;

    PROCNAME("numaaGetValue");

    if (!pfval && !pival)
        return ERROR_INT("no return val requested", procName, 1);
    if (pfval) *pfval = 0.0;
    if (pival) *pival = 0;
    if (!naa)
        return ERROR_INT("naa not defined", procName, 1);
    n = numaaGetCount(naa);
    if (i < 0 || i >= n)
        return ERROR_INT("invalid index into naa", procName, 1);
    na = naa->numa[i];
    if (j < 0 || j >= na->n)
        return ERROR_INT("invalid index into na", procName, 1);
    if (pfval) *pfval = na->array[j];
    if (pival) *pival = (l_int32)(na->array[j]);
    return 0;
}
Exemple #4
0
/*!
 *  numaaAddNuma()
 *
 *      Input:  naa
 *              na   (to be added)
 *              copyflag  (L_INSERT, L_COPY, L_CLONE)
 *      Return: 0 if OK, 1 on error
 */
l_int32
numaaAddNuma(NUMAA   *naa,
             NUMA    *na,
             l_int32  copyflag)
{
l_int32  n;
NUMA    *nac;

    PROCNAME("numaaAddNuma");

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

    if (copyflag == L_INSERT) {
        nac = na;
    } else if (copyflag == L_COPY) {
        if ((nac = numaCopy(na)) == NULL)
            return ERROR_INT("nac not made", procName, 1);
    } else if (copyflag == L_CLONE) {
        nac = numaClone(na);
    } else {
        return ERROR_INT("invalid copyflag", procName, 1);
    }

    n = numaaGetCount(naa);
    if (n >= naa->nalloc)
        numaaExtendArray(naa);
    naa->numa[n] = nac;
    naa->n++;
    return 0;
}
Exemple #5
0
/*!
 *  numaaTruncate()
 *
 *      Input:  naa
 *      Return: 0 if OK, 1 on error
 *
 *  Notes:
 *      (1) This identifies the largest index containing a numa that
 *          has any numbers within it, destroys all numa beyond that
 *          index, and resets the count.
 */
l_int32
numaaTruncate(NUMAA  *naa)
{
l_int32  i, n, nn;
NUMA    *na;

    PROCNAME("numaaTruncate");

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

    n = numaaGetCount(naa);
    for (i = n - 1; i >= 0; i--) {
        na = numaaGetNuma(naa, i, L_CLONE);
        if (!na)
            continue;
        nn = numaGetCount(na);
        numaDestroy(&na);
        if (nn == 0)
            numaDestroy(&naa->numa[i]);
        else
            break;
    }
    naa->n = i + 1;
    return 0;
}
Exemple #6
0
/*!
 *  pixaSort2dByIndex()
 * 
 *      Input:  pixas
 *              naa (numaa that maps from the new pixaa to the input pixas)
 *              copyflag (L_CLONE or L_COPY)
 *      Return: pixaa (sorted), or null on error
 */
PIXAA *
pixaSort2dByIndex(PIXA    *pixas,
                  NUMAA   *naa,
                  l_int32  copyflag)
{
l_int32  pixtot, ntot, i, j, n, nn, index;
BOX     *box;
NUMA    *na;
PIX     *pix;
PIXA    *pixa;
PIXAA   *pixaa;

    PROCNAME("pixaSort2dByIndex");

    if (!pixas)
        return (PIXAA *)ERROR_PTR("pixas not defined", procName, NULL);
    if (!naa)
        return (PIXAA *)ERROR_PTR("naindex not defined", procName, NULL);

        /* Check counts */
    ntot = numaaGetNumberCount(naa);
    pixtot = pixaGetCount(pixas);
    if (ntot != pixtot)
        return (PIXAA *)ERROR_PTR("element count mismatch", procName, NULL);

    n = numaaGetCount(naa);
    pixaa = pixaaCreate(n);
    for (i = 0; i < n; i++) {
        na = numaaGetNuma(naa, i, L_CLONE);
        nn = numaGetCount(na);
        pixa = pixaCreate(nn);
        for (j = 0; j < nn; j++) {
            numaGetIValue(na, j, &index);
            pix = pixaGetPix(pixas, index, copyflag);
            box = pixaGetBox(pixas, index, copyflag);
            pixaAddPix(pixa, pix, L_INSERT);
            pixaAddBox(pixa, box, L_INSERT);
        }
        pixaaAddPixa(pixaa, pixa, L_INSERT);
        numaDestroy(&na);
    }

    return pixaa;
}
Exemple #7
0
/*!
 *  numaaGetNumberCount()
 *
 *      Input:  naa
 *      Return: count (total number of numbers in the numaa),
 *                     or 0 if no numbers or on error
 */
l_int32
numaaGetNumberCount(NUMAA  *naa)
{
NUMA    *na;
l_int32  n, sum, i;

    PROCNAME("numaaGetNumberCount");

    if (!naa)
        return ERROR_INT("naa not defined", procName, 0);

    n = numaaGetCount(naa);
    for (sum = 0, i = 0; i < n; i++) {
        na = numaaGetNuma(naa, i, L_CLONE);
        sum += numaGetCount(na);
        numaDestroy(&na);
    }

    return sum;
}
Exemple #8
0
/*!
 *  numaaAddNumber()
 *
 *      Input:  naa
 *              index (of numa within numaa)
 *              val  (float or int to be added; stored as a float)
 *      Return: 0 if OK, 1 on error
 *
 *  Notes:
 *      (1) Adds to an existing numa only.
 */
l_int32
numaaAddNumber(NUMAA     *naa,
               l_int32    index,
               l_float32  val)
{
l_int32  n;
NUMA    *na;

    PROCNAME("numaaAddNumber");

    if (!naa)
        return ERROR_INT("naa not defined", procName, 1);
    n = numaaGetCount(naa);
    if (index < 0 || index >= n)
        return ERROR_INT("invalid index in naa", procName, 1);

    na = numaaGetNuma(naa, index, L_CLONE);
    numaAddNumber(na, val);
    numaDestroy(&na);
    return 0;
}
Exemple #9
0
/*!
 *  numaaReplaceNuma()
 *
 *      Input:  naa
 *              index  (to the index-th numa)
 *              numa (insert and replace any existing one)
 *      Return: 0 if OK, 1 on error
 *
 *  Notes:
 *      (1) Any existing numa is destroyed, and the input one
 *          is inserted in its place.
 *      (2) If the index is invalid, return 1 (error)
 */
l_int32
numaaReplaceNuma(NUMAA   *naa,
                 l_int32  index,
                 NUMA    *na)
{
l_int32  n;

    PROCNAME("numaaReplaceNuma");

    if (!naa)
        return ERROR_INT("naa not defined", procName, 1);
    if (!na)
        return ERROR_INT("na not defined", procName, 1);
    n = numaaGetCount(naa);
    if (index < 0 || index >= n)
        return ERROR_INT("index not valid", procName, 1);

    numaDestroy(&naa->numa[index]);
    naa->numa[index] = na;
    return 0;
}
Exemple #10
0
/*!
 *  boxaSort2dByIndex()
 *
 *      Input:  boxas
 *              naa (numaa that maps from the new baa to the input boxa)
 *      Return: baa (sorted boxaa), or null on error
 */
BOXAA *
boxaSort2dByIndex(BOXA   *boxas,
                  NUMAA  *naa)
{
l_int32  ntot, boxtot, i, j, n, nn, index;
BOX     *box;
BOXA    *boxa;
BOXAA   *baa;
NUMA    *na;

    PROCNAME("boxaSort2dByIndex");

    if (!boxas)
        return (BOXAA *)ERROR_PTR("boxas not defined", procName, NULL);
    if (!naa)
        return (BOXAA *)ERROR_PTR("naindex not defined", procName, NULL);

        /* Check counts */
    ntot = numaaGetNumberCount(naa);
    boxtot = boxaGetCount(boxas);
    if (ntot != boxtot)
        return (BOXAA *)ERROR_PTR("element count mismatch", procName, NULL);

    n = numaaGetCount(naa);
    baa = boxaaCreate(n);
    for (i = 0; i < n; i++) {
        na = numaaGetNuma(naa, i, L_CLONE);
        nn = numaGetCount(na);
        boxa = boxaCreate(nn);
        for (j = 0; j < nn; j++) {
            numaGetIValue(na, i, &index);
            box = boxaGetBox(boxas, index, L_COPY);
            boxaAddBox(boxa, box, L_INSERT);
        }
        boxaaAddBoxa(baa, boxa, L_INSERT);
        numaDestroy(&na);
    }

    return baa;
}
/*!
 * \brief   numaaCompareImagesByBoxes()
 *
 * \param[in]    naa1 for image 1, formatted by boxaExtractSortedPattern()
 * \param[in]    naa2 ditto; for image 2
 * \param[in]    nperline number of box regions to be used in each textline
 * \param[in]    nreq number of complete row matches required
 * \param[in]    maxshiftx max allowed x shift between two patterns, in pixels
 * \param[in]    maxshifty max allowed y shift between two patterns, in pixels
 * \param[in]    delx max allowed difference in x data, after alignment
 * \param[in]    dely max allowed difference in y data, after alignment
 * \param[out]   psame 1 if %nreq row matches are found; 0 otherwise
 * \param[in]    debugflag 1 for debug output
 * \return  0 if OK, 1 on error
 *
 * <pre>
 * Notes:
 *      (1) Each input numaa describes a set of sorted bounding boxes
 *          (sorted by textline and, within each textline, from
 *          left to right) in the images from which they are derived.
 *          See boxaExtractSortedPattern() for a description of the data
 *          format in each of the input numaa.
 *      (2) This function does an alignment between the input
 *          descriptions of bounding boxes for two images. The
 *          input parameter %nperline specifies the number of boxes
 *          to consider in each line when testing for a match, and
 *          %nreq is the required number of lines that must be well-aligned
 *          to get a match.
 *      (3) Testing by alignment has 3 steps:
 *          (a) Generating the location of word bounding boxes from the
 *              images (prior to calling this function).
 *          (b) Listing all possible pairs of aligned rows, based on
 *              tolerances in horizontal and vertical positions of
 *              the boxes.  Specifically, all pairs of rows are enumerated
 *              whose first %nperline boxes can be brought into close
 *              alignment, based on the delx parameter for boxes in the
 *              line and within the overall the %maxshiftx and %maxshifty
 *              constraints.
 *          (c) Each pair, starting with the first, is used to search
 *              for a set of %nreq - 1 other pairs that can all be aligned
 *              with a difference in global translation of not more
 *              than (%delx, %dely).
 * </pre>
 */
l_int32
numaaCompareImagesByBoxes(NUMAA    *naa1,
                          NUMAA    *naa2,
                          l_int32   nperline,
                          l_int32   nreq,
                          l_int32   maxshiftx,
                          l_int32   maxshifty,
                          l_int32   delx,
                          l_int32   dely,
                          l_int32  *psame,
                          l_int32   debugflag)
{
l_int32   n1, n2, i, j, nbox, y1, y2, xl1, xl2;
l_int32   shiftx, shifty, match;
l_int32  *line1, *line2;  /* indicator for sufficient boxes in a line */
l_int32  *yloc1, *yloc2;  /* arrays of y value for first box in a line */
l_int32  *xleft1, *xleft2;  /* arrays of x value for left side of first box */
NUMA     *na1, *na2, *nai1, *nai2, *nasx, *nasy;

    PROCNAME("numaaCompareImagesByBoxes");

    if (!psame)
        return ERROR_INT("&same not defined", procName, 1);
    *psame = 0;
    if (!naa1)
        return ERROR_INT("naa1 not defined", procName, 1);
    if (!naa2)
        return ERROR_INT("naa2 not defined", procName, 1);
    if (nperline < 1)
        return ERROR_INT("nperline < 1", procName, 1);
    if (nreq < 1)
        return ERROR_INT("nreq < 1", procName, 1);

    n1 = numaaGetCount(naa1);
    n2 = numaaGetCount(naa2);
    if (n1 < nreq || n2 < nreq)
        return 0;

        /* Find the lines in naa1 and naa2 with sufficient boxes.
         * Also, find the y-values for each of the lines, and the
         * LH x-values of the first box in each line. */
    line1 = (l_int32 *)LEPT_CALLOC(n1, sizeof(l_int32));
    line2 = (l_int32 *)LEPT_CALLOC(n2, sizeof(l_int32));
    yloc1 = (l_int32 *)LEPT_CALLOC(n1, sizeof(l_int32));
    yloc2 = (l_int32 *)LEPT_CALLOC(n2, sizeof(l_int32));
    xleft1 = (l_int32 *)LEPT_CALLOC(n1, sizeof(l_int32));
    xleft2 = (l_int32 *)LEPT_CALLOC(n2, sizeof(l_int32));
    for (i = 0; i < n1; i++) {
        na1 = numaaGetNuma(naa1, i, L_CLONE);
        numaGetIValue(na1, 0, yloc1 + i);
        numaGetIValue(na1, 1, xleft1 + i);
        nbox = (numaGetCount(na1) - 1) / 2;
        if (nbox >= nperline)
            line1[i] = 1;
        numaDestroy(&na1);
    }
    for (i = 0; i < n2; i++) {
        na2 = numaaGetNuma(naa2, i, L_CLONE);
        numaGetIValue(na2, 0, yloc2 + i);
        numaGetIValue(na2, 1, xleft2 + i);
        nbox = (numaGetCount(na2) - 1) / 2;
        if (nbox >= nperline)
            line2[i] = 1;
        numaDestroy(&na2);
    }

        /* Enumerate all possible line matches.  A 'possible' line
         * match is one where the x and y shifts for the first box
         * in each line are within the maxshiftx and maxshifty
         * constraints, and the left and right sides of the remaining
         * (nperline - 1) successive boxes are within delx of each other.
         * The result is a set of four numas giving parameters of
         * each set of matching lines. */
    nai1 = numaCreate(0);  /* line index 1 of match */
    nai2 = numaCreate(0);  /* line index 2 of match */
    nasx = numaCreate(0);  /* shiftx for match */
    nasy = numaCreate(0);  /* shifty for match */
    for (i = 0; i < n1; i++) {
        if (line1[i] == 0) continue;
        y1 = yloc1[i];
        xl1 = xleft1[i];
        na1 = numaaGetNuma(naa1, i, L_CLONE);
        for (j = 0; j < n2; j++) {
            if (line2[j] == 0) continue;
            y2 = yloc2[j];
            if (L_ABS(y1 - y2) > maxshifty) continue;
            xl2 = xleft2[j];
            if (L_ABS(xl1 - xl2) > maxshiftx) continue;
            shiftx = xl1 - xl2;  /* shift to add to x2 values */
            shifty = y1 - y2;  /* shift to add to y2 values */
            na2 = numaaGetNuma(naa2, j, L_CLONE);

                /* Now check if 'nperline' boxes in the two lines match */
            match = testLineAlignmentX(na1, na2, shiftx, delx, nperline);
            if (match) {
                numaAddNumber(nai1, i);
                numaAddNumber(nai2, j);
                numaAddNumber(nasx, shiftx);
                numaAddNumber(nasy, shifty);
            }
            numaDestroy(&na2);
        }
        numaDestroy(&na1);
    }

        /* Determine if there are a sufficient number of mutually
         * aligned matches.  Mutually aligned matches place an additional
         * constraint on the 'possible' matches, where the relative
         * shifts must not exceed the (delx, dely) distances. */
    countAlignedMatches(nai1, nai2, nasx, nasy, n1, n2, delx, dely,
                        nreq, psame, debugflag);

    LEPT_FREE(line1);
    LEPT_FREE(line2);
    LEPT_FREE(yloc1);
    LEPT_FREE(yloc2);
    LEPT_FREE(xleft1);
    LEPT_FREE(xleft2);
    numaDestroy(&nai1);
    numaDestroy(&nai2);
    numaDestroy(&nasx);
    numaDestroy(&nasy);
    return 0;
}