/*! * selaAddDwaLinear() * * Input: sela (<optional>) * Return: sela with additional sels, or null on error * * Notes: * (1) Adds all linear (horizontal, vertical) sels from * 2 to 63 pixels in length, which are the sizes over * which dwa code can be generated. */ SELA * selaAddDwaLinear(SELA *sela) { char name[L_BUF_SIZE]; l_int32 i; SEL *sel; PROCNAME("selaAddDwaLinear"); if (!sela) { if ((sela = selaCreate(0)) == NULL) return (SELA *)ERROR_PTR("sela not made", procName, NULL); } for (i = 2; i < 64; i++) { sel = selCreateBrick(1, i, 0, i / 2, 1); snprintf(name, L_BUF_SIZE, "sel_%dh", i); selaAddSel(sela, sel, name, 0); } for (i = 2; i < 64; i++) { sel = selCreateBrick(i, 1, i / 2, 0, 1); snprintf(name, L_BUF_SIZE, "sel_%dv", i); selaAddSel(sela, sel, name, 0); } return sela; }
main(int argc, char **argv) { l_int32 i, j, w, h, same, width, height, cx, cy; l_uint32 val; PIX *pixs, *pixse, *pixd1, *pixd2; SEL *sel; static char mainName[] = "rasterop_reg"; if (argc != 1) return ERROR_INT(" Syntax: rasterop_reg", mainName, 1); pixs = pixRead("feyn.tif"); for (width = 1; width <= 25; width += 3) { for (height = 1; height <= 25; height += 4) { cx = width / 2; cy = height / 2; /* Dilate using an actual sel */ sel = selCreateBrick(height, width, cy, cx, SEL_HIT); pixd1 = pixDilate(NULL, pixs, sel); /* Dilate using a pix as a sel */ pixse = pixCreate(width, height, 1); pixSetAll(pixse); pixd2 = pixCopy(NULL, pixs); w = pixGetWidth(pixs); h = pixGetHeight(pixs); for (i = 0; i < h; i++) { for (j = 0; j < w; j++) { pixGetPixel(pixs, j, i, &val); if (val) pixRasterop(pixd2, j - cx, i - cy, width, height, PIX_SRC | PIX_DST, pixse, 0, 0); } } pixEqual(pixd1, pixd2, &same); if (same == 1) fprintf(stderr, "Correct for (%d,%d)\n", width, height); else { fprintf(stderr, "Error: results are different!\n"); fprintf(stderr, "SE: width = %d, height = %d\n", width, height); pixWrite("/tmp/junkout1", pixd1, IFF_PNG); pixWrite("/tmp/junkout2", pixd2, IFF_PNG); return 1; } pixDestroy(&pixse); pixDestroy(&pixd1); pixDestroy(&pixd2); selDestroy(&sel); } } pixDestroy(&pixs); return 0; }
/*! * selaAddBasic() * * Input: sela (<optional>) * Return: sela with additional sels, or null on error * * Notes: * (1) Adds the following sels: * - all linear (horiz, vert) brick sels that are * necessary for decomposable sels up to size 63 * - square brick sels up to size 10 * - 4 diagonal sels */ SELA * selaAddBasic(SELA *sela) { char name[L_BUF_SIZE]; l_int32 i, size; SEL *sel; PROCNAME("selaAddBasic"); if (!sela) { if ((sela = selaCreate(0)) == NULL) return (SELA *)ERROR_PTR("sela not made", procName, NULL); } /*--------------------------------------------------------------* * Linear horizontal and vertical sels * *--------------------------------------------------------------*/ for (i = 0; i < num_linear; i++) { size = basic_linear[i]; sel = selCreateBrick(1, size, 0, size / 2, 1); snprintf(name, L_BUF_SIZE, "sel_%dh", size); selaAddSel(sela, sel, name, 0); } for (i = 0; i < num_linear; i++) { size = basic_linear[i]; sel = selCreateBrick(size, 1, size / 2, 0, 1); snprintf(name, L_BUF_SIZE, "sel_%dv", size); selaAddSel(sela, sel, name, 0); } /*-----------------------------------------------------------* * 2-d Bricks * *-----------------------------------------------------------*/ for (i = 2; i <= 5; i++) { sel = selCreateBrick(i, i, i / 2, i / 2, 1); snprintf(name, L_BUF_SIZE, "sel_%d", i); selaAddSel(sela, sel, name, 0); } /*-----------------------------------------------------------* * Diagonals * *-----------------------------------------------------------*/ /* 0c 1 1 0 */ sel = selCreateBrick(2, 2, 0, 0, 1); selSetElement(sel, 0, 0, 0); selSetElement(sel, 1, 1, 0); selaAddSel(sela, sel, "sel_2dp", 0); /* 1c 0 0 1 */ sel = selCreateBrick(2, 2, 0, 0, 1); selSetElement(sel, 0, 1, 0); selSetElement(sel, 1, 0, 0); selaAddSel(sela, sel, "sel_2dm", 0); /* Diagonal, slope +, size 5 */ sel = selCreate(5, 5, "sel_5dp"); sel->cy = 2; sel->cx = 2; selSetElement(sel, 0, 4, 1); selSetElement(sel, 1, 3, 1); selSetElement(sel, 2, 2, 1); selSetElement(sel, 3, 1, 1); selSetElement(sel, 4, 0, 1); selaAddSel(sela, sel, "sel_5dp", 0); /* Diagonal, slope -, size 5 */ sel = selCreate(5, 5, "sel_5dm"); sel->cy = 2; sel->cx = 2; selSetElement(sel, 0, 0, 1); selSetElement(sel, 1, 1, 1); selSetElement(sel, 2, 2, 1); selSetElement(sel, 3, 3, 1); selSetElement(sel, 4, 4, 1); selaAddSel(sela, sel, "sel_5dm", 0); return sela; }
/*! * selaAddHitMiss() * * Input: sela (<optional>) * Return: sela with additional sels, or null on error */ SELA * selaAddHitMiss(SELA *sela) { SEL *sel; PROCNAME("selaAddHitMiss"); if (!sela) { if ((sela = selaCreate(0)) == NULL) return (SELA *)ERROR_PTR("sela not made", procName, NULL); } #if 0 /* use just for testing */ sel = selCreateBrick(3, 3, 1, 1, 2); selaAddSel(sela, sel, "sel_bad", 0); #endif /*--------------------------------------------------------------* * Isolated foreground pixel * *--------------------------------------------------------------*/ sel = selCreateBrick(3, 3, 1, 1, SEL_MISS); selSetElement(sel, 1, 1, SEL_HIT); selaAddSel(sela, sel, "sel_3hm", 0); /*--------------------------------------------------------------* * Horizontal and vertical edges * *--------------------------------------------------------------*/ sel = selCreateBrick(2, 3, 0, 1, SEL_HIT); selSetElement(sel, 1, 0, SEL_MISS); selSetElement(sel, 1, 1, SEL_MISS); selSetElement(sel, 1, 2, SEL_MISS); selaAddSel(sela, sel, "sel_3de", 0); sel = selCreateBrick(2, 3, 1, 1, SEL_HIT); selSetElement(sel, 0, 0, SEL_MISS); selSetElement(sel, 0, 1, SEL_MISS); selSetElement(sel, 0, 2, SEL_MISS); selaAddSel(sela, sel, "sel_3ue", 0); sel = selCreateBrick(3, 2, 1, 0, SEL_HIT); selSetElement(sel, 0, 1, SEL_MISS); selSetElement(sel, 1, 1, SEL_MISS); selSetElement(sel, 2, 1, SEL_MISS); selaAddSel(sela, sel, "sel_3re", 0); sel = selCreateBrick(3, 2, 1, 1, SEL_HIT); selSetElement(sel, 0, 0, SEL_MISS); selSetElement(sel, 1, 0, SEL_MISS); selSetElement(sel, 2, 0, SEL_MISS); selaAddSel(sela, sel, "sel_3le", 0); /*--------------------------------------------------------------* * Slanted edge * *--------------------------------------------------------------*/ sel = selCreateBrick(13, 6, 6, 2, SEL_DONT_CARE); selSetElement(sel, 0, 3, SEL_MISS); selSetElement(sel, 0, 5, SEL_HIT); selSetElement(sel, 4, 2, SEL_MISS); selSetElement(sel, 4, 4, SEL_HIT); selSetElement(sel, 8, 1, SEL_MISS); selSetElement(sel, 8, 3, SEL_HIT); selSetElement(sel, 12, 0, SEL_MISS); selSetElement(sel, 12, 2, SEL_HIT); selaAddSel(sela, sel, "sel_sl1", 0); /*--------------------------------------------------------------* * Corners * * This allows for up to 3 missing edge pixels at the corner * *--------------------------------------------------------------*/ sel = selCreateBrick(4, 4, 1, 1, SEL_MISS); selSetElement(sel, 1, 1, SEL_DONT_CARE); selSetElement(sel, 1, 2, SEL_DONT_CARE); selSetElement(sel, 2, 1, SEL_DONT_CARE); selSetElement(sel, 1, 3, SEL_HIT); selSetElement(sel, 2, 2, SEL_HIT); selSetElement(sel, 2, 3, SEL_HIT); selSetElement(sel, 3, 1, SEL_HIT); selSetElement(sel, 3, 2, SEL_HIT); selSetElement(sel, 3, 3, SEL_HIT); selaAddSel(sela, sel, "sel_ulc", 0); sel = selCreateBrick(4, 4, 1, 2, SEL_MISS); selSetElement(sel, 1, 1, SEL_DONT_CARE); selSetElement(sel, 1, 2, SEL_DONT_CARE); selSetElement(sel, 2, 2, SEL_DONT_CARE); selSetElement(sel, 1, 0, SEL_HIT); selSetElement(sel, 2, 0, SEL_HIT); selSetElement(sel, 2, 1, SEL_HIT); selSetElement(sel, 3, 0, SEL_HIT); selSetElement(sel, 3, 1, SEL_HIT); selSetElement(sel, 3, 2, SEL_HIT); selaAddSel(sela, sel, "sel_urc", 0); sel = selCreateBrick(4, 4, 2, 1, SEL_MISS); selSetElement(sel, 1, 1, SEL_DONT_CARE); selSetElement(sel, 2, 1, SEL_DONT_CARE); selSetElement(sel, 2, 2, SEL_DONT_CARE); selSetElement(sel, 0, 1, SEL_HIT); selSetElement(sel, 0, 2, SEL_HIT); selSetElement(sel, 0, 3, SEL_HIT); selSetElement(sel, 1, 2, SEL_HIT); selSetElement(sel, 1, 3, SEL_HIT); selSetElement(sel, 2, 3, SEL_HIT); selaAddSel(sela, sel, "sel_llc", 0); sel = selCreateBrick(4, 4, 2, 2, SEL_MISS); selSetElement(sel, 1, 2, SEL_DONT_CARE); selSetElement(sel, 2, 1, SEL_DONT_CARE); selSetElement(sel, 2, 2, SEL_DONT_CARE); selSetElement(sel, 0, 0, SEL_HIT); selSetElement(sel, 0, 1, SEL_HIT); selSetElement(sel, 0, 2, SEL_HIT); selSetElement(sel, 1, 0, SEL_HIT); selSetElement(sel, 1, 1, SEL_HIT); selSetElement(sel, 2, 0, SEL_HIT); selaAddSel(sela, sel, "sel_lrc", 0); return sela; }
/*! * pixGenerateSelBoundary() * * Input: pix (1 bpp, typically small, to be used as a pattern) * hitdist (min distance from fg boundary pixel) * missdist (min distance from bg boundary pixel) * hitskip (number of boundary pixels skipped between hits) * missskip (number of boundary pixels skipped between misses) * topflag (flag for extra pixels of bg added above) * botflag (flag for extra pixels of bg added below) * leftflag (flag for extra pixels of bg added to left) * rightflag (flag for extra pixels of bg added to right) * &pixe (<optional return> input pix expanded by extra pixels) * Return: sel (hit-miss for input pattern), or null on error * * Notes: * (1) All fg elements selected are exactly hitdist pixels away from * the nearest fg boundary pixel, and ditto for bg elements. * Valid inputs of hitdist and missdist are 0, 1, 2, 3 and 4. * For example, a hitdist of 0 puts the hits at the fg boundary. * Usually, the distances should be > 0 avoid the effect of * noise at the boundary. * (2) Set hitskip < 0 if no hits are to be used. Ditto for missskip. * If both hitskip and missskip are < 0, the sel would be empty, * and NULL is returned. * (3) The 4 flags determine whether the sel is increased on that side * to allow bg misses to be placed all along that boundary. * The increase in sel size on that side is the minimum necessary * to allow the misses to be placed at mindist. For text characters, * the topflag and botflag are typically set to 1, and the leftflag * and rightflag to 0. * (4) The input pix, as extended by the extra pixels on selected sides, * can optionally be returned. For debugging, call * pixDisplayHitMissSel() to visualize the hit-miss sel superimposed * on the generating bitmap. * (5) This is probably the best of the three sel generators, in the * sense that you have the most flexibility with the smallest number * of hits and misses. */ SEL * pixGenerateSelBoundary(PIX *pixs, l_int32 hitdist, l_int32 missdist, l_int32 hitskip, l_int32 missskip, l_int32 topflag, l_int32 botflag, l_int32 leftflag, l_int32 rightflag, PIX **ppixe) { l_int32 ws, hs, w, h, x, y, ix, iy, i, npt; PIX *pixt1, *pixt2, *pixt3, *pixfg, *pixbg; SEL *selh, *selm, *sel_3, *sel; PTA *ptah, *ptam; PROCNAME("pixGenerateSelBoundary"); if (ppixe) *ppixe = NULL; if (!pixs) return (SEL *)ERROR_PTR("pixs not defined", procName, NULL); if (pixGetDepth(pixs) != 1) return (SEL *)ERROR_PTR("pixs not 1 bpp", procName, NULL); if (hitdist < 0 || hitdist > 4 || missdist < 0 || missdist > 4) return (SEL *)ERROR_PTR("dist not in {0 .. 4}", procName, NULL); if (hitskip < 0 && missskip < 0) return (SEL *)ERROR_PTR("no hits or misses", procName, NULL); /* Locate the foreground */ pixClipToForeground(pixs, &pixt1, NULL); if (!pixt1) return (SEL *)ERROR_PTR("pixt1 not made", procName, NULL); ws = pixGetWidth(pixt1); hs = pixGetHeight(pixt1); w = ws; h = hs; /* Crop out a region including the foreground, and add pixels * on sides depending on the side flags */ if (topflag || botflag || leftflag || rightflag) { x = y = 0; if (topflag) { h += missdist + 1; y = missdist + 1; } if (botflag) h += missdist + 1; if (leftflag) { w += missdist + 1; x = missdist + 1; } if (rightflag) w += missdist + 1; pixt2 = pixCreate(w, h, 1); pixRasterop(pixt2, x, y, ws, hs, PIX_SRC, pixt1, 0, 0); } else { pixt2 = pixClone(pixt1); } if (ppixe) *ppixe = pixClone(pixt2); pixDestroy(&pixt1); /* Identify fg and bg pixels that are exactly hitdist and * missdist (rsp) away from the boundary pixels in their set. * Then get a subsampled set of these points. */ sel_3 = selCreateBrick(3, 3, 1, 1, SEL_HIT); if (hitskip >= 0) { selh = selCreateBrick(2 * hitdist + 1, 2 * hitdist + 1, hitdist, hitdist, SEL_HIT); pixt3 = pixErode(NULL, pixt2, selh); pixfg = pixErode(NULL, pixt3, sel_3); pixXor(pixfg, pixfg, pixt3); ptah = pixSubsampleBoundaryPixels(pixfg, hitskip); pixDestroy(&pixt3); pixDestroy(&pixfg); selDestroy(&selh); } if (missskip >= 0) { selm = selCreateBrick(2 * missdist + 1, 2 * missdist + 1, missdist, missdist, SEL_HIT); pixt3 = pixDilate(NULL, pixt2, selm); pixbg = pixDilate(NULL, pixt3, sel_3); pixXor(pixbg, pixbg, pixt3); ptam = pixSubsampleBoundaryPixels(pixbg, missskip); pixDestroy(&pixt3); pixDestroy(&pixbg); selDestroy(&selm); } selDestroy(&sel_3); pixDestroy(&pixt2); /* Generate the hit-miss sel from these point */ sel = selCreateBrick(h, w, h / 2, w / 2, SEL_DONT_CARE); if (hitskip >= 0) { npt = ptaGetCount(ptah); for (i = 0; i < npt; i++) { ptaGetIPt(ptah, i, &ix, &iy); selSetElement(sel, iy, ix, SEL_HIT); } } if (missskip >= 0) { npt = ptaGetCount(ptam); for (i = 0; i < npt; i++) { ptaGetIPt(ptam, i, &ix, &iy); selSetElement(sel, iy, ix, SEL_MISS); } } ptaDestroy(&ptah); ptaDestroy(&ptam); return sel; }
/*! * pixGenerateSelRandom() * * Input: pix (1 bpp, typically small, to be used as a pattern) * hitfract (fraction of allowable fg pixels that are hits) * missfract (fraction of allowable bg pixels that are misses) * distance (min distance from boundary pixel; use 0 for default) * toppix (number of extra pixels of bg added above) * botpix (number of extra pixels of bg added below) * leftpix (number of extra pixels of bg added to left) * rightpix (number of extra pixels of bg added to right) * &pixe (<optional return> input pix expanded by extra pixels) * Return: sel (hit-miss for input pattern), or null on error * * Notes: * (1) Either of hitfract and missfract can be zero. If both are zero, * the sel would be empty, and NULL is returned. * (2) No elements are selected that are less than 'distance' pixels away * from a boundary pixel of the same color. This makes the * match much more robust to edge noise. Valid inputs of * 'distance' are 0, 1, 2, 3 and 4. If distance is either 0 or * greater than 4, we reset it to the default value. * (3) The 4 numbers for adding rectangles of pixels outside the fg * can be use if the pattern is expected to be surrounded by bg * (white) pixels. On the other hand, if the pattern may be near * other fg (black) components on some sides, use 0 for those sides. * (4) The input pix, as extended by the extra pixels on selected sides, * can optionally be returned. For debugging, call * pixDisplayHitMissSel() to visualize the hit-miss sel superimposed * on the generating bitmap. */ SEL * pixGenerateSelRandom(PIX *pixs, l_float32 hitfract, l_float32 missfract, l_int32 distance, l_int32 toppix, l_int32 botpix, l_int32 leftpix, l_int32 rightpix, PIX **ppixe) { l_int32 ws, hs, w, h, x, y, i, j, thresh; l_uint32 val; PIX *pixt1, *pixt2, *pixfg, *pixbg; SEL *seld, *sel; PROCNAME("pixGenerateSelRandom"); if (ppixe) *ppixe = NULL; if (!pixs) return (SEL *)ERROR_PTR("pixs not defined", procName, NULL); if (pixGetDepth(pixs) != 1) return (SEL *)ERROR_PTR("pixs not 1 bpp", procName, NULL); if (hitfract <= 0.0 && missfract <= 0.0) return (SEL *)ERROR_PTR("no hits or misses", procName, NULL); if (hitfract > 1.0 || missfract > 1.0) return (SEL *)ERROR_PTR("fraction can't be > 1.0", procName, NULL); if (distance <= 0) distance = DEFAULT_DISTANCE_TO_BOUNDARY; if (distance > MAX_DISTANCE_TO_BOUNDARY) { L_WARNING("distance too large; setting to max value", procName); distance = MAX_DISTANCE_TO_BOUNDARY; } /* Locate the foreground */ pixClipToForeground(pixs, &pixt1, NULL); if (!pixt1) return (SEL *)ERROR_PTR("pixt1 not made", procName, NULL); ws = pixGetWidth(pixt1); hs = pixGetHeight(pixt1); w = ws; h = hs; /* Crop out a region including the foreground, and add pixels * on sides depending on the side flags */ if (toppix || botpix || leftpix || rightpix) { x = y = 0; if (toppix) { h += toppix; y = toppix; } if (botpix) h += botpix; if (leftpix) { w += leftpix; x = leftpix; } if (rightpix) w += rightpix; pixt2 = pixCreate(w, h, 1); pixRasterop(pixt2, x, y, ws, hs, PIX_SRC, pixt1, 0, 0); } else pixt2 = pixClone(pixt1); if (ppixe) *ppixe = pixClone(pixt2); pixDestroy(&pixt1); /* Identify fg and bg pixels that are at least 'distance' pixels * away from the boundary pixels in their set */ seld = selCreateBrick(2 * distance + 1, 2 * distance + 1, distance, distance, SEL_HIT); pixfg = pixErode(NULL, pixt2, seld); pixbg = pixDilate(NULL, pixt2, seld); pixInvert(pixbg, pixbg); selDestroy(&seld); pixDestroy(&pixt2); /* Generate the sel from a random selection of these points */ sel = selCreateBrick(h, w, h / 2, w / 2, SEL_DONT_CARE); if (hitfract > 0.0) { thresh = (l_int32)(hitfract * (l_float64)RAND_MAX); for (i = 0; i < h; i++) { for (j = 0; j < w; j++) { pixGetPixel(pixfg, j, i, &val); if (val) { if (rand() < thresh) selSetElement(sel, i, j, SEL_HIT); } } } } if (missfract > 0.0) { thresh = (l_int32)(missfract * (l_float64)RAND_MAX); for (i = 0; i < h; i++) { for (j = 0; j < w; j++) { pixGetPixel(pixbg, j, i, &val); if (val) { if (rand() < thresh) selSetElement(sel, i, j, SEL_MISS); } } } } pixDestroy(&pixfg); pixDestroy(&pixbg); return sel; }
/*! * pixGenerateSelWithRuns() * * Input: pix (1 bpp, typically small, to be used as a pattern) * nhlines (number of hor lines along which elements are found) * nvlines (number of vert lines along which elements are found) * distance (min distance from boundary pixel; use 0 for default) * minlength (min runlength to set hit or miss; use 0 for default) * toppix (number of extra pixels of bg added above) * botpix (number of extra pixels of bg added below) * leftpix (number of extra pixels of bg added to left) * rightpix (number of extra pixels of bg added to right) * &pixe (<optional return> input pix expanded by extra pixels) * Return: sel (hit-miss for input pattern), or null on error * * Notes: * (1) The horizontal and vertical lines along which elements are * selected are roughly equally spaced. The actual locations of * the hits and misses are the centers of respective run-lengths. * (2) No elements are selected that are less than 'distance' pixels away * from a boundary pixel of the same color. This makes the * match much more robust to edge noise. Valid inputs of * 'distance' are 0, 1, 2, 3 and 4. If distance is either 0 or * greater than 4, we reset it to the default value. * (3) The 4 numbers for adding rectangles of pixels outside the fg * can be use if the pattern is expected to be surrounded by bg * (white) pixels. On the other hand, if the pattern may be near * other fg (black) components on some sides, use 0 for those sides. * (4) The pixels added to a side allow you to have miss elements there. * There is a constraint between distance, minlength, and * the added pixels for this to work. We illustrate using the * default values. If you add 5 pixels to the top, and use a * distance of 1, then you end up with a vertical run of at least * 4 bg pixels along the top edge of the image. If you use a * minimum runlength of 3, each vertical line will always find * a miss near the center of its run. However, if you use a * minimum runlength of 5, you will not get a miss on every vertical * line. As another example, if you have 7 added pixels and a * distance of 2, you can use a runlength up to 5 to guarantee * that the miss element is recorded. We give a warning if the * contraint does not guarantee a miss element outside the * image proper. * (5) The input pix, as extended by the extra pixels on selected sides, * can optionally be returned. For debugging, call * pixDisplayHitMissSel() to visualize the hit-miss sel superimposed * on the generating bitmap. */ SEL * pixGenerateSelWithRuns(PIX *pixs, l_int32 nhlines, l_int32 nvlines, l_int32 distance, l_int32 minlength, l_int32 toppix, l_int32 botpix, l_int32 leftpix, l_int32 rightpix, PIX **ppixe) { l_int32 ws, hs, w, h, x, y, xval, yval, i, j, nh, nm; l_float32 delh, delw; NUMA *nah, *nam; PIX *pixt1, *pixt2, *pixfg, *pixbg; PTA *ptah, *ptam; SEL *seld, *sel; PROCNAME("pixGenerateSelWithRuns"); if (ppixe) *ppixe = NULL; if (!pixs) return (SEL *)ERROR_PTR("pixs not defined", procName, NULL); if (pixGetDepth(pixs) != 1) return (SEL *)ERROR_PTR("pixs not 1 bpp", procName, NULL); if (nhlines < 1 && nvlines < 1) return (SEL *)ERROR_PTR("nvlines and nhlines both < 1", procName, NULL); if (distance <= 0) distance = DEFAULT_DISTANCE_TO_BOUNDARY; if (minlength <= 0) minlength = DEFAULT_MIN_RUNLENGTH; if (distance > MAX_DISTANCE_TO_BOUNDARY) { L_WARNING("distance too large; setting to max value", procName); distance = MAX_DISTANCE_TO_BOUNDARY; } /* Locate the foreground */ pixClipToForeground(pixs, &pixt1, NULL); if (!pixt1) return (SEL *)ERROR_PTR("pixt1 not made", procName, NULL); ws = pixGetWidth(pixt1); hs = pixGetHeight(pixt1); w = ws; h = hs; /* Crop out a region including the foreground, and add pixels * on sides depending on the side flags */ if (toppix || botpix || leftpix || rightpix) { x = y = 0; if (toppix) { h += toppix; y = toppix; if (toppix < distance + minlength) L_WARNING("no miss elements in added top pixels", procName); } if (botpix) { h += botpix; if (botpix < distance + minlength) L_WARNING("no miss elements in added bot pixels", procName); } if (leftpix) { w += leftpix; x = leftpix; if (leftpix < distance + minlength) L_WARNING("no miss elements in added left pixels", procName); } if (rightpix) { w += rightpix; if (rightpix < distance + minlength) L_WARNING("no miss elements in added right pixels", procName); } pixt2 = pixCreate(w, h, 1); pixRasterop(pixt2, x, y, ws, hs, PIX_SRC, pixt1, 0, 0); } else pixt2 = pixClone(pixt1); if (ppixe) *ppixe = pixClone(pixt2); pixDestroy(&pixt1); /* Identify fg and bg pixels that are at least 'distance' pixels * away from the boundary pixels in their set */ seld = selCreateBrick(2 * distance + 1, 2 * distance + 1, distance, distance, SEL_HIT); pixfg = pixErode(NULL, pixt2, seld); pixbg = pixDilate(NULL, pixt2, seld); pixInvert(pixbg, pixbg); selDestroy(&seld); pixDestroy(&pixt2); /* Accumulate hit and miss points */ ptah = ptaCreate(0); ptam = ptaCreate(0); if (nhlines >= 1) { delh = (l_float32)h / (l_float32)(nhlines + 1); for (i = 0, y = 0; i < nhlines; i++) { y += (l_int32)(delh + 0.5); nah = pixGetRunCentersOnLine(pixfg, -1, y, minlength); nam = pixGetRunCentersOnLine(pixbg, -1, y, minlength); nh = numaGetCount(nah); nm = numaGetCount(nam); for (j = 0; j < nh; j++) { numaGetIValue(nah, j, &xval); ptaAddPt(ptah, xval, y); } for (j = 0; j < nm; j++) { numaGetIValue(nam, j, &xval); ptaAddPt(ptam, xval, y); } numaDestroy(&nah); numaDestroy(&nam); } } if (nvlines >= 1) { delw = (l_float32)w / (l_float32)(nvlines + 1); for (i = 0, x = 0; i < nvlines; i++) { x += (l_int32)(delw + 0.5); nah = pixGetRunCentersOnLine(pixfg, x, -1, minlength); nam = pixGetRunCentersOnLine(pixbg, x, -1, minlength); nh = numaGetCount(nah); nm = numaGetCount(nam); for (j = 0; j < nh; j++) { numaGetIValue(nah, j, &yval); ptaAddPt(ptah, x, yval); } for (j = 0; j < nm; j++) { numaGetIValue(nam, j, &yval); ptaAddPt(ptam, x, yval); } numaDestroy(&nah); numaDestroy(&nam); } } /* Make the Sel with those points */ sel = selCreateBrick(h, w, h / 2, w / 2, SEL_DONT_CARE); nh = ptaGetCount(ptah); for (i = 0; i < nh; i++) { ptaGetIPt(ptah, i, &x, &y); selSetElement(sel, y, x, SEL_HIT); } nm = ptaGetCount(ptam); for (i = 0; i < nm; i++) { ptaGetIPt(ptam, i, &x, &y); selSetElement(sel, y, x, SEL_MISS); } pixDestroy(&pixfg); pixDestroy(&pixbg); ptaDestroy(&ptah); ptaDestroy(&ptam); return sel; }
int main_find_pattern(int argc, char **argv) { char *filein, *fileout, *patternfile; l_int32 w, h, i, n; BOX *box, *boxe; BOXA *boxa1, *boxa2; PIX *pixs, *pixp, *pixpe; PIX *pixd, *pixt1, *pixt2, *pixhmt; SEL *sel_2h, *sel; static char mainName[] = "findpattern1"; filein = "feyn.tif"; patternfile = "char.tif"; fileout = "result.findpattern1"; if ((pixs = pixRead(filein)) == NULL) printf("pixs not made\n"); if ((pixp = pixRead(patternfile)) == NULL) printf("pixp not made\n"); w = pixGetWidth(pixp); h = pixGetHeight(pixp); /* generate the hit-miss Sel with runs */ sel = pixGenerateSelWithRuns(pixp, NumHorLines, NumVertLines, 0, MinRunlength, 7, 7, 0, 0, &pixpe); /* display the Sel two ways */ selWriteStream(stderr, sel); pixt1 = pixDisplayHitMissSel(pixpe, sel, 9, HitColor, MissColor); pixDisplay(pixt1, 200, 200); pixWrite("junkpixt", pixt1, IFF_PNG); /* use the Sel to find all instances in the page */ startTimer(); pixhmt = pixHMT(NULL, pixs, sel); fprintf(stderr, "Time to find patterns = %7.3f\n", stopTimer()); /* small erosion to remove noise; typically not necessary if * there are enough elements in the Sel */ sel_2h = selCreateBrick(1, 2, 0, 0, SEL_HIT); pixt2 = pixErode(NULL, pixhmt, sel_2h); /* display the result visually by placing the Sel at each * location found */ pixd = pixDilate(NULL, pixt2, sel); pixWrite(fileout, pixd, IFF_TIFF_G4); /* display outut with an outline around each located pattern */ boxa1 = pixConnCompBB(pixt2, 8); n = boxaGetCount(boxa1); boxa2 = boxaCreate(n); for (i = 0; i < n; i++) { box = boxaGetBox(boxa1, i, L_COPY); boxe = boxCreate(box->x - w / 2, box->y - h / 2, w + 4, h + 4); boxaAddBox(boxa2, boxe, L_INSERT); pixRenderBox(pixs, boxe, 4, L_FLIP_PIXELS); boxDestroy(&box); } pixWrite("junkoutline", pixs, IFF_TIFF_G4); //boxaWriteStream(stderr, boxa2); //TODO ??? pixDestroy(&pixs); pixDestroy(&pixp); pixDestroy(&pixpe); pixDestroy(&pixt1); pixDestroy(&pixt2); pixDestroy(&pixhmt); pixDestroy(&pixd); selDestroy(&sel); selDestroy(&sel_2h); boxaDestroy(&boxa1); boxaDestroy(&boxa2); printf("\n---\nEND\n"); getchar(); return 0; }
main(int argc, char **argv) { char *selnameh, *selnamev; l_int32 ok, same, w, h, i, bordercolor, extraborder; l_int32 width[3] = {21, 1, 21}; l_int32 height[3] = {1, 7, 7}; PIX *pixs, *pixref; PIX *pixt0, *pixt1, *pixt2, *pixt3, *pixt4; SEL *sel; SELA *sela; static char mainName[] = "binmorph3_reg"; if (argc != 1) exit(ERROR_INT(" Syntax: binmorph3_reg", mainName, 1)); if ((pixs = pixRead("feyn.tif")) == NULL) exit(ERROR_INT("pix not made", mainName, 1)); #if TEST_SYMMETRIC resetMorphBoundaryCondition(SYMMETRIC_MORPH_BC); #endif /* TEST_SYMMETRIC */ for (i = 0; i < 3; i++) { w = width[i]; h = height[i]; sel = selCreateBrick(h, w, h / 2, w / 2, SEL_HIT); selnameh = NULL; selnamev = NULL; /* Get the selnames for horiz and vert */ sela = selaAddBasic(NULL); if (w > 1) { if ((selnameh = selaGetBrickName(sela, w, 1)) == NULL) { selaDestroy(&sela); return ERROR_INT("dwa hor sel not defined", mainName, 1); } } if (h > 1) { if ((selnamev = selaGetBrickName(sela, 1, h)) == NULL) { selaDestroy(&sela); return ERROR_INT("dwa vert sel not defined", mainName, 1); } } fprintf(stderr, "w = %d, h = %d, selh = %s, selv = %s\n", w, h, selnameh, selnamev); ok = TRUE; selaDestroy(&sela); /* ----------------- Dilation ----------------- */ fprintf(stderr, "Testing dilation\n"); pixref = pixDilate(NULL, pixs, sel); pixt1 = pixDilateBrickDwa(NULL, pixs, w, h); pixEqual(pixref, pixt1, &same); if (!same) { fprintf(stderr, "pixref != pixt1 !\n"); ok = FALSE; } pixDestroy(&pixt1); if (w > 1) pixt1 = pixMorphDwa_1(NULL, pixs, L_MORPH_DILATE, selnameh); else pixt1 = pixClone(pixs); if (h > 1) pixt2 = pixMorphDwa_1(NULL, pixt1, L_MORPH_DILATE, selnamev); else pixt2 = pixClone(pixt1); pixEqual(pixref, pixt2, &same); if (!same) { fprintf(stderr, "pixref != pixt2 !\n"); ok = FALSE; } pixDestroy(&pixt1); pixDestroy(&pixt2); pixt1 = pixAddBorder(pixs, 32, 0); if (w > 1) pixt2 = pixFMorphopGen_1(NULL, pixt1, L_MORPH_DILATE, selnameh); else pixt2 = pixClone(pixt1); if (h > 1) pixt3 = pixFMorphopGen_1(NULL, pixt2, L_MORPH_DILATE, selnamev); else pixt3 = pixClone(pixt2); pixt4 = pixRemoveBorder(pixt3, 32); pixEqual(pixref, pixt4, &same); if (!same) { fprintf(stderr, "pixref != pixt4 !\n"); ok = FALSE; } pixDestroy(&pixref); pixDestroy(&pixt1); pixDestroy(&pixt2); pixDestroy(&pixt3); pixDestroy(&pixt4); /* ----------------- Erosion ----------------- */ fprintf(stderr, "Testing erosion\n"); pixref = pixErode(NULL, pixs, sel); pixt1 = pixErodeBrickDwa(NULL, pixs, w, h); pixEqual(pixref, pixt1, &same); if (!same) { fprintf(stderr, "pixref != pixt1 !\n"); ok = FALSE; } pixDestroy(&pixt1); if (w > 1) pixt1 = pixMorphDwa_1(NULL, pixs, L_MORPH_ERODE, selnameh); else pixt1 = pixClone(pixs); if (h > 1) pixt2 = pixMorphDwa_1(NULL, pixt1, L_MORPH_ERODE, selnamev); else pixt2 = pixClone(pixt1); pixEqual(pixref, pixt2, &same); if (!same) { fprintf(stderr, "pixref != pixt2 !\n"); ok = FALSE; } pixDestroy(&pixt1); pixDestroy(&pixt2); pixt1 = pixAddBorder(pixs, 32, 0); if (w > 1) pixt2 = pixFMorphopGen_1(NULL, pixt1, L_MORPH_ERODE, selnameh); else pixt2 = pixClone(pixt1); if (h > 1) pixt3 = pixFMorphopGen_1(NULL, pixt2, L_MORPH_ERODE, selnamev); else pixt3 = pixClone(pixt2); pixt4 = pixRemoveBorder(pixt3, 32); pixEqual(pixref, pixt4, &same); if (!same) { fprintf(stderr, "pixref != pixt4 !\n"); ok = FALSE; } pixDestroy(&pixref); pixDestroy(&pixt1); pixDestroy(&pixt2); pixDestroy(&pixt3); pixDestroy(&pixt4); /* ----------------- Opening ----------------- */ fprintf(stderr, "Testing opening\n"); pixref = pixOpen(NULL, pixs, sel); pixt1 = pixOpenBrickDwa(NULL, pixs, w, h); pixEqual(pixref, pixt1, &same); if (!same) { fprintf(stderr, "pixref != pixt1 !\n"); ok = FALSE; } pixDestroy(&pixt1); if (h == 1) pixt2 = pixMorphDwa_1(NULL, pixs, L_MORPH_OPEN, selnameh); else if (w == 1) pixt2 = pixMorphDwa_1(NULL, pixs, L_MORPH_OPEN, selnamev); else { pixt1 = pixMorphDwa_1(NULL, pixs, L_MORPH_ERODE, selnameh); pixt2 = pixMorphDwa_1(NULL, pixt1, L_MORPH_ERODE, selnamev); pixMorphDwa_1(pixt1, pixt2, L_MORPH_DILATE, selnameh); pixMorphDwa_1(pixt2, pixt1, L_MORPH_DILATE, selnamev); pixDestroy(&pixt1); } pixEqual(pixref, pixt2, &same); if (!same) { fprintf(stderr, "pixref != pixt2 !\n"); ok = FALSE; } pixDestroy(&pixt2); pixt1 = pixAddBorder(pixs, 32, 0); if (h == 1) pixt3 = pixFMorphopGen_1(NULL, pixt1, L_MORPH_OPEN, selnameh); else if (w == 1) pixt3 = pixFMorphopGen_1(NULL, pixt1, L_MORPH_OPEN, selnamev); else { pixt2 = pixFMorphopGen_1(NULL, pixt1, L_MORPH_ERODE, selnameh); pixt3 = pixFMorphopGen_1(NULL, pixt2, L_MORPH_ERODE, selnamev); pixFMorphopGen_1(pixt2, pixt3, L_MORPH_DILATE, selnameh); pixFMorphopGen_1(pixt3, pixt2, L_MORPH_DILATE, selnamev); pixDestroy(&pixt2); } pixt4 = pixRemoveBorder(pixt3, 32); pixEqual(pixref, pixt4, &same); if (!same) { fprintf(stderr, "pixref != pixt4 !\n"); ok = FALSE; } pixDestroy(&pixref); pixDestroy(&pixt1); pixDestroy(&pixt3); pixDestroy(&pixt4); /* ----------------- Closing ----------------- */ fprintf(stderr, "Testing closing\n"); pixref = pixClose(NULL, pixs, sel); /* Note: L_MORPH_CLOSE for h==1 or w==1 gives safe closing, * so we can't use it here. */ if (h == 1) { pixt1 = pixMorphDwa_1(NULL, pixs, L_MORPH_DILATE, selnameh); pixt2 = pixMorphDwa_1(NULL, pixt1, L_MORPH_ERODE, selnameh); } else if (w == 1) { pixt1 = pixMorphDwa_1(NULL, pixs, L_MORPH_DILATE, selnamev); pixt2 = pixMorphDwa_1(NULL, pixt1, L_MORPH_ERODE, selnamev); } else { pixt1 = pixMorphDwa_1(NULL, pixs, L_MORPH_DILATE, selnameh); pixt2 = pixMorphDwa_1(NULL, pixt1, L_MORPH_DILATE, selnamev); pixMorphDwa_1(pixt1, pixt2, L_MORPH_ERODE, selnameh); pixMorphDwa_1(pixt2, pixt1, L_MORPH_ERODE, selnamev); } pixDestroy(&pixt1); pixEqual(pixref, pixt2, &same); if (!same) { fprintf(stderr, "pixref != pixt2 !\n"); ok = FALSE; } pixDestroy(&pixt2); /* Note: by adding only 32 pixels of border, we get * the normal closing operation, even when calling * with L_MORPH_CLOSE, because it requires 32 pixels * of border to be safe. */ pixt1 = pixAddBorder(pixs, 32, 0); if (h == 1) pixt3 = pixFMorphopGen_1(NULL, pixt1, L_MORPH_CLOSE, selnameh); else if (w == 1) pixt3 = pixFMorphopGen_1(NULL, pixt1, L_MORPH_CLOSE, selnamev); else { pixt2 = pixFMorphopGen_1(NULL, pixt1, L_MORPH_DILATE, selnameh); pixt3 = pixFMorphopGen_1(NULL, pixt2, L_MORPH_DILATE, selnamev); pixFMorphopGen_1(pixt2, pixt3, L_MORPH_ERODE, selnameh); pixFMorphopGen_1(pixt3, pixt2, L_MORPH_ERODE, selnamev); pixDestroy(&pixt2); } pixt4 = pixRemoveBorder(pixt3, 32); pixEqual(pixref, pixt4, &same); if (!same) { fprintf(stderr, "pixref != pixt4 !\n"); ok = FALSE; } pixDestroy(&pixref); pixDestroy(&pixt1); pixDestroy(&pixt3); pixDestroy(&pixt4); /* ------------- Safe Closing ----------------- */ fprintf(stderr, "Testing safe closing\n"); pixref = pixCloseSafe(NULL, pixs, sel); pixt0 = pixCloseSafeBrick(NULL, pixs, w, h); pixEqual(pixref, pixt0, &same); if (!same) { fprintf(stderr, "pixref != pixt0 !\n"); ok = FALSE; } pixDestroy(&pixt0); pixt1 = pixCloseBrickDwa(NULL, pixs, w, h); pixEqual(pixref, pixt1, &same); if (!same) { fprintf(stderr, "pixref != pixt1 !\n"); ok = FALSE; } pixDestroy(&pixt1); bordercolor = getMorphBorderPixelColor(L_MORPH_ERODE, 1); if (bordercolor == 0) /* asymmetric b.c. */ extraborder = 32; else /* symmetric b.c. */ extraborder = 0; /* Note: for safe closing we need 64 border pixels. * However, when we implement a separable Sel * with pixMorphDwa_*(), we must do dilation and * erosion explicitly, and these functions only * add/remove a 32-pixel border. Thus, for that * case we must add an additional 32-pixel border * before doing the operations. That is the reason * why the implementation in morphdwa.c adds the * 64 bit border and then uses the lower-level * pixFMorphopGen_*() functions. */ if (h == 1) pixt3 = pixMorphDwa_1(NULL, pixs, L_MORPH_CLOSE, selnameh); else if (w == 1) pixt3 = pixMorphDwa_1(NULL, pixs, L_MORPH_CLOSE, selnamev); else { pixt0 = pixAddBorder(pixs, extraborder, 0); pixt1 = pixMorphDwa_1(NULL, pixt0, L_MORPH_DILATE, selnameh); pixt2 = pixMorphDwa_1(NULL, pixt1, L_MORPH_DILATE, selnamev); pixMorphDwa_1(pixt1, pixt2, L_MORPH_ERODE, selnameh); pixMorphDwa_1(pixt2, pixt1, L_MORPH_ERODE, selnamev); pixt3 = pixRemoveBorder(pixt2, extraborder); pixDestroy(&pixt0); pixDestroy(&pixt1); pixDestroy(&pixt2); } pixEqual(pixref, pixt3, &same); if (!same) { fprintf(stderr, "pixref != pixt3 !\n"); ok = FALSE; } pixDestroy(&pixt3); pixt1 = pixAddBorder(pixs, 32 + extraborder, 0); if (h == 1) pixt3 = pixFMorphopGen_1(NULL, pixt1, L_MORPH_CLOSE, selnameh); else if (w == 1) pixt3 = pixFMorphopGen_1(NULL, pixt1, L_MORPH_CLOSE, selnamev); else { pixt2 = pixFMorphopGen_1(NULL, pixt1, L_MORPH_DILATE, selnameh); pixt3 = pixFMorphopGen_1(NULL, pixt2, L_MORPH_DILATE, selnamev); pixFMorphopGen_1(pixt2, pixt3, L_MORPH_ERODE, selnameh); pixFMorphopGen_1(pixt3, pixt2, L_MORPH_ERODE, selnamev); pixDestroy(&pixt2); } pixt4 = pixRemoveBorder(pixt3, 32 + extraborder); pixEqual(pixref, pixt4, &same); if (!same) { fprintf(stderr, "pixref != pixt4 !\n"); ok = FALSE; } pixDestroy(&pixref); pixDestroy(&pixt1); pixDestroy(&pixt3); pixDestroy(&pixt4); if (ok) fprintf(stderr, "All morph tests OK!\n"); selDestroy(&sel); lept_free(selnameh); lept_free(selnamev); } pixDestroy(&pixs); return 0; }
int main(int argc, char **argv) { l_int32 i, j, w, h, same, width, height, cx, cy; l_uint32 val; BOX *box; PIX *pix0, *pixs, *pixse, *pixd1, *pixd2; SEL *sel; L_REGPARAMS *rp; if (regTestSetup(argc, argv, &rp)) return 1; pix0 = pixRead("feyn-fract.tif"); box = boxCreate(293, 37, pixGetWidth(pix0) - 691, pixGetHeight(pix0) -145); pixs = pixClipRectangle(pix0, box, NULL); boxDestroy(&box); if (rp->display) pixDisplay(pixs, 100, 100); /* Test 63 different sizes */ for (width = 1; width <= 25; width += 3) { /* 9 values */ for (height = 1; height <= 25; height += 4) { /* 7 values */ cx = width / 2; cy = height / 2; /* Dilate using an actual sel */ sel = selCreateBrick(height, width, cy, cx, SEL_HIT); pixd1 = pixDilate(NULL, pixs, sel); /* Dilate using a pix as a sel */ pixse = pixCreate(width, height, 1); pixSetAll(pixse); pixd2 = pixCopy(NULL, pixs); w = pixGetWidth(pixs); h = pixGetHeight(pixs); for (i = 0; i < h; i++) { for (j = 0; j < w; j++) { pixGetPixel(pixs, j, i, &val); if (val) pixRasterop(pixd2, j - cx, i - cy, width, height, PIX_SRC | PIX_DST, pixse, 0, 0); } } pixEqual(pixd1, pixd2, &same); regTestCompareValues(rp, 1, same, 0.0); /* 0 - 62 */ if (same == 0) { fprintf(stderr, "Results differ for SE (width,height) = (%d,%d)\n", width, height); } pixDestroy(&pixse); pixDestroy(&pixd1); pixDestroy(&pixd2); selDestroy(&sel); } } pixDestroy(&pix0); pixDestroy(&pixs); return regTestCleanup(rp); }
main(int argc, char **argv) { l_int32 i, ok, same; char sequence[512]; PIX *pixs, *pixref; PIX *pixt1, *pixt2, *pixt3, *pixt4, *pixt5, *pixt6; PIX *pixt7, *pixt8, *pixt9, *pixt10, *pixt11; PIX *pixt12, *pixt13, *pixt14; SEL *sel; static char mainName[] = "binmorph1_reg"; if (argc != 1) exit(ERROR_INT(" Syntax: binmorph1_reg", mainName, 1)); if ((pixs = pixRead("feyn.tif")) == NULL) exit(ERROR_INT("pix not made", mainName, 1)); #if TEST_SYMMETRIC /* This works properly if there is an added border */ resetMorphBoundaryCondition(SYMMETRIC_MORPH_BC); #if 1 pixt1 = pixAddBorder(pixs, 32, 0); pixTransferAllData(pixs, &pixt1, 0, 0); #endif #endif /* TEST_SYMMETRIC */ /* This is our test sel */ sel = selCreateBrick(HEIGHT, WIDTH, HEIGHT / 2, WIDTH / 2, SEL_HIT); /* Dilation */ fprintf(stderr, "Testing dilation\n"); ok = TRUE; pixref = pixDilate(NULL, pixs, sel); /* new one */ pixt1 = pixCreateTemplate(pixs); pixDilate(pixt1, pixs, sel); /* existing one */ pixEqual(pixref, pixt1, &same); if (!same) { fprintf(stderr, "pixref != pixt1 !\n"); ok = FALSE; } pixt2 = pixCopy(NULL, pixs); pixDilate(pixt2, pixt2, sel); /* in-place */ pixEqual(pixref, pixt2, &same); if (!same) { fprintf(stderr, "pixref != pixt2 !\n"); ok = FALSE; } sprintf(sequence, "d%d.%d", WIDTH, HEIGHT); pixt3 = pixMorphSequence(pixs, sequence, 0); /* sequence, atomic */ pixEqual(pixref, pixt3, &same); if (!same) { fprintf(stderr, "pixref != pixt3 !\n"); ok = FALSE; } sprintf(sequence, "d%d.1 + d1.%d", WIDTH, HEIGHT); pixt4 = pixMorphSequence(pixs, sequence, 0); /* sequence, separable */ pixEqual(pixref, pixt4, &same); if (!same) { fprintf(stderr, "pixref != pixt4 !\n"); ok = FALSE; } pixt5 = pixDilateBrick(NULL, pixs, WIDTH, HEIGHT); /* new one */ pixEqual(pixref, pixt5, &same); if (!same) { fprintf(stderr, "pixref != pixt5 !\n"); ok = FALSE; } pixt6 = pixCreateTemplate(pixs); pixDilateBrick(pixt6, pixs, WIDTH, HEIGHT); /* existing one */ pixEqual(pixref, pixt6, &same); if (!same) { fprintf(stderr, "pixref != pixt6 !\n"); ok = FALSE; } pixt7 = pixCopy(NULL, pixs); pixDilateBrick(pixt7, pixt7, WIDTH, HEIGHT); /* in-place */ pixEqual(pixref, pixt7, &same); if (!same) { fprintf(stderr, "pixref != pixt7 !\n"); ok = FALSE; } pixt8 = pixDilateBrickDwa(NULL, pixs, WIDTH, HEIGHT); /* new one */ pixEqual(pixref, pixt8, &same); if (!same) { fprintf(stderr, "pixref != pixt8 !\n"); ok = FALSE; } pixt9 = pixCreateTemplate(pixs); pixDilateBrickDwa(pixt9, pixs, WIDTH, HEIGHT); /* existing one */ pixEqual(pixref, pixt9, &same); if (!same) { fprintf(stderr, "pixref != pixt9 !\n"); ok = FALSE; } pixt10 = pixCopy(NULL, pixs); pixDilateBrickDwa(pixt10, pixt10, WIDTH, HEIGHT); /* in-place */ pixEqual(pixref, pixt10, &same); if (!same) { fprintf(stderr, "pixref != pixt10 !\n"); ok = FALSE; } pixt11 = pixCreateTemplate(pixs); pixDilateCompBrickDwa(pixt11, pixs, WIDTH, HEIGHT); /* existing one */ pixEqual(pixref, pixt11, &same); if (!same) { fprintf(stderr, "pixref != pixt11 !\n"); ok = FALSE; } sprintf(sequence, "d%d.%d", WIDTH, HEIGHT); pixt12 = pixMorphCompSequence(pixs, sequence, 0); /* comp sequence */ pixEqual(pixref, pixt12, &same); if (!same) { fprintf(stderr, "pixref != pixt12!\n"); ok = FALSE; } pixt13 = pixMorphSequenceDwa(pixs, sequence, 0); /* dwa sequence */ pixEqual(pixref, pixt13, &same); if (!same) { fprintf(stderr, "pixref != pixt13!\n"); ok = FALSE; } pixDestroy(&pixref); pixDestroy(&pixt1); pixDestroy(&pixt2); pixDestroy(&pixt3); pixDestroy(&pixt4); pixDestroy(&pixt5); pixDestroy(&pixt6); pixDestroy(&pixt7); pixDestroy(&pixt8); pixDestroy(&pixt9); pixDestroy(&pixt10); pixDestroy(&pixt11); pixDestroy(&pixt12); pixDestroy(&pixt13); /* Erosion */ fprintf(stderr, "Testing erosion\n"); pixref = pixErode(NULL, pixs, sel); /* new one */ pixt1 = pixCreateTemplate(pixs); pixErode(pixt1, pixs, sel); /* existing one */ pixEqual(pixref, pixt1, &same); if (!same) { fprintf(stderr, "pixref != pixt1 !\n"); ok = FALSE; } pixt2 = pixCopy(NULL, pixs); pixErode(pixt2, pixt2, sel); /* in-place */ pixEqual(pixref, pixt2, &same); if (!same) { fprintf(stderr, "pixref != pixt2 !\n"); ok = FALSE; } sprintf(sequence, "e%d.%d", WIDTH, HEIGHT); pixt3 = pixMorphSequence(pixs, sequence, 0); /* sequence, atomic */ pixEqual(pixref, pixt3, &same); if (!same) { fprintf(stderr, "pixref != pixt3 !\n"); ok = FALSE; } sprintf(sequence, "e%d.1 + e1.%d", WIDTH, HEIGHT); pixt4 = pixMorphSequence(pixs, sequence, 0); /* sequence, separable */ pixEqual(pixref, pixt4, &same); if (!same) { fprintf(stderr, "pixref != pixt4 !\n"); ok = FALSE; } pixt5 = pixErodeBrick(NULL, pixs, WIDTH, HEIGHT); /* new one */ pixEqual(pixref, pixt5, &same); if (!same) { fprintf(stderr, "pixref != pixt5 !\n"); ok = FALSE; } pixt6 = pixCreateTemplate(pixs); pixErodeBrick(pixt6, pixs, WIDTH, HEIGHT); /* existing one */ pixEqual(pixref, pixt6, &same); if (!same) { fprintf(stderr, "pixref != pixt6 !\n"); ok = FALSE; } pixt7 = pixCopy(NULL, pixs); pixErodeBrick(pixt7, pixt7, WIDTH, HEIGHT); /* in-place */ pixEqual(pixref, pixt7, &same); if (!same) { fprintf(stderr, "pixref != pixt7 !\n"); ok = FALSE; } pixt8 = pixErodeBrickDwa(NULL, pixs, WIDTH, HEIGHT); /* new one */ pixEqual(pixref, pixt8, &same); if (!same) { fprintf(stderr, "pixref != pixt8 !\n"); ok = FALSE; } pixt9 = pixCreateTemplate(pixs); pixErodeBrickDwa(pixt9, pixs, WIDTH, HEIGHT); /* existing one */ pixEqual(pixref, pixt9, &same); if (!same) { fprintf(stderr, "pixref != pixt9 !\n"); ok = FALSE; } pixt10 = pixCopy(NULL, pixs); pixErodeBrickDwa(pixt10, pixt10, WIDTH, HEIGHT); /* in-place */ pixEqual(pixref, pixt10, &same); if (!same) { fprintf(stderr, "pixref != pixt10 !\n"); ok = FALSE; } pixt11 = pixCreateTemplate(pixs); pixErodeCompBrickDwa(pixt11, pixs, WIDTH, HEIGHT); /* existing one */ pixEqual(pixref, pixt11, &same); if (!same) { fprintf(stderr, "pixref != pixt11 !\n"); ok = FALSE; } sprintf(sequence, "e%d.%d", WIDTH, HEIGHT); pixt12 = pixMorphCompSequence(pixs, sequence, 0); /* comp sequence */ pixEqual(pixref, pixt12, &same); if (!same) { fprintf(stderr, "pixref != pixt12!\n"); ok = FALSE; } pixt13 = pixMorphSequenceDwa(pixs, sequence, 0); /* dwa sequence */ pixEqual(pixref, pixt13, &same); if (!same) { fprintf(stderr, "pixref != pixt13!\n"); ok = FALSE; } pixDestroy(&pixref); pixDestroy(&pixt1); pixDestroy(&pixt2); pixDestroy(&pixt3); pixDestroy(&pixt4); pixDestroy(&pixt5); pixDestroy(&pixt6); pixDestroy(&pixt7); pixDestroy(&pixt8); pixDestroy(&pixt9); pixDestroy(&pixt10); pixDestroy(&pixt11); pixDestroy(&pixt12); pixDestroy(&pixt13); /* Opening */ fprintf(stderr, "Testing opening\n"); pixref = pixOpen(NULL, pixs, sel); /* new one */ pixt1 = pixCreateTemplate(pixs); pixOpen(pixt1, pixs, sel); /* existing one */ pixEqual(pixref, pixt1, &same); if (!same) { fprintf(stderr, "pixref != pixt1 !\n"); ok = FALSE; } pixt2 = pixCopy(NULL, pixs); pixOpen(pixt2, pixt2, sel); /* in-place */ pixEqual(pixref, pixt2, &same); if (!same) { fprintf(stderr, "pixref != pixt2 !\n"); ok = FALSE; } sprintf(sequence, "o%d.%d", WIDTH, HEIGHT); pixt3 = pixMorphSequence(pixs, sequence, 0); /* sequence, atomic */ pixEqual(pixref, pixt3, &same); if (!same) { fprintf(stderr, "pixref != pixt3 !\n"); ok = FALSE; } sprintf(sequence, "e%d.%d + d%d.%d", WIDTH, HEIGHT, WIDTH, HEIGHT); pixt4 = pixMorphSequence(pixs, sequence, 0); /* sequence, separable */ pixEqual(pixref, pixt4, &same); if (!same) { fprintf(stderr, "pixref != pixt4 !\n"); ok = FALSE; } sprintf(sequence, "e%d.1 + e1.%d + d%d.1 + d1.%d", WIDTH, HEIGHT, WIDTH, HEIGHT); pixt5 = pixMorphSequence(pixs, sequence, 0); /* sequence, separable^2 */ pixEqual(pixref, pixt5, &same); if (!same) { fprintf(stderr, "pixref != pixt5 !\n"); ok = FALSE; } pixt6 = pixOpenBrick(NULL, pixs, WIDTH, HEIGHT); /* new one */ pixEqual(pixref, pixt6, &same); if (!same) { fprintf(stderr, "pixref != pixt6 !\n"); ok = FALSE; } pixt7 = pixCreateTemplate(pixs); pixOpenBrick(pixt7, pixs, WIDTH, HEIGHT); /* existing one */ pixEqual(pixref, pixt7, &same); if (!same) { fprintf(stderr, "pixref != pixt7 !\n"); ok = FALSE; } pixt8 = pixCopy(NULL, pixs); /* in-place */ pixOpenBrick(pixt8, pixt8, WIDTH, HEIGHT); /* existing one */ pixEqual(pixref, pixt8, &same); if (!same) { fprintf(stderr, "pixref != pixt8 !\n"); ok = FALSE; } pixt9 = pixOpenBrickDwa(NULL, pixs, WIDTH, HEIGHT); /* new one */ pixEqual(pixref, pixt9, &same); if (!same) { fprintf(stderr, "pixref != pixt9 !\n"); ok = FALSE; } pixt10 = pixCreateTemplate(pixs); pixOpenBrickDwa(pixt10, pixs, WIDTH, HEIGHT); /* existing one */ pixEqual(pixref, pixt10, &same); if (!same) { fprintf(stderr, "pixref != pixt10 !\n"); ok = FALSE; } pixt11 = pixCopy(NULL, pixs); pixOpenBrickDwa(pixt11, pixt11, WIDTH, HEIGHT); /* in-place */ pixEqual(pixref, pixt11, &same); if (!same) { fprintf(stderr, "pixref != pixt11 !\n"); ok = FALSE; } sprintf(sequence, "o%d.%d", WIDTH, HEIGHT); pixt12 = pixMorphCompSequence(pixs, sequence, 0); /* comp sequence */ pixEqual(pixref, pixt12, &same); if (!same) { fprintf(stderr, "pixref != pixt12!\n"); ok = FALSE; } #if 0 pixWrite("/tmp/junkref.png", pixref, IFF_PNG); pixWrite("/tmp/junk12.png", pixt12, IFF_PNG); pixt13 = pixXor(NULL, pixref, pixt12); pixWrite("/tmp/junk12a.png", pixt13, IFF_PNG); pixDestroy(&pixt13); #endif pixt13 = pixMorphSequenceDwa(pixs, sequence, 0); /* dwa sequence */ pixEqual(pixref, pixt13, &same); if (!same) { fprintf(stderr, "pixref != pixt13!\n"); ok = FALSE; } pixt14 = pixCreateTemplate(pixs); pixOpenCompBrickDwa(pixt14, pixs, WIDTH, HEIGHT); /* existing one */ pixEqual(pixref, pixt14, &same); if (!same) { fprintf(stderr, "pixref != pixt14 !\n"); ok = FALSE; } pixDestroy(&pixref); pixDestroy(&pixt1); pixDestroy(&pixt2); pixDestroy(&pixt3); pixDestroy(&pixt4); pixDestroy(&pixt5); pixDestroy(&pixt6); pixDestroy(&pixt7); pixDestroy(&pixt8); pixDestroy(&pixt9); pixDestroy(&pixt10); pixDestroy(&pixt11); pixDestroy(&pixt12); pixDestroy(&pixt13); pixDestroy(&pixt14); /* Closing */ fprintf(stderr, "Testing closing\n"); pixref = pixClose(NULL, pixs, sel); /* new one */ pixt1 = pixCreateTemplate(pixs); pixClose(pixt1, pixs, sel); /* existing one */ pixEqual(pixref, pixt1, &same); if (!same) { fprintf(stderr, "pixref != pixt1 !\n"); ok = FALSE; } pixt2 = pixCopy(NULL, pixs); pixClose(pixt2, pixt2, sel); /* in-place */ pixEqual(pixref, pixt2, &same); if (!same) { fprintf(stderr, "pixref != pixt2 !\n"); ok = FALSE; } sprintf(sequence, "d%d.%d + e%d.%d", WIDTH, HEIGHT, WIDTH, HEIGHT); pixt3 = pixMorphSequence(pixs, sequence, 0); /* sequence, separable */ pixEqual(pixref, pixt3, &same); if (!same) { fprintf(stderr, "pixref != pixt3 !\n"); ok = FALSE; } sprintf(sequence, "d%d.1 + d1.%d + e%d.1 + e1.%d", WIDTH, HEIGHT, WIDTH, HEIGHT); pixt4 = pixMorphSequence(pixs, sequence, 0); /* sequence, separable^2 */ pixEqual(pixref, pixt4, &same); if (!same) { fprintf(stderr, "pixref != pixt4 !\n"); ok = FALSE; } pixt5 = pixCloseBrick(NULL, pixs, WIDTH, HEIGHT); /* new one */ pixEqual(pixref, pixt5, &same); if (!same) { fprintf(stderr, "pixref != pixt5 !\n"); ok = FALSE; } pixt6 = pixCreateTemplate(pixs); pixCloseBrick(pixt6, pixs, WIDTH, HEIGHT); /* existing one */ pixEqual(pixref, pixt6, &same); if (!same) { fprintf(stderr, "pixref != pixt6 !\n"); ok = FALSE; } pixt7 = pixCopy(NULL, pixs); /* in-place */ pixCloseBrick(pixt7, pixt7, WIDTH, HEIGHT); /* existing one */ pixEqual(pixref, pixt7, &same); if (!same) { fprintf(stderr, "pixref != pixt7 !\n"); ok = FALSE; } pixDestroy(&pixref); pixDestroy(&pixt1); pixDestroy(&pixt2); pixDestroy(&pixt3); pixDestroy(&pixt4); pixDestroy(&pixt5); pixDestroy(&pixt6); pixDestroy(&pixt7); /* Safe closing (using pix, not pixs) */ fprintf(stderr, "Testing safe closing\n"); pixref = pixCloseSafe(NULL, pixs, sel); /* new one */ pixt1 = pixCreateTemplate(pixs); pixCloseSafe(pixt1, pixs, sel); /* existing one */ pixEqual(pixref, pixt1, &same); if (!same) { fprintf(stderr, "pixref != pixt1 !\n"); ok = FALSE; } pixt2 = pixCopy(NULL, pixs); pixCloseSafe(pixt2, pixt2, sel); /* in-place */ pixEqual(pixref, pixt2, &same); if (!same) { fprintf(stderr, "pixref != pixt2 !\n"); ok = FALSE; } sprintf(sequence, "c%d.%d", WIDTH, HEIGHT); pixt3 = pixMorphSequence(pixs, sequence, 0); /* sequence, atomic */ pixEqual(pixref, pixt3, &same); if (!same) { fprintf(stderr, "pixref != pixt3 !\n"); ok = FALSE; } sprintf(sequence, "b32 + d%d.%d + e%d.%d", WIDTH, HEIGHT, WIDTH, HEIGHT); pixt4 = pixMorphSequence(pixs, sequence, 0); /* sequence, separable */ pixEqual(pixref, pixt4, &same); if (!same) { fprintf(stderr, "pixref != pixt4 !\n"); ok = FALSE; } sprintf(sequence, "b32 + d%d.1 + d1.%d + e%d.1 + e1.%d", WIDTH, HEIGHT, WIDTH, HEIGHT); pixt5 = pixMorphSequence(pixs, sequence, 0); /* sequence, separable^2 */ pixEqual(pixref, pixt5, &same); if (!same) { fprintf(stderr, "pixref != pixt5 !\n"); ok = FALSE; } pixt6 = pixCloseSafeBrick(NULL, pixs, WIDTH, HEIGHT); /* new one */ pixEqual(pixref, pixt6, &same); if (!same) { fprintf(stderr, "pixref != pixt6 !\n"); ok = FALSE; } pixt7 = pixCreateTemplate(pixs); pixCloseSafeBrick(pixt7, pixs, WIDTH, HEIGHT); /* existing one */ pixEqual(pixref, pixt7, &same); if (!same) { fprintf(stderr, "pixref != pixt7 !\n"); ok = FALSE; } pixt8 = pixCopy(NULL, pixs); /* in-place */ pixCloseSafeBrick(pixt8, pixt8, WIDTH, HEIGHT); /* existing one */ pixEqual(pixref, pixt8, &same); if (!same) { fprintf(stderr, "pixref != pixt8 !\n"); ok = FALSE; } pixt9 = pixCloseBrickDwa(NULL, pixs, WIDTH, HEIGHT); /* new one */ pixEqual(pixref, pixt9, &same); if (!same) { fprintf(stderr, "pixref != pixt9 !\n"); ok = FALSE; } pixt10 = pixCreateTemplate(pixs); pixCloseBrickDwa(pixt10, pixs, WIDTH, HEIGHT); /* existing one */ pixEqual(pixref, pixt10, &same); if (!same) { fprintf(stderr, "pixref != pixt10 !\n"); ok = FALSE; } pixt11 = pixCopy(NULL, pixs); pixCloseBrickDwa(pixt11, pixt11, WIDTH, HEIGHT); /* in-place */ pixEqual(pixref, pixt11, &same); if (!same) { fprintf(stderr, "pixref != pixt11 !\n"); ok = FALSE; } sprintf(sequence, "c%d.%d", WIDTH, HEIGHT); pixt12 = pixMorphCompSequence(pixs, sequence, 0); /* comp sequence */ pixEqual(pixref, pixt12, &same); if (!same) { fprintf(stderr, "pixref != pixt12!\n"); ok = FALSE; } pixt13 = pixMorphSequenceDwa(pixs, sequence, 0); /* dwa sequence */ pixEqual(pixref, pixt13, &same); if (!same) { fprintf(stderr, "pixref != pixt13!\n"); ok = FALSE; } pixt14 = pixCreateTemplate(pixs); pixCloseCompBrickDwa(pixt14, pixs, WIDTH, HEIGHT); /* existing one */ pixEqual(pixref, pixt14, &same); if (!same) { fprintf(stderr, "pixref != pixt14 !\n"); ok = FALSE; } #if 0 pixWrite("/tmp/junkref.png", pixref, IFF_PNG); pixWrite("/tmp/junk12.png", pixt12, IFF_PNG); pixt13 = pixXor(NULL, pixref, pixt12); pixWrite("/tmp/junk12a.png", pixt13, IFF_PNG); pixDestroy(&pixt13); #endif pixDestroy(&pixref); pixDestroy(&pixt1); pixDestroy(&pixt2); pixDestroy(&pixt3); pixDestroy(&pixt4); pixDestroy(&pixt5); pixDestroy(&pixt6); pixDestroy(&pixt7); pixDestroy(&pixt8); pixDestroy(&pixt9); pixDestroy(&pixt10); pixDestroy(&pixt11); pixDestroy(&pixt12); pixDestroy(&pixt13); pixDestroy(&pixt14); if (ok) fprintf(stderr, "All morph tests OK!\n"); pixDestroy(&pixs); selDestroy(&sel); exit(0); }