Exemple #1
0
int main(int    argc,
         char **argv)
{
l_int32       i, j;
l_float32     f;
PIX          *pix1, *pix2;
L_REGPARAMS  *rp;

    if (regTestSetup(argc, argv, &rp))
        return 1;

    pix1 = pixCreate(500, 500, 8);
    pix2 = 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(pix1, j, i, (l_int32)f);
            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);
            pixSetPixel(pix2, j, i, (l_int32)f);
        }
    }
    DoWatershed(rp, pix1);  /* 0 - 11 */
    DoWatershed(rp, pix2);  /* 12 - 23 */
    pixDestroy(&pix1);
    pixDestroy(&pix2);
    return regTestCleanup(rp);
}
Exemple #2
0
/**
 * create a B/W image from a char_sample
 */
    Pix *CubeUtils::PixFromCharSample(CharSamp * char_samp) {
        // parameter check
        if (char_samp == NULL) {
            return NULL;
        }

        // get the raw data
        int stride = char_samp->Stride();
        int wid = char_samp->Width();
        int hgt = char_samp->Height();

        Pix *pix = pixCreate(wid, hgt, 1);
        if (pix == NULL) {
            return NULL;
        }

        // copy the contents
        unsigned char *line = char_samp->RawData();
        for (int y = 0; y < hgt; y++, line += stride) {
            for (int x = 0; x < wid; x++) {
                if (line[x] != 0) {
                    pixSetPixel(pix, x, y, 0);
                } else {
                    pixSetPixel(pix, x, y, 255);
                }
            }
        }

        return pix;
    }
Exemple #3
0
/*!
 *  pixDisplayHitMissSel()
 *
 *      Input:  pixs (1 bpp)
 *              sel (hit-miss in general)
 *              scalefactor (an integer >= 1; use 0 for default)
 *              hitcolor (RGB0 color for center of hit pixels)
 *              misscolor (RGB0 color for center of miss pixels)
 *      Return: pixd (RGB showing both pixs and sel), or null on error
 *  Notes:
 *    (1) We don't allow scalefactor to be larger than MAX_SEL_SCALEFACTOR
 *    (2) The colors are conveniently given as 4 bytes in hex format,
 *        such as 0xff008800.  The least significant byte is ignored.
 */
PIX *
pixDisplayHitMissSel(PIX      *pixs,
                     SEL      *sel,
                     l_int32   scalefactor,
                     l_uint32  hitcolor,
                     l_uint32  misscolor)
{
l_int32    i, j, type;
l_float32  fscale;
PIX       *pixt, *pixd;
PIXCMAP   *cmap;

    PROCNAME("pixDisplayHitMissSel");

    if (!pixs)
        return (PIX *)ERROR_PTR("pixs not defined", procName, NULL);
    if (pixGetDepth(pixs) != 1)
        return (PIX *)ERROR_PTR("pixs not 1 bpp", procName, NULL);
    if (!sel)
        return (PIX *)ERROR_PTR("sel not defined", procName, NULL);

    if (scalefactor <= 0)
        scalefactor = DEFAULT_SEL_SCALEFACTOR;
    if (scalefactor > MAX_SEL_SCALEFACTOR) {
        L_WARNING("scalefactor too large; using max value", procName);
        scalefactor = MAX_SEL_SCALEFACTOR;
    }

        /* Generate a version of pixs with a colormap */
    pixt = pixConvert1To8(NULL, pixs, 0, 1);
    cmap = pixcmapCreate(8);
    pixcmapAddColor(cmap, 255, 255, 255);
    pixcmapAddColor(cmap, 0, 0, 0);
    pixcmapAddColor(cmap, hitcolor >> 24, (hitcolor >> 16) & 0xff,
                    (hitcolor >> 8) & 0xff);
    pixcmapAddColor(cmap, misscolor >> 24, (misscolor >> 16) & 0xff,
                    (misscolor >> 8) & 0xff);
    pixSetColormap(pixt, cmap);

        /* Color the hits and misses */
    for (i = 0; i < sel->sy; i++) {
        for (j = 0; j < sel->sx; j++) {
            selGetElement(sel, i, j, &type);
            if (type == SEL_DONT_CARE)
                continue;
            if (type == SEL_HIT)
                pixSetPixel(pixt, j, i, 2);
            else  /* type == SEL_MISS */
                pixSetPixel(pixt, j, i, 3);
        }
    }

        /* Scale it up */
    fscale = (l_float32)scalefactor;
    pixd = pixScaleBySampling(pixt, fscale, fscale);

    pixDestroy(&pixt);
    return pixd;
}
Exemple #4
0
/*!
 *  pixSubsampleBoundaryPixels()
 *
 *      Input:  pixs (1 bpp, with only boundary pixels in fg)
 *              skip (number to skip between samples as you traverse boundary)
 *      Return: pta, or null on error
 *
 *  Notes:
 *      (1) If skip = 0, we take all the fg pixels.
 *      (2) We try to traverse the boundaries in a regular way.
 *          Some pixels may be missed, and these are then subsampled
 *          randomly with a fraction determined by 'skip'.
 *      (3) The most natural approach is to use a depth first (stack-based)
 *          method to find the fg pixels.  However, the pixel runs are
 *          4-connected and there are relatively few branches.  So
 *          instead of doing a proper depth-first search, we get nearly
 *          the same result using two nested while loops: the outer
 *          one continues a raster-based search for the next fg pixel,
 *          and the inner one does a reasonable job running along
 *          each 4-connected coutour.
 */
PTA *
pixSubsampleBoundaryPixels(PIX     *pixs,
                           l_int32  skip)
{
l_int32  x, y, xn, yn, xs, ys, xa, ya, count;
PIX     *pixt;
PTA     *pta;

    PROCNAME("pixSubsampleBoundaryPixels");

    if (!pixs)
        return (PTA *)ERROR_PTR("pixs not defined", procName, NULL);
    if (pixGetDepth(pixs) != 1)
        return (PTA *)ERROR_PTR("pixs not 1 bpp", procName, NULL);
    if (skip < 0)
        return (PTA *)ERROR_PTR("skip < 0", procName, NULL);

    if (skip == 0)
        return ptaGetPixelsFromPix(pixs, NULL);

    pta = ptaCreate(0);
    pixt = pixCopy(NULL, pixs);
    xs = ys = 0;
    while (nextOnPixelInRaster(pixt, xs, ys, &xn, &yn)) {  /* new series */
        xs = xn;
        ys = yn;

            /* Add first point in this series */
        ptaAddPt(pta, xs, ys);

            /* Trace out boundary, erasing all and saving every (skip + 1)th */
        x = xs;
        y = ys;
        pixSetPixel(pixt, x, y, 0);
        count = 0;
        while (adjacentOnPixelInRaster(pixt, x, y, &xa, &ya)) {
            x = xa;
            y = ya;
            pixSetPixel(pixt, x, y, 0);
            if (count == skip) {
                ptaAddPt(pta, x, y);
                count = 0;
            }
            else {
                count++;
            }
        }
    }

    pixDestroy(&pixt);
    return pta;
}
Exemple #5
0
// Renders just the outline to the given pix (no fill), with left and top
// being the coords of the upper-left corner of the pix.
void C_OUTLINE::render_outline(int left, int top, Pix* pix) const {
  ICOORD pos = start;
  for (int stepindex = 0; stepindex < stepcount; ++stepindex) {
    ICOORD next_step = step(stepindex);
    if (next_step.y() < 0) {
      pixSetPixel(pix, pos.x() - left, top - pos.y(), 1);
    } else if (next_step.y() > 0) {
      pixSetPixel(pix, pos.x() - left - 1, top - pos.y() - 1, 1);
    } else if (next_step.x() < 0) {
      pixSetPixel(pix, pos.x() - left - 1, top - pos.y(), 1);
    } else if (next_step.x() > 0) {
      pixSetPixel(pix, pos.x() - left, top - pos.y() - 1, 1);
    }
    pos += next_step;
  }
}
// Returns a pix representing the sample. (Int features only.)
Pix* TrainingSample::RenderToPix(const UNICHARSET* unicharset) const {
  Pix* pix = pixCreate(kIntFeatureExtent, kIntFeatureExtent, 1);
  for (uint32_t f = 0; f < num_features_; ++f) {
    int start_x = features_[f].X;
    int start_y = kIntFeatureExtent - features_[f].Y;
    double dx = cos((features_[f].Theta / 256.0) * 2.0 * M_PI - M_PI);
    double dy = -sin((features_[f].Theta / 256.0) * 2.0 * M_PI - M_PI);
    for (int i = 0; i <= 5; ++i) {
      int x = static_cast<int>(start_x + dx * i);
      int y = static_cast<int>(start_y + dy * i);
      if (x >= 0 && x < 256 && y >= 0 && y < 256)
        pixSetPixel(pix, x, y, 1);
    }
  }
  if (unicharset != nullptr)
    pixSetText(pix, unicharset->id_to_unichar(class_id_));
  return pix;
}
main(int    argc,
     char **argv)
{
PIX            *pixs, *pixd, *pixt;
l_int32         i, j, maxval, val;
l_float32       gamma;
static char     mainName[] = "falsecolortest";

    if (argc != 2)
	exit(ERROR_INT(" Syntax:  falsecolortest gamma", mainName, 1));

    gamma = atof(argv[1]);
    maxval = 0xff;
    if (DEPTH == 16)
        maxval = 0xffff;

    pixs = pixCreate(WIDTH, HEIGHT, DEPTH);
    for (i = 0; i < HEIGHT; i++) {
        for (j = 0; j < WIDTH; j++) {
	    val = maxval * j / WIDTH;
	    pixSetPixel(pixs, j, i, val);
	}
    }
    fprintf(stderr, "before depth = %d\n", pixGetDepth(pixs));
    pixWrite("/tmp/junkout16.png", pixs, IFF_PNG);
    pixt = pixRead("/tmp/junkout16.png");
    pixWrite("/tmp/junkoutafter.png", pixt, IFF_PNG);
    fprintf(stderr, "after depth = %d\n", pixGetDepth(pixt));

    pixd = pixConvertGrayToFalseColor(pixt, gamma);
    pixDisplay(pixd, 50, 50);
    pixWrite("/tmp/junkout.png", pixd, IFF_PNG);
    pixDestroy(&pixs);
    pixDestroy(&pixt);
    pixDestroy(&pixd);
    return 0;
}
int main(int    argc,
         char **argv)
{
l_int32      i, j;
l_float32    f;
l_uint32     redval, greenval;
PIX         *pixs, *pixd, *pix0, *pix1, *pix2;
static char  mainName[] = "locminmax_reg";

    if (argc != 1)
        return 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, &pix1, &pix2); */
    pixLocalExtrema(pixs, 0, 0, &pix1, &pix2);
    fprintf(stderr, "Time for extrema: %7.3f\n", stopTimer());
    composeRGBPixel(255, 0, 0, &redval);
    composeRGBPixel(0, 255, 0, &greenval);
    pixd = pixConvertTo32(pixs);
    pixPaintThroughMask(pixd, pix2, 0, 0, greenval);
    pixPaintThroughMask(pixd, pix1, 0, 0, redval);
    pixDisplay(pixd, 510, 0);
    pixWrite("/tmp/junkpixd.png", pixd, IFF_PNG);
    pixDestroy(&pix1);
    pixDestroy(&pix2);
    pixDestroy(&pixs);
    pixDestroy(&pixd);

    pix0 = pixRead("karen8.jpg");
    pixs = pixBlockconv(pix0, 10, 10);
    pixDisplay(pixs, 0, 400);
    pixWrite("/tmp/junkconv.png", pixs, IFF_PNG);
    startTimer();
/*    pixSelectedLocalExtrema(pixs, 1, &pix1, &pix2); */
    pixLocalExtrema(pixs, 50, 100, &pix1, &pix2);
    fprintf(stderr, "Time for extrema: %7.3f\n", stopTimer());
    composeRGBPixel(255, 0, 0, &redval);
    composeRGBPixel(0, 255, 0, &greenval);
    pixd = pixConvertTo32(pixs);
    pixPaintThroughMask(pixd, pix2, 0, 0, greenval);
    pixPaintThroughMask(pixd, pix1, 0, 0, redval);
    pixDisplay(pixd, 350, 400);
    pixWrite("/tmp/junkpixd2.png", pixd, IFF_PNG);
    pixDestroy(&pix0);
    pixDestroy(&pix1);
    pixDestroy(&pix2);
    pixDestroy(&pixs);
    pixDestroy(&pixd);
    return 0;
}
Exemple #9
0
main(int    argc,
     char **argv)
{
l_int32      i, j, same;
PIX         *pixm, *pixmi, *pixs1, *pixs1_8;
PIX         *pixs2, *pixs2_8, *pixs3, *pixs3_8;
PIX         *pixb1, *pixb2, *pixb3, *pixmin, *pixd;
PIXA        *pixac;
static char  mainName[] = "grayfill_reg";


    pixDisplayWrite(NULL, -1);
    pixac = pixaCreate(0);

        /* Mask */
    pixm = pixCreate(200, 200, 8);
    for (i = 0; i < 200; i++)
        for (j = 0; j < 200; j++)
            pixSetPixel(pixm, j, i, 20 + L_ABS((100 - i) * (100 - j)) / 50);
    pixmi = pixInvert(NULL, pixm);

        /* Seed1 */
    pixs1 = pixCreate(200, 200, 8);
    for (i = 99; i <= 101; i++)
        for (j = 99; j <= 101; j++)
            pixSetPixel(pixs1, j, i, 50 - i/100 - j/100);
    pixs1_8 = pixCopy(NULL, pixs1);

        /* Seed2 */
    pixs2 = pixCreate(200, 200, 8);
    for (i = 99; i <= 101; i++)
        for (j = 99; j <= 101; j++)
            pixSetPixel(pixs2, j, i, 205 - i/100 - j/100);
    pixs2_8 = pixCopy(NULL, pixs2);

        /* Inverse grayscale fill */
    pixSaveTiled(pixm, pixac, 1, 1, 10, 8);
    pixSaveTiled(pixs1, pixac, 1, 0, 10, 0);
    pixSeedfillGrayInv(pixs1, pixm, 4);
    pixSeedfillGrayInv(pixs1_8, pixm, 8);
    pixSaveTiled(pixs1, pixac, 1, 0, 10, 0);
    pixSaveTiled(pixs1_8, pixac, 1, 0, 10, 0);
    pixb1 = pixThresholdToBinary(pixs1, 20);
    pixSaveTiled(pixb1, pixac, 1, 0, 10, 0);
    pixCombineMasked(pixs1, pixm, pixb1);
    pixSaveTiled(pixs1, pixac, 1, 0, 10, 0);
    pixDestroy(&pixs1);
    pixDestroy(&pixs1_8);
    pixDestroy(&pixb1);

        /* Standard grayscale fill */
    pixSaveTiled(pixmi, pixac, 1, 1, 10, 0);
    pixSaveTiled(pixs2, pixac, 1, 0, 10, 0);
    pixSeedfillGray(pixs2, pixmi, 4);
    pixSeedfillGray(pixs2_8, pixmi, 8);
    pixSaveTiled(pixs2, pixac, 1, 0, 10, 0);
    pixSaveTiled(pixs2_8, pixac, 1, 0, 10, 0);
    pixb2 = pixThresholdToBinary(pixs2, 205);
    pixSaveTiled(pixb2, pixac, 1, 0, 10, 0);
    pixDestroy(&pixs2);
    pixDestroy(&pixs2_8);
    pixDestroy(&pixb2);

        /* Basin fill from minima as seed */
    pixSaveTiled(pixm, pixac, 1, 1, 10, 8);
    pixLocalExtrema(pixm, 0, 0, &pixmin, NULL);
    pixSaveTiled(pixmin, pixac, 1, 0, 10, 0);
    pixs3 = pixSeedfillGrayBasin(pixmin, pixm, 30, 4);
    pixs3_8 = pixSeedfillGrayBasin(pixmin, pixm, 30, 8);
    pixSaveTiled(pixs3, pixac, 1, 0, 10, 0);
    pixSaveTiled(pixs3_8, pixac, 1, 0, 10, 0);
    pixb3 = pixThresholdToBinary(pixs3, 60);
    pixSaveTiled(pixb3, pixac, 1, 0, 10, 0);
    pixDestroy(&pixs3);
    pixDestroy(&pixs3_8);
    pixDestroy(&pixb3);

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

        /* Compare hybrid and iterative gray seedfills */
    pixs1 = pixCopy(NULL, pixm);
    pixs2 = pixCopy(NULL, pixm);
    pixAddConstantGray(pixs1, -30);
    pixAddConstantGray(pixs2, 60);

    PixTestEqual(pixs1, pixs2, pixm, 1, 4);
    PixTestEqual(pixs1, pixs2, pixm, 2, 8);
    PixTestEqual(pixs2, pixs1, pixm, 3, 4);
    PixTestEqual(pixs2, pixs1, pixm, 4, 8);
    pixDestroy(&pixs1);
    pixDestroy(&pixs2);

    pixDestroy(&pixm);
    pixDestroy(&pixmi);
    pixDestroy(&pixmin);
    return 0;
}
Exemple #10
0
/*!
 * \brief   pixReadStreamPnm()
 *
 * \param[in]    fp file stream opened for read
 * \return  pix, or NULL on error
 */
PIX *
pixReadStreamPnm(FILE  *fp)
{
l_uint8    val8, rval8, gval8, bval8;
l_uint16   val16;
l_int32    w, h, d, bpl, wpl, i, j, type;
l_int32    val, rval, gval, bval;
l_uint32   rgbval;
l_uint32  *line, *data;
PIX       *pix;

    PROCNAME("pixReadStreamPnm");

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

    if (freadHeaderPnm(fp, &w, &h, &d, &type, NULL, NULL))
        return (PIX *)ERROR_PTR( "header read failed", procName, NULL);
    if ((pix = pixCreate(w, h, d)) == NULL)
        return (PIX *)ERROR_PTR( "pix not made", procName, NULL);
    pixSetInputFormat(pix, IFF_PNM);
    data = pixGetData(pix);
    wpl = pixGetWpl(pix);

        /* Old "ascii" format */
    if (type <= 3) {
        for (i = 0; i < h; i++) {
            for (j = 0; j < w; j++) {
                if (type == 1 || type == 2) {
                    if (pnmReadNextAsciiValue(fp, &val))
                        return (PIX *)ERROR_PTR( "read abend", procName, pix);
                    pixSetPixel(pix, j, i, val);
                } else {  /* type == 3 */
                    if (pnmReadNextAsciiValue(fp, &rval))
                        return (PIX *)ERROR_PTR( "read abend", procName, pix);
                    if (pnmReadNextAsciiValue(fp, &gval))
                        return (PIX *)ERROR_PTR( "read abend", procName, pix);
                    if (pnmReadNextAsciiValue(fp, &bval))
                        return (PIX *)ERROR_PTR( "read abend", procName, pix);
                    composeRGBPixel(rval, gval, bval, &rgbval);
                    pixSetPixel(pix, j, i, rgbval);
                }
            }
        }
        return pix;
    }

        /* "raw" format for 1 bpp */
    if (type == 4) {
        bpl = (d * w + 7) / 8;
        for (i = 0; i < h; i++) {
            line = data + i * wpl;
            for (j = 0; j < bpl; j++) {
                if (fread(&val8, 1, 1, fp) != 1)
                    return (PIX *)ERROR_PTR( "read error in 4", procName, pix);
                SET_DATA_BYTE(line, j, val8);
            }
        }
        return pix;
    }

        /* "raw" format for grayscale */
    if (type == 5) {
        bpl = (d * w + 7) / 8;
        for (i = 0; i < h; i++) {
            line = data + i * wpl;
            if (d != 16) {
                for (j = 0; j < w; j++) {
                    if (fread(&val8, 1, 1, fp) != 1)
                        return (PIX *)ERROR_PTR( "error in 5", procName, pix);
                    if (d == 2)
                        SET_DATA_DIBIT(line, j, val8);
                    else if (d == 4)
                        SET_DATA_QBIT(line, j, val8);
                    else  /* d == 8 */
                        SET_DATA_BYTE(line, j, val8);
                }
            } else {  /* d == 16 */
                for (j = 0; j < w; j++) {
                    if (fread(&val16, 2, 1, fp) != 1)
                        return (PIX *)ERROR_PTR( "16 bpp error", procName, pix);
                    SET_DATA_TWO_BYTES(line, j, val16);
                }
            }
        }
        return pix;
    }

        /* "raw" format, type == 6; rgb */
    for (i = 0; i < h; i++) {
        line = data + i * wpl;
        for (j = 0; j < wpl; j++) {
            if (fread(&rval8, 1, 1, fp) != 1)
                return (PIX *)ERROR_PTR( "read error type 6", procName, pix);
            if (fread(&gval8, 1, 1, fp) != 1)
                return (PIX *)ERROR_PTR( "read error type 6", procName, pix);
            if (fread(&bval8, 1, 1, fp) != 1)
                return (PIX *)ERROR_PTR( "read error type 6", procName, pix);
            composeRGBPixel(rval8, gval8, bval8, &rgbval);
            line[j] = rgbval;
        }
    }
    return pix;
}
Exemple #11
0
/*!
 * \brief   pixConnCompIncrAdd()
 *
 * \param[in]     pixs 32 bpp, with pixels labeled by c.c.
 * \param[in]     ptaa with each pta of pixel locations indexed by c.c.
 * \param[out]    pncc number of c.c
 * \param[in]     x,y location of added pixel
 * \param[in]     debug 0 for no output; otherwise output whenever
 *                      debug <= nvals, up to debug == 3
 * \return   -1 if nothing happens; 0 if a pixel is added; 1 on error
 *
 * <pre>
 * Notes:
 *      (1) This adds a pixel and updates the labeled connected components.
 *          Before calling this function, initialize the process using
 *          pixConnCompIncrInit().
 *      (2) As a result of adding a pixel, one of the following can happen,
 *          depending on the number of neighbors with non-zero value:
 *          (a) nothing: the pixel is already a member of a c.c.
 *          (b) no neighbors: a new component is added, increasing the
 *              number of c.c.
 *          (c) one neighbor: the pixel is added to an existing c.c.
 *          (d) more than one neighbor: the added pixel causes joining of
 *              two or more c.c., reducing the number of c.c.  A maximum
 *              of 4 c.c. can be joined.
 *      (3) When two c.c. are joined, the pixels in the larger index are
 *          relabeled to those of the smaller in pixs, and their locations
 *          are transferred to the pta with the smaller index in the ptaa.
 *          The pta corresponding to the larger index is then deleted.
 *      (4) This is an efficient implementation of a "union-find" operation,
 *          which supports the generation and merging of disjoint sets
 *          of pixels.  This function can be called about 1.3 million times
 *          per second.
 * </pre>
 */
l_int32
pixConnCompIncrAdd(PIX       *pixs,
                   PTAA      *ptaa,
                   l_int32   *pncc,
                   l_float32  x,
                   l_float32  y,
                   l_int32    debug)
{
l_int32   conn, i, j, w, h, count, nvals, ns, firstindex;
l_uint32  val;
l_int32  *neigh;
PTA      *ptas, *ptad;

    PROCNAME("pixConnCompIncrAdd");

    if (!pixs || pixGetDepth(pixs) != 32)
        return ERROR_INT("pixs not defined or not 32 bpp", procName, 1);
    if (!ptaa)
        return ERROR_INT("ptaa not defined", procName, 1);
    if (!pncc)
        return ERROR_INT("&ncc not defined", procName, 1);
    conn = pixs->special;
    if (conn != 4 && conn != 8)
        return ERROR_INT("connectivity must be 4 or 8", procName, 1);
    pixGetDimensions(pixs, &w, &h, NULL);
    if (x < 0 || x >= w)
        return ERROR_INT("invalid x pixel location", procName, 1);
    if (y < 0 || y >= h)
        return ERROR_INT("invalid y pixel location", procName, 1);

    pixGetPixel(pixs, x, y, &val);
    if (val > 0)  /* already belongs to a set */
        return -1;

        /* Find unique neighbor pixel values in increasing order of value.
         * If %nvals > 0, these are returned in the %neigh array, which
         * is of size %nvals.  Note that the pixel values in each
         * connected component are used as the index into the pta
         * array of the ptaa, giving the pixel locations. */
    pixGetSortedNeighborValues(pixs, x, y, conn, &neigh, &nvals);

        /* If there are no neighbors, just add a new component */
    if (nvals == 0) {
        count = ptaaGetCount(ptaa);
        pixSetPixel(pixs, x, y, count);
        ptas = ptaCreate(1);
        ptaAddPt(ptas, x, y);
        ptaaAddPta(ptaa, ptas, L_INSERT);
        *pncc += 1;
        LEPT_FREE(neigh);
        return 0;
    }

        /* Otherwise, there is at least one neighbor.  Add the pixel
         * to the first neighbor c.c. */
    firstindex = neigh[0];
    pixSetPixel(pixs, x, y, firstindex);
    ptaaAddPt(ptaa, neigh[0], x, y);
    if (nvals == 1) {
        if (debug == 1)
            fprintf(stderr, "nvals = %d: neigh = (%d)\n", nvals, neigh[0]);
        LEPT_FREE(neigh);
        return 0;
    }

        /* If nvals > 1, there are at least 2 neighbors, so this pixel
         * joins at least one pair of existing c.c.  Join each component
         * to the first component in the list, which is the one with
         * the smallest integer label.  This is done in two steps:
         *  (a) re-label the pixels in the component to the label of the
         *      first component, and
         *  (b) save the pixel locations in the pta for the first component. */
    if (nvals == 2) {
        if (debug >= 1 && debug <= 2) {
            fprintf(stderr, "nvals = %d: neigh = (%d,%d)\n", nvals,
                    neigh[0], neigh[1]);
        }
    } else if (nvals == 3) {
        if (debug >= 1 && debug <= 3) {
            fprintf(stderr, "nvals = %d: neigh = (%d,%d,%d)\n", nvals,
                    neigh[0], neigh[1], neigh[2]);
        }
    } else {  /* nvals == 4 */
        if (debug >= 1 && debug <= 4) {
            fprintf(stderr, "nvals = %d: neigh = (%d,%d,%d,%d)\n", nvals,
                    neigh[0], neigh[1], neigh[2], neigh[3]);
        }
    }
    ptad = ptaaGetPta(ptaa, firstindex, L_CLONE);
    for (i = 1; i < nvals; i++) {
        ptas = ptaaGetPta(ptaa, neigh[i], L_CLONE);
        ns = ptaGetCount(ptas);
        for (j = 0; j < ns; j++) {  /* relabel pixels */
            ptaGetPt(ptas, j, &x, &y);
            pixSetPixel(pixs, x, y, firstindex);
        }
        ptaJoin(ptad, ptas, 0, -1);  /* add relabeled pixel locations */
        *pncc -= 1;
        ptaDestroy(&ptaa->pta[neigh[i]]);
        ptaDestroy(&ptas);  /* the clone */
    }
    ptaDestroy(&ptad);  /* the clone */
    LEPT_FREE(neigh);
    return 0;
}
Exemple #12
0
l_int32 main(int    argc,
             char **argv)
{
l_int32       irval, igval, ibval;
l_float32     rval, gval, bval, fract, fgfract;
L_BMF        *bmf;
BOX          *box;
BOXA         *boxa;
FPIX         *fpix;
PIX          *pixs, *pix1, *pix2, *pix3, *pix4, *pix5, *pix6, *pix7;
PIX          *pix8, *pix9, *pix10, *pix11, *pix12, *pix13, *pix14, *pix15;
PIXA         *pixa;
L_REGPARAMS  *rp;

    if (regTestSetup(argc, argv, &rp))
              return 1;

    pixa = pixaCreate(0);
    pixs = pixRead("breviar38.150.jpg");
/*    pixs = pixRead("breviar32.150.jpg"); */
    pixaAddPix(pixa, pixs, L_CLONE);
    regTestWritePixAndCheck(rp, pixs, IFF_JFIF_JPEG);  /* 0 */
    pixDisplayWithTitle(pixs, 0, 0, "Input image", rp->display);

        /* Extract the blue component, which is small in all the text
         * regions, including in the highlight color region */
    pix1 = pixGetRGBComponent(pixs, COLOR_BLUE);
    pixaAddPix(pixa, pix1, L_CLONE);
    regTestWritePixAndCheck(rp, pix1, IFF_JFIF_JPEG);  /* 1 */
    pixDisplayWithTitle(pix1, 200, 0, "Blue component", rp->display);

        /* Do a background normalization, with the background set to
         * approximately 200 */
    pix2 = pixBackgroundNormSimple(pix1, NULL, NULL);
    pixaAddPix(pixa, pix2, L_COPY);
    regTestWritePixAndCheck(rp, pix2, IFF_JFIF_JPEG);  /* 2 */
    pixDisplayWithTitle(pix2, 400, 0, "BG normalized to 200", rp->display);

        /* Do a linear transform on the gray pixels, with 50 going to
         * black and 160 going to white.  50 is sufficiently low to
         * make both the red and black print quite dark.  Quantize
         * to a few equally spaced gray levels.  This is the image
         * to which highlight color will be applied. */
    pixGammaTRC(pix2, pix2, 1.0, 50, 160);
    pix3 = pixThresholdOn8bpp(pix2, 7, 1);
    pixaAddPix(pixa, pix3, L_CLONE);
    regTestWritePixAndCheck(rp, pix3, IFF_JFIF_JPEG);  /* 3 */
    pixDisplayWithTitle(pix3, 600, 0, "Basic quantized with white bg",
                        rp->display);

        /* Identify the regions of red text.  First, make a mask
         * consisting of all pixels such that (R-B)/B is larger
         * than 2.0.  This will have all the red, plus a lot of
         * the dark pixels. */
    fpix = pixComponentFunction(pixs, 1.0, 0.0, -1.0, 0.0, 0.0, 1.0);
    pix4 = fpixThresholdToPix(fpix, 2.0);
    pixInvert(pix4, pix4);  /* red plus some dark text */
    pixaAddPix(pixa, pix4, L_CLONE);
    regTestWritePixAndCheck(rp, pix4, IFF_PNG);  /* 4 */
    pixDisplayWithTitle(pix4, 800, 0, "Red plus dark pixels", rp->display);

        /* Make a mask consisting of all the red and background pixels */
    pix5 = pixGetRGBComponent(pixs, COLOR_RED);
    pix6 = pixThresholdToBinary(pix5, 128);
    pixInvert(pix6, pix6);  /* red plus background (white) */

        /* Intersect the two masks to get a mask consisting of pixels
         * that are almost certainly red.  This is the seed. */
    pix7 = pixAnd(NULL, pix4, pix6);  /* red only (seed) */
    pixaAddPix(pixa, pix7, L_COPY);
    regTestWritePixAndCheck(rp, pix7, IFF_PNG);  /* 5 */
    pixDisplayWithTitle(pix7, 0, 600, "Seed for red color", rp->display);

        /* Make the clipping mask by thresholding the image with
         * the background cleaned to white. */
    pix8 =  pixThresholdToBinary(pix2, 230);  /* mask */
    pixaAddPix(pixa, pix8, L_CLONE);
    regTestWritePixAndCheck(rp, pix8, IFF_PNG);  /* 6 */
    pixDisplayWithTitle(pix8, 200, 600, "Clipping mask for red components",
                        rp->display);

        /* Fill into the mask from the seed */
    pixSeedfillBinary(pix7, pix7, pix8, 8);  /* filled: red plus touching */
    regTestWritePixAndCheck(rp, pix7, IFF_PNG);  /* 7 */
    pixDisplayWithTitle(pix7, 400, 600, "Red component mask filled",
                        rp->display);

        /* Remove long horizontal and vertical lines from the filled result */
    pix9 = pixMorphSequence(pix7, "o40.1", 0);
    pixSubtract(pix7, pix7, pix9);  /* remove long horizontal lines */
    pixDestroy(&pix9);
    pix9 = pixMorphSequence(pix7, "o1.40", 0);
    pixSubtract(pix7, pix7, pix9);  /* remove long vertical lines */

        /* Close the regions to be colored  */
    pix10 = pixMorphSequence(pix7, "c5.1", 0);
    pixaAddPix(pixa, pix10, L_CLONE);
    regTestWritePixAndCheck(rp, pix10, IFF_PNG);  /* 8 */
    pixDisplayWithTitle(pix10, 600, 600,
                        "Components defining regions allowing coloring",
                        rp->display);

        /* Sanity check on amount to be colored.  Only accept images
         * with less than 10% of all the pixels with highlight color */
    pixForegroundFraction(pix10, &fgfract);
    if (fgfract >= 0.10) {
        L_INFO("too much highlighting: fract = %6.3f; removing it\n",
               rp->testname, fgfract);
        pixClearAll(pix10);
        pixSetPixel(pix10, 0, 0, 1);
    }

        /* Get the bounding boxes of the regions to be colored */
    boxa = pixConnCompBB(pix10, 8);

        /* Get a color to paint that is representative of the
         * actual highlight color in the image.  Scale each
         * color component up from the average by an amount necessary
         * to saturate the red.  Then divide the green and
         * blue components by 2.0.  */
    pixGetAverageMaskedRGB(pixs, pix7, 0, 0, 1, L_MEAN_ABSVAL,
                           &rval, &gval, &bval);
    fract = 255.0 / rval;
    irval = lept_roundftoi(fract * rval);
    igval = lept_roundftoi(fract * gval / 2.0);
    ibval = lept_roundftoi(fract * bval / 2.0);
    fprintf(stderr, "(r,g,b) = (%d,%d,%d)\n", irval, igval, ibval);

        /* Color the quantized gray version in the selected regions */
    pix11 = pixColorGrayRegions(pix3, boxa, L_PAINT_DARK, 220, irval,
                                igval, ibval);
    pixaAddPix(pixa, pix11, L_CLONE);
    regTestWritePixAndCheck(rp, pix11, IFF_PNG);  /* 9 */
    pixDisplayWithTitle(pix11, 800, 600, "Final colored result", rp->display);
    pixaAddPix(pixa, pixs, L_CLONE);

        /* Test colorization on gray and cmapped gray */
    pix12 = pixColorGrayRegions(pix2, boxa, L_PAINT_DARK, 220, 0, 255, 0);
    pixaAddPix(pixa, pix12, L_CLONE);
    regTestWritePixAndCheck(rp, pix12, IFF_PNG);  /* 10 */
    pixDisplayWithTitle(pix12, 900, 600, "Colorizing boxa gray", rp->display);

    box = boxCreate(200, 200, 250, 350);
    pix13 = pixCopy(NULL, pix2);
    pixColorGray(pix13, box, L_PAINT_DARK, 220, 0, 0, 255);
    pixaAddPix(pixa, pix13, L_CLONE);
    regTestWritePixAndCheck(rp, pix13, IFF_PNG);  /* 11 */
    pixDisplayWithTitle(pix13, 1000, 600, "Colorizing box gray", rp->display);

    pix14 = pixThresholdTo4bpp(pix2, 6, 1);
    pix15 = pixColorGrayRegions(pix14, boxa, L_PAINT_DARK, 220, 0, 0, 255);
    pixaAddPix(pixa, pix15, L_CLONE);
    regTestWritePixAndCheck(rp, pix15, IFF_PNG);  /* 12 */
    pixDisplayWithTitle(pix15, 1100, 600, "Colorizing boxa cmap", rp->display);

    pixColorGrayCmap(pix14, box, L_PAINT_DARK, 0, 255, 255);
    pixaAddPix(pixa, pix14, L_CLONE);
    regTestWritePixAndCheck(rp, pix14, IFF_PNG);  /* 13 */
    pixDisplayWithTitle(pix14, 1200, 600, "Colorizing box cmap", rp->display);
    boxDestroy(&box);

        /* Generate a pdf of the intermediate results */
    lept_mkdir("lept");
    L_INFO("Writing to /tmp/lept/colorize.pdf\n", rp->testname);
    pixaConvertToPdf(pixa, 90, 1.0, 0, 0, "Colorizing highlighted text",
                     "/tmp/lept/colorize.pdf");


    pixaDestroy(&pixa);
    fpixDestroy(&fpix);
    boxDestroy(&box);
    boxaDestroy(&boxa);
    pixDestroy(&pixs);
    pixDestroy(&pix1);
    pixDestroy(&pix2);
    pixDestroy(&pix3);
    pixDestroy(&pix4);
    pixDestroy(&pix5);
    pixDestroy(&pix6);
    pixDestroy(&pix7);
    pixDestroy(&pix8);
    pixDestroy(&pix9);
    pixDestroy(&pix10);
    pixDestroy(&pix11);
    pixDestroy(&pix12);
    pixDestroy(&pix13);
    pixDestroy(&pix14);
    pixDestroy(&pix15);

        /* Test the color detector */
    pixa = pixaCreate(7);
    bmf = bmfCreate("./fonts", 4);
    pix1 = TestForRedColor(rp, "brev06.75.jpg", 1, bmf);  /* 14 */
    pixaAddPix(pixa, pix1, L_INSERT);
    pix1 = TestForRedColor(rp, "brev10.75.jpg", 0, bmf);  /* 15 */
    pixaAddPix(pixa, pix1, L_INSERT);
    pix1 = TestForRedColor(rp, "brev14.75.jpg", 1, bmf);  /* 16 */
    pixaAddPix(pixa, pix1, L_INSERT);
    pix1 = TestForRedColor(rp, "brev20.75.jpg", 1, bmf);  /* 17 */
    pixaAddPix(pixa, pix1, L_INSERT);
    pix1 = TestForRedColor(rp, "brev36.75.jpg", 0, bmf);  /* 18 */
    pixaAddPix(pixa, pix1, L_INSERT);
    pix1 = TestForRedColor(rp, "brev53.75.jpg", 1, bmf);  /* 19 */
    pixaAddPix(pixa, pix1, L_INSERT);
    pix1 = TestForRedColor(rp, "brev56.75.jpg", 1, bmf);  /* 20 */
    pixaAddPix(pixa, pix1, L_INSERT);

        /* Generate a pdf of the color detector results */
    L_INFO("Writing to /tmp/lept/colordetect.pdf\n", rp->testname);
    pixaConvertToPdf(pixa, 45, 1.0, 0, 0, "Color detection",
                     "/tmp/lept/colordetect.pdf");
    pixaDestroy(&pixa);
    bmfDestroy(&bmf);

    return regTestCleanup(rp);
}
Exemple #13
0
main(int    argc,
     char **argv)
{
l_int32      i, j, w1, h1, w2, h2, w, h, same;
BOX         *box1, *box2;
PIX         *pixs, *pixs1, *pixs2, *pix1, *pix2;
PIX         *pixg, *pixg1, *pixg2, *pixc2, *pixbl, *pixd;
PIXA        *pixa;
static char  mainName[] = "blend2_reg";

        /* --- Set up the 8 bpp blending image --- */
    pixg = pixCreate(660, 500, 8);
    for (i = 0; i < 500; i++)
        for (j = 0; j < 660; j++)
            pixSetPixel(pixg, j, i, (l_int32)(0.775 * j) % 256);

        /* --- Set up the initial color images to be blended together --- */
    pixs1 = pixRead("wyom.jpg");
    pixs2 = pixRead("fish24.jpg");
    pixGetDimensions(pixs1, &w1, &h1, NULL);
    pixGetDimensions(pixs2, &w2, &h2, NULL);
    h = L_MIN(h1, h2);
    w = L_MIN(w1, w2);
    box1 = boxCreate(0, 0, w1, h1);
    box2 = boxCreate(0, 300, 660, 500);
    pix1 = pixClipRectangle(pixs1, box1, NULL);
    pix2 = pixClipRectangle(pixs2, box2, NULL);
    pixDestroy(&pixs1);
    pixDestroy(&pixs2);
    boxDestroy(&box1);
    boxDestroy(&box2);

        /* --- Blend 2 rgb images --- */
    pixa = pixaCreate(0);
    pixSaveTiled(pixg, pixa, 1, 1, 40, 32);
    pixd = pixBlendWithGrayMask(pix1, pix2, pixg, 50, 50);
    pixSaveTiled(pix1, pixa, 1, 1, 40, 32);
    pixSaveTiled(pix2, pixa, 1, 0, 40, 32);
    pixSaveTiled(pixd, pixa, 1, 0, 40, 32);
    pixDestroy(&pixd);

        /* --- Blend 2 grayscale images --- */
    pixg1 = pixConvertRGBToLuminance(pix1);
    pixg2 = pixConvertRGBToLuminance(pix2);
    pixd = pixBlendWithGrayMask(pixg1, pixg2, pixg, 50, 50);
    pixSaveTiled(pixg1, pixa, 1, 1, 40, 32);
    pixSaveTiled(pixg2, pixa, 1, 0, 40, 32);
    pixSaveTiled(pixd, pixa, 1, 0, 40, 32);
    pixDestroy(&pixg1);
    pixDestroy(&pixg2);
    pixDestroy(&pixd);

        /* --- Blend a colormap image and an rgb image --- */
    pixc2 = pixFixedOctcubeQuantGenRGB(pix2, 2);
    pixd = pixBlendWithGrayMask(pix1, pixc2, pixg, 50, 50);
    pixSaveTiled(pix1, pixa, 1, 1, 40, 32);
    pixSaveTiled(pixc2, pixa, 1, 0, 40, 32);
    pixSaveTiled(pixd, pixa, 1, 0, 40, 32);
    pixDestroy(&pixc2);
    pixDestroy(&pixd);

        /* --- Blend a colormap image and a grayscale image --- */
    pixg1 = pixConvertRGBToLuminance(pix1);
    pixc2 = pixFixedOctcubeQuantGenRGB(pix2, 2);
    pixd = pixBlendWithGrayMask(pixg1, pixc2, pixg, 50, 50);
    pixSaveTiled(pixg1, pixa, 1, 1, 40, 32);
    pixSaveTiled(pixc2, pixa, 1, 0, 40, 32);
    pixSaveTiled(pixd, pixa, 1, 0, 40, 32);
    pixDestroy(&pixd);
    pixd = pixBlendWithGrayMask(pixg1, pixc2, pixg, -100, -100);
    pixSaveTiled(pixg1, pixa, 1, 1, 40, 32);
    pixSaveTiled(pixc2, pixa, 1, 0, 40, 32);
    pixSaveTiled(pixd, pixa, 1, 0, 40, 32);
    pixDestroy(&pixd);
    pixDestroy(&pixg1);
    pixDestroy(&pixc2);

        /* --- Test png read/write with alpha channel --- */
        /* First make pixs1, using pixg as the alpha channel */
    pixs = pixRead("fish24.jpg");
    box1 = boxCreate(0, 300, 660, 500);
    pixs1 = pixClipRectangle(pixs, box1, NULL);
    pixSaveTiled(pixs1, pixa, 1, 1, 40, 32);
    pixSetRGBComponent(pixs1, pixg, L_ALPHA_CHANNEL);
        /* To see the alpha channel, blend with a black image */
    pixbl = pixCreate(660, 500, 32);
    pixd = pixBlendWithGrayMask(pixbl, pixs1, NULL, 0, 0);
    pixSaveTiled(pixd, pixa, 1, 0, 40, 32);
    pixDestroy(&pixd);
        /* Write out the RGBA image and read it back */
    l_pngSetWriteAlpha(1);
    pixWrite("/tmp/junkpixs1.png", pixs1, IFF_PNG);
    l_pngSetStripAlpha(0);
    pixs2 = pixRead("/tmp/junkpixs1.png");
        /* Make sure that the alpha channel image hasn't changed */
    pixg2 = pixGetRGBComponent(pixs2, L_ALPHA_CHANNEL);
    pixEqual(pixg, pixg2, &same);
    if (same)
        fprintf(stderr, "PNG with alpha read/write OK\n");
    else
        fprintf(stderr, "PNG with alpha read/write failed\n");
        /* Blend again with a black image */
    pixd = pixBlendWithGrayMask(pixbl, pixs2, NULL, 0, 0);
    pixSaveTiled(pixd, pixa, 1, 0, 40, 32);
    pixDestroy(&pixd);
        /* Blend with a white image */
    pixSetAll(pixbl);
    pixd = pixBlendWithGrayMask(pixbl, pixs2, NULL, 0, 0);
    pixSaveTiled(pixd, pixa, 1, 0, 40, 32);
    pixDestroy(&pixd);
    l_pngSetWriteAlpha(0);  /* reset to default */
    l_pngSetStripAlpha(1);  /* reset to default */
    pixDestroy(&pixbl);
    pixDestroy(&pixs);
    pixDestroy(&pixs1);
    pixDestroy(&pixs2);
    pixDestroy(&pixg2);
    boxDestroy(&box1);

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

    pixDestroy(&pixg);
    pixDestroy(&pix1);
    pixDestroy(&pix2);
    return 0;
}
Exemple #14
0
/*!
 *  pixOtsuAdaptiveThreshold()
 *
 *      Input:  pixs (8 bpp)
 *              sx, sy (desired tile dimensions; actual size may vary)
 *              smoothx, smoothy (half-width of convolution kernel applied to
 *                                threshold array: use 0 for no smoothing)
 *              scorefract (fraction of the max Otsu score; typ. 0.1;
 *                          use 0.0 for standard Otsu)
 *              &pixth (<optional return> array of threshold values
 *                      found for each tile)
 *              &pixd (<optional return> thresholded input pixs, based on
 *                     the threshold array)
 *      Return: 0 if OK, 1 on error
 *
 *  Notes:
 *      (1) The Otsu method finds a single global threshold for an image.
 *          This function allows a locally adapted threshold to be
 *          found for each tile into which the image is broken up.
 *      (2) The array of threshold values, one for each tile, constitutes
 *          a highly downscaled image.  This array is optionally
 *          smoothed using a convolution.  The full width and height of the
 *          convolution kernel are (2 * @smoothx + 1) and (2 * @smoothy + 1).
 *      (3) The minimum tile dimension allowed is 16.  If such small
 *          tiles are used, it is recommended to use smoothing, because
 *          without smoothing, each small tile determines the splitting
 *          threshold independently.  A tile that is entirely in the
 *          image bg will then hallucinate fg, resulting in a very noisy
 *          binarization.  The smoothing should be large enough that no
 *          tile is only influenced by one type (fg or bg) of pixels,
 *          because it will force a split of its pixels.
 *      (4) To get a single global threshold for the entire image, use
 *          input values of @sx and @sy that are larger than the image.
 *          For this situation, the smoothing parameters are ignored.
 *      (5) The threshold values partition the image pixels into two classes:
 *          one whose values are less than the threshold and another
 *          whose values are greater than or equal to the threshold.
 *          This is the same use of 'threshold' as in pixThresholdToBinary().
 *      (6) The scorefract is the fraction of the maximum Otsu score, which
 *          is used to determine the range over which the histogram minimum
 *          is searched.  See numaSplitDistribution() for details on the
 *          underlying method of choosing a threshold.
 *      (7) This uses enables a modified version of the Otsu criterion for
 *          splitting the distribution of pixels in each tile into a
 *          fg and bg part.  The modification consists of searching for
 *          a minimum in the histogram over a range of pixel values where
 *          the Otsu score is within a defined fraction, @scorefract,
 *          of the max score.  To get the original Otsu algorithm, set
 *          @scorefract == 0.
 */
l_int32
pixOtsuAdaptiveThreshold(PIX       *pixs,
                         l_int32    sx,
                         l_int32    sy,
                         l_int32    smoothx,
                         l_int32    smoothy,
                         l_float32  scorefract,
                         PIX      **ppixth,
                         PIX      **ppixd)
{
l_int32     w, h, nx, ny, i, j, thresh;
l_uint32    val;
PIX        *pixt, *pixb, *pixthresh, *pixth, *pixd;
PIXTILING  *pt;

    PROCNAME("pixOtsuAdaptiveThreshold");

    if (!ppixth && !ppixd){
        return ERROR_INT("neither &pixth nor &pixd defined", procName, 1);
	    LOGE("neither &pixth nor &pixd defined");
	}
    if (ppixth) *ppixth = NULL;
    if (ppixd) *ppixd = NULL;
    if (!pixs || pixGetDepth(pixs) != 8){
        return ERROR_INT("pixs not defined or not 8 bpp", procName, 1);
		LOGE("pixs not defined or not 8 bpp");
	}
    if (sx < 16 || sy < 16){
        return ERROR_INT("sx and sy must be >= 16", procName, 1);
		LOGE("sx and sy must be >= 16");
	}
        /* Compute the threshold array for the tiles */
    pixGetDimensions(pixs, &w, &h, NULL);
    nx = L_MAX(1, w / sx);
    ny = L_MAX(1, h / sy);

    smoothx = L_MIN(smoothx, (nx - 1) / 2);
    smoothy = L_MIN(smoothy, (ny - 1) / 2);

    pt = pixTilingCreate(pixs, nx, ny, 0, 0, 0, 0);
    pixthresh = pixCreate(nx, ny, 8);
    for (i = 0; i < ny; i++) {
        for (j = 0; j < nx; j++) {
            pixt = pixTilingGetTile(pt, i, j);
            pixSplitDistributionFgBg(pixt, scorefract, 1, &thresh,
                                     NULL, NULL, 0);
            pixSetPixel(pixthresh, j, i, thresh);  /* see note (4) */
            pixDestroy(&pixt);
        }
    }

        /* Optionally smooth the threshold array */
    if (smoothx > 0 || smoothy > 0)
        pixth = pixBlockconv(pixthresh, smoothx, smoothy);
    else
        pixth = pixClone(pixthresh);
    pixDestroy(&pixthresh);

        /* Optionally apply the threshold array to binarize pixs */
    if (ppixd) {
        pixd = pixCreate(w, h, 1);
        for (i = 0; i < ny; i++) {
            for (j = 0; j < nx; j++) {
                pixt = pixTilingGetTile(pt, i, j);
                pixGetPixel(pixth, j, i, &val);
                pixb = pixThresholdToBinary(pixt, val);
                pixTilingPaintTile(pixd, i, j, pixb, pt);
                pixDestroy(&pixt);
                pixDestroy(&pixb);
            }
        }
        *ppixd = pixd;
    }

    if (ppixth)
        *ppixth = pixth;
    else
        pixDestroy(&pixth);

    pixTilingDestroy(&pt);

    return 0;
}
Exemple #15
0
main(int    argc,
     char **argv)
{
char         *str;
l_int32       i, j, same, ok;
l_float32     sum, avediff, rmsdiff;
L_KERNEL     *kel1, *kel2, *kel3, *kel4, *kelx, *kely;
BOX          *box;
PIX          *pix, *pixs, *pixb, *pixg, *pixr, *pixd, *pixp, *pixt;
PIX          *pixt1, *pixt2, *pixt3;
PIXA         *pixa;
SARRAY       *sa;
L_REGPARAMS  *rp;

    if (regTestSetup(argc, argv, &rp))
        return 1;

    pixa = pixaCreate(0);

        /* Test creating from a string */
    kel1 = kernelCreateFromString(5, 5, 2, 2, kdatastr);
    pixd = kernelDisplayInPix(kel1, 41, 2);
    pixWrite("/tmp/pixkern.png", pixd, IFF_PNG);
    regTestCheckFile(rp, "/tmp/pixkern.png");  /* 0 */
    pixSaveTiled(pixd, pixa, 1, 1, 20, 8);
    pixDestroy(&pixd);
    kernelDestroy(&kel1);

        /* Test read/write for kernel.  Note that both get
         * compared to the same golden file, which is
         * overwritten with a copy of /tmp/kern2.kel */
    kel1 = kernelCreateFromString(5, 5, 2, 2, kdatastr);
    kernelWrite("/tmp/kern1.kel", kel1);
    regTestCheckFile(rp, "/tmp/kern1.kel");  /* 1 */
    kel2 = kernelRead("/tmp/kern1.kel");
    kernelWrite("/tmp/kern2.kel", kel2);
    regTestCheckFile(rp, "/tmp/kern2.kel");  /* 2 */
    regTestCompareFiles(rp, 1, 2);  /* 3 */
    kernelDestroy(&kel1);
    kernelDestroy(&kel2);

        /* Test creating from a file */
    sa = sarrayCreate(0);
    sarrayAddString(sa, (char *)"# small 3x3 kernel", L_COPY);
    sarrayAddString(sa, (char *)"3 5", L_COPY);
    sarrayAddString(sa, (char *)"1 2", L_COPY);
    sarrayAddString(sa, (char *)"20.5   50   80    50   20", L_COPY);
    sarrayAddString(sa, (char *)"82.    120  180   120  80", L_COPY);
    sarrayAddString(sa, (char *)"22.1   50   80    50   20", L_COPY);
    str = sarrayToString(sa, 1);
    l_binaryWrite("/tmp/kernfile.kel", "w", str, strlen(str));
    kel2 = kernelCreateFromFile("/tmp/kernfile.kel");
    pixd = kernelDisplayInPix(kel2, 41, 2);
    pixSaveTiled(pixd, pixa, 1, 1, 20, 0);
    pixWrite("/tmp/ker1.png", pixd, IFF_PNG);
    regTestCheckFile(rp, "/tmp/ker1.png");  /* 4 */
    pixDestroy(&pixd);
    sarrayDestroy(&sa);
    lept_free(str);
    kernelDestroy(&kel2);

        /* Test creating from a pix */
    pixt = pixCreate(5, 3, 8);
    pixSetPixel(pixt, 0, 0, 20);
    pixSetPixel(pixt, 1, 0, 50);
    pixSetPixel(pixt, 2, 0, 80);
    pixSetPixel(pixt, 3, 0, 50);
    pixSetPixel(pixt, 4, 0, 20);
    pixSetPixel(pixt, 0, 1, 80);
    pixSetPixel(pixt, 1, 1, 120);
    pixSetPixel(pixt, 2, 1, 180);
    pixSetPixel(pixt, 3, 1, 120);
    pixSetPixel(pixt, 4, 1, 80);
    pixSetPixel(pixt, 0, 0, 20);
    pixSetPixel(pixt, 1, 2, 50);
    pixSetPixel(pixt, 2, 2, 80);
    pixSetPixel(pixt, 3, 2, 50);
    pixSetPixel(pixt, 4, 2, 20);
    kel3 = kernelCreateFromPix(pixt, 1, 2);
    pixd = kernelDisplayInPix(kel3, 41, 2);
    pixSaveTiled(pixd, pixa, 1, 0, 20, 0);
    pixWrite("/tmp/ker2.png", pixd, IFF_PNG);
    regTestCheckFile(rp, "/tmp/ker2.png");  /* 5 */
    pixDestroy(&pixd);
    pixDestroy(&pixt);
    kernelDestroy(&kel3);

        /* Test convolution with kel1 */
    pixs = pixRead("test24.jpg");
    pixg = pixScaleRGBToGrayFast(pixs, 3, COLOR_GREEN);
    pixSaveTiled(pixg, pixa, 1, 1, 20, 0);
    kel1 = kernelCreateFromString(5, 5, 2, 2, kdatastr);
    pixd = pixConvolve(pixg, kel1, 8, 1);
    pixSaveTiled(pixd, pixa, 1, 0, 20, 0);
    pixWrite("/tmp/ker3.png", pixd, IFF_PNG);
    regTestCheckFile(rp, "/tmp/ker3.png");  /* 6 */
    pixDestroy(&pixs);
    pixDestroy(&pixg);
    pixDestroy(&pixd);
    kernelDestroy(&kel1);

        /* Test convolution with flat rectangular kel; also test
         * block convolution with tiling. */
    pixs = pixRead("test24.jpg");
    pixg = pixScaleRGBToGrayFast(pixs, 3, COLOR_GREEN);
    kel2 = makeFlatKernel(11, 11, 5, 5);
    pixd = pixConvolve(pixg, kel2, 8, 1);
    pixSaveTiled(pixd, pixa, 1, 1, 20, 0);
    pixWrite("/tmp/ker4.png", pixd, IFF_PNG);
    regTestCheckFile(rp, "/tmp/ker4.png");  /* 7 */
    pixt = pixBlockconv(pixg, 5, 5);
    pixSaveTiled(pixt, pixa, 1, 0, 20, 0);
    pixWrite("/tmp/ker5.png", pixt, IFF_PNG);
    regTestCheckFile(rp, "/tmp/ker5.png");  /* 8 */
    if (rp->display)
        pixCompareGray(pixd, pixt, L_COMPARE_ABS_DIFF, GPLOT_X11, NULL,
                       NULL, NULL, NULL);
    pixt2 = pixBlockconvTiled(pixg, 5, 5, 3, 6);
    pixSaveTiled(pixt2, pixa, 1, 0, 20, 0);
    pixWrite("/tmp/ker5a.png", pixt2, IFF_PNG);
    regTestCheckFile(rp, "/tmp/ker5a.png");  /* 9 */
    pixDestroy(&pixt2);

    ok = TRUE;
    for (i = 1; i <= 7; i++) {
        for (j = 1; j <= 7; j++) {
            if (i == 1 && j == 1) continue;
            pixt2 = pixBlockconvTiled(pixg, 5, 5, j, i);
            pixEqual(pixt2, pixd, &same);
            if (!same) {
                fprintf(stderr," Error for nx = %d, ny = %d\n", j, i);
                ok = FALSE;
            }
            pixDestroy(&pixt2);
        }
    }
    if (ok)
        fprintf(stderr, "OK: Tiled results identical to pixConvolve()\n");
    else
        fprintf(stderr, "ERROR: Tiled results not identical to pixConvolve()\n");
          
    pixDestroy(&pixs);
    pixDestroy(&pixg);
    pixDestroy(&pixd);
    pixDestroy(&pixt);
    kernelDestroy(&kel2);

        /* Do another flat rectangular test; this time with white at edge.
         * About 1% of the pixels near the image edge differ by 1 between
         * the pixConvolve() and pixBlockconv().  For what it's worth,
         * pixConvolve() gives the more accurate result; namely, 255 for
         * pixels at the edge. */
    pix = pixRead("pageseg1.tif");
    box = boxCreate(100, 100, 2260, 3160);
    pixb = pixClipRectangle(pix, box, NULL);
    pixs = pixScaleToGray4(pixb);

    kel3 = makeFlatKernel(7, 7, 3, 3);
    startTimer();
    pixt = pixConvolve(pixs, kel3, 8, 1);
    fprintf(stderr, "Generic convolution time: %5.3f sec\n", stopTimer());
    pixSaveTiled(pixt, pixa, 1, 1, 20, 0);
    pixWrite("/tmp/conv1.png", pixt, IFF_PNG);
    regTestCheckFile(rp, "/tmp/conv1.png");  /* 10 */

    startTimer();
    pixt2 = pixBlockconv(pixs, 3, 3);
    fprintf(stderr, "Flat block convolution time: %5.3f sec\n", stopTimer());
    pixSaveTiled(pixt2, pixa, 1, 0, 20, 0);
    pixWrite("/tmp/conv2.png", pixt2, IFF_PNG);  /* ditto */
    regTestCheckFile(rp, "/tmp/conv2.png");  /* 11 */

    pixCompareGray(pixt, pixt2, L_COMPARE_ABS_DIFF, GPLOT_PNG, NULL,
                   &avediff, &rmsdiff, NULL);
#ifndef  _WIN32
    sleep(1);  /* give gnuplot time to write out the file */
#else
    Sleep(1000);
#endif  /* _WIN32 */
    pixp = pixRead("/tmp/grayroot.png");
    pixSaveTiled(pixp, pixa, 1, 0, 20, 0);
    pixWrite("/tmp/conv3.png", pixp, IFF_PNG);
    regTestCheckFile(rp, "/tmp/conv3.png");  /* 12 */
    fprintf(stderr, "Ave diff = %6.4f, RMS diff = %6.4f\n", avediff, rmsdiff);
    if (avediff <= 0.01)
        fprintf(stderr, "OK: avediff = %6.4f <= 0.01\n", avediff);
    else
        fprintf(stderr, "Bad?: avediff = %6.4f > 0.01\n", avediff);

    pixDestroy(&pixt);
    pixDestroy(&pixt2);
    pixDestroy(&pixs);
    pixDestroy(&pixp);
    pixDestroy(&pix);
    pixDestroy(&pixb);
    boxDestroy(&box);
    kernelDestroy(&kel3);

        /* Do yet another set of flat rectangular tests, this time
         * on an RGB image */
    pixs = pixRead("test24.jpg");
    kel4 = makeFlatKernel(7, 7, 3, 3);
    startTimer();
    pixt1 = pixConvolveRGB(pixs, kel4);
    fprintf(stderr, "Time 7x7 non-separable: %7.3f sec\n", stopTimer());
    pixWrite("/tmp/conv4.jpg", pixt1, IFF_JFIF_JPEG);
    regTestCheckFile(rp, "/tmp/conv4.jpg");  /* 13 */

    kelx = makeFlatKernel(1, 7, 0, 3);
    kely = makeFlatKernel(7, 1, 3, 0);
    startTimer();
    pixt2 = pixConvolveRGBSep(pixs, kelx, kely);
    fprintf(stderr, "Time 7x1,1x7 separable: %7.3f sec\n", stopTimer());
    pixWrite("/tmp/conv5.jpg", pixt2, IFF_JFIF_JPEG);
    regTestCheckFile(rp, "/tmp/conv5.jpg");  /* 14 */

    startTimer();
    pixt3 = pixBlockconv(pixs, 3, 3);
    fprintf(stderr, "Time 7x7 blockconv: %7.3f sec\n", stopTimer());
    pixWrite("/tmp/conv6.jpg", pixt3, IFF_JFIF_JPEG);
    regTestCheckFile(rp, "/tmp/conv6.jpg");  /* 15 */
    regTestComparePix(rp, pixt1, pixt2);  /* 16 */
    regTestCompareSimilarPix(rp, pixt2, pixt3, 15, 0.0005, 0);  /* 17 */

    pixDestroy(&pixs);
    pixDestroy(&pixt1);
    pixDestroy(&pixt2);
    pixDestroy(&pixt3);
    kernelDestroy(&kel4);
    kernelDestroy(&kelx);
    kernelDestroy(&kely);

        /* Test generation and convolution with gaussian kernel */
    pixs = pixRead("test8.jpg");
    pixSaveTiled(pixs, pixa, 1, 1, 20, 0);
    kel1 = makeGaussianKernel(5, 5, 3.0, 5.0);
    kernelGetSum(kel1, &sum);
    fprintf(stderr, "Sum for gaussian kernel = %f\n", sum);
    kernelWrite("/tmp/gauss.kel", kel1);
    pixt = pixConvolve(pixs, kel1, 8, 1);
    pixt2 = pixConvolve(pixs, kel1, 16, 0);
    pixSaveTiled(pixt, pixa, 1, 0, 20, 0);
    pixSaveTiled(pixt2, pixa, 1, 0, 20, 0);
    pixWrite("/tmp/ker6.png", pixt, IFF_PNG);
    regTestCheckFile(rp, "/tmp/ker6.png");  /* 18 */
    pixDestroy(&pixt);
    pixDestroy(&pixt2);

    pixt = kernelDisplayInPix(kel1, 25, 2);
    pixSaveTiled(pixt, pixa, 1, 0, 20, 0);
    pixDestroy(&pixt);
    kernelDestroy(&kel1);
    pixDestroy(&pixs);

        /* Test generation and convolution with separable gaussian kernel */
    pixs = pixRead("test8.jpg");
    pixSaveTiled(pixs, pixa, 1, 1, 20, 0);
    makeGaussianKernelSep(5, 5, 3.0, 5.0, &kelx, &kely);
    kernelGetSum(kelx, &sum);
    fprintf(stderr, "Sum for x gaussian kernel = %f\n", sum);
    kernelGetSum(kely, &sum);
    fprintf(stderr, "Sum for y gaussian kernel = %f\n", sum);
    kernelWrite("/tmp/gauss.kelx", kelx);
    kernelWrite("/tmp/gauss.kely", kely);

    pixt = pixConvolveSep(pixs, kelx, kely, 8, 1);
    pixt2 = pixConvolveSep(pixs, kelx, kely, 16, 0);
    pixSaveTiled(pixt, pixa, 1, 0, 20, 0);
    pixSaveTiled(pixt2, pixa, 1, 0, 20, 0);
    pixWrite("/tmp/ker7.png", pixt, IFF_PNG);
    regTestCheckFile(rp, "/tmp/ker7.png");  /* 19 */
    pixDestroy(&pixt);
    pixDestroy(&pixt2);

    pixt = kernelDisplayInPix(kelx, 25, 2);
    pixSaveTiled(pixt, pixa, 1, 0, 20, 0);
    pixDestroy(&pixt);
    pixt = kernelDisplayInPix(kely, 25, 2);
    pixSaveTiled(pixt, pixa, 1, 0, 20, 0);
    pixDestroy(&pixt);
    kernelDestroy(&kelx);
    kernelDestroy(&kely);
    pixDestroy(&pixs);

        /* Test generation and convolution with diff of gaussians kernel */
/*    pixt = pixRead("marge.jpg");
    pixs = pixConvertRGBToLuminance(pixt);
    pixDestroy(&pixt); */
    pixs = pixRead("test8.jpg");
    pixSaveTiled(pixs, pixa, 1, 1, 20, 0);
    kel1 = makeDoGKernel(7, 7, 1.5, 2.7);
    kernelGetSum(kel1, &sum);
    fprintf(stderr, "Sum for DoG kernel = %f\n", sum);
    kernelWrite("/tmp/dog.kel", kel1);
    pixt = pixConvolve(pixs, kel1, 8, 0);
/*    pixInvert(pixt, pixt); */
    pixSaveTiled(pixt, pixa, 1, 0, 20, 0);
    pixWrite("/tmp/ker8.png", pixt, IFF_PNG);
    regTestCheckFile(rp, "/tmp/ker8.png");  /* 20 */
    pixDestroy(&pixt);

    pixt = kernelDisplayInPix(kel1, 20, 2);
    pixSaveTiled(pixt, pixa, 1, 0, 20, 0);
    pixDestroy(&pixt);
    kernelDestroy(&kel1);
    pixDestroy(&pixs);

    pixd = pixaDisplay(pixa, 0, 0);
    pixDisplayWithTitle(pixd, 100, 100, NULL, rp->display);
    pixWrite("/tmp/kernel.jpg", pixd, IFF_JFIF_JPEG);
    pixDestroy(&pixd);
    pixaDestroy(&pixa);

    regTestCleanup(rp);
    return 0;
}
Exemple #16
0
/*!
 *  identifyWatershedBasin()
 *
 *      Input:  wshed
 *              index (index of basin to be located)
 *              level (of basin at point at which the two basins met)
 *              &box (<return> bounding box of basin)
 *              &pixd (<return> pix of basin, cropped to its bounding box)
 *      Return: 0 if OK, 1 on error
 *
 *  Notes:
 *      (1) This is a static function, so we assume pixlab, pixs and pixt
 *          exist and are the same size.
 *      (2) It selects all pixels that have the label @index in pixlab
 *          and that have a value in pixs that is less than @level.
 *      (3) It is used whenever two seeded basins meet (typically at a saddle),
 *          or when one seeded basin meets a 'filler'.  All identified
 *          basins are saved as a watershed.
 */
static l_int32
identifyWatershedBasin(L_WSHED *wshed,
                       l_int32 index,
                       l_int32 level,
                       BOX **pbox,
                       PIX **ppixd) {
    l_int32 imin, imax, jmin, jmax, minx, miny, maxx, maxy;
    l_int32 bw, bh, i, j, w, h, x, y;
    l_int32 *lut;
    l_uint32 label, bval, lval;
    void **lines8, **linelab32, **linet1;
    BOX *box;
    PIX *pixs, *pixt, *pixd;
    L_QUEUE *lq;

    PROCNAME("identifyWatershedBasin");

    if (!pbox)
        return ERROR_INT("&box not defined", procName, 1);
    *pbox = NULL;
    if (!ppixd)
        return ERROR_INT("&pixd not defined", procName, 1);
    *ppixd = NULL;
    if (!wshed)
        return ERROR_INT("wshed not defined", procName, 1);

    /* Make a queue and an auxiliary stack */
    lq = lqueueCreate(0);
    lq->stack = lstackCreate(0);

    pixs = wshed->pixs;
    pixt = wshed->pixt;
    lines8 = wshed->lines8;
    linelab32 = wshed->linelab32;
    linet1 = wshed->linet1;
    lut = wshed->lut;
    pixGetDimensions(pixs, &w, &h, NULL);

    /* Prime the queue with the seed pixel for this watershed. */
    minx = miny = 1000000;
    maxx = maxy = 0;
    ptaGetIPt(wshed->ptas, index, &x, &y);
    pixSetPixel(pixt, x, y, 1);
    pushNewPixel(lq, x, y, &minx, &maxx, &miny, &maxy);
    if (wshed->debug) fprintf(stderr, "prime: (x,y) = (%d, %d)\n", x, y);

    /* Each pixel in a spreading breadth-first search is inspected.
     * It is accepted as part of this watershed, and pushed on
     * the search queue, if:
     *     (1) It has a label value equal to @index
     *     (2) The pixel value is less than @level, the overflow
     *         height at which the two basins join.
     *     (3) It has not yet been seen in this search.  */
    while (lqueueGetCount(lq) > 0) {
        popNewPixel(lq, &x, &y);
        imin = L_MAX(0, y - 1);
        imax = L_MIN(h - 1, y + 1);
        jmin = L_MAX(0, x - 1);
        jmax = L_MIN(w - 1, x + 1);
        for (i = imin; i <= imax; i++) {
            for (j = jmin; j <= jmax; j++) {
                if (j == x && i == y) continue;  /* parent */
                label = GET_DATA_FOUR_BYTES(linelab32[i], j);
                if (label == MAX_LABEL_VALUE || lut[label] != index) continue;
                bval = GET_DATA_BIT(linet1[i], j);
                if (bval == 1) continue;  /* already seen */
                lval = GET_DATA_BYTE(lines8[i], j);
                if (lval >= level) continue;  /* too high */
                SET_DATA_BIT(linet1[i], j);
                pushNewPixel(lq, j, i, &minx, &maxx, &miny, &maxy);
            }
        }
    }

    /* Extract the box and pix, and clear pixt */
    bw = maxx - minx + 1;
    bh = maxy - miny + 1;
    box = boxCreate(minx, miny, bw, bh);
    pixd = pixClipRectangle(pixt, box, NULL);
    pixRasterop(pixt, minx, miny, bw, bh, PIX_SRC ^ PIX_DST, pixd, 0, 0);
    *pbox = box;
    *ppixd = pixd;

    lqueueDestroy(&lq, 1);
    return 0;
}
Exemple #17
0
int main(int argc,
         char **argv) {
    char *filein, *fileout;
    l_int32 i;
    l_uint32 val;
    l_float32 size;
    PIX *pixs, *pixd, *pixm, *pixmi, *pixt1, *pixt2, *pixt3;
    static char mainName[] = "seedfilltest";

    if (argc != 3)
        return ERROR_INT(" Syntax:  seedfilltest filein fileout", mainName, 1);

    filein = argv[1];
    fileout = argv[2];
    pixd = NULL;

    if ((pixm = pixRead(filein)) == NULL)
        return ERROR_INT("pixm not made", mainName, 1);
    pixmi = pixInvert(NULL, pixm);

    size = pixGetWidth(pixm) * pixGetHeight(pixm);
    pixs = pixCreateTemplate(pixm);
    for (i = 0; i < 100; i++) {
        pixGetPixel(pixm, XS + 5 * i, YS + 5 * i, &val);
        if (val == 0) break;
    }
    if (i == 100)
        return ERROR_INT("no seed pixel found", mainName, 1);
    pixSetPixel(pixs, XS + 5 * i, YS + 5 * i, 1);

#if 0
    /* hole filling; use "hole-filler.png" */
pixt1 = pixHDome(pixmi, 100, 4);
pixt2 = pixThresholdToBinary(pixt1, 10);
/*    pixInvert(pixt1, pixt1); */
pixDisplay(pixt1, 100, 500);
pixDisplay(pixt2, 600, 500);
pixt3 = pixHolesByFilling(pixt2, 4);
pixDilateBrick(pixt3, pixt3, 7, 7);
pixd = pixConvertTo8(pixt3, FALSE);
pixDisplay(pixd, 0, 100);
pixSeedfillGray(pixd, pixmi, CONNECTIVITY);
pixInvert(pixd, pixd);
pixDisplay(pixmi, 500, 100);
pixDisplay(pixd, 1000, 100);
pixWrite("/tmp/junkpixm.png", pixmi, IFF_PNG);
pixWrite("/tmp/junkpixd.png", pixd, IFF_PNG);
#endif

#if 0
    /* hole filling; use "hole-filler.png" */
pixt1 = pixThresholdToBinary(pixm, 110);
pixInvert(pixt1, pixt1);
pixDisplay(pixt1, 100, 500);
pixt2 = pixHolesByFilling(pixt1, 4);
pixd = pixConvertTo8(pixt2, FALSE);
pixDisplay(pixd, 0, 100);
pixSeedfillGray(pixd, pixmi, CONNECTIVITY);
pixInvert(pixd, pixd);
pixDisplay(pixmi, 500, 100);
pixDisplay(pixd, 1000, 100);
pixWrite("/tmp/junkpixm.png", pixmi, IFF_PNG);
pixWrite("/tmp/junkpixd.png", pixd, IFF_PNG);
#endif

#if 0
    /* hole filling; use "hole-filler.png" */
pixd = pixInvert(NULL, pixm);
pixAddConstantGray(pixd, -50);
pixDisplay(pixd, 0, 100);
/*    pixt1 = pixThresholdToBinary(pixd, 20);
pixDisplayWithTitle(pixt1, 600, 600, "pixt1", DFLAG); */
pixSeedfillGray(pixd, pixmi, CONNECTIVITY);
/*    pixInvert(pixd, pixd); */
pixDisplay(pixmi, 500, 100);
pixDisplay(pixd, 1000, 100);
pixWrite("/tmp/junkpixm.png", pixmi, IFF_PNG);
pixWrite("/tmp/junkpixd.png", pixd, IFF_PNG);
#endif

#if 0
    /* test in-place seedfill for speed */
pixd = pixClone(pixs);
startTimer();
pixSeedfillBinary(pixs, pixs, pixmi, CONNECTIVITY);
fprintf(stderr, "Filling rate: %7.4f Mpix/sec\n",
    (size/1000000.) / stopTimer());

pixWrite(fileout, pixd, IFF_PNG);
pixOr(pixd, pixd, pixm);
pixWrite("/tmp/junkout1.png", pixd, IFF_PNG);
#endif

#if 0
    /* test seedfill to dest for speed */
pixd = pixCreateTemplate(pixm);
startTimer();
for (i = 0; i < NTIMES; i++) {
    pixSeedfillBinary(pixd, pixs, pixmi, CONNECTIVITY);
}
fprintf(stderr, "Filling rate: %7.4f Mpix/sec\n",
    (size/1000000.) * NTIMES / stopTimer());

pixWrite(fileout, pixd, IFF_PNG);
pixOr(pixd, pixd, pixm);
pixWrite("/tmp/junkout1.png", pixd, IFF_PNG);
#endif

    /* use same connectivity to compare with the result of the
     * slow parallel operation */
#if 1
    pixDestroy(&pixd);
    pixd = pixSeedfillMorph(pixs, pixmi, 100, CONNECTIVITY);
    pixOr(pixd, pixd, pixm);
    pixWrite("/tmp/junkout2.png", pixd, IFF_PNG);
#endif

    pixDestroy(&pixs);
    pixDestroy(&pixm);
    pixDestroy(&pixmi);
    pixDestroy(&pixd);
    return 0;
}
Exemple #18
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 *pix1, *pix2, *pix3, *pix4, *pix5, *pix6, *pix7, *pix8;
    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, &pix1, &pix2);
    fprintf(stderr, "Time for extrema: %7.3f\n", stopTimer());
    pixSetOrClearBorder(pix1, 2, 2, 2, 2, PIX_CLR);
    composeRGBPixel(255, 0, 0, &redval);
    composeRGBPixel(0, 255, 0, &greenval);
    pixc = pixConvertTo32(pixs);
    pixPaintThroughMask(pixc, pix2, 0, 0, greenval);
    pixPaintThroughMask(pixc, pix1, 0, 0, redval);
    pixSaveTiled(pixc, pixac, 1.0, 0, 10, 32);
    pixWrite("/tmp/pixc.png", pixc, IFF_PNG);
    pixSaveTiled(pix1, pixac, 1.0, 0, 10, 32);
    pixSelectMinInConnComp(pixs, pix1, &pta, NULL);
/*    ptaWriteStream(stderr, pta, 1); */
    pix3 = pixGenerateFromPta(pta, w, h);
    pixSaveTiled(pix3, pixac, 1.0, 1, 10, 32);

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

    wshed = wshedCreate(pixs, pix3, 10, 0);
    startTimer();
    wshedApply(wshed);
    fprintf(stderr, "Time for wshed: %7.3f\n", stopTimer());
    pix6 = pixaDisplayRandomCmap(wshed->pixad, w, h);
    pixSaveTiled(pix6, pixac, 1.0, 1, 10, 32);
    numaWriteStream(stderr, wshed->nalevels);
    pix7 = wshedRenderFill(wshed);
    pixSaveTiled(pix7, pixac, 1.0, 0, 10, 32);
    pix8 = wshedRenderColors(wshed);
    pixSaveTiled(pix8, 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(&pix1);
    pixDestroy(&pix2);
    pixDestroy(&pix3);
    pixDestroy(&pix6);
    pixDestroy(&pix7);
    pixDestroy(&pix8);
    pixDestroy(&pixs);
    pixDestroy(&pixc);
    ptaDestroy(&pta);
    return 0;
}
main(int    argc,
     char **argv)
{
l_int32       i, j, x, y, rval, gval, bval;
l_uint32      pixel;
l_float32     frval, fgval, fbval;
NUMA         *nahue, *nasat, *napk;
PIX          *pixs, *pixhsv, *pixh, *pixg, *pixf, *pixd;
PIX          *pixr, *pixt1, *pixt2, *pixt3;
PIXA         *pixa, *pixapk;
PTA          *ptapk;
L_REGPARAMS  *rp;
	l_chooseDisplayProg(L_DISPLAY_WITH_XV);

    if (regTestSetup(argc, argv, &rp))
        return 1;

        /* Make a graded frame color */
    pixs = pixCreate(650, 900, 32);
    for (i = 0; i < 900; i++) {
        rval = 40 + i / 30;
        for (j = 0; j < 650; j++) {
            gval = 255 - j / 30;
            bval = 70 + j / 30;
            composeRGBPixel(rval, gval, bval, &pixel);
            pixSetPixel(pixs, j, i, pixel);
        }
    }
            
        /* Place an image inside the frame and convert to HSV */
    pixt1 = pixRead("1555-3.jpg");
    pixt2 = pixScale(pixt1, 0.5, 0.5);
    pixRasterop(pixs, 100, 100, 2000, 2000, PIX_SRC, pixt2, 0, 0);
    pixDestroy(&pixt1);
    pixDestroy(&pixt2);
    pixDisplayWithTitle(pixs, 400, 0, "Input image", rp->display);
    pixa = pixaCreate(0);
    pixhsv = pixConvertRGBToHSV(NULL, pixs);

        /* Work in the HS projection of HSV */
    pixh = pixMakeHistoHS(pixhsv, 5, &nahue, &nasat);
    pixg = pixMaxDynamicRange(pixh, L_LOG_SCALE);
    pixf = pixConvertGrayToFalseColor(pixg, 1.0);
    regTestWritePixAndCheck(rp, pixf, IFF_PNG);   /* 0 */
    pixDisplayWithTitle(pixf, 100, 0, "False color HS histo", rp->display);
    pixaAddPix(pixa, pixs, L_COPY);
    pixaAddPix(pixa, pixhsv, L_INSERT);
    pixaAddPix(pixa, pixg, L_INSERT);
    pixaAddPix(pixa, pixf, L_INSERT);
    gplotSimple1(nahue, GPLOT_PNG, "/tmp/junkhue", "Histogram of hue values");
#ifndef  _WIN32
    sleep(1);
#else
    Sleep(1000);
#endif  /* _WIN32 */
    pixt3 = pixRead("/tmp/junkhue.png");
    regTestWritePixAndCheck(rp, pixt3, IFF_PNG);  /* 1 */
    pixDisplayWithTitle(pixt3, 100, 300, "Histo of hue", rp->display);
    pixaAddPix(pixa, pixt3, L_INSERT);
    gplotSimple1(nasat, GPLOT_PNG, "/tmp/junksat",
                 "Histogram of saturation values");
#ifndef  _WIN32
    sleep(1);
#else
    Sleep(1000);
#endif  /* _WIN32 */
    pixt3 = pixRead("/tmp/junksat.png");
    regTestWritePixAndCheck(rp, pixt3, IFF_PNG);  /* 2 */
    pixDisplayWithTitle(pixt3, 100, 800, "Histo of saturation", rp->display);
    pixaAddPix(pixa, pixt3, L_INSERT);
    pixd = pixaDisplayTiledAndScaled(pixa, 32, 270, 7, 0, 30, 3);
    regTestWritePixAndCheck(rp, pixd, IFF_PNG);  /* 3 */
    pixDisplayWithTitle(pixd, 0, 400, "Hue and Saturation Mosaic", rp->display);
    pixDestroy(&pixd);
    pixaDestroy(&pixa);
    numaDestroy(&nahue);
    numaDestroy(&nasat);

        /* Find all the peaks */
    pixFindHistoPeaksHSV(pixh, L_HS_HISTO, 20, 20, 6, 2.0,
                         &ptapk, &napk, &pixapk);
    numaWriteStream(stderr, napk);
    ptaWriteStream(stderr, ptapk, 1);
    pixd = pixaDisplayTiledInRows(pixapk, 32, 1400, 1.0, 0, 30, 2);
    regTestWritePixAndCheck(rp, pixd, IFF_PNG);  /* 4 */
    pixDisplayWithTitle(pixd, 0, 550, "Peaks in HS", rp->display);
    pixDestroy(&pixh);
    pixDestroy(&pixd);
    pixaDestroy(&pixapk);

        /* Make masks for each of the peaks */
    pixa = pixaCreate(0);
    pixr = pixScaleBySampling(pixs, 0.4, 0.4);
    for (i = 0; i < 6; i++) {
        ptaGetIPt(ptapk, i, &x, &y);
        pixt1 = pixMakeRangeMaskHS(pixr, y, 20, x, 20, L_INCLUDE_REGION);
        pixaAddPix(pixa, pixt1, L_INSERT);
        pixGetAverageMaskedRGB(pixr, pixt1, 0, 0, 1, L_MEAN_ABSVAL,
                               &frval, &fgval, &fbval);
        composeRGBPixel((l_int32)frval, (l_int32)fgval, (l_int32)fbval,
                        &pixel);
        pixt2 = pixCreateTemplate(pixr);
        pixSetAll(pixt2);
        pixPaintThroughMask(pixt2, pixt1, 0, 0, pixel);
        pixaAddPix(pixa, pixt2, L_INSERT);
        pixt3 = pixCreateTemplate(pixr);
        pixSetAllArbitrary(pixt3, pixel);
        pixaAddPix(pixa, pixt3, L_INSERT);
    }
    pixd = pixaDisplayTiledAndScaled(pixa, 32, 225, 3, 0, 30, 3);
    regTestWritePixAndCheck(rp, pixd, IFF_PNG);  /* 5 */
    pixDisplayWithTitle(pixd, 600, 0, "Masks over peaks", rp->display);
    pixDestroy(&pixs);
    pixDestroy(&pixr);
    pixDestroy(&pixd);
    pixaDestroy(&pixa);
    ptaDestroy(&ptapk);
    numaDestroy(&napk);

    regTestCleanup(rp);
    return 0;
}
Exemple #20
0
/*!
 *  selaAddTJunctions()
 *
 *      Input:  sela (<optional>)
 *              hlsize (length of each line of hits from origin)
 *              mdist (distance of misses from the origin)
 *              norient (number of orientations; max of 8)
 *              debugflag (1 for debug output)
 *      Return: sela with additional sels, or null on error
 *
 *  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.
 */
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;
        pixaGetPixDimensions(pixa, 0, &w, NULL, NULL);
        pixt = pixaDisplayTiledAndScaled(pixa, 32, w, 4, 0, 10, 2);
        pixWriteTempfile("/tmp", "tsel1.png", pixt, IFF_PNG, 0);
        pixDisplay(pixt, 0, 100);
        pixDestroy(&pixt);
        pixt = selaDisplayInPix(sela, 15, 2, 20, 4);
        pixWriteTempfile("/tmp", "tsel2.png", pixt, IFF_PNG, 0);
        pixDisplay(pixt, 500, 100);
        pixDestroy(&pixt);
        selaWriteStream(stderr, sela);
    }
    pixaDestroy(&pixa);

    return sela;
}
Exemple #21
0
/*!
 *  generateBinaryMaze()
 *
 *      Input:  w, h  (size of maze)
 *              xi, yi  (initial location)
 *              wallps (probability that a pixel to the side is ON)
 *              ranis (ratio of prob that pixel in forward direction
 *                     is a wall to the probability that pixel in
 *                     side directions is a wall)
 *      Return: pix, or null on error
 *
 *  Notes:
 *      (1) We have two input probability factors that determine the
 *          density of walls and average length of straight passages.
 *          When ranis < 1.0, you are more likely to generate a wall
 *          to the side than going forward.  Enter 0.0 for either if
 *          you want to use the default values.
 *      (2) This is a type of percolation problem, and exhibits
 *          different phases for different parameters wallps and ranis.
 *          For larger values of these parameters, regions in the maze
 *          are not explored because the maze generator walls them
 *          off and cannot get through.  The boundary between the
 *          two phases in this two-dimensional parameter space goes
 *          near these values:
 *                wallps       ranis
 *                0.35         1.00
 *                0.40         0.85
 *                0.45         0.70
 *                0.50         0.50
 *                0.55         0.40
 *                0.60         0.30
 *                0.65         0.25
 *                0.70         0.19
 *                0.75         0.15
 *                0.80         0.11
 *      (3) Because here is a considerable amount of overhead in calling
 *          pixGetPixel() and pixSetPixel(), this function can be sped
 *          up with little effort using raster line pointers and the
 *          GET_DATA* and SET_DATA* macros.
 */
PIX *
generateBinaryMaze(l_int32  w,
                   l_int32  h,
                   l_int32  xi,
                   l_int32  yi,
                   l_float32  wallps,
                   l_float32  ranis)
{
l_int32    x, y, dir;
l_uint32   val;
l_float32  frand, wallpf, testp;
MAZEEL    *el, *elp;
PIX       *pixd;  /* the destination maze */
PIX       *pixm;  /* for bookkeeping, to indicate pixels already visited */
L_QUEUE   *lq;

    /* On Windows, seeding is apparently necessary to get decent mazes.
     * Windows rand() returns a value up to 2^15 - 1, whereas unix
     * rand() returns a value up to 2^31 - 1.  Therefore the generated
     * mazes will differ on the two platforms. */
#ifdef _WIN32
    srand(28*333);
#endif /* _WIN32 */

    if (w < MIN_MAZE_WIDTH)
        w = MIN_MAZE_WIDTH;
    if (h < MIN_MAZE_HEIGHT)
        h = MIN_MAZE_HEIGHT;
    if (xi <= 0 || xi >= w)
        xi = w / 6;
    if (yi <= 0 || yi >= h)
        yi = h / 5;
    if (wallps < 0.05 || wallps > 0.95)
        wallps = DEFAULT_WALL_PROBABILITY;
    if (ranis < 0.05 || ranis > 1.0)
        ranis = DEFAULT_ANISOTROPY_RATIO;
    wallpf = wallps * ranis;

#if  DEBUG_MAZE
    fprintf(stderr, "(w, h) = (%d, %d), (xi, yi) = (%d, %d)\n", w, h, xi, yi);
    fprintf(stderr, "Using: prob(wall) = %7.4f, anisotropy factor = %7.4f\n",
            wallps, ranis);
#endif  /* DEBUG_MAZE */

        /* These are initialized to OFF */
    pixd = pixCreate(w, h, 1);
    pixm = pixCreate(w, h, 1);

    lq = lqueueCreate(0);

        /* Prime the queue with the first pixel; it is OFF */
    el = mazeelCreate(xi, yi, START_LOC);
    pixSetPixel(pixm, xi, yi, 1);  /* mark visited */
    lqueueAdd(lq, el);

        /* While we're at it ... */
    while (lqueueGetCount(lq) > 0) {
        elp = (MAZEEL *)lqueueRemove(lq);
        x = elp->x;
        y = elp->y;
        dir = elp->dir;
        if (x > 0) {  /* check west */
            pixGetPixel(pixm, x - 1, y, &val);
            if (val == 0) {  /* not yet visited */
                pixSetPixel(pixm, x - 1, y, 1);  /* mark visited */
                frand = (l_float32)rand() / (l_float32)RAND_MAX;
                testp = wallps;
                if (dir == DIR_WEST)
                    testp = wallpf;
                if (frand <= testp) {  /* make it a wall */
                    pixSetPixel(pixd, x - 1, y, 1);
                }
                else {  /* not a wall */
                    el = mazeelCreate(x - 1, y, DIR_WEST);
                    lqueueAdd(lq, el);
                }
            }
        }
        if (y > 0) {  /* check north */
            pixGetPixel(pixm, x, y - 1, &val);
            if (val == 0) {  /* not yet visited */
                pixSetPixel(pixm, x, y - 1, 1);  /* mark visited */
                frand = (l_float32)rand() / (l_float32)RAND_MAX;
                testp = wallps;
                if (dir == DIR_NORTH)
                    testp = wallpf;
                if (frand <= testp) {  /* make it a wall */
                    pixSetPixel(pixd, x, y - 1, 1);
                }
                else {  /* not a wall */
                    el = mazeelCreate(x, y - 1, DIR_NORTH);
                    lqueueAdd(lq, el);
                }
            }
        }
        if (x < w - 1) {  /* check east */
            pixGetPixel(pixm, x + 1, y, &val);
            if (val == 0) {  /* not yet visited */
                pixSetPixel(pixm, x + 1, y, 1);  /* mark visited */
                frand = (l_float32)rand() / (l_float32)RAND_MAX;
                testp = wallps;
                if (dir == DIR_EAST)
                    testp = wallpf;
                if (frand <= testp) {  /* make it a wall */
                    pixSetPixel(pixd, x + 1, y, 1);
                }
                else {  /* not a wall */
                    el = mazeelCreate(x + 1, y, DIR_EAST);
                    lqueueAdd(lq, el);
                }
            }
        }
        if (y < h - 1) {  /* check south */
            pixGetPixel(pixm, x, y + 1, &val);
            if (val == 0) {  /* not yet visited */
                pixSetPixel(pixm, x, y + 1, 1);  /* mark visited */
                frand = (l_float32)rand() / (l_float32)RAND_MAX;
                testp = wallps;
                if (dir == DIR_SOUTH)
                    testp = wallpf;
                if (frand <= testp) {  /* make it a wall */
                    pixSetPixel(pixd, x, y + 1, 1);
                }
                else {  /* not a wall */
                    el = mazeelCreate(x, y + 1, DIR_SOUTH);
                    lqueueAdd(lq, el);
                }
            }
        }
        FREE(elp);
    }

    lqueueDestroy(&lq, TRUE);
    pixDestroy(&pixm);
    return pixd;
}
main(int    argc,
     char **argv)
{
l_int32       i, j, x, y, val;
PIX          *pixsq, *pixs, *pixc, *pixd;
PIXA         *pixa;
L_REGPARAMS  *rp;

    if (regTestSetup(argc, argv, &rp))
        return 1;

    pixsq = pixCreate(3, 3, 32);
    pixSetAllArbitrary(pixsq, 0x00ff0000);
    pixa = pixaCreate(6);

        /* Moderately dense */
    pixs = pixCreate(300, 300, 8);
    for (i = 0; i < 100; i++) {
        x = (153 * i * i * i + 59) % 299;
        y = (117 * i * i * i + 241) % 299;
        val = (97 * i + 74) % 256;
        pixSetPixel(pixs, x, y, val);
    }

    pixd = pixSeedspread(pixs, 4);  /* 4-cc */
    pixc = pixConvertTo32(pixd);
    for (i = 0; i < 100; i++) {
        x = (153 * i * i * i + 59) % 299;
        y = (117 * i * i * i + 241) % 299;
        pixRasterop(pixc, x - 1, y - 1, 3, 3, PIX_SRC, pixsq, 0, 0);
    }
    pixSaveTiled(pixc, pixa, REDUCTION, 1, 20, 32);
    regTestWritePixAndCheck(rp, pixc, IFF_PNG);  /* 0 */
    pixDisplayWithTitle(pixc, 100, 100, "4-cc", rp->display);
    pixDestroy(&pixd);
    pixDestroy(&pixc);

    pixd = pixSeedspread(pixs, 8);  /* 8-cc */
    pixc = pixConvertTo32(pixd);
    for (i = 0; i < 100; i++) {
        x = (153 * i * i * i + 59) % 299;
        y = (117 * i * i * i + 241) % 299;
        pixRasterop(pixc, x - 1, y - 1, 3, 3, PIX_SRC, pixsq, 0, 0);
    }
    pixSaveTiled(pixc, pixa, REDUCTION, 0, 20, 0);
    regTestWritePixAndCheck(rp, pixc, IFF_PNG);  /* 1 */
    pixDisplayWithTitle(pixc, 410, 100, "8-cc", rp->display);
    pixDestroy(&pixd);
    pixDestroy(&pixc);
    pixDestroy(&pixs);

        /* Regular lattice */
    pixs = pixCreate(200, 200, 8);
    for (i = 5; i <= 195; i += 10) {
        for (j = 5; j <= 195; j += 10) {
            pixSetPixel(pixs, i, j, (7 * i + 17 * j) % 255);
        }
    }
    pixd = pixSeedspread(pixs, 4);  /* 4-cc */
    pixc = pixConvertTo32(pixd);
    for (i = 5; i <= 195; i += 10) {
        for (j = 5; j <= 195; j += 10) {
            pixRasterop(pixc, j - 1, i - 1, 3, 3, PIX_SRC, pixsq, 0, 0);
        }
    }
    pixSaveTiled(pixc, pixa, REDUCTION, 1, 20, 0);
    regTestWritePixAndCheck(rp, pixc, IFF_PNG);  /* 2 */
    pixDisplayWithTitle(pixc, 100, 430, "4-cc", rp->display);
    pixDestroy(&pixd);
    pixDestroy(&pixc);

    pixd = pixSeedspread(pixs, 8);  /* 8-cc */
    pixc = pixConvertTo32(pixd);
    for (i = 5; i <= 195; i += 10) {
        for (j = 5; j <= 195; j += 10) {
            pixRasterop(pixc, j - 1, i - 1, 3, 3, PIX_SRC, pixsq, 0, 0);
        }
    }
    pixSaveTiled(pixc, pixa, REDUCTION, 0, 20, 0);
    regTestWritePixAndCheck(rp, pixc, IFF_PNG);  /* 3 */
    pixDisplayWithTitle(pixc, 310, 430, "8-cc", rp->display);
    pixDestroy(&pixd);
    pixDestroy(&pixc);
    pixDestroy(&pixs);

        /* Very sparse points */
    pixs = pixCreate(200, 200, 8);
    pixSetPixel(pixs, 60, 20, 90);
    pixSetPixel(pixs, 160, 40, 130);
    pixSetPixel(pixs, 80, 80, 205);
    pixSetPixel(pixs, 40, 160, 115);
    pixd = pixSeedspread(pixs, 4);  /* 4-cc */
    pixc = pixConvertTo32(pixd);
    pixRasterop(pixc, 60 - 1, 20 - 1, 3, 3, PIX_SRC, pixsq, 0, 0);
    pixRasterop(pixc, 160 - 1, 40 - 1, 3, 3, PIX_SRC, pixsq, 0, 0);
    pixRasterop(pixc, 80 - 1, 80 - 1, 3, 3, PIX_SRC, pixsq, 0, 0);
    pixRasterop(pixc, 40 - 1, 160 - 1, 3, 3, PIX_SRC, pixsq, 0, 0);
    pixSaveTiled(pixc, pixa, REDUCTION, 1, 20, 0);
    regTestWritePixAndCheck(rp, pixc, IFF_PNG);  /* 4 */
    pixDisplayWithTitle(pixc, 100, 600, "4-cc", rp->display);
    pixDestroy(&pixd);
    pixDestroy(&pixc);

    pixd = pixSeedspread(pixs, 8);  /* 8-cc */
    pixc = pixConvertTo32(pixd);
    pixRasterop(pixc, 60 - 1, 20 - 1, 3, 3, PIX_SRC, pixsq, 0, 0);
    pixRasterop(pixc, 160 - 1, 40 - 1, 3, 3, PIX_SRC, pixsq, 0, 0);
    pixRasterop(pixc, 80 - 1, 80 - 1, 3, 3, PIX_SRC, pixsq, 0, 0);
    pixRasterop(pixc, 40 - 1, 160 - 1, 3, 3, PIX_SRC, pixsq, 0, 0);
    pixSaveTiled(pixc, pixa, REDUCTION, 0, 20, 0);
    regTestWritePixAndCheck(rp, pixc, IFF_PNG);  /* 5 */
    pixDisplayWithTitle(pixc, 310, 660, "8-cc", rp->display);
    pixDestroy(&pixd);
    pixDestroy(&pixc);
    pixDestroy(&pixs);
    pixDestroy(&pixsq);

    pixd = pixaDisplay(pixa, 0, 0);
    regTestWritePixAndCheck(rp, pixd, IFF_PNG);  /* 6 */
    pixDisplayWithTitle(pixc, 720, 100, "Final", rp->display);

    pixaDestroy(&pixa);
    pixDestroy(&pixd);
    return regTestCleanup(rp);
}
Exemple #23
0
/*!
 *  pixSearchBinaryMaze()
 *
 *      Input:  pixs (1 bpp, maze)
 *              xi, yi  (beginning point; use same initial point
 *                       that was used to generate the maze)
 *              xf, yf  (end point, or close to it)
 *              &ppixd (<optional return> maze with path illustrated, or
 *                     if no path possible, the part of the maze
 *                     that was searched)
 *      Return: pta (shortest path), or null if either no path
 *              exists or on error
 *
 *  Notes:
 *      (1) Because of the overhead in calling pixGetPixel() and
 *          pixSetPixel(), we have used raster line pointers and the
 *          GET_DATA* and SET_DATA* macros for many of the pix accesses.
 *      (2) Commentary:
 *            The goal is to find the shortest path between beginning and
 *          end points, without going through walls, and there are many
 *          ways to solve this problem.
 *            We use a queue to implement a breadth-first search.  Two auxiliary
 *          "image" data structures can be used: one to mark the visited
 *          pixels and one to give the direction to the parent for each
 *          visited pixels.  The first structure is used to avoid putting
 *          pixels on the queue more than once, and the second is used
 *          for retracing back to the origin, like the breadcrumbs in
 *          Hansel and Gretel.  Each pixel taken off the queue is destroyed
 *          after it is used to locate the allowed neighbors.  In fact,
 *          only one distance image is required, if you initialize it
 *          to some value that signifies "not yet visited."  (We use
 *          a binary image for marking visited pixels because it is clearer.)
 *          This method for a simple search of a binary maze is implemented in
 *          searchBinaryMaze().
 *            An alternative method would store the (manhattan) distance
 *          from the start point with each pixel on the queue.  The children
 *          of each pixel get a distance one larger than the parent.  These
 *          values can be stored in an auxiliary distance map image
 *          that is constructed simultaneously with the search.  Once the
 *          end point is reached, the distance map is used to backtrack
 *          along a minimum path.  There may be several equal length
 *          minimum paths, any one of which can be chosen this way.
 */
PTA *
pixSearchBinaryMaze(PIX     *pixs,
                    l_int32  xi,
                    l_int32  yi, 
                    l_int32  xf,
                    l_int32  yf,
                    PIX    **ppixd)
{
l_int32    i, j, x, y, w, h, d, found;
l_uint32   val, rpixel, gpixel, bpixel;
void     **lines1, **linem1, **linep8, **lined32;
MAZEEL    *el, *elp;
PIX       *pixd;  /* the shortest path written on the maze image */
PIX       *pixm;  /* for bookkeeping, to indicate pixels already visited */
PIX       *pixp;  /* for bookkeeping, to indicate direction to parent */
L_QUEUE   *lq;
PTA       *pta;

    PROCNAME("pixSearchBinaryMaze");

    if (ppixd) *ppixd = NULL;
    if (!pixs)
        return (PTA *)ERROR_PTR("pixs not defined", procName, NULL);
    pixGetDimensions(pixs, &w, &h, &d);
    if (d != 1)
        return (PTA *)ERROR_PTR("pixs not 1 bpp", procName, NULL);
    if (xi <= 0 || xi >= w)
        return (PTA *)ERROR_PTR("xi not valid", procName, NULL);
    if (yi <= 0 || yi >= h)
        return (PTA *)ERROR_PTR("yi not valid", procName, NULL);
    pixGetPixel(pixs, xi, yi, &val);
    if (val != 0)
        return (PTA *)ERROR_PTR("(xi,yi) not bg pixel", procName, NULL);
    pixd = NULL;
    pta = NULL;

        /* Find a bg pixel near input point (xf, yf) */
    localSearchForBackground(pixs, &xf, &yf, 5);

#if  DEBUG_MAZE
    fprintf(stderr, "(xi, yi) = (%d, %d), (xf, yf) = (%d, %d)\n",
            xi, yi, xf, yf);
#endif  /* DEBUG_MAZE */

    pixm = pixCreate(w, h, 1);  /* initialized to OFF */
    pixp = pixCreate(w, h, 8);  /* direction to parent stored as enum val */
    lines1 = pixGetLinePtrs(pixs, NULL);
    linem1 = pixGetLinePtrs(pixm, NULL);
    linep8 = pixGetLinePtrs(pixp, NULL);

    lq = lqueueCreate(0);

        /* Prime the queue with the first pixel; it is OFF */
    el = mazeelCreate(xi, yi, 0);  /* don't need direction here */
    pixSetPixel(pixm, xi, yi, 1);  /* mark visited */
    lqueueAdd(lq, el);

        /* Fill up the pix storing directions to parents,
         * stopping when we hit the point (xf, yf)  */
    found = FALSE;
    while (lqueueGetCount(lq) > 0) {
        elp = (MAZEEL *)lqueueRemove(lq);
        x = elp->x;
        y = elp->y;
        if (x == xf && y == yf) {
            found = TRUE;
            FREE(elp);
            break;
        }
            
        if (x > 0) {  /* check to west */
            val = GET_DATA_BIT(linem1[y], x - 1);
            if (val == 0) {  /* not yet visited */
                SET_DATA_BIT(linem1[y], x - 1);  /* mark visited */
                val = GET_DATA_BIT(lines1[y], x - 1);
                if (val == 0) {  /* bg, not a wall */
                    SET_DATA_BYTE(linep8[y], x - 1, DIR_EAST);  /* parent E */
                    el = mazeelCreate(x - 1, y, 0);
                    lqueueAdd(lq, el);
                }
            }
        }
        if (y > 0) {  /* check north */
            val = GET_DATA_BIT(linem1[y - 1], x);
            if (val == 0) {  /* not yet visited */
                SET_DATA_BIT(linem1[y - 1], x);  /* mark visited */
                val = GET_DATA_BIT(lines1[y - 1], x);
                if (val == 0) {  /* bg, not a wall */
                    SET_DATA_BYTE(linep8[y - 1], x, DIR_SOUTH);  /* parent S */
                    el = mazeelCreate(x, y - 1, 0);
                    lqueueAdd(lq, el);
                }
            }
        }
        if (x < w - 1) {  /* check east */
            val = GET_DATA_BIT(linem1[y], x + 1);
            if (val == 0) {  /* not yet visited */
                SET_DATA_BIT(linem1[y], x + 1);  /* mark visited */
                val = GET_DATA_BIT(lines1[y], x + 1);
                if (val == 0) {  /* bg, not a wall */
                    SET_DATA_BYTE(linep8[y], x + 1, DIR_WEST);  /* parent W */
                    el = mazeelCreate(x + 1, y, 0);
                    lqueueAdd(lq, el);
                }
            }
        }
        if (y < h - 1) {  /* check south */
            val = GET_DATA_BIT(linem1[y + 1], x);
            if (val == 0) {  /* not yet visited */
                SET_DATA_BIT(linem1[y + 1], x);  /* mark visited */
                val = GET_DATA_BIT(lines1[y + 1], x);
                if (val == 0) {  /* bg, not a wall */
                    SET_DATA_BYTE(linep8[y + 1], x, DIR_NORTH);  /* parent N */
                    el = mazeelCreate(x, y + 1, 0);
                    lqueueAdd(lq, el);
                }
            }
        }
        FREE(elp);
    }

    lqueueDestroy(&lq, TRUE);
    pixDestroy(&pixm);
    FREE(linem1);

    if (ppixd) {
        pixd = pixUnpackBinary(pixs, 32, 1);
        *ppixd = pixd;
    }
    composeRGBPixel(255, 0, 0, &rpixel);  /* start point */
    composeRGBPixel(0, 255, 0, &gpixel);
    composeRGBPixel(0, 0, 255, &bpixel);  /* end point */


    if (!found) {
        L_INFO(" No path found", procName);
        if (pixd) {  /* paint all visited locations */
            lined32 = pixGetLinePtrs(pixd, NULL);
            for (i = 0; i < h; i++) {
                for (j = 0; j < w; j++) {
                    val = GET_DATA_BYTE(linep8[i], j);
                    if (val != 0 && pixd)
                        SET_DATA_FOUR_BYTES(lined32[i], j, gpixel);
                }
            }
            FREE(lined32);
        }
    }
    else {   /* write path onto pixd */
        L_INFO(" Path found", procName);
        pta = ptaCreate(0);
        x = xf;
        y = yf;
        while (1) {
            ptaAddPt(pta, x, y);
            if (x == xi && y == yi)
                break;
            if (pixd)
                pixSetPixel(pixd, x, y, gpixel);
            pixGetPixel(pixp, x, y, &val);
            if (val == DIR_NORTH)
                y--;
            else if (val == DIR_SOUTH)
                y++;
            else if (val == DIR_EAST)
                x++;
            else if (val == DIR_WEST)
                x--;
        }
    }
    if (pixd) {
        pixSetPixel(pixd, xi, yi, rpixel);
        pixSetPixel(pixd, xf, yf, bpixel);
    }

    pixDestroy(&pixp);
    FREE(lines1);
    FREE(linep8);
    return pta;
}
Exemple #24
0
int main(int    argc,
         char **argv)
{
char        *filein, *fileout;
l_int32      x, y, n, i;
PIX         *pixs;
PTA         *pta;
PTAA        *ptaa, *ptaa2, *ptaa3;
static char  mainName[] = "cornertest";

    if (argc != 3)
        return ERROR_INT(" Syntax:  cornertest filein fileout", mainName, 1);

    filein = argv[1];
    fileout = argv[2];
    if ((pixs = pixRead(filein)) == NULL)
        return ERROR_INT("pixs not made", mainName, 1);

        /* Clean noise in LR corner of witten.tif */
    pixSetPixel(pixs, 2252, 3051, 0);
    pixSetPixel(pixs, 2252, 3050, 0);
    pixSetPixel(pixs, 2251, 3050, 0);

    pta = pixFindCornerPixels(pixs);
    ptaWriteStream(stderr, pta, 1);

        /* Test pta and ptaa I/O */
#if 1
    ptaa = ptaaCreate(3);
    ptaaAddPta(ptaa, pta, L_COPY);
    ptaaAddPta(ptaa, pta, L_COPY);
    ptaaAddPta(ptaa, pta, L_COPY);
    ptaaWriteStream(stderr, ptaa, 1);
    ptaaWrite("/tmp/junkptaa", ptaa, 1);
    ptaa2 = ptaaRead("/tmp/junkptaa");
    ptaaWrite("/tmp/junkptaa2", ptaa2, 1);
    ptaaWrite("/tmp/junkptaa3", ptaa, 0);
    ptaa3 = ptaaRead("/tmp/junkptaa3");
    ptaaWrite("/tmp/junkptaa4", ptaa3, 0);
    ptaaDestroy(&ptaa);
    ptaaDestroy(&ptaa2);
    ptaaDestroy(&ptaa3);
#endif

        /* mark corner pixels */
    n = ptaGetCount(pta);
    for (i = 0; i < n; i++) {
        ptaGetIPt(pta, i, &x, &y);
        pixRenderLine(pixs, x - LINE_SIZE, y, x + LINE_SIZE, y, 5,
                      L_FLIP_PIXELS);
        pixRenderLine(pixs, x, y - LINE_SIZE, x, y + LINE_SIZE, 5,
                      L_FLIP_PIXELS);
    }

    pixWrite(fileout, pixs, IFF_PNG);

    pixDestroy(&pixs);
    ptaDestroy(&pta);
    ptaDestroy(&pta);
    return 0;
}
Exemple #25
0
/*!
 *  pixSearchGrayMaze()
 *
 *      Input:  pixs (1 bpp, maze)
 *              xi, yi  (beginning point; use same initial point
 *                       that was used to generate the maze)
 *              xf, yf  (end point, or close to it)
 *              &ppixd (<optional return> maze with path illustrated, or
 *                     if no path possible, the part of the maze
 *                     that was searched)
 *      Return: pta (shortest path), or null if either no path
 *              exists or on error
 *
 *  Commentary:
 *      Consider first a slight generalization of the binary maze
 *      search problem.  Suppose that you can go through walls,
 *      but the cost is higher (say, an increment of 3 to go into
 *      a wall pixel rather than 1)?  You're still trying to find
 *      the shortest path.  One way to do this is with an ordered
 *      queue, and a simple way to visualize an ordered queue is as 
 *      a set of stacks, each stack being marked with the distance
 *      of each pixel in the stack from the start.  We place the
 *      start pixel in stack 0, pop it, and process its 4 children.
 *      Each pixel is given a distance that is incremented from that
 *      of its parent (0 in this case), depending on if it is a wall
 *      pixel or not.  That value may be recorded on a distance map,
 *      according to the algorithm below.  For children of the first
 *      pixel, those not on a wall go in stack 1, and wall
 *      children go in stack 3.  Stack 0 being emptied, the process
 *      then continues with pixels being popped from stack 1.
 *      Here is the algorithm for each child pixel.  The pixel's
 *      distance value, were it to be placed on a stack, is compared
 *      with the value for it that is on the distance map.  There
 *      are three possible cases:
 *         (1) If the pixel has not yet been registered, it is pushed
 *             on its stack and the distance is written to the map.
 *         (2) If it has previously been registered with a higher distance,
 *             the distance on the map is relaxed to that of the
 *             current pixel, which is then placed on its stack.
 *         (3) If it has previously been registered with an equal
 *             or lower value, the pixel is discarded.
 *      The pixels are popped and processed successively from
 *      stack 1, and when stack 1 is empty, popping starts on stack 2.
 *      This continues until the destination pixel is popped off
 *      a stack.   The minimum path is then derived from the distance map,
 *      going back from the end point as before.  This is just Dijkstra's
 *      algorithm for a directed graph; here, the underlying graph
 *      (consisting of the pixels and four edges connecting each pixel
 *      to its 4-neighbor) is a special case of a directed graph, where
 *      each edge is bi-directional.  The implementation of this generalized
 *      maze search is left as an exercise to the reader.
 *
 *      Let's generalize a bit further.  Suppose the "maze" is just
 *      a grayscale image -- think of it as an elevation map.  The cost
 *      of moving on this surface depends on the height, or the gradient,
 *      or whatever you want.  All that is required is that the cost
 *      is specified and non-negative on each link between adjacent
 *      pixels.  Now the problem becomes: find the least cost path
 *      moving on this surface between two specified end points.
 *      For example, if the cost across an edge between two pixels
 *      depends on the "gradient", you can use:
 *           cost = 1 + L_ABS(deltaV)
 *      where deltaV is the difference in value between two adjacent
 *      pixels.  If the costs are all integers, we can still use an array
 *      of stacks to avoid ordering the queue (e.g., by using a heap sort.)
 *      This is a neat problem, because you don't even have to build a
 *      maze -- you can can use it on any grayscale image!
 *    
 *      Rather than using an array of stacks, a more practical
 *      approach is to implement with a priority queue, which is
 *      a queue that is sorted so that the elements with the largest
 *      (or smallest) key values always come off first.  The
 *      priority queue is efficiently implemented as a heap, and
 *      this is how we do it.  Suppose you run the algorithm
 *      using a priority queue, doing the bookkeeping with an
 *      auxiliary image data structure that saves the distance of
 *      each pixel put on the queue as before, according to the method
 *      described above.  We implement it as a 2-way choice by
 *      initializing the distance array to a large value and putting
 *      a pixel on the queue if its distance is less than the value
 *      found on the array.  When you finally pop the end pixel from
 *      the queue, you're done, and you can trace the path backward,
 *      either always going downhill or using an auxiliary image to
 *      give you the direction to go at each step.  This is implemented
 *      here in searchGrayMaze().
 *
 *      Do we really have to use a sorted queue?  Can we solve this
 *      generalized maze with an unsorted queue of pixels?  (Or even
 *      an unsorted stack, doing a depth-first search (DFS)?)
 *      Consider a different algorithm for this generalized maze, where
 *      we travel again breadth first, but this time use a single,
 *      unsorted queue.  An auxiliary image is used as before to
 *      store the distances and to determine if pixels get pushed
 *      on the stack or dropped.  As before, we must allow pixels
 *      to be revisited, with relaxation of the distance if a shorter
 *      path arrives later.  As a result, we will in general have
 *      multiple instances of the same pixel on the stack with different
 *      distances.  However, because the queue is not ordered, some of
 *      these pixels will be popped when another instance with a lower
 *      distance is still on the stack.  Here, we're just popping them
 *      in the order they go on, rather than setting up a priority
 *      based on minimum distance.  Thus, unlike the priority queue,
 *      when a pixel is popped we have to check the distance map to
 *      see if a pixel with a lower distance has been put on the queue,
 *      and, if so, we discard the pixel we just popped.  So the
 *      "while" loop looks like this:
 *        - pop a pixel from the queue
 *        - check its distance against the distance stored in the
 *          distance map; if larger, discard
 *        - otherwise, for each of its neighbors:
 *            - compute its distance from the start pixel
 *            - compare this distance with that on the distance map:
 *                - if the distance map value higher, relax the distance
 *                  and push the pixel on the queue
 *                - if the distance map value is lower, discard the pixel
 *
 *      How does this loop terminate?  Before, with an ordered queue,
 *      it terminates when you pop the end pixel.  But with an unordered
 *      queue (or stack), the first time you hit the end pixel, the
 *      distance is not guaranteed to be correct, because the pixels
 *      along the shortest path may not have yet been visited and relaxed.
 *      Because the shortest path can theoretically go anywhere,
 *      we must keep going.  How do we know when to stop?   Dijkstra
 *      uses an ordered queue to systematically remove nodes from
 *      further consideration.  (Each time a pixel is popped, we're
 *      done with it; it's "finalized" in the Dijkstra sense because
 *      we know the shortest path to it.)  However, with an unordered
 *      queue, the brute force answer is: stop when the queue
 *      (or stack) is empty, because then every pixel in the image
 *      has been assigned its minimum "distance" from the start pixel.
 *
 *      This is similar to the situation when you use a stack for the
 *      simpler uniform-step problem: with breadth-first search (BFS)
 *      the pixels on the queue are automatically ordered, so you are
 *      done when you locate the end pixel as a neighbor of a popped pixel;
 *      whereas depth-first search (DFS), using a stack, requires,
 *      in general, a search of every accessible pixel.  Further, if
 *      a pixel is revisited with a smaller distance, that distance is
 *      recorded and the pixel is put on the stack again.
 *
 *      But surely, you ask, can't we stop sooner?  What if the
 *      start and end pixels are very close to each other?
 *      OK, suppose they are, and you have very high walls and a
 *      long snaking level path that is actually the minimum cost.
 *      That long path can wind back and forth across the entire
 *      maze many times before ending up at the end point, which
 *      could be just over a wall from the start.  With the unordered
 *      queue, you very quickly get a high distance for the end
 *      pixel, which will be relaxed to the minimum distance only
 *      after all the pixels of the path have been visited and placed
 *      on the queue, multiple times for many of them.  So that's the
 *      price for not ordering the queue!
 */
PTA *
pixSearchGrayMaze(PIX     *pixs,
                  l_int32  xi,
                  l_int32  yi,
                  l_int32  xf,
                  l_int32  yf,
                  PIX    **ppixd)
{
l_int32   x, y, w, h, d;
l_uint32  val, valr, vals, rpixel, gpixel, bpixel;
void    **lines8, **liner32, **linep8;
l_int32   cost, dist, distparent, sival, sivals;
MAZEEL   *el, *elp;
PIX      *pixd;  /* optionally plot the path on this RGB version of pixs */
PIX      *pixr;  /* for bookkeeping, to indicate the minimum distance */
                 /* to pixels already visited */
PIX      *pixp;  /* for bookkeeping, to indicate direction to parent */
L_HEAP   *lh;
PTA      *pta;

    PROCNAME("pixSearchGrayMaze");

    if (ppixd) *ppixd = NULL;
    if (!pixs)
        return (PTA *)ERROR_PTR("pixs not defined", procName, NULL);
    pixGetDimensions(pixs, &w, &h, &d);
    if (d != 8)
        return (PTA *)ERROR_PTR("pixs not 8 bpp", procName, NULL);
    if (xi <= 0 || xi >= w)
        return (PTA *)ERROR_PTR("xi not valid", procName, NULL);
    if (yi <= 0 || yi >= h)
        return (PTA *)ERROR_PTR("yi not valid", procName, NULL);
    pixd = NULL;
    pta = NULL;

    pixr = pixCreate(w, h, 32);
    pixSetAll(pixr);  /* initialize to max value */
    pixp = pixCreate(w, h, 8);  /* direction to parent stored as enum val */
    lines8 = pixGetLinePtrs(pixs, NULL);
    linep8 = pixGetLinePtrs(pixp, NULL);
    liner32 = pixGetLinePtrs(pixr, NULL);

    lh = lheapCreate(0, L_SORT_INCREASING);  /* always remove closest pixels */

        /* Prime the heap with the first pixel */
    pixGetPixel(pixs, xi, yi, &val);
    el = mazeelCreate(xi, yi, 0);  /* don't need direction here */
    el->distance = 0;
    pixGetPixel(pixs, xi, yi, &val);
    el->val = val;
    pixSetPixel(pixr, xi, yi, 0);  /* distance is 0 */
    lheapAdd(lh, el);

        /* Breadth-first search with priority queue (implemented by
           a heap), labeling direction to parents in pixp and minimum
           distance to visited pixels in pixr.  Stop when we pull
           the destination point (xf, yf) off the queue. */
    while (lheapGetCount(lh) > 0) {
        elp = (MAZEEL *)lheapRemove(lh);
        if (!elp)
            return (PTA *)ERROR_PTR("heap broken!!", procName, NULL);
        x = elp->x;
        y = elp->y;
        if (x == xf && y == yf) {  /* exit condition */
            FREE(elp);
            break;
        }
        distparent = (l_int32)elp->distance;
        val = elp->val;
        sival = val;
            
        if (x > 0) {  /* check to west */
            vals = GET_DATA_BYTE(lines8[y], x - 1);
            valr = GET_DATA_FOUR_BYTES(liner32[y], x - 1);
            sivals = (l_int32)vals;
            cost = 1 + L_ABS(sivals - sival);  /* cost to move to this pixel */
            dist = distparent + cost;
            if (dist < valr) {  /* shortest path so far to this pixel */
                SET_DATA_FOUR_BYTES(liner32[y], x - 1, dist);  /* new dist */
                SET_DATA_BYTE(linep8[y], x - 1, DIR_EAST);  /* parent to E */
                el = mazeelCreate(x - 1, y, 0);
                el->val = vals;
                el->distance = dist;
                lheapAdd(lh, el);
            }
        }
        if (y > 0) {  /* check north */
            vals = GET_DATA_BYTE(lines8[y - 1], x);
            valr = GET_DATA_FOUR_BYTES(liner32[y - 1], x);
            sivals = (l_int32)vals;
            cost = 1 + L_ABS(sivals - sival);  /* cost to move to this pixel */
            dist = distparent + cost;
            if (dist < valr) {  /* shortest path so far to this pixel */
                SET_DATA_FOUR_BYTES(liner32[y - 1], x, dist);  /* new dist */
                SET_DATA_BYTE(linep8[y - 1], x, DIR_SOUTH);  /* parent to S */
                el = mazeelCreate(x, y - 1, 0);
                el->val = vals;
                el->distance = dist;
                lheapAdd(lh, el);
            }
        }
        if (x < w - 1) {  /* check east */
            vals = GET_DATA_BYTE(lines8[y], x + 1);
            valr = GET_DATA_FOUR_BYTES(liner32[y], x + 1);
            sivals = (l_int32)vals;
            cost = 1 + L_ABS(sivals - sival);  /* cost to move to this pixel */
            dist = distparent + cost;
            if (dist < valr) {  /* shortest path so far to this pixel */
                SET_DATA_FOUR_BYTES(liner32[y], x + 1, dist);  /* new dist */
                SET_DATA_BYTE(linep8[y], x + 1, DIR_WEST);  /* parent to W */
                el = mazeelCreate(x + 1, y, 0);
                el->val = vals;
                el->distance = dist;
                lheapAdd(lh, el);
            }
        }
        if (y < h - 1) {  /* check south */
            vals = GET_DATA_BYTE(lines8[y + 1], x);
            valr = GET_DATA_FOUR_BYTES(liner32[y + 1], x);
            sivals = (l_int32)vals;
            cost = 1 + L_ABS(sivals - sival);  /* cost to move to this pixel */
            dist = distparent + cost;
            if (dist < valr) {  /* shortest path so far to this pixel */
                SET_DATA_FOUR_BYTES(liner32[y + 1], x, dist);  /* new dist */
                SET_DATA_BYTE(linep8[y + 1], x, DIR_NORTH);  /* parent to N */
                el = mazeelCreate(x, y + 1, 0);
                el->val = vals;
                el->distance = dist;
                lheapAdd(lh, el);
            }
        }
        FREE(elp);
    }

    lheapDestroy(&lh, TRUE);

    if (ppixd) {
        pixd = pixConvert8To32(pixs);
        *ppixd = pixd;
    }
    composeRGBPixel(255, 0, 0, &rpixel);  /* start point */
    composeRGBPixel(0, 255, 0, &gpixel);
    composeRGBPixel(0, 0, 255, &bpixel);  /* end point */

    x = xf;
    y = yf;
    pta = ptaCreate(0);
    while (1) {  /* write path onto pixd */
        ptaAddPt(pta, x, y);
        if (x == xi && y == yi)
            break;
        if (pixd)
            pixSetPixel(pixd, x, y, gpixel);
        pixGetPixel(pixp, x, y, &val);
        if (val == DIR_NORTH)
            y--;
        else if (val == DIR_SOUTH)
            y++;
        else if (val == DIR_EAST)
            x++;
        else if (val == DIR_WEST)
            x--;
        pixGetPixel(pixr, x, y, &val);

#if  DEBUG_PATH
        fprintf(stderr, "(x,y) = (%d, %d); dist = %d\n", x, y, val);
#endif  /* DEBUG_PATH */

    }
    if (pixd) {
        pixSetPixel(pixd, xi, yi, rpixel);
        pixSetPixel(pixd, xf, yf, bpixel);
    }

    pixDestroy(&pixp);
    pixDestroy(&pixr);
    FREE(lines8);
    FREE(linep8);
    FREE(liner32);
    return pta;
}
Exemple #26
0
/*!
 *  kernelDisplayInPix()
 *
 *      Input:  kernel
 *              size (of grid interiors; odd; either 1 or a minimum size
 *                    of 17 is enforced)
 *              gthick (grid thickness; either 0 or a minimum size of 2
 *                      is enforced)
 *      Return: pix (display of kernel), or null on error
 *
 *  Notes:
 *      (1) This gives a visual representation of a kernel.
 *      (2) There are two modes of display:
 *          (a) Grid lines of minimum width 2, surrounding regions
 *              representing kernel elements of minimum size 17,
 *              with a "plus" mark at the kernel origin, or
 *          (b) A pix without grid lines and using 1 pixel per kernel element.
 *      (3) For both cases, the kernel absolute value is displayed,
 *          normalized such that the maximum absolute value is 255.
 *      (4) Large 2D separable kernels should be used for convolution
 *          with two 1D kernels.  However, for the bilateral filter,
 *          the computation time is independent of the size of the
 *          2D content kernel.
 */
PIX *
kernelDisplayInPix(L_KERNEL     *kel,
                   l_int32       size,
                   l_int32       gthick)
{
l_int32    i, j, w, h, sx, sy, cx, cy, width, x0, y0;
l_int32    normval;
l_float32  minval, maxval, max, val, norm;
PIX       *pixd, *pixt0, *pixt1;

    PROCNAME("kernelDisplayInPix");

    if (!kel)
        return (PIX *)ERROR_PTR("kernel not defined", procName, NULL);

        /* Normalize the max value to be 255 for display */
    kernelGetParameters(kel, &sy, &sx, &cy, &cx);
    kernelGetMinMax(kel, &minval, &maxval);
    max = L_MAX(maxval, -minval);
    if (max == 0.0)
        return (PIX *)ERROR_PTR("kernel elements all 0.0", procName, NULL);
    norm = 255. / (l_float32)max;

        /* Handle the 1 element/pixel case; typically with large kernels */
    if (size == 1 && gthick == 0) {
        pixd = pixCreate(sx, sy, 8);
        for (i = 0; i < sy; i++) {
            for (j = 0; j < sx; j++) {
                kernelGetElement(kel, i, j, &val);
                normval = (l_int32)(norm * L_ABS(val));
                pixSetPixel(pixd, j, i, normval);
            }
        }
        return pixd;
    }

        /* Enforce the constraints for the grid line version */
    if (size < 17) {
        L_WARNING("size < 17; setting to 17\n", procName);
        size = 17;
    }
    if (size % 2 == 0)
        size++;
    if (gthick < 2) {
        L_WARNING("grid thickness < 2; setting to 2\n", procName);
        gthick = 2;
    }

    w = size * sx + gthick * (sx + 1);
    h = size * sy + gthick * (sy + 1);
    pixd = pixCreate(w, h, 8);

        /* Generate grid lines */
    for (i = 0; i <= sy; i++)
        pixRenderLine(pixd, 0, gthick / 2 + i * (size + gthick),
                      w - 1, gthick / 2 + i * (size + gthick),
                      gthick, L_SET_PIXELS);
    for (j = 0; j <= sx; j++)
        pixRenderLine(pixd, gthick / 2 + j * (size + gthick), 0,
                      gthick / 2 + j * (size + gthick), h - 1,
                      gthick, L_SET_PIXELS);

        /* Generate mask for each element */
    pixt0 = pixCreate(size, size, 1);
    pixSetAll(pixt0);

        /* Generate crossed lines for origin pattern */
    pixt1 = pixCreate(size, size, 1);
    width = size / 8;
    pixRenderLine(pixt1, size / 2, (l_int32)(0.12 * size),
                           size / 2, (l_int32)(0.88 * size),
                           width, L_SET_PIXELS);
    pixRenderLine(pixt1, (l_int32)(0.15 * size), size / 2,
                           (l_int32)(0.85 * size), size / 2,
                           width, L_FLIP_PIXELS);
    pixRasterop(pixt1, size / 2 - width, size / 2 - width,
                2 * width, 2 * width, PIX_NOT(PIX_DST), NULL, 0, 0);

        /* Paste the patterns in */
    y0 = gthick;
    for (i = 0; i < sy; i++) {
        x0 = gthick;
        for (j = 0; j < sx; j++) {
            kernelGetElement(kel, i, j, &val);
            normval = (l_int32)(norm * L_ABS(val));
            pixSetMaskedGeneral(pixd, pixt0, normval, x0, y0);
	    if (i == cy && j == cx)
                pixPaintThroughMask(pixd, pixt1, x0, y0, 255 - normval);
            x0 += size + gthick;
        }
        y0 += size + gthick;
    }

    pixDestroy(&pixt0);
    pixDestroy(&pixt1);
    return pixd;
}
Exemple #27
0
/*!
 * \brief   selaAddCrossJunctions()
 *
 * \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 intersection of two lines.
 *          If the lines are very thin, they must be nearly orthogonal
 *          to register.
 *      (2) The number of Sels generated is equal to %norient.
 *      (3) If %norient == 2, this generates 2 Sels of crosses, each with
 *          two perpendicular lines of hits.  One Sel has horizontal and
 *          vertical hits; the other has hits along lines at +-45 degrees.
 *          Likewise, if %norient == 3, this generates 3 Sels of crosses
 *          oriented at 30 degrees with each other.
 *      (4) 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 *
selaAddCrossJunctions(SELA      *sela,
                      l_float32  hlsize,
                      l_float32  mdist,
                      l_int32    norient,
                      l_int32    debugflag)
{
char       name[L_BUF_SIZE];
l_int32    i, j, w, xc, yc;
l_float64  pi, halfpi, radincr, radang;
l_float64  angle;
PIX       *pixc, *pixm, *pixt;
PIXA      *pixa;
PTA       *pta1, *pta2, *pta3, *pta4;
SEL       *sel;

    PROCNAME("selaAddCrossJunctions");

    if (hlsize <= 0)
        return (SELA *)ERROR_PTR("hlsize not > 0", 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_float64)norient;
    w = (l_int32)(2.2 * (L_MAX(hlsize, mdist) + 0.5));
    if (w % 2 == 0)
        w++;
    xc = w / 2;
    yc = w / 2;

    pixa = pixaCreate(norient);
    for (i = 0; i < norient; i++) {

            /* 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, radang);
        pta2 = generatePtaLineFromPt(xc, yc, hlsize + 1, radang + halfpi);
        pta3 = generatePtaLineFromPt(xc, yc, hlsize + 1, radang + pi);
        pta4 = generatePtaLineFromPt(xc, yc, hlsize + 1, radang + pi + halfpi);
        ptaJoin(pta1, pta2, 0, -1);
        ptaJoin(pta1, pta3, 0, -1);
        ptaJoin(pta1, pta4, 0, -1);
        pixRenderPta(pixm, pta1, L_SET_PIXELS);
        pixPaintThroughMask(pixc, pixm, 0, 0, 0x00ff0000);
        ptaDestroy(&pta1);
        ptaDestroy(&pta2);
        ptaDestroy(&pta3);
        ptaDestroy(&pta4);

            /* Add red misses between the lines */
        for (j = 0; j < 4; j++) {
            angle = radang + (j - 0.5) * halfpi;
            pixSetPixel(pixc, xc + (l_int32)(mdist * cos(angle)),
                        yc + (l_int32)(mdist * sin(angle)), 0xff000000);
        }

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

            /* Generate the sel */
        sel = selCreateFromColorPix(pixc, NULL);
        sprintf(name, "sel_cross_%d", i);
        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, 1, 0, 10, 2);
        pixWrite("/tmp/lept/sel/xsel1.png", pixt, IFF_PNG);
        pixDisplay(pixt, 0, 100);
        pixDestroy(&pixt);
        pixt = selaDisplayInPix(sela, 15, 2, 20, 1);
        pixWrite("/tmp/lept/sel/xsel2.png", pixt, IFF_PNG);
        pixDisplay(pixt, 500, 100);
        pixDestroy(&pixt);
        selaWriteStream(stderr, sela);
    }
    pixaDestroy(&pixa);

    return sela;
}