/*! * pixRasteropHip() * * Input: pixd (in-place operation) * by (top of horizontal band) * bh (height of horizontal band) * hshift (horizontal shift of band; hshift > 0 is to right) * incolor (L_BRING_IN_WHITE, L_BRING_IN_BLACK) * Return: 0 if OK; 1 on error * * Notes: * (1) This rasterop translates a horizontal band of the * image either left or right, bringing in either white * or black pixels from outside the image. * (2) The horizontal band extends the full width of pixd. * (3) If a colormap exists, the nearest color to white or black * is brought in. */ l_int32 pixRasteropHip(PIX *pixd, l_int32 by, l_int32 bh, l_int32 hshift, l_int32 incolor) { l_int32 w, h, d, index, op; PIX *pixt; PIXCMAP *cmap; PROCNAME("pixRasteropHip"); if (!pixd) return ERROR_INT("pixd not defined", procName, 1); if (incolor != L_BRING_IN_WHITE && incolor != L_BRING_IN_BLACK) return ERROR_INT("invalid value for incolor", procName, 1); if (bh <= 0) return ERROR_INT("bh must be > 0", procName, 1); if (hshift == 0) return 0; pixGetDimensions(pixd, &w, &h, &d); rasteropHipLow(pixGetData(pixd), h, d, pixGetWpl(pixd), by, bh, hshift); cmap = pixGetColormap(pixd); if (!cmap) { if ((d == 1 && incolor == L_BRING_IN_BLACK) || (d > 1 && incolor == L_BRING_IN_WHITE)) op = PIX_SET; else op = PIX_CLR; /* Set the pixels brought in at left or right */ if (hshift > 0) pixRasterop(pixd, 0, by, hshift, bh, op, NULL, 0, 0); else /* hshift < 0 */ pixRasterop(pixd, w + hshift, by, -hshift, bh, op, NULL, 0, 0); return 0; } /* Get the nearest index and fill with that */ if (incolor == L_BRING_IN_BLACK) pixcmapGetRankIntensity(cmap, 0.0, &index); else /* white */ pixcmapGetRankIntensity(cmap, 1.0, &index); pixt = pixCreate(L_ABS(hshift), bh, d); pixSetAllArbitrary(pixt, index); if (hshift > 0) pixRasterop(pixd, 0, by, hshift, bh, PIX_SRC, pixt, 0, 0); else /* hshift < 0 */ pixRasterop(pixd, w + hshift, by, -hshift, bh, PIX_SRC, pixt, 0, 0); pixDestroy(&pixt); return 0; }
/*! * pixBilinearColor() * * Input: pixs (32 bpp) * vc (vector of 8 coefficients for bilinear transformation) * colorval (e.g., 0 to bring in BLACK, 0xffffff00 for WHITE) * Return: pixd, or null on error */ PIX * pixBilinearColor(PIX *pixs, l_float32 *vc, l_uint32 colorval) { l_int32 i, j, w, h, d, wpls, wpld; l_uint32 val; l_uint32 *datas, *datad, *lined; l_float32 x, y; PIX *pix1, *pix2, *pixd; PROCNAME("pixBilinearColor"); if (!pixs) return (PIX *) ERROR_PTR("pixs not defined", procName, NULL); pixGetDimensions(pixs, &w, &h, &d); if (d != 32) return (PIX *) ERROR_PTR("pixs must be 32 bpp", procName, NULL); if (!vc) return (PIX *) ERROR_PTR("vc not defined", procName, NULL); datas = pixGetData(pixs); wpls = pixGetWpl(pixs); pixd = pixCreateTemplate(pixs); pixSetAllArbitrary(pixd, colorval); datad = pixGetData(pixd); wpld = pixGetWpl(pixd); /* Iterate over destination pixels */ for (i = 0; i < h; i++) { lined = datad + i * wpld; for (j = 0; j < w; j++) { /* Compute float src pixel location corresponding to (i,j) */ bilinearXformPt(vc, j, i, &x, &y); linearInterpolatePixelColor(datas, wpls, w, h, x, y, colorval, &val); *(lined + j) = val; } } /* If rgba, transform the pixs alpha channel and insert in pixd */ if (pixGetSpp(pixs) == 4) { pix1 = pixGetRGBComponent(pixs, L_ALPHA_CHANNEL); pix2 = pixBilinearGray(pix1, vc, 255); /* bring in opaque */ pixSetRGBComponent(pixd, pix2, L_ALPHA_CHANNEL); pixDestroy(&pix1); pixDestroy(&pix2); } return pixd; }
/*! * pixaDisplayUnsplit() * * Input: pixa * nx (number of mosaic cells horizontally) * ny (number of mosaic cells vertically) * borderwidth (of added border on all sides) * bordercolor (in our RGBA format: 0xrrggbbaa) * Return: pix of tiled images, or null on error * * Notes: * (1) This is a logical inverse of pixaSplitPix(). It * constructs a pix from a mosaic of tiles, all of equal size. * (2) For added generality, a border of arbitrary color can * be added to each of the tiles. * (3) In use, pixa will typically have either been generated * from pixaSplitPix() or will derived from a pixa that * was so generated. * (4) All pix in the pixa must be of equal depth, and, if * colormapped, have the same colormap. */ PIX * pixaDisplayUnsplit(PIXA *pixa, l_int32 nx, l_int32 ny, l_int32 borderwidth, l_uint32 bordercolor) { l_int32 w, h, d, wt, ht; l_int32 i, j, k, x, y, n; PIX *pixt, *pixd; PROCNAME("pixaDisplayUnsplit"); if (!pixa) return (PIX *)ERROR_PTR("pixa not defined", procName, NULL); if (nx <= 0 || ny <= 0) return (PIX *)ERROR_PTR("nx and ny must be > 0", procName, NULL); if ((n = pixaGetCount(pixa)) == 0) return (PIX *)ERROR_PTR("no components", procName, NULL); if (n != nx * ny) return (PIX *)ERROR_PTR("n != nx * ny", procName, NULL); borderwidth = L_MAX(0, borderwidth); pixaGetPixDimensions(pixa, 0, &wt, &ht, &d); w = nx * (wt + 2 * borderwidth); h = ny * (ht + 2 * borderwidth); if ((pixd = pixCreate(w, h, d)) == NULL) return (PIX *)ERROR_PTR("pixd not made", procName, NULL); pixt = pixaGetPix(pixa, 0, L_CLONE); pixCopyColormap(pixd, pixt); pixDestroy(&pixt); if (borderwidth > 0) pixSetAllArbitrary(pixd, bordercolor); y = borderwidth; for (i = 0, k = 0; i < ny; i++) { x = borderwidth; for (j = 0; j < nx; j++, k++) { pixt = pixaGetPix(pixa, k, L_CLONE); pixRasterop(pixd, x, y, wt, ht, PIX_SRC, pixt, 0, 0); pixDestroy(&pixt); x += wt + 2 * borderwidth; } y += ht + 2 * borderwidth; } return pixd; }
/*! * pixInitAccumulate() * * Input: w, h (of accumulate array) * offset (initialize the 32 bpp to have this * value; not more than 0x40000000) * Return: pixd (32 bpp), or null on error * * Notes: * (1) The offset must be >= 0. * (2) The offset is used so that we can do arithmetic * with negative number results on l_uint32 data; it * prevents the l_uint32 data from going negative. * (3) Because we use l_int32 intermediate data results, * these should never exceed the max of l_int32 (0x7fffffff). * We do not permit the offset to be above 0x40000000, * which is half way between 0 and the max of l_int32. * (4) The same offset should be used for initialization, * multiplication by a constant, and final extraction! * (5) If you're only adding positive values, offset can be 0. */ PIX * pixInitAccumulate(l_int32 w, l_int32 h, l_uint32 offset) { PIX *pixd; PROCNAME("pixInitAccumulate"); if ((pixd = pixCreate(w, h, 32)) == NULL) return (PIX *)ERROR_PTR("pixd not made", procName, NULL); if (offset > 0x40000000) offset = 0x40000000; pixSetAllArbitrary(pixd, offset); return pixd; }
// Helper writes a grey image to a file for use by scrollviewer. // Normally for speed we don't display the image in the layout debug windows. // If textord_debug_images is true, we draw the image as a background to some // of the debug windows. printable determines whether these // images are optimized for printing instead of screen display. static void WriteDebugBackgroundImage(bool printable, Pix* pix_binary) { Pix* grey_pix = pixCreate(pixGetWidth(pix_binary), pixGetHeight(pix_binary), 8); // Printable images are light grey on white, but for screen display // they are black on dark grey so the other colors show up well. if (printable) { pixSetAll(grey_pix); pixSetMasked(grey_pix, pix_binary, 192); } else { pixSetAllArbitrary(grey_pix, 64); pixSetMasked(grey_pix, pix_binary, 0); } AlignedBlob::IncrementDebugPix(); pixWrite(AlignedBlob::textord_debug_pix().string(), grey_pix, IFF_PNG); pixDestroy(&grey_pix); }
/*! * pixaSplitPix() * * Input: pixs (with individual components on a lattice) * nx (number of mosaic cells horizontally) * ny (number of mosaic cells vertically) * borderwidth (of added border on all sides) * bordercolor (in our RGBA format: 0xrrggbbaa) * Return: pixa, or null on error * * Notes: * (1) This is a variant on pixaCreateFromPix(), where we * simply divide the image up into (approximately) equal * subunits. If you want the subimages to have essentially * the same aspect ratio as the input pix, use nx = ny. * (2) If borderwidth is 0, we ignore the input bordercolor and * redefine it to white. * (3) The bordercolor is always used to initialize each tiled pix, * so that if the src is clipped, the unblitted part will * be this color. This avoids 1 pixel wide black stripes at the * left and lower edges. */ PIXA * pixaSplitPix(PIX *pixs, l_int32 nx, l_int32 ny, l_int32 borderwidth, l_uint32 bordercolor) { l_int32 w, h, d, cellw, cellh, i, j; PIX *pixt; PIXA *pixa; PROCNAME("pixaSplitPix"); if (!pixs) return (PIXA *)ERROR_PTR("pixs not defined", procName, NULL); if (nx <= 0 || ny <= 0) return (PIXA *)ERROR_PTR("nx and ny must be > 0", procName, NULL); borderwidth = L_MAX(0, borderwidth); if ((pixa = pixaCreate(nx * ny)) == NULL) return (PIXA *)ERROR_PTR("pixa not made", procName, NULL); pixGetDimensions(pixs, &w, &h, &d); cellw = (w + nx - 1) / nx; /* round up */ cellh = (h + ny - 1) / ny; for (i = 0; i < ny; i++) { for (j = 0; j < nx; j++) { if ((pixt = pixCreate(cellw + 2 * borderwidth, cellh + 2 * borderwidth, d)) == NULL) return (PIXA *)ERROR_PTR("pixt not made", procName, NULL); pixCopyColormap(pixt, pixs); if (borderwidth == 0) { /* initialize full image to white */ if (d == 1) pixClearAll(pixt); else pixSetAll(pixt); } else pixSetAllArbitrary(pixt, bordercolor); pixRasterop(pixt, borderwidth, borderwidth, cellw, cellh, PIX_SRC, pixs, j * cellw, i * cellh); pixaAddPix(pixa, pixt, L_INSERT); } } return pixa; }
/*! * pixProjectiveColor() * * Input: pixs (32 bpp) * vc (vector of 8 coefficients for projective transformation) * colorval (e.g., 0 to bring in BLACK, 0xffffff00 for WHITE) * Return: pixd, or null on error */ PIX * pixProjectiveColor(PIX *pixs, l_float32 *vc, l_uint32 colorval) { l_int32 i, j, w, h, d, wpls, wpld; l_uint32 val; l_uint32 *datas, *datad, *lined; l_float32 x, y; PIX *pixd; PROCNAME("pixProjectiveColor"); if (!pixs) return (PIX *)ERROR_PTR("pixs not defined", procName, NULL); pixGetDimensions(pixs, &w, &h, &d); if (d != 32) return (PIX *)ERROR_PTR("pixs must be 32 bpp", procName, NULL); if (!vc) return (PIX *)ERROR_PTR("vc not defined", procName, NULL); datas = pixGetData(pixs); wpls = pixGetWpl(pixs); pixd = pixCreateTemplate(pixs); pixSetAllArbitrary(pixd, colorval); datad = pixGetData(pixd); wpld = pixGetWpl(pixd); /* Iterate over destination pixels */ for (i = 0; i < h; i++) { lined = datad + i * wpld; for (j = 0; j < w; j++) { /* Compute float src pixel location corresponding to (i,j) */ projectiveXformPt(vc, j, i, &x, &y); linearInterpolatePixelColor(datas, wpls, w, h, x, y, colorval, &val); *(lined + j) = val; } } return pixd; }
/*! * pixProjectiveGray() * * Input: pixs (8 bpp) * vc (vector of 8 coefficients for projective transformation) * grayval (0 to bring in BLACK, 255 for WHITE) * Return: pixd, or null on error */ PIX * pixProjectiveGray(PIX *pixs, l_float32 *vc, l_uint8 grayval) { l_int32 i, j, w, h, wpls, wpld, val; l_uint32 *datas, *datad, *lined; l_float32 x, y; PIX *pixd; PROCNAME("pixProjectiveGray"); if (!pixs) return (PIX *)ERROR_PTR("pixs not defined", procName, NULL); pixGetDimensions(pixs, &w, &h, NULL); if (pixGetDepth(pixs) != 8) return (PIX *)ERROR_PTR("pixs must be 8 bpp", procName, NULL); if (!vc) return (PIX *)ERROR_PTR("vc not defined", procName, NULL); datas = pixGetData(pixs); wpls = pixGetWpl(pixs); pixd = pixCreateTemplate(pixs); pixSetAllArbitrary(pixd, grayval); datad = pixGetData(pixd); wpld = pixGetWpl(pixd); /* Iterate over destination pixels */ for (i = 0; i < h; i++) { lined = datad + i * wpld; for (j = 0; j < w; j++) { /* Compute float src pixel location corresponding to (i,j) */ projectiveXformPt(vc, j, i, &x, &y); linearInterpolatePixelGray(datas, wpls, w, h, x, y, grayval, &val); SET_DATA_BYTE(lined, j, val); } } return pixd; }
/*! * wshedCreate() * * Input: pixs (8 bpp source) * pixm (1 bpp 'marker' seed) * mindepth (minimum depth; anything less is not saved) * debugflag (1 for debug output) * Return: WShed, or null on error * * Notes: * (1) It is not necessary for the fg pixels in the seed image * be at minima, or that they be isolated. We extract a * single pixel from each connected component, and a seed * anywhere in a watershed will eventually label the watershed * when the filling level reaches it. * (2) Set mindepth to some value to ignore noise in pixs that * can create small local minima. Any watershed shallower * than mindepth, even if it has a seed, will not be saved; * It will either be incorporated in another watershed or * eliminated. */ L_WSHED * wshedCreate(PIX *pixs, PIX *pixm, l_int32 mindepth, l_int32 debugflag) { l_int32 w, h; L_WSHED *wshed; PROCNAME("wshedCreate"); if (!pixs) return (L_WSHED *)ERROR_PTR("pixs is not defined", procName, NULL); if (pixGetDepth(pixs) != 8) return (L_WSHED *)ERROR_PTR("pixs is not 8 bpp", procName, NULL); if (!pixm) return (L_WSHED *)ERROR_PTR("pixm is not defined", procName, NULL); if (pixGetDepth(pixm) != 1) return (L_WSHED *)ERROR_PTR("pixm is not 1 bpp", procName, NULL); pixGetDimensions(pixs, &w, &h, NULL); if (pixGetWidth(pixm) != w || pixGetHeight(pixm) != h) return (L_WSHED *)ERROR_PTR("pixs/m sizes are unequal", procName, NULL); if ((wshed = (L_WSHED *)CALLOC(1, sizeof(L_WSHED))) == NULL) return (L_WSHED *)ERROR_PTR("wshed not made", procName, NULL); wshed->pixs = pixClone(pixs); wshed->pixm = pixClone(pixm); wshed->mindepth = L_MAX(1, mindepth); wshed->pixlab = pixCreate(w, h, 32); pixSetAllArbitrary(wshed->pixlab, MAX_LABEL_VALUE); wshed->pixt = pixCreate(w, h, 1); wshed->lines8 = pixGetLinePtrs(pixs, NULL); wshed->linem1 = pixGetLinePtrs(pixm, NULL); wshed->linelab32 = pixGetLinePtrs(wshed->pixlab, NULL); wshed->linet1 = pixGetLinePtrs(wshed->pixt, NULL); wshed->debug = debugflag; return wshed; }
/*! * pixaccCreate() * * Input: w, h (of 32 bpp internal Pix) * negflag (0 if only positive numbers are involved; * 1 if there will be negative numbers) * Return: pixacc, or null on error * * Notes: * (1) Use @negflag = 1 for safety if any negative numbers are going * to be used in the chain of operations. Negative numbers * arise, e.g., by subtracting a pix, or by adding a pix * that has been pre-multiplied by a negative number. * (2) Initializes the internal 32 bpp pix, similarly to the * initialization in pixInitAccumulate(). */ PIXACC * pixaccCreate(l_int32 w, l_int32 h, l_int32 negflag) { PIXACC *pixacc; PROCNAME("pixaccCreate"); if ((pixacc = (PIXACC *) CALLOC(1, sizeof(PIXACC))) == NULL) return (PIXACC *) ERROR_PTR("pixacc not made", procName, NULL); pixacc->w = w; pixacc->h = h; if ((pixacc->pix = pixCreate(w, h, 32)) == NULL) return (PIXACC *) ERROR_PTR("pix not made", procName, NULL); if (negflag) { pixacc->offset = 0x40000000; pixSetAllArbitrary(pixacc->pix, pixacc->offset); } return pixacc; }
int main(int argc, char **argv) { char dilateseq[BUF_SIZE], erodeseq[BUF_SIZE]; char openseq[BUF_SIZE], closeseq[BUF_SIZE]; char wtophatseq[BUF_SIZE], btophatseq[BUF_SIZE]; char *filein; l_int32 w, h, d; PIX *pixs, *pixt, *pixt2, *pixt3, *pixt3a, *pixt4; PIX *pixg, *pixd, *pixd1, *pixd2, *pixd3; PIXACC *pacc; PIXCMAP *cmap; static char mainName[] = "graymorph1_reg"; if (argc != 2) return ERROR_INT(" Syntax: graymorph1_reg filein", mainName, 1); filein = argv[1]; if ((pixs = pixRead(filein)) == NULL) return ERROR_INT("pixs not made", mainName, 1); pixGetDimensions(pixs, &w, &h, &d); if (d != 8) return ERROR_INT("pixs not 8 bpp", mainName, 1); /* -------- Test gray morph, including interpreter ------------ */ pixd = pixDilateGray(pixs, WSIZE, HSIZE); sprintf(dilateseq, "D%d.%d", WSIZE, HSIZE); pixg = pixGrayMorphSequence(pixs, dilateseq, HORIZ_SEP, 0); pixCompare(pixd, pixg, "results are the same", "results are different"); pixDestroy(&pixg); pixDestroy(&pixd); pixd = pixErodeGray(pixs, WSIZE, HSIZE); sprintf(erodeseq, "E%d.%d", WSIZE, HSIZE); pixg = pixGrayMorphSequence(pixs, erodeseq, HORIZ_SEP, 100); pixCompare(pixd, pixg, "results are the same", "results are different"); pixDestroy(&pixg); pixDestroy(&pixd); pixd = pixOpenGray(pixs, WSIZE, HSIZE); sprintf(openseq, "O%d.%d", WSIZE, HSIZE); pixg = pixGrayMorphSequence(pixs, openseq, HORIZ_SEP, 200); pixCompare(pixd, pixg, "results are the same", "results are different"); pixDestroy(&pixg); pixDestroy(&pixd); pixd = pixCloseGray(pixs, WSIZE, HSIZE); sprintf(closeseq, "C%d.%d", WSIZE, HSIZE); pixg = pixGrayMorphSequence(pixs, closeseq, HORIZ_SEP, 300); pixCompare(pixd, pixg, "results are the same", "results are different"); pixDestroy(&pixg); pixDestroy(&pixd); pixd = pixTophat(pixs, WSIZE, HSIZE, L_TOPHAT_WHITE); sprintf(wtophatseq, "Tw%d.%d", WSIZE, HSIZE); pixg = pixGrayMorphSequence(pixs, wtophatseq, HORIZ_SEP, 400); pixCompare(pixd, pixg, "results are the same", "results are different"); pixDestroy(&pixg); pixDestroy(&pixd); pixd = pixTophat(pixs, WSIZE, HSIZE, L_TOPHAT_BLACK); sprintf(btophatseq, "Tb%d.%d", WSIZE, HSIZE); pixg = pixGrayMorphSequence(pixs, btophatseq, HORIZ_SEP, 500); pixCompare(pixd, pixg, "results are the same", "results are different"); pixDestroy(&pixg); /* ------------- Test erode/dilate duality -------------- */ pixd = pixDilateGray(pixs, WSIZE, HSIZE); pixInvert(pixs, pixs); pixd2 = pixErodeGray(pixs, WSIZE, HSIZE); pixInvert(pixd2, pixd2); pixCompare(pixd, pixd2, "results are the same", "results are different"); pixDestroy(&pixd); pixDestroy(&pixd2); /* ------------- Test open/close duality -------------- */ pixd = pixOpenGray(pixs, WSIZE, HSIZE); pixInvert(pixs, pixs); pixd2 = pixCloseGray(pixs, WSIZE, HSIZE); pixInvert(pixd2, pixd2); pixCompare(pixd, pixd2, "results are the same", "results are different"); pixDestroy(&pixd); pixDestroy(&pixd2); /* ------------- Test tophat duality -------------- */ pixd = pixTophat(pixs, WSIZE, HSIZE, L_TOPHAT_WHITE); pixInvert(pixs, pixs); pixd2 = pixTophat(pixs, WSIZE, HSIZE, L_TOPHAT_BLACK); pixCompare(pixd, pixd2, "Correct: images are duals", "Error: images are not duals"); pixDestroy(&pixd); pixDestroy(&pixd2); pixInvert(pixs, pixs); pixd = pixGrayMorphSequence(pixs, "Tw9.5", HORIZ_SEP, 100); pixInvert(pixs, pixs); pixd2 = pixGrayMorphSequence(pixs, "Tb9.5", HORIZ_SEP, 300); pixCompare(pixd, pixd2, "Correct: images are duals", "Error: images are not duals"); pixDestroy(&pixd); pixDestroy(&pixd2); /* ------------- Test opening/closing for large sels -------------- */ pixd = pixGrayMorphSequence(pixs, "C9.9 + C19.19 + C29.29 + C39.39 + C49.49", HORIZ_SEP, 100); pixDestroy(&pixd); pixd = pixGrayMorphSequence(pixs, "O9.9 + O19.19 + O29.29 + O39.39 + O49.49", HORIZ_SEP, 400); pixDestroy(&pixd); /* ---------- Closing plus white tophat result ------------ * * Parameters: wsize, hsize = 9, 29 * * ---------------------------------------------------------*/ pixd = pixCloseGray(pixs, 9, 9); pixd1 = pixTophat(pixd, 9, 9, L_TOPHAT_WHITE); pixd2 = pixGrayMorphSequence(pixs, "C9.9 + TW9.9", HORIZ_SEP, 0); pixCompare(pixd1, pixd2, "correct: same", "wrong: different"); pixd3 = pixMaxDynamicRange(pixd1, L_LINEAR_SCALE); pixDisplayWrite(pixd3, 1); pixDestroy(&pixd); pixDestroy(&pixd1); pixDestroy(&pixd2); pixDestroy(&pixd3); pixd = pixCloseGray(pixs, 29, 29); pixd1 = pixTophat(pixd, 29, 29, L_TOPHAT_WHITE); pixd2 = pixGrayMorphSequence(pixs, "C29.29 + Tw29.29", HORIZ_SEP, 0); pixCompare(pixd1, pixd2, "correct: same", "wrong: different"); pixd3 = pixMaxDynamicRange(pixd1, L_LINEAR_SCALE); pixDisplayWrite(pixd3, 1); pixDestroy(&pixd); pixDestroy(&pixd1); pixDestroy(&pixd2); pixDestroy(&pixd3); /* --------- hdome with parameter height = 100 ------------*/ pixd = pixHDome(pixs, 100, 4); pixd2 = pixMaxDynamicRange(pixd, L_LINEAR_SCALE); pixDisplayWrite(pixd2, 1); pixDestroy(&pixd2); /* ----- Contrast enhancement with morph parameters 9, 9 -------*/ pixd1 = pixInitAccumulate(w, h, 0x8000); pixAccumulate(pixd1, pixs, L_ARITH_ADD); pixMultConstAccumulate(pixd1, 3., 0x8000); pixd2 = pixOpenGray(pixs, 9, 9); pixAccumulate(pixd1, pixd2, L_ARITH_SUBTRACT); pixDestroy(&pixd2); pixd2 = pixCloseGray(pixs, 9, 9); pixAccumulate(pixd1, pixd2, L_ARITH_SUBTRACT); pixDestroy(&pixd2); pixd = pixFinalAccumulate(pixd1, 0x8000, 8); pixDisplayWrite(pixd, 1); pixDestroy(&pixd1); /* Do the same thing with the Pixacc */ pacc = pixaccCreate(w, h, 1); pixaccAdd(pacc, pixs); pixaccMultConst(pacc, 3.); pixd1 = pixOpenGray(pixs, 9, 9); pixaccSubtract(pacc, pixd1); pixDestroy(&pixd1); pixd1 = pixCloseGray(pixs, 9, 9); pixaccSubtract(pacc, pixd1); pixDestroy(&pixd1); pixd2 = pixaccFinal(pacc, 8); pixaccDestroy(&pacc); pixDisplayWrite(pixd2, 1); pixCompare(pixd, pixd2, "Correct: same", "Wrong: different"); pixDestroy(&pixd); pixDestroy(&pixd2); /* ---- Tophat result on feynman stamp, to extract diagrams ----- */ pixDestroy(&pixs); pixs = pixRead("feynman-stamp.jpg"); /* Make output image to hold five intermediate images */ w = pixGetWidth(pixs); h = pixGetHeight(pixs); pixd = pixCreate(5 * w + 18, h + 6, 32); /* composite output image */ pixSetAllArbitrary(pixd, 0x0000ff00); /* set to blue */ /* Paste in the input image */ pixt = pixRemoveColormap(pixs, REMOVE_CMAP_TO_FULL_COLOR); pixRasterop(pixd, 3, 3, w, h, PIX_SRC, pixt, 0, 0); /* 1st one */ /* pixWrite("/tmp/junkgray.jpg", pixt, IFF_JFIF_JPEG); */ pixDestroy(&pixt); /* Paste in the grayscale version */ cmap = pixGetColormap(pixs); if (cmap) pixt = pixRemoveColormap(pixs, REMOVE_CMAP_TO_GRAYSCALE); else pixt = pixConvertRGBToGray(pixs, 0.33, 0.34, 0.33); pixt2 = pixConvertTo32(pixt); /* 8 --> 32 bpp */ pixRasterop(pixd, w + 6, 3, w, h, PIX_SRC, pixt2, 0, 0); /* 2nd one */ pixDestroy(&pixt2); /* Paste in a log dynamic range scaled version of the white tophat */ pixt2 = pixTophat(pixt, 3, 3, L_TOPHAT_WHITE); pixt3a = pixMaxDynamicRange(pixt2, L_LOG_SCALE); pixt3 = pixConvertTo32(pixt3a); pixRasterop(pixd, 2 * w + 9, 3, w, h, PIX_SRC, pixt3, 0, 0); /* 3rd */ /* pixWrite("/tmp/junktophat.jpg", pixt2, IFF_JFIF_JPEG); */ pixDestroy(&pixt3); pixDestroy(&pixt3a); pixDestroy(&pixt); /* Stretch the range and threshold to binary; paste it in */ pixt3a = pixGammaTRC(NULL, pixt2, 1.0, 0, 80); pixt3 = pixThresholdToBinary(pixt3a, 70); pixt4 = pixConvertTo32(pixt3); pixRasterop(pixd, 3 * w + 12, 3, w, h, PIX_SRC, pixt4, 0, 0); /* 4th */ /* pixWrite("/tmp/junkbin.png", pixt3, IFF_PNG); */ pixDestroy(&pixt2); pixDestroy(&pixt3a); pixDestroy(&pixt4); /* Invert; this is the final result */ pixInvert(pixt3, pixt3); pixt4 = pixConvertTo32(pixt3); pixRasterop(pixd, 4 * w + 15, 3, w, h, PIX_SRC, pixt4, 0, 0); /* 5th */ pixWrite("/tmp/junkbininvert.png", pixt3, IFF_PNG); pixDisplayWrite(pixd, 1); /* pixWrite("/tmp/junkall.jpg", pixd, IFF_JFIF_JPEG); */ pixDestroy(&pixt3); pixDestroy(&pixt4); pixDestroy(&pixd); pixDisplayMultiple("/tmp/display/file*"); pixDestroy(&pixs); return 0; }
int main(int argc, char **argv) { char dilateseq[512], erodeseq[512]; char openseq[512], closeseq[512]; char wtophatseq[512], btophatseq[512]; l_int32 w, h; PIX *pixs, *pix1, *pix2, *pix3, *pix4, *pix5; PIXA *pixa; PIXACC *pacc; PIXCMAP *cmap; L_REGPARAMS *rp; if (regTestSetup(argc, argv, &rp)) return 1; pixs = pixRead("aneurisms8.jpg"); pixa = pixaCreate(0); /* =========================================================== */ /* -------- Test gray morph, including interpreter ------------ */ pix1 = pixDilateGray(pixs, WSIZE, HSIZE); sprintf(dilateseq, "D%d.%d", WSIZE, HSIZE); pix2 = pixGrayMorphSequence(pixs, dilateseq, 0, 0); regTestWritePixAndCheck(rp, pix1, IFF_PNG); /* 0 */ regTestComparePix(rp, pix1, pix2); /* 1 */ pixaAddPix(pixa, pix1, L_INSERT); pixDestroy(&pix2); pix1 = pixErodeGray(pixs, WSIZE, HSIZE); sprintf(erodeseq, "E%d.%d", WSIZE, HSIZE); pix2 = pixGrayMorphSequence(pixs, erodeseq, 0, 100); regTestWritePixAndCheck(rp, pix1, IFF_PNG); /* 2 */ regTestComparePix(rp, pix1, pix2); /* 3 */ pixaAddPix(pixa, pix1, L_INSERT); pixDestroy(&pix2); pix1 = pixOpenGray(pixs, WSIZE, HSIZE); sprintf(openseq, "O%d.%d", WSIZE, HSIZE); pix2 = pixGrayMorphSequence(pixs, openseq, 0, 200); regTestWritePixAndCheck(rp, pix1, IFF_PNG); /* 4 */ regTestComparePix(rp, pix1, pix2); /* 5 */ pixaAddPix(pixa, pix1, L_INSERT); pixDestroy(&pix2); pix1 = pixCloseGray(pixs, WSIZE, HSIZE); sprintf(closeseq, "C%d.%d", WSIZE, HSIZE); pix2 = pixGrayMorphSequence(pixs, closeseq, 0, 300); regTestWritePixAndCheck(rp, pix1, IFF_PNG); /* 6 */ regTestComparePix(rp, pix1, pix2); /* 7 */ pixaAddPix(pixa, pix1, L_INSERT); pixDestroy(&pix2); pix1 = pixTophat(pixs, WSIZE, HSIZE, L_TOPHAT_WHITE); sprintf(wtophatseq, "Tw%d.%d", WSIZE, HSIZE); pix2 = pixGrayMorphSequence(pixs, wtophatseq, 0, 400); regTestWritePixAndCheck(rp, pix1, IFF_PNG); /* 8 */ regTestComparePix(rp, pix1, pix2); /* 9 */ pixaAddPix(pixa, pix1, L_INSERT); pixDestroy(&pix2); pix1 = pixTophat(pixs, WSIZE, HSIZE, L_TOPHAT_BLACK); sprintf(btophatseq, "Tb%d.%d", WSIZE, HSIZE); pix2 = pixGrayMorphSequence(pixs, btophatseq, 0, 500); regTestWritePixAndCheck(rp, pix1, IFF_PNG); /* 10 */ regTestComparePix(rp, pix1, pix2); /* 11 */ pixaAddPix(pixa, pix1, L_INSERT); pixDestroy(&pix2); /* ------------- Test erode/dilate duality -------------- */ pix1 = pixDilateGray(pixs, WSIZE, HSIZE); pix2 = pixInvert(NULL, pixs); pix3 = pixErodeGray(pix2, WSIZE, HSIZE); pixInvert(pix3, pix3); regTestWritePixAndCheck(rp, pix1, IFF_PNG); /* 12 */ regTestComparePix(rp, pix1, pix3); /* 13 */ pixaAddPix(pixa, pix1, L_INSERT); pixDestroy(&pix2); pixDestroy(&pix3); /* ------------- Test open/close duality -------------- */ pix1 = pixOpenGray(pixs, WSIZE, HSIZE); pix2 = pixInvert(NULL, pixs); pix3 = pixCloseGray(pix2, WSIZE, HSIZE); pixInvert(pix3, pix3); regTestWritePixAndCheck(rp, pix1, IFF_PNG); /* 14 */ regTestComparePix(rp, pix1, pix3); /* 15 */ pixaAddPix(pixa, pix1, L_INSERT); pixDestroy(&pix2); pixDestroy(&pix3); /* ------------- Test tophat duality -------------- */ pix1 = pixTophat(pixs, WSIZE, HSIZE, L_TOPHAT_WHITE); pix2 = pixInvert(NULL, pixs); pix3 = pixTophat(pix2, WSIZE, HSIZE, L_TOPHAT_BLACK); regTestWritePixAndCheck(rp, pix1, IFF_PNG); /* 16 */ regTestComparePix(rp, pix1, pix3); /* 17 */ pixaAddPix(pixa, pix1, L_INSERT); pixDestroy(&pix2); pixDestroy(&pix3); pix1 = pixGrayMorphSequence(pixs, "Tw9.5", 0, 100); pix2 = pixInvert(NULL, pixs); pix3 = pixGrayMorphSequence(pix2, "Tb9.5", 0, 300); regTestWritePixAndCheck(rp, pix1, IFF_PNG); /* 18 */ regTestComparePix(rp, pix1, pix3); /* 19 */ pixaAddPix(pixa, pix1, L_INSERT); pixDestroy(&pix2); pixDestroy(&pix3); /* ------------- Test opening/closing for large sels -------------- */ pix1 = pixGrayMorphSequence(pixs, "C9.9 + C19.19 + C29.29 + C39.39 + C49.49", 0, 100); regTestWritePixAndCheck(rp, pix1, IFF_PNG); /* 20 */ pixaAddPix(pixa, pix1, L_INSERT); pix1 = pixGrayMorphSequence(pixs, "O9.9 + O19.19 + O29.29 + O39.39 + O49.49", 0, 400); regTestWritePixAndCheck(rp, pix1, IFF_PNG); /* 21 */ pixaAddPix(pixa, pix1, L_INSERT); pix1 = pixaDisplayTiledInColumns(pixa, 4, 1.0, 20, 2); regTestWritePixAndCheck(rp, pix1, IFF_PNG); /* 22 */ pixDisplayWithTitle(pix1, 0, 0, NULL, rp->display); pixaDestroy(&pixa); pixDestroy(&pix1); /* =========================================================== */ pixa = pixaCreate(0); /* ---------- Closing plus white tophat result ------------ * * Parameters: wsize, hsize = 9, 29 * * ---------------------------------------------------------*/ pix1 = pixCloseGray(pixs, 9, 9); pix2 = pixTophat(pix1, 9, 9, L_TOPHAT_WHITE); pix3 = pixGrayMorphSequence(pixs, "C9.9 + TW9.9", 0, 0); regTestWritePixAndCheck(rp, pix1, IFF_PNG); /* 23 */ regTestComparePix(rp, pix2, pix3); /* 24 */ pixaAddPix(pixa, pix1, L_INSERT); pix1 = pixMaxDynamicRange(pix2, L_LINEAR_SCALE); regTestWritePixAndCheck(rp, pix1, IFF_PNG); /* 25 */ pixaAddPix(pixa, pix1, L_INSERT); pixDestroy(&pix2); pixDestroy(&pix3); pix1 = pixCloseGray(pixs, 29, 29); pix2 = pixTophat(pix1, 29, 29, L_TOPHAT_WHITE); pix3 = pixGrayMorphSequence(pixs, "C29.29 + Tw29.29", 0, 0); regTestWritePixAndCheck(rp, pix1, IFF_PNG); /* 26 */ regTestComparePix(rp, pix2, pix3); /* 27 */ pixaAddPix(pixa, pix1, L_INSERT); pix1 = pixMaxDynamicRange(pix2, L_LINEAR_SCALE); regTestWritePixAndCheck(rp, pix1, IFF_PNG); /* 28 */ pixaAddPix(pixa, pix1, L_INSERT); pixDestroy(&pix2); pixDestroy(&pix3); /* --------- hdome with parameter height = 100 ------------*/ pix1 = pixHDome(pixs, 100, 4); pix2 = pixMaxDynamicRange(pix1, L_LINEAR_SCALE); regTestWritePixAndCheck(rp, pix1, IFF_PNG); /* 29 */ regTestWritePixAndCheck(rp, pix2, IFF_PNG); /* 30 */ pixaAddPix(pixa, pix1, L_INSERT); pixaAddPix(pixa, pix2, L_INSERT); /* ----- Contrast enhancement with morph parameters 9, 9 -------*/ pixGetDimensions(pixs, &w, &h, NULL); pix1 = pixInitAccumulate(w, h, 0x8000); pixAccumulate(pix1, pixs, L_ARITH_ADD); pixMultConstAccumulate(pix1, 3., 0x8000); pix2 = pixOpenGray(pixs, 9, 9); regTestWritePixAndCheck(rp, pix2, IFF_PNG); /* 31 */ pixaAddPix(pixa, pix2, L_INSERT); pixAccumulate(pix1, pix2, L_ARITH_SUBTRACT); pix2 = pixCloseGray(pixs, 9, 9); regTestWritePixAndCheck(rp, pix2, IFF_PNG); /* 32 */ pixaAddPix(pixa, pix2, L_INSERT); pixAccumulate(pix1, pix2, L_ARITH_SUBTRACT); pix2 = pixFinalAccumulate(pix1, 0x8000, 8); regTestWritePixAndCheck(rp, pix2, IFF_PNG); /* 33 */ pixaAddPix(pixa, pix2, L_INSERT); pixDestroy(&pix1); /* Do the same thing with the Pixacc */ pacc = pixaccCreate(w, h, 1); pixaccAdd(pacc, pixs); pixaccMultConst(pacc, 3.); pix1 = pixOpenGray(pixs, 9, 9); pixaccSubtract(pacc, pix1); pixDestroy(&pix1); pix1 = pixCloseGray(pixs, 9, 9); pixaccSubtract(pacc, pix1); pixDestroy(&pix1); pix1 = pixaccFinal(pacc, 8); pixaccDestroy(&pacc); regTestWritePixAndCheck(rp, pix1, IFF_PNG); /* 34 */ pixaAddPix(pixa, pix1, L_INSERT); regTestComparePix(rp, pix1, pix2); /* 35 */ pix1 = pixaDisplayTiledInColumns(pixa, 4, 1.0, 20, 2); regTestWritePixAndCheck(rp, pix1, IFF_PNG); /* 36 */ pixDisplayWithTitle(pix1, 1100, 0, NULL, rp->display); pixaDestroy(&pixa); pixDestroy(&pix1); pixDestroy(&pixs); /* =========================================================== */ pixa = pixaCreate(0); /* ---- Tophat result on feynman stamp, to extract diagrams ----- */ pixs = pixRead("feynman-stamp.jpg"); pixGetDimensions(pixs, &w, &h, NULL); /* Make output image to hold five intermediate images */ pix1 = pixCreate(5 * w + 18, h + 6, 32); /* composite output image */ pixSetAllArbitrary(pix1, 0x0000ff00); /* set to blue */ /* Paste in the input image */ pix2 = pixRemoveColormap(pixs, REMOVE_CMAP_TO_FULL_COLOR); pixRasterop(pix1, 3, 3, w, h, PIX_SRC, pix2, 0, 0); /* 1st one */ regTestWritePixAndCheck(rp, pix2, IFF_PNG); /* 37 */ pixaAddPix(pixa, pix2, L_INSERT); /* Paste in the grayscale version */ cmap = pixGetColormap(pixs); if (cmap) pix2 = pixRemoveColormap(pixs, REMOVE_CMAP_TO_GRAYSCALE); else pix2 = pixConvertRGBToGray(pixs, 0.33, 0.34, 0.33); pix3 = pixConvertTo32(pix2); /* 8 --> 32 bpp */ pixRasterop(pix1, w + 6, 3, w, h, PIX_SRC, pix3, 0, 0); /* 2nd one */ regTestWritePixAndCheck(rp, pix3, IFF_PNG); /* 38 */ pixaAddPix(pixa, pix3, L_INSERT); /* Paste in a log dynamic range scaled version of the white tophat */ pix3 = pixTophat(pix2, 3, 3, L_TOPHAT_WHITE); pix4 = pixMaxDynamicRange(pix3, L_LOG_SCALE); pix5 = pixConvertTo32(pix4); pixRasterop(pix1, 2 * w + 9, 3, w, h, PIX_SRC, pix5, 0, 0); /* 3rd */ regTestWritePixAndCheck(rp, pix5, IFF_PNG); /* 39 */ pixaAddPix(pixa, pix5, L_INSERT); pixDestroy(&pix2); pixDestroy(&pix4); /* Stretch the range and threshold to binary; paste it in */ pix2 = pixGammaTRC(NULL, pix3, 1.0, 0, 80); pix4 = pixThresholdToBinary(pix2, 70); pix5 = pixConvertTo32(pix4); pixRasterop(pix1, 3 * w + 12, 3, w, h, PIX_SRC, pix5, 0, 0); /* 4th */ regTestWritePixAndCheck(rp, pix5, IFF_PNG); /* 40 */ pixaAddPix(pixa, pix5, L_INSERT); pixDestroy(&pix2); pixDestroy(&pix3); /* Invert; this is the final result */ pixInvert(pix4, pix4); pix5 = pixConvertTo32(pix4); pixRasterop(pix1, 4 * w + 15, 3, w, h, PIX_SRC, pix5, 0, 0); /* 5th */ regTestWritePixAndCheck(rp, pix5, IFF_PNG); /* 41 */ pixaAddPix(pixa, pix5, L_INSERT); pixDestroy(&pix1); pixDestroy(&pix4); pix1 = pixaDisplayTiledInRows(pixa, 32, 1700, 1.0, 0, 20, 2); regTestWritePixAndCheck(rp, pix1, IFF_PNG); /* 42 */ pixDisplayWithTitle(pix1, 0, 800, NULL, rp->display); pixaDestroy(&pixa); pixDestroy(&pix1); pixDestroy(&pixs); return regTestCleanup(rp); }
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); }
int main(int argc, char **argv) { char label[512]; l_int32 rval, gval, bval, w, h, i, j, rwhite, gwhite, bwhite, count; l_uint32 pixel; GPLOT *gplot1, *gplot2; NUMA *naseq, *na; NUMAA *naa1, *naa2; PIX *pixs, *pixt, *pixt0, *pixt1, *pixt2; PIX *pixr, *pixg, *pixb; /* for color content extraction */ PIXA *pixa, *pixat; PIXCMAP *cmap; L_REGPARAMS *rp; if (regTestSetup(argc, argv, &rp)) return 1; /* Generate a pdf of results when called with display */ pixa = pixaCreate(0); /* Generate colors by sampling hue with max sat and value. * This image has been saved as 19-colors.png. */ pixat = pixaCreate(19); for (i = 0; i < 19; i++) { convertHSVToRGB((240 * i / 18), 255, 255, &rval, &gval, &bval); composeRGBPixel(rval, gval, bval, &pixel); pixt1 = pixCreate(50, 100, 32); pixSetAllArbitrary(pixt1, pixel); pixaAddPix(pixat, pixt1, L_INSERT); } pixt2 = pixaDisplayTiledInRows(pixat, 32, 1100, 1.0, 0, 0, 0); regTestWritePixAndCheck(rp, pixt2, IFF_PNG); /* 0 */ pixaAddPix(pixa, pixt2, L_INSERT); pixaDestroy(&pixat); /* Colorspace conversion in rgb */ pixs = pixRead("wyom.jpg"); pixaAddPix(pixa, pixs, L_INSERT); pixt = pixConvertRGBToHSV(NULL, pixs); regTestWritePixAndCheck(rp, pixt, IFF_JFIF_JPEG); /* 1 */ pixaAddPix(pixa, pixt, L_COPY); pixConvertHSVToRGB(pixt, pixt); regTestWritePixAndCheck(rp, pixt, IFF_JFIF_JPEG); /* 2 */ pixaAddPix(pixa, pixt, L_INSERT); /* Colorspace conversion on a colormap */ pixt = pixOctreeQuantNumColors(pixs, 25, 0); regTestWritePixAndCheck(rp, pixt, IFF_JFIF_JPEG); /* 3 */ pixaAddPix(pixa, pixt, L_COPY); cmap = pixGetColormap(pixt); if (rp->display) pixcmapWriteStream(stderr, cmap); pixcmapConvertRGBToHSV(cmap); if (rp->display) pixcmapWriteStream(stderr, cmap); regTestWritePixAndCheck(rp, pixt, IFF_JFIF_JPEG); /* 4 */ pixaAddPix(pixa, pixt, L_COPY); pixcmapConvertHSVToRGB(cmap); if (rp->display) pixcmapWriteStream(stderr, cmap); regTestWritePixAndCheck(rp, pixt, IFF_JFIF_JPEG); /* 5 */ pixaAddPix(pixa, pixt, L_INSERT); /* Color content extraction */ pixColorContent(pixs, 0, 0, 0, 0, &pixr, &pixg, &pixb); regTestWritePixAndCheck(rp, pixr, IFF_JFIF_JPEG); /* 6 */ pixaAddPix(pixa, pixr, L_INSERT); regTestWritePixAndCheck(rp, pixg, IFF_JFIF_JPEG); /* 7 */ pixaAddPix(pixa, pixg, L_INSERT); regTestWritePixAndCheck(rp, pixb, IFF_JFIF_JPEG); /* 8 */ pixaAddPix(pixa, pixb, L_INSERT); /* Color content measurement. This tests the global * mapping of (r,g,b) --> (white), for 20 different * values of (r,g,b). For each mappings, we compute * the color magnitude and threshold it at six values. * For each of those six thresholds, we plot the * fraction of pixels that exceeds the threshold * color magnitude, where the red value (mapped to * white) goes between 100 and 195. */ pixat = pixaCreate(20); naseq = numaMakeSequence(100, 5, 20); naa1 = numaaCreate(6); naa2 = numaaCreate(6); for (i = 0; i < 6; i++) { na = numaCreate(20); numaaAddNuma(naa1, na, L_COPY); numaaAddNuma(naa2, na, L_INSERT); } pixGetDimensions(pixs, &w, &h, NULL); for (i = 0; i < 20; i++) { rwhite = 100 + 5 * i; gwhite = 200 - 5 * i; bwhite = 150; pixt0 = pixGlobalNormRGB(NULL, pixs, rwhite, gwhite, bwhite, 255); pixaAddPix(pixat, pixt0, L_INSERT); pixt1 = pixColorMagnitude(pixs, rwhite, gwhite, bwhite, L_MAX_DIFF_FROM_AVERAGE_2); for (j = 0; j < 6; j++) { pixt2 = pixThresholdToBinary(pixt1, 30 + 10 * j); pixInvert(pixt2, pixt2); pixCountPixels(pixt2, &count, NULL); na = numaaGetNuma(naa1, j, L_CLONE); numaAddNumber(na, (l_float32)count / (l_float32)(w * h)); numaDestroy(&na); pixDestroy(&pixt2); } pixDestroy(&pixt1); pixt1 = pixColorMagnitude(pixs, rwhite, gwhite, bwhite, L_MAX_MIN_DIFF_FROM_2); for (j = 0; j < 6; j++) { pixt2 = pixThresholdToBinary(pixt1, 30 + 10 * j); pixInvert(pixt2, pixt2); pixCountPixels(pixt2, &count, NULL); na = numaaGetNuma(naa2, j, L_CLONE); numaAddNumber(na, (l_float32)count / (l_float32)(w * h)); numaDestroy(&na); pixDestroy(&pixt2); } pixDestroy(&pixt1); } gplot1 = gplotCreate("/tmp/regout/colorspace.10", GPLOT_PNG, "Fraction with given color (diff from average)", "white point space for red", "amount of color"); gplot2 = gplotCreate("/tmp/regout/colorspace.11", GPLOT_PNG, "Fraction with given color (min diff)", "white point space for red", "amount of color"); for (j = 0; j < 6; j++) { na = numaaGetNuma(naa1, j, L_CLONE); sprintf(label, "thresh %d", 30 + 10 * j); gplotAddPlot(gplot1, naseq, na, GPLOT_LINES, label); numaDestroy(&na); na = numaaGetNuma(naa2, j, L_CLONE); gplotAddPlot(gplot2, naseq, na, GPLOT_LINES, label); numaDestroy(&na); } gplotMakeOutput(gplot1); gplotMakeOutput(gplot2); gplotDestroy(&gplot1); gplotDestroy(&gplot2); pixt1 = pixaDisplayTiledAndScaled(pixat, 32, 250, 4, 0, 10, 2); regTestWritePixAndCheck(rp, pixt1, IFF_JFIF_JPEG); /* 9 */ pixaAddPix(pixa, pixt1, L_INSERT); pixDisplayWithTitle(pixt1, 0, 100, "Color magnitude", rp->display); pixaDestroy(&pixat); numaDestroy(&naseq); numaaDestroy(&naa1); numaaDestroy(&naa2); /* Give gnuplot time to write out the files */ #ifndef _WIN32 sleep(1); #else Sleep(1000); #endif /* _WIN32 */ /* Save as golden files, or check against them */ regTestCheckFile(rp, "/tmp/regout/colorspace.10.png"); /* 10 */ regTestCheckFile(rp, "/tmp/regout/colorspace.11.png"); /* 11 */ if (rp->display) { pixt = pixRead("/tmp/regout/colorspace.10.png"); pixaAddPix(pixa, pixt, L_INSERT); pixt = pixRead("/tmp/regout/colorspace.11.png"); pixaAddPix(pixa, pixt, L_INSERT); pixaConvertToPdf(pixa, 0, 1.0, 0, 0, "colorspace tests", "/tmp/regout/colorspace.pdf"); L_INFO("Output pdf: /tmp/regout/colorspace.pdf\n", rp->testname); } pixaDestroy(&pixa); return regTestCleanup(rp); }
int main(int argc, char **argv) { char label[512]; l_int32 rval, gval, bval, w, h, i, j, rwhite, gwhite, bwhite, count; l_uint32 pixel; GPLOT *gplot1, *gplot2; NUMA *naseq, *na; NUMAA *naa1, *naa2; PIX *pixs, *pixt, *pixt0, *pixt1, *pixt2; PIX *pixr, *pixg, *pixb; PIXA *pixa; PIXCMAP *cmap; static char mainName[] = "colorspacetest"; if (argc != 2) return ERROR_INT(" Syntax: colorspacetest filein", mainName, 1); if ((pixs = pixRead(argv[1])) == NULL) return ERROR_INT("pixs not made", mainName, 1); /* Generate colors by sampling hue with max sat and value. * This was used to make the color strip 19-colors.png. */ pixa = pixaCreate(19); for (i = 0; i < 19; i++) { convertHSVToRGB((240 * i / 18), 255, 255, &rval, &gval, &bval); composeRGBPixel(rval, gval, bval, &pixel); pixt1 = pixCreate(50, 100, 32); pixSetAllArbitrary(pixt1, pixel); pixaAddPix(pixa, pixt1, L_INSERT); } pixt2 = pixaDisplayTiledInRows(pixa, 32, 1100, 1.0, 0, 0, 0); pixDisplayWrite(pixt2, 1); pixDestroy(&pixt2); pixaDestroy(&pixa); /* Colorspace conversion in rgb */ pixDisplayWrite(pixs, 1); pixt = pixConvertRGBToHSV(NULL, pixs); pixDisplayWrite(pixt, 1); pixConvertHSVToRGB(pixt, pixt); pixDisplayWrite(pixt, 1); pixDestroy(&pixt); /* Colorspace conversion on a colormap */ pixt = pixOctreeQuantNumColors(pixs, 25, 0); pixDisplayWrite(pixt, 1); cmap = pixGetColormap(pixt); pixcmapWriteStream(stderr, cmap); pixcmapConvertRGBToHSV(cmap); pixcmapWriteStream(stderr, cmap); pixDisplayWrite(pixt, 1); pixcmapConvertHSVToRGB(cmap); pixcmapWriteStream(stderr, cmap); pixDisplayWrite(pixt, 1); pixDestroy(&pixt); /* Color content extraction */ pixColorContent(pixs, 0, 0, 0, 0, &pixr, &pixg, &pixb); pixDisplayWrite(pixr, 1); pixDisplayWrite(pixg, 1); pixDisplayWrite(pixb, 1); pixDestroy(&pixr); pixDestroy(&pixg); pixDestroy(&pixb); /* Color content measurement */ pixa = pixaCreate(20); naseq = numaMakeSequence(100, 5, 20); naa1 = numaaCreate(6); naa2 = numaaCreate(6); for (i = 0; i < 6; i++) { na = numaCreate(20); numaaAddNuma(naa1, na, L_COPY); numaaAddNuma(naa2, na, L_INSERT); } pixGetDimensions(pixs, &w, &h, NULL); for (i = 0; i < 20; i++) { rwhite = 100 + 5 * i; gwhite = 200 - 5 * i; bwhite = 150; pixt0 = pixGlobalNormRGB(NULL, pixs, rwhite, gwhite, bwhite, 255); pixaAddPix(pixa, pixt0, L_INSERT); pixt1 = pixColorMagnitude(pixs, rwhite, gwhite, bwhite, L_MAX_DIFF_FROM_AVERAGE_2); for (j = 0; j < 6; j++) { pixt2 = pixThresholdToBinary(pixt1, 30 + 10 * j); pixInvert(pixt2, pixt2); pixCountPixels(pixt2, &count, NULL); na = numaaGetNuma(naa1, j, L_CLONE); numaAddNumber(na, (l_float32)count / (l_float32)(w * h)); numaDestroy(&na); pixDestroy(&pixt2); } pixDestroy(&pixt1); pixt1 = pixColorMagnitude(pixs, rwhite, gwhite, bwhite, L_MAX_MIN_DIFF_FROM_2); for (j = 0; j < 6; j++) { pixt2 = pixThresholdToBinary(pixt1, 30 + 10 * j); pixInvert(pixt2, pixt2); pixCountPixels(pixt2, &count, NULL); na = numaaGetNuma(naa2, j, L_CLONE); numaAddNumber(na, (l_float32)count / (l_float32)(w * h)); numaDestroy(&na); pixDestroy(&pixt2); } pixDestroy(&pixt1); } gplot1 = gplotCreate("/tmp/junkplot1", GPLOT_X11, "Fraction with given color (diff from average)", "white point space for red", "amount of color"); gplot2 = gplotCreate("/tmp/junkplot2", GPLOT_X11, "Fraction with given color (min diff)", "white point space for red", "amount of color"); for (j = 0; j < 6; j++) { na = numaaGetNuma(naa1, j, L_CLONE); sprintf(label, "thresh %d", 30 + 10 * j); gplotAddPlot(gplot1, naseq, na, GPLOT_LINES, label); numaDestroy(&na); na = numaaGetNuma(naa2, j, L_CLONE); gplotAddPlot(gplot2, naseq, na, GPLOT_LINES, label); numaDestroy(&na); } gplotMakeOutput(gplot1); gplotMakeOutput(gplot2); gplotDestroy(&gplot1); gplotDestroy(&gplot2); pixt1 = pixaDisplayTiledAndScaled(pixa, 32, 250, 4, 0, 10, 2); pixWrite("/tmp/junkcolormag", pixt1, IFF_PNG); pixDisplayWithTitle(pixt1, 0, 100, "Color magnitude", 1); pixDestroy(&pixt1); pixaDestroy(&pixa); numaDestroy(&naseq); numaaDestroy(&naa1); numaaDestroy(&naa2); pixDisplayMultiple("/tmp/display/file*"); pixDestroy(&pixs); return 0; }
/*! * pixaDisplayOnColor() * * Input: pixa * w, h (if set to 0, determines the size from the * b.b. of the components in pixa) * color (background color to use) * Return: pix, or null on error * * Notes: * (1) This uses the boxes to place each pix in the rendered composite. * (2) Set w = h = 0 to use the b.b. of the components to determine * the size of the returned pix. * (3) If any pix in @pixa are colormapped, or if the pix have * different depths, it returns a 32 bpp pix. Otherwise, * the depth of the returned pixa equals that of the pix in @pixa. * (4) If the pixa is empty, return null. */ PIX * pixaDisplayOnColor(PIXA *pixa, l_int32 w, l_int32 h, l_uint32 bgcolor) { l_int32 i, n, xb, yb, wb, hb, hascmap, maxdepth, same; BOXA *boxa; PIX *pixt1, *pixt2, *pixd; PIXA *pixat; PROCNAME("pixaDisplayOnColor"); if (!pixa) return (PIX *)ERROR_PTR("pixa not defined", procName, NULL); if ((n = pixaGetCount(pixa)) == 0) return (PIX *)ERROR_PTR("no components", procName, NULL); /* If w and h are not input, determine the minimum size * required to contain the origin and all c.c. */ if (w == 0 || h == 0) { boxa = pixaGetBoxa(pixa, L_CLONE); boxaGetExtent(boxa, &w, &h, NULL); boxaDestroy(&boxa); } /* If any pix have colormaps, or if they have different depths, * generate rgb */ pixaAnyColormaps(pixa, &hascmap); pixaGetDepthInfo(pixa, &maxdepth, &same); if (hascmap || !same) { maxdepth = 32; pixat = pixaCreate(n); for (i = 0; i < n; i++) { pixt1 = pixaGetPix(pixa, i, L_CLONE); pixt2 = pixConvertTo32(pixt1); pixaAddPix(pixat, pixt2, L_INSERT); pixDestroy(&pixt1); } } else pixat = pixaCopy(pixa, L_CLONE); /* Make the output pix and set the background color */ if ((pixd = pixCreate(w, h, maxdepth)) == NULL) return (PIX *)ERROR_PTR("pixd not made", procName, NULL); if ((maxdepth == 1 && bgcolor > 0) || (maxdepth == 2 && bgcolor >= 0x3) || (maxdepth == 4 && bgcolor >= 0xf) || (maxdepth == 8 && bgcolor >= 0xff) || (maxdepth == 16 && bgcolor >= 0xffff) || (maxdepth == 32 && bgcolor >= 0xffffff00)) { pixSetAll(pixd); } else if (bgcolor > 0) pixSetAllArbitrary(pixd, bgcolor); /* Blit each pix into its place */ for (i = 0; i < n; i++) { if (pixaGetBoxGeometry(pixat, i, &xb, &yb, &wb, &hb)) { L_WARNING("no box found!", procName); continue; } pixt1 = pixaGetPix(pixat, i, L_CLONE); pixRasterop(pixd, xb, yb, wb, hb, PIX_SRC, pixt1, 0, 0); pixDestroy(&pixt1); } pixaDestroy(&pixat); return pixd; }
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; }
/*! * pixProjectivePtaWithAlpha() * * Input: pixs (32 bpp rgb) * ptad (4 pts of final coordinate space) * ptas (4 pts of initial coordinate space) * pixg (<optional> 8 bpp, for alpha channel, can be null) * fract (between 0.0 and 1.0, with 0.0 fully transparent * and 1.0 fully opaque) * border (of pixels added to capture transformed source pixels) * Return: pixd, or null on error * * Notes: * (1) The alpha channel is transformed separately from pixs, * and aligns with it, being fully transparent outside the * boundary of the transformed pixs. For pixels that are fully * transparent, a blending function like pixBlendWithGrayMask() * will give zero weight to corresponding pixels in pixs. * (2) If pixg is NULL, it is generated as an alpha layer that is * partially opaque, using @fract. Otherwise, it is cropped * to pixs if required and @fract is ignored. The alpha channel * in pixs is never used. * (3) Colormaps are removed. * (4) When pixs is transformed, it doesn't matter what color is brought * in because the alpha channel will be transparent (0) there. * (5) To avoid losing source pixels in the destination, it may be * necessary to add a border to the source pix before doing * the projective transformation. This can be any non-negative * number. * (6) The input @ptad and @ptas are in a coordinate space before * the border is added. Internally, we compensate for this * before doing the projective transform on the image after * the border is added. * (7) The default setting for the border values in the alpha channel * is 0 (transparent) for the outermost ring of pixels and * (0.5 * fract * 255) for the second ring. When blended over * a second image, this * (a) shrinks the visible image to make a clean overlap edge * with an image below, and * (b) softens the edges by weakening the aliasing there. * Use l_setAlphaMaskBorder() to change these values. */ PIX * pixProjectivePtaWithAlpha(PIX *pixs, PTA *ptad, PTA *ptas, PIX *pixg, l_float32 fract, l_int32 border) { l_int32 ws, hs, d; PIX *pixd, *pixb1, *pixb2, *pixg2, *pixga; PTA *ptad2, *ptas2; PROCNAME("pixProjectivePtaWithAlpha"); if (!pixs) return (PIX *)ERROR_PTR("pixs not defined", procName, NULL); pixGetDimensions(pixs, &ws, &hs, &d); if (d != 32 && pixGetColormap(pixs) == NULL) return (PIX *)ERROR_PTR("pixs not cmapped or 32 bpp", procName, NULL); if (pixg && pixGetDepth(pixg) != 8) { L_WARNING("pixg not 8 bpp; using @fract transparent alpha", procName); pixg = NULL; } if (!pixg && (fract < 0.0 || fract > 1.0)) { L_WARNING("invalid fract; using 1.0 (fully transparent)", procName); fract = 1.0; } if (!pixg && fract == 0.0) L_WARNING("fully opaque alpha; image will not be blended", procName); if (!ptad) return (PIX *)ERROR_PTR("ptad not defined", procName, NULL); if (!ptas) return (PIX *)ERROR_PTR("ptas not defined", procName, NULL); /* Add border; the color doesn't matter */ pixb1 = pixAddBorder(pixs, border, 0); /* Transform the ptr arrays to work on the bordered image */ ptad2 = ptaTransform(ptad, border, border, 1.0, 1.0); ptas2 = ptaTransform(ptas, border, border, 1.0, 1.0); /* Do separate projective transform of rgb channels of pixs * and of pixg */ pixd = pixProjectivePtaColor(pixb1, ptad2, ptas2, 0); if (!pixg) { pixg2 = pixCreate(ws, hs, 8); if (fract == 1.0) pixSetAll(pixg2); else pixSetAllArbitrary(pixg2, (l_int32)(255.0 * fract)); } else pixg2 = pixResizeToMatch(pixg, NULL, ws, hs); if (ws > 10 && hs > 10) { /* see note 7 */ pixSetBorderRingVal(pixg2, 1, (l_int32)(255.0 * fract * AlphaMaskBorderVals[0])); pixSetBorderRingVal(pixg2, 2, (l_int32)(255.0 * fract * AlphaMaskBorderVals[1])); } pixb2 = pixAddBorder(pixg2, border, 0); /* must be black border */ pixga = pixProjectivePtaGray(pixb2, ptad2, ptas2, 0); pixSetRGBComponent(pixd, pixga, L_ALPHA_CHANNEL); pixDestroy(&pixg2); pixDestroy(&pixb1); pixDestroy(&pixb2); pixDestroy(&pixga); ptaDestroy(&ptad2); ptaDestroy(&ptas2); return pixd; }
/*! * pixRotateWithAlpha() * * Input: pixs (32 bpp rgb or cmapped) * angle (radians; clockwise is positive) * pixg (<optional> 8 bpp, can be null) * fract (between 0.0 and 1.0, with 0.0 fully transparent * and 1.0 fully opaque) * Return: pixd (32 bpp rgba), or null on error * * Notes: * (1) The alpha channel is transformed separately from pixs, * and aligns with it, being fully transparent outside the * boundary of the transformed pixs. For pixels that are fully * transparent, a blending function like pixBlendWithGrayMask() * will give zero weight to corresponding pixels in pixs. * (2) Rotation is about the center of the image; for very small * rotations, just return a clone. The dest is automatically * expanded so that no image pixels are lost. * (3) Rotation is by area mapping. It doesn't matter what * color is brought in because the alpha channel will * be transparent (black) there. * (4) If pixg is NULL, it is generated as an alpha layer that is * partially opaque, using @fract. Otherwise, it is cropped * to pixs if required and @fract is ignored. The alpha * channel in pixs is never used. * (4) Colormaps are removed to 32 bpp. * (5) The default setting for the border values in the alpha channel * is 0 (transparent) for the outermost ring of pixels and * (0.5 * fract * 255) for the second ring. When blended over * a second image, this * (a) shrinks the visible image to make a clean overlap edge * with an image below, and * (b) softens the edges by weakening the aliasing there. * Use l_setAlphaMaskBorder() to change these values. * (6) A subtle use of gamma correction is to remove gamma correction * before rotation and restore it afterwards. This is done * by sandwiching this function between a gamma/inverse-gamma * photometric transform: * pixt = pixGammaTRCWithAlpha(NULL, pixs, 1.0 / gamma, 0, 255); * pixd = pixRotateWithAlpha(pixt, angle, NULL, fract); * pixGammaTRCWithAlpha(pixd, pixd, gamma, 0, 255); * pixDestroy(&pixt); * This has the side-effect of producing artifacts in the very * dark regions. * * *** Warning: implicit assumption about RGB component ordering *** */ PIX * pixRotateWithAlpha(PIX *pixs, l_float32 angle, PIX *pixg, l_float32 fract) { l_int32 ws, hs, d, spp; PIX *pixd, *pix32, *pixg2, *pixgr; PROCNAME("pixRotateWithAlpha"); if (!pixs) return (PIX *) ERROR_PTR("pixs not defined", procName, NULL); pixGetDimensions(pixs, &ws, &hs, &d); if (d != 32 && pixGetColormap(pixs) == NULL) return (PIX *) ERROR_PTR("pixs not cmapped or 32 bpp", procName, NULL); if (pixg && pixGetDepth(pixg) != 8) { L_WARNING("pixg not 8 bpp; using @fract transparent alpha\n", procName); pixg = NULL; } if (!pixg && (fract < 0.0 || fract > 1.0)) { L_WARNING("invalid fract; using fully opaque\n", procName); fract = 1.0; } if (!pixg && fract == 0.0) L_WARNING("transparent alpha; image will not be blended\n", procName); /* Make sure input to rotation is 32 bpp rgb, and rotate it */ if (d != 32) pix32 = pixConvertTo32(pixs); else pix32 = pixClone(pixs); spp = pixGetSpp(pix32); pixSetSpp(pix32, 3); /* ignore the alpha channel for the rotation */ pixd = pixRotate(pix32, angle, L_ROTATE_AREA_MAP, L_BRING_IN_WHITE, ws, hs); pixSetSpp(pix32, spp); /* restore initial value in case it's a clone */ pixDestroy(&pix32); /* Set up alpha layer with a fading border and rotate it */ if (!pixg) { pixg2 = pixCreate(ws, hs, 8); if (fract == 1.0) pixSetAll(pixg2); else if (fract > 0.0) pixSetAllArbitrary(pixg2, (l_int32)(255.0 * fract)); } else { pixg2 = pixResizeToMatch(pixg, NULL, ws, hs); } if (ws > 10 && hs > 10) { /* see note 8 */ pixSetBorderRingVal(pixg2, 1, (l_int32)(255.0 * fract * AlphaMaskBorderVals[0])); pixSetBorderRingVal(pixg2, 2, (l_int32)(255.0 * fract * AlphaMaskBorderVals[1])); } pixgr = pixRotate(pixg2, angle, L_ROTATE_AREA_MAP, L_BRING_IN_BLACK, ws, hs); /* Combine into a 4 spp result */ pixSetRGBComponent(pixd, pixgr, L_ALPHA_CHANNEL); pixDestroy(&pixg2); pixDestroy(&pixgr); return pixd; }
// Auto page segmentation. Divide the page image into blocks of uniform // text linespacing and images. // Width, height and resolution are derived from the input image. // If the pix is non-NULL, then it is assumed to be the input, and it is // copied to the image, otherwise the image is used directly. // The output goes in the blocks list with corresponding TO_BLOCKs in the // to_blocks list. // If single_column is true, then no attempt is made to divide the image // into columns, but multiple blocks are still made if the text is of // non-uniform linespacing. int Tesseract::AutoPageSeg(int width, int height, int resolution, bool single_column, IMAGE* image, BLOCK_LIST* blocks, TO_BLOCK_LIST* to_blocks) { int vertical_x = 0; int vertical_y = 1; TabVector_LIST v_lines; TabVector_LIST h_lines; ICOORD bleft(0, 0); Boxa* boxa = NULL; Pixa* pixa = NULL; // The blocks made by the ColumnFinder. Moved to blocks before return. BLOCK_LIST found_blocks; #ifdef HAVE_LIBLEPT if (pix_binary_ != NULL) { if (textord_debug_images) { Pix* grey_pix = pixCreate(width, height, 8); // Printable images are light grey on white, but for screen display // they are black on dark grey so the other colors show up well. if (textord_debug_printable) { pixSetAll(grey_pix); pixSetMasked(grey_pix, pix_binary_, 192); } else { pixSetAllArbitrary(grey_pix, 64); pixSetMasked(grey_pix, pix_binary_, 0); } AlignedBlob::IncrementDebugPix(); pixWrite(AlignedBlob::textord_debug_pix().string(), grey_pix, IFF_PNG); pixDestroy(&grey_pix); } if (tessedit_dump_pageseg_images) pixWrite("tessinput.png", pix_binary_, IFF_PNG); // Leptonica is used to find the lines and image regions in the input. LineFinder::FindVerticalLines(resolution, pix_binary_, &vertical_x, &vertical_y, &v_lines); LineFinder::FindHorizontalLines(resolution, pix_binary_, &h_lines); if (tessedit_dump_pageseg_images) pixWrite("tessnolines.png", pix_binary_, IFF_PNG); ImageFinder::FindImages(pix_binary_, &boxa, &pixa); if (tessedit_dump_pageseg_images) pixWrite("tessnoimages.png", pix_binary_, IFF_PNG); // Copy the Pix to the IMAGE. image->FromPix(pix_binary_); if (single_column) v_lines.clear(); } #endif TO_BLOCK_LIST land_blocks, port_blocks; TBOX page_box; // The rest of the algorithm uses the usual connected components. find_components(blocks, &land_blocks, &port_blocks, &page_box); TO_BLOCK_IT to_block_it(&port_blocks); ASSERT_HOST(!to_block_it.empty()); for (to_block_it.mark_cycle_pt(); !to_block_it.cycled_list(); to_block_it.forward()) { TO_BLOCK* to_block = to_block_it.data(); TBOX blkbox = to_block->block->bounding_box(); if (to_block->line_size >= 2) { // Note: if there are multiple blocks, then v_lines, boxa, and pixa // are empty on the next iteration, but in this case, we assume // that there aren't any interesting line separators or images, since // it means that we have a pre-defined unlv zone file. ColumnFinder finder(static_cast<int>(to_block->line_size), blkbox.botleft(), blkbox.topright(), &v_lines, &h_lines, vertical_x, vertical_y); if (finder.FindBlocks(height, resolution, single_column, to_block, boxa, pixa, &found_blocks, to_blocks) < 0) return -1; finder.ComputeDeskewVectors(&deskew_, &reskew_); boxa = NULL; pixa = NULL; } } #ifdef HAVE_LIBLEPT boxaDestroy(&boxa); pixaDestroy(&pixa); #endif blocks->clear(); BLOCK_IT block_it(blocks); // Move the found blocks to the input/output blocks. block_it.add_list_after(&found_blocks); if (textord_debug_images) { // The debug image is no longer needed so delete it. unlink(AlignedBlob::textord_debug_pix().string()); } return 0; }
/*! * pixProjectiveSampled() * * Input: pixs (all depths) * vc (vector of 8 coefficients for projective transformation) * incolor (L_BRING_IN_WHITE, L_BRING_IN_BLACK) * Return: pixd, or null on error * * Notes: * (1) Brings in either black or white pixels from the boundary. * (2) Retains colormap, which you can do for a sampled transform.. * (3) For 8 or 32 bpp, much better quality is obtained by the * somewhat slower pixProjective(). See that function * for relative timings between sampled and interpolated. */ PIX * pixProjectiveSampled(PIX *pixs, l_float32 *vc, l_int32 incolor) { l_int32 i, j, w, h, d, x, y, wpls, wpld, color, cmapindex; l_uint32 val; l_uint32 *datas, *datad, *lines, *lined; PIX *pixd; PIXCMAP *cmap; PROCNAME("pixProjectiveSampled"); if (!pixs) return (PIX *)ERROR_PTR("pixs not defined", procName, NULL); if (!vc) return (PIX *)ERROR_PTR("vc not defined", procName, NULL); if (incolor != L_BRING_IN_WHITE && incolor != L_BRING_IN_BLACK) return (PIX *)ERROR_PTR("invalid incolor", procName, NULL); pixGetDimensions(pixs, &w, &h, &d); if (d != 1 && d != 2 && d != 4 && d != 8 && d != 32) return (PIX *)ERROR_PTR("depth not 1, 2, 4, 8 or 16", procName, NULL); /* Init all dest pixels to color to be brought in from outside */ pixd = pixCreateTemplate(pixs); if ((cmap = pixGetColormap(pixs)) != NULL) { if (incolor == L_BRING_IN_WHITE) color = 1; else color = 0; pixcmapAddBlackOrWhite(cmap, color, &cmapindex); pixSetAllArbitrary(pixd, cmapindex); } else { if ((d == 1 && incolor == L_BRING_IN_WHITE) || (d > 1 && incolor == L_BRING_IN_BLACK)) pixClearAll(pixd); else pixSetAll(pixd); } /* Scan over the dest pixels */ datas = pixGetData(pixs); wpls = pixGetWpl(pixs); datad = pixGetData(pixd); wpld = pixGetWpl(pixd); for (i = 0; i < h; i++) { lined = datad + i * wpld; for (j = 0; j < w; j++) { projectiveXformSampledPt(vc, j, i, &x, &y); if (x < 0 || y < 0 || x >=w || y >= h) continue; lines = datas + y * wpls; if (d == 1) { val = GET_DATA_BIT(lines, x); SET_DATA_BIT_VAL(lined, j, val); } else if (d == 8) { val = GET_DATA_BYTE(lines, x); SET_DATA_BYTE(lined, j, val); } else if (d == 32) { lined[j] = lines[x]; } else if (d == 2) { val = GET_DATA_DIBIT(lines, x); SET_DATA_DIBIT(lined, j, val); } else if (d == 4) { val = GET_DATA_QBIT(lines, x); SET_DATA_QBIT(lined, j, val); } } } return pixd; }