/*! * selaAddDwaCombs() * * Input: sela (<optional>) * Return: sela with additional sels, or null on error * * Notes: * (1) Adds all comb (horizontal, vertical) Sels that are * used in composite linear morphological operations * up to 63 pixels in length, which are the sizes over * which dwa code can be generated. */ SELA * selaAddDwaCombs(SELA *sela) { char name[L_BUF_SIZE]; l_int32 i, f1, f2, prevsize, size; SEL *selh, *selv; PROCNAME("selaAddDwaCombs"); if (!sela) { if ((sela = selaCreate(0)) == NULL) return (SELA *)ERROR_PTR("sela not made", procName, NULL); } prevsize = 0; for (i = 4; i < 64; i++) { selectComposableSizes(i, &f1, &f2); size = f1 * f2; if (size == prevsize) continue; selectComposableSels(i, L_HORIZ, NULL, &selh); selectComposableSels(i, L_VERT, NULL, &selv); snprintf(name, L_BUF_SIZE, "sel_comb_%dh", size); selaAddSel(sela, selh, name, 0); snprintf(name, L_BUF_SIZE, "sel_comb_%dv", size); selaAddSel(sela, selv, name, 0); prevsize = size; } return sela; }
main(int argc, char **argv) { PIX *pixd; SEL *sel1, *sel2, *sel3, *sel4; SELA *sela; static char mainName[] = "livre_orient"; sel1 = selCreateFromString(textsel1, 5, 6, NULL); sel2 = selCreateFromString(textsel2, 5, 6, NULL); sel3 = selCreateFromString(textsel3, 5, 6, NULL); sel4 = selCreateFromString(textsel4, 5, 6, NULL); sela = selaCreate(4); selaAddSel(sela, sel1, "textsel1", L_INSERT); selaAddSel(sela, sel2, "textsel2", L_INSERT); selaAddSel(sela, sel3, "textsel3", L_INSERT); selaAddSel(sela, sel4, "textsel4", L_INSERT); pixd = selaDisplayInPix(sela, 28, 3, 30, 4); pixWrite("/tmp/orient.png", pixd, IFF_PNG); pixDisplay(pixd, 100, 100); pixDestroy(&pixd); selaDestroy(&sela); return 0; }
/*! * 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; }
/*! * \brief sela8ccThin() * * \param[in] sela [optional] * \return sela with additional sels, or NULL on error * * <pre> * Notes: * (1) Adds the 9 basic sels for 8-cc thinning. * </pre> */ SELA * sela8ccThin(SELA *sela) { SEL *sel; if (!sela) sela = selaCreate(9); sel = selCreateFromString(sel_8_1, 3, 3, "sel_8_1"); selaAddSel(sela, sel, NULL, 0); sel = selCreateFromString(sel_8_2, 3, 3, "sel_8_2"); selaAddSel(sela, sel, NULL, 0); sel = selCreateFromString(sel_8_3, 3, 3, "sel_8_3"); selaAddSel(sela, sel, NULL, 0); sel = selCreateFromString(sel_8_4, 3, 3, "sel_8_4"); selaAddSel(sela, sel, NULL, 0); sel = selCreateFromString(sel_8_5, 3, 3, "sel_8_5"); selaAddSel(sela, sel, NULL, 0); sel = selCreateFromString(sel_8_6, 3, 3, "sel_8_6"); selaAddSel(sela, sel, NULL, 0); sel = selCreateFromString(sel_8_7, 3, 3, "sel_8_7"); selaAddSel(sela, sel, NULL, 0); sel = selCreateFromString(sel_8_8, 3, 3, "sel_8_8"); selaAddSel(sela, sel, NULL, 0); sel = selCreateFromString(sel_8_9, 3, 3, "sel_8_9"); selaAddSel(sela, sel, NULL, 0); return sela; }
/*! * \brief sela4and8ccThin() * * \param[in] sela [optional] * \return sela with additional sels, or NULL on error * * <pre> * Notes: * (1) Adds the 2 basic sels for either 4-cc or 8-cc thinning. * </pre> */ SELA * sela4and8ccThin(SELA *sela) { SEL *sel; if (!sela) sela = selaCreate(2); sel = selCreateFromString(sel_48_1, 3, 3, "sel_48_1"); selaAddSel(sela, sel, NULL, 0); sel = selCreateFromString(sel_48_2, 3, 3, "sel_48_2"); selaAddSel(sela, sel, NULL, 0); return sela; }
main(int argc, char **argv) { PIX *pix; SEL *sel; SELA *sela1, *sela2; L_REGPARAMS *rp; if (regTestSetup(argc, argv, &rp)) return 1; /* selaRead() / selaWrite() */ sela1 = selaAddBasic(NULL); selaWrite("/tmp/sel.0.sela", sela1); regTestCheckFile(rp, "/tmp/sel.0.sela"); /* 0 */ sela2 = selaRead("/tmp/sel.0.sela"); selaWrite("/tmp/sel.1.sela", sela2); regTestCheckFile(rp, "/tmp/sel.1.sela"); /* 1 */ regTestCompareFiles(rp, 0, 1); /* 2 */ selaDestroy(&sela1); selaDestroy(&sela2); /* Create from file and display result */ sela1 = selaCreateFromFile("flipsels.txt"); pix = selaDisplayInPix(sela1, 31, 3, 15, 4); regTestWritePixAndCheck(rp, pix, IFF_PNG); /* 3 */ pixDisplayWithTitle(pix, 100, 100, NULL, rp->display); selaWrite("/tmp/sel.3.sela", sela1); regTestCheckFile(rp, "/tmp/sel.3.sela"); /* 4 */ pixDestroy(&pix); selaDestroy(&sela1); /* Create the same set of Sels from compiled strings and compare */ sela2 = selaCreate(4); sel = selCreateFromString(textsel1, 5, 6, "textsel1"); selaAddSel(sela2, sel, NULL, 0); sel = selCreateFromString(textsel2, 5, 6, "textsel2"); selaAddSel(sela2, sel, NULL, 0); sel = selCreateFromString(textsel3, 5, 6, "textsel3"); selaAddSel(sela2, sel, NULL, 0); sel = selCreateFromString(textsel4, 5, 6, "textsel4"); selaAddSel(sela2, sel, NULL, 0); selaWrite("/tmp/sel.4.sela", sela2); regTestCheckFile(rp, "/tmp/sel.4.sela"); /* 5 */ regTestCompareFiles(rp, 4, 5); /* 6 */ selaDestroy(&sela2); return regTestCleanup(rp); }
int main(int argc, char **argv) { SEL *sel1, *sel2, *sel3, *sel4; SELA *sela; PIX *pix, *pixd; PIXA *pixa; static char mainName[] = "flipselgen"; if (argc != 1) return ERROR_INT(" Syntax: flipselgen", mainName, 1); sela = selaCreate(0); sel1 = selCreateFromString(textsel1, 5, 6, "flipsel1"); sel2 = selCreateFromString(textsel2, 5, 6, "flipsel2"); sel3 = selCreateFromString(textsel3, 5, 6, "flipsel3"); sel4 = selCreateFromString(textsel4, 5, 6, "flipsel4"); selaAddSel(sela, sel1, NULL, 0); selaAddSel(sela, sel2, NULL, 0); selaAddSel(sela, sel3, NULL, 0); selaAddSel(sela, sel4, NULL, 0); pixa = pixaCreate(4); pix = selDisplayInPix(sel1, 23, 2); pixDisplayWithTitle(pix, 100, 100, "sel1", DFLAG); pixaAddPix(pixa, pix, L_INSERT); pix = selDisplayInPix(sel2, 23, 2); pixDisplayWithTitle(pix, 275, 100, "sel2", DFLAG); pixaAddPix(pixa, pix, L_INSERT); pix = selDisplayInPix(sel3, 23, 2); pixDisplayWithTitle(pix, 450, 100, "sel3", DFLAG); pixaAddPix(pixa, pix, L_INSERT); pix = selDisplayInPix(sel4, 23, 2); pixDisplayWithTitle(pix, 625, 100, "sel4", DFLAG); pixaAddPix(pixa, pix, L_INSERT); pixd = pixaDisplayTiled(pixa, 800, 0, 15); pixDisplayWithTitle(pixd, 100, 300, "allsels", DFLAG); pixDestroy(&pixd); pixaDestroy(&pixa); if (fhmtautogen(sela, INDEX, NULL)) return ERROR_INT(" Generation failed", mainName, 1); selaDestroy(&sela); return 0; }
/*! * pixThin() * * Input: pixs (1 bpp) * type (L_THIN_FG, L_THIN_BG) * connectivity (4 or 8) * maxiters (max number of iters allowed; use 0 to iterate * until completion) * Return: pixd, or null on error * * Notes: * (1) See "Connectivity-preserving morphological image transformations," * Dan S. Bloomberg, in SPIE Visual Communications and Image * Processing, Conference 1606, pp. 320-334, November 1991, * Boston, MA. A web version is available at * http://www.leptonica.com/papers/conn.pdf * (2) We implement here two of the best iterative * morphological thinning algorithms, for 4 c.c and 8 c.c. * Each iteration uses a mixture of parallel operations * (using several different 3x3 Sels) and serial operations. * Specifically, each thinning iteration consists of * four sequential thinnings from each of four directions. * Each of these thinnings is a parallel composite * operation, where the union of a set of HMTs are set * subtracted from the input. For 4-cc thinning, we * use 3 HMTs in parallel, and for 8-cc thinning we use 4 HMTs. * (3) A "good" thinning algorithm is one that generates a skeleton * that is near the medial axis and has neither pruned * real branches nor left extra dendritic branches. * (4) To thin the foreground, which is the usual situation, * use type == L_THIN_FG. Thickening the foreground is equivalent * to thinning the background (type == L_THIN_BG), where the * opposite connectivity gets preserved. For example, to thicken * the fg using 4-connectivity, we thin the bg using Sels that * preserve 8-connectivity. */ PIX * pixThin(PIX *pixs, l_int32 type, l_int32 connectivity, l_int32 maxiters) { PIX *pixd; SEL *sel; SELA *sela; PROCNAME("pixThin"); if (!pixs) return (PIX *)ERROR_PTR("pixs not defined", procName, NULL); if (pixGetDepth(pixs) != 1) return (PIX *)ERROR_PTR("pixs not 1 bpp", procName, NULL); if (type != L_THIN_FG && type != L_THIN_BG) return (PIX *)ERROR_PTR("invalid fg/bg type", procName, NULL); if (connectivity != 4 && connectivity != 8) return (PIX *)ERROR_PTR("connectivity not 4 or 8", procName, NULL); if (maxiters == 0) maxiters = 10000; sela = selaCreate(4); if (connectivity == 4) { sel = selCreateFromString(sel_4_1, 3, 3, "sel_4_1"); selaAddSel(sela, sel, NULL, 0); sel = selCreateFromString(sel_4_2, 3, 3, "sel_4_2"); selaAddSel(sela, sel, NULL, 0); sel = selCreateFromString(sel_4_3, 3, 3, "sel_4_3"); selaAddSel(sela, sel, NULL, 0); } else { /* connectivity == 8 */ sel = selCreateFromString(sel_8_2, 3, 3, "sel_8_2"); selaAddSel(sela, sel, NULL, 0); sel = selCreateFromString(sel_8_3, 3, 3, "sel_8_3"); selaAddSel(sela, sel, NULL, 0); sel = selCreateFromString(sel_8_5, 3, 3, "sel_8_5"); selaAddSel(sela, sel, NULL, 0); sel = selCreateFromString(sel_8_6, 3, 3, "sel_8_6"); selaAddSel(sela, sel, NULL, 0); } pixd = pixThinGeneral(pixs, type, sela, maxiters); selaDestroy(&sela); return pixd; }
/*! * pixThinExamples() * * Input: pixs (1 bpp) * type (L_THIN_FG, L_THIN_BG) * index (into specific examples; valid 1-9; see notes) * maxiters (max number of iters allowed; use 0 to iterate * until completion) * selfile (<optional> filename for output sel display) * Return: pixd, or null on error * * Notes: * (1) See notes in pixThin(). The examples are taken from * the paper referenced there. * (2) Here we allow specific sets of HMTs to be used in * parallel for thinning from each of four directions. * One iteration consists of four such parallel thins. * (3) The examples are indexed as follows: * Thinning (e.g., run to completion): * index = 1 sel_4_1, sel_4_5, sel_4_6 * index = 2 sel_4_1, sel_4_7, sel_4_7_rot * index = 3 sel_48_1, sel_48_1_rot, sel_48_2 * index = 4 sel_8_2, sel_8_3, sel_48_2 * index = 5 sel_8_1, sel_8_5, sel_8_6 * index = 6 sel_8_2, sel_8_3, sel_8_8, sel_8_9 * index = 7 sel_8_5, sel_8_6, sel_8_7, sel_8_7_rot * Thickening: * index = 8 sel_4_2, sel_4_3 (e.g,, do just a few iterations) * index = 9 sel_8_4 (e.g., do just a few iterations) */ PIX * pixThinExamples(PIX *pixs, l_int32 type, l_int32 index, l_int32 maxiters, const char *selfile) { PIX *pixd, *pixt; SEL *sel; SELA *sela; PROCNAME("pixThinExamples"); if (!pixs) return (PIX *)ERROR_PTR("pixs not defined", procName, NULL); if (pixGetDepth(pixs) != 1) return (PIX *)ERROR_PTR("pixs not 1 bpp", procName, NULL); if (type != L_THIN_FG && type != L_THIN_BG) return (PIX *)ERROR_PTR("invalid fg/bg type", procName, NULL); if (index < 1 || index > 9) return (PIX *)ERROR_PTR("invalid index", procName, NULL); if (maxiters == 0) maxiters = 10000; switch(index) { case 1: sela = selaCreate(3); sel = selCreateFromString(sel_4_1, 3, 3, "sel_4_1"); selaAddSel(sela, sel, NULL, 0); sel = selCreateFromString(sel_4_5, 3, 3, "sel_4_5"); selaAddSel(sela, sel, NULL, 0); sel = selCreateFromString(sel_4_6, 3, 3, "sel_4_6"); selaAddSel(sela, sel, NULL, 0); break; case 2: sela = selaCreate(3); sel = selCreateFromString(sel_4_1, 3, 3, "sel_4_1"); selaAddSel(sela, sel, NULL, 0); sel = selCreateFromString(sel_4_7, 3, 3, "sel_4_7"); selaAddSel(sela, sel, NULL, 0); sel = selRotateOrth(sel, 1); selaAddSel(sela, sel, "sel_4_7_rot", 0); break; case 3: sela = selaCreate(3); sel = selCreateFromString(sel_48_1, 3, 3, "sel_48_1"); selaAddSel(sela, sel, NULL, 0); sel = selRotateOrth(sel, 1); selaAddSel(sela, sel, "sel_48_1_rot", 0); sel = selCreateFromString(sel_48_2, 3, 3, "sel_48_2"); selaAddSel(sela, sel, NULL, 0); break; case 4: sela = selaCreate(3); sel = selCreateFromString(sel_8_2, 3, 3, "sel_8_2"); selaAddSel(sela, sel, NULL, 0); sel = selCreateFromString(sel_8_3, 3, 3, "sel_8_3"); selaAddSel(sela, sel, NULL, 0); sel = selCreateFromString(sel_48_2, 3, 3, "sel_48_2"); selaAddSel(sela, sel, NULL, 0); break; case 5: sela = selaCreate(3); sel = selCreateFromString(sel_8_1, 3, 3, "sel_8_1"); selaAddSel(sela, sel, NULL, 0); sel = selCreateFromString(sel_8_5, 3, 3, "sel_8_5"); selaAddSel(sela, sel, NULL, 0); sel = selCreateFromString(sel_8_6, 3, 3, "sel_8_6"); selaAddSel(sela, sel, NULL, 0); break; case 6: sela = selaCreate(4); sel = selCreateFromString(sel_8_2, 3, 3, "sel_8_2"); selaAddSel(sela, sel, NULL, 0); sel = selCreateFromString(sel_8_3, 3, 3, "sel_8_3"); selaAddSel(sela, sel, NULL, 0); sel = selCreateFromString(sel_8_8, 3, 3, "sel_8_8"); selaAddSel(sela, sel, NULL, 0); sel = selCreateFromString(sel_8_9, 3, 3, "sel_8_9"); selaAddSel(sela, sel, NULL, 0); break; case 7: sela = selaCreate(4); sel = selCreateFromString(sel_8_5, 3, 3, "sel_8_5"); selaAddSel(sela, sel, NULL, 0); sel = selCreateFromString(sel_8_6, 3, 3, "sel_8_6"); selaAddSel(sela, sel, NULL, 0); sel = selCreateFromString(sel_8_7, 3, 3, "sel_8_7"); selaAddSel(sela, sel, NULL, 0); sel = selRotateOrth(sel, 1); selaAddSel(sela, sel, "sel_8_7_rot", 0); break; case 8: /* thicken for this one; just a few iterations */ sela = selaCreate(2); sel = selCreateFromString(sel_4_2, 3, 3, "sel_4_2"); selaAddSel(sela, sel, NULL, 0); sel = selCreateFromString(sel_4_3, 3, 3, "sel_4_3"); selaAddSel(sela, sel, NULL, 0); pixt = pixThinGeneral(pixs, type, sela, maxiters); pixd = pixRemoveBorderConnComps(pixt, 4); pixDestroy(&pixt); break; case 9: /* thicken for this one; just a few iterations */ sela = selaCreate(1); sel = selCreateFromString(sel_8_4, 3, 3, "sel_8_4"); selaAddSel(sela, sel, NULL, 0); pixt = pixThinGeneral(pixs, type, sela, maxiters); pixd = pixRemoveBorderConnComps(pixt, 4); pixDestroy(&pixt); break; default: return (PIX *)ERROR_PTR("invalid index", procName, NULL); } if (index <= 7) pixd = pixThinGeneral(pixs, type, sela, maxiters); /* Optionally display the sels */ if (selfile) { pixt = selaDisplayInPix(sela, 35, 3, 15, 4); pixWrite(selfile, pixt, IFF_PNG); pixDestroy(&pixt); } selaDestroy(&sela); return pixd; }
/*! * 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; }
/*! * selaAddTJunctions() * * Input: sela (<optional>) * hlsize (length of each line of hits from origin) * mdist (distance of misses from the origin) * norient (number of orientations; max of 8) * debugflag (1 for debug output) * Return: sela with additional sels, or null on error * * Notes: * (1) Adds hitmiss Sels for the T-junction of two lines. * If the lines are very thin, they must be nearly orthogonal * to register. * (2) The number of Sels generated is 4 * @norient. * (3) It is suggested that @hlsize be chosen at least 1 greater * than @mdist. Try values of (@hlsize, @mdist) such as * (6,5), (7,6), (8,7), (9,7), etc. */ SELA * selaAddTJunctions(SELA *sela, l_float32 hlsize, l_float32 mdist, l_int32 norient, l_int32 debugflag) { char name[L_BUF_SIZE]; l_int32 i, j, k, w, xc, yc; l_float64 pi, halfpi, radincr, jang, radang; l_float64 angle[3], dist[3]; PIX *pixc, *pixm, *pixt; PIXA *pixa; PTA *pta1, *pta2, *pta3; SEL *sel; PROCNAME("selaAddTJunctions"); if (hlsize <= 2) return (SELA *)ERROR_PTR("hlsizel not > 1", procName, NULL); if (norient < 1 || norient > 8) return (SELA *)ERROR_PTR("norient not in [1, ... 8]", procName, NULL); if (!sela) { if ((sela = selaCreate(0)) == NULL) return (SELA *)ERROR_PTR("sela not made", procName, NULL); } pi = 3.1415926535; halfpi = 3.1415926535 / 2.0; radincr = halfpi / (l_float32)norient; w = (l_int32)(2.4 * (L_MAX(hlsize, mdist) + 0.5)); if (w % 2 == 0) w++; xc = w / 2; yc = w / 2; pixa = pixaCreate(4 * norient); for (i = 0; i < norient; i++) { for (j = 0; j < 4; j++) { /* 4 orthogonal orientations */ jang = (l_float32)j * halfpi; /* Set the don't cares */ pixc = pixCreate(w, w, 32); pixSetAll(pixc); /* Add the green lines of hits */ pixm = pixCreate(w, w, 1); radang = (l_float32)i * radincr; pta1 = generatePtaLineFromPt(xc, yc, hlsize + 1, jang + radang); pta2 = generatePtaLineFromPt(xc, yc, hlsize + 1, jang + radang + halfpi); pta3 = generatePtaLineFromPt(xc, yc, hlsize + 1, jang + radang + pi); ptaJoin(pta1, pta2, 0, -1); ptaJoin(pta1, pta3, 0, -1); pixRenderPta(pixm, pta1, L_SET_PIXELS); pixPaintThroughMask(pixc, pixm, 0, 0, 0x00ff0000); ptaDestroy(&pta1); ptaDestroy(&pta2); ptaDestroy(&pta3); /* Add red misses between the lines */ angle[0] = radang + jang - halfpi; angle[1] = radang + jang + 0.5 * halfpi; angle[2] = radang + jang + 1.5 * halfpi; dist[0] = 0.8 * mdist; dist[1] = dist[2] = mdist; for (k = 0; k < 3; k++) { pixSetPixel(pixc, xc + (l_int32)(dist[k] * cos(angle[k])), yc + (l_int32)(dist[k] * sin(angle[k])), 0xff000000); } /* Add dark green for origin */ pixSetPixel(pixc, xc, yc, 0x00550000); /* Generate the sel */ sel = selCreateFromColorPix(pixc, NULL); sprintf(name, "sel_cross_%d", 4 * i + j); selaAddSel(sela, sel, name, 0); if (debugflag) { pixt = pixScaleBySampling(pixc, 10.0, 10.0); pixaAddPix(pixa, pixt, L_INSERT); } pixDestroy(&pixm); pixDestroy(&pixc); } } if (debugflag) { l_int32 w; pixaGetPixDimensions(pixa, 0, &w, NULL, NULL); pixt = pixaDisplayTiledAndScaled(pixa, 32, w, 4, 0, 10, 2); pixWriteTempfile("/tmp", "tsel1.png", pixt, IFF_PNG, 0); pixDisplay(pixt, 0, 100); pixDestroy(&pixt); pixt = selaDisplayInPix(sela, 15, 2, 20, 4); pixWriteTempfile("/tmp", "tsel2.png", pixt, IFF_PNG, 0); pixDisplay(pixt, 500, 100); pixDestroy(&pixt); selaWriteStream(stderr, sela); } pixaDestroy(&pixa); return sela; }
/*! * 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; }
int main(int argc, char **argv) { BOX *box; PIX *pix, *pixs, *pixd, *pixt; PIXA *pixa; SEL *sel, *sel1, *sel2, *sel3; SELA *sela4, *sela8, *sela48; static char mainName[] = "ccthin1_reg"; if (argc != 1) return ERROR_INT(" Syntax: ccthin1_reg", mainName, 1); /* Generate and display all of the 4-cc sels */ sela4 = selaCreate(9); sel = selCreateFromString(sel_4_1, 3, 3, "sel_4_1"); selaAddSel(sela4, sel, NULL, 0); sel = selCreateFromString(sel_4_2, 3, 3, "sel_4_2"); selaAddSel(sela4, sel, NULL, 0); sel = selCreateFromString(sel_4_3, 3, 3, "sel_4_3"); selaAddSel(sela4, sel, NULL, 0); sel = selCreateFromString(sel_4_4, 3, 3, "sel_4_4"); selaAddSel(sela4, sel, NULL, 0); sel = selCreateFromString(sel_4_5, 3, 3, "sel_4_5"); selaAddSel(sela4, sel, NULL, 0); sel = selCreateFromString(sel_4_6, 3, 3, "sel_4_6"); selaAddSel(sela4, sel, NULL, 0); sel = selCreateFromString(sel_4_7, 3, 3, "sel_4_7"); selaAddSel(sela4, sel, NULL, 0); sel = selCreateFromString(sel_4_8, 3, 3, "sel_4_8"); selaAddSel(sela4, sel, NULL, 0); sel = selCreateFromString(sel_4_9, 3, 3, "sel_4_9"); selaAddSel(sela4, sel, NULL, 0); pixt = selaDisplayInPix(sela4, 35, 3, 15, 3); pixWrite("/tmp/junkallsel4.png", pixt, IFF_PNG); pixDestroy(&pixt); selaDestroy(&sela4); /* Generate and display all of the 8-cc sels */ sela8 = selaCreate(9); sel = selCreateFromString(sel_8_1, 3, 3, "sel_8_1"); selaAddSel(sela8, sel, NULL, 0); sel = selCreateFromString(sel_8_2, 3, 3, "sel_8_2"); selaAddSel(sela8, sel, NULL, 0); sel = selCreateFromString(sel_8_3, 3, 3, "sel_8_3"); selaAddSel(sela8, sel, NULL, 0); sel = selCreateFromString(sel_8_4, 3, 3, "sel_8_4"); selaAddSel(sela8, sel, NULL, 0); sel = selCreateFromString(sel_8_5, 3, 3, "sel_8_5"); selaAddSel(sela8, sel, NULL, 0); sel = selCreateFromString(sel_8_6, 3, 3, "sel_8_6"); selaAddSel(sela8, sel, NULL, 0); sel = selCreateFromString(sel_8_7, 3, 3, "sel_8_7"); selaAddSel(sela8, sel, NULL, 0); sel = selCreateFromString(sel_8_8, 3, 3, "sel_8_8"); selaAddSel(sela8, sel, NULL, 0); sel = selCreateFromString(sel_8_9, 3, 3, "sel_8_9"); selaAddSel(sela8, sel, NULL, 0); pixt = selaDisplayInPix(sela8, 35, 3, 15, 3); pixWrite("/tmp/junkallsel8.png", pixt, IFF_PNG); pixDestroy(&pixt); selaDestroy(&sela8); /* Generate and display all of the 4 and 8-cc preserving sels */ sela48 = selaCreate(3); sel = selCreateFromString(sel_48_1, 3, 3, "sel_48_1"); selaAddSel(sela48, sel, NULL, 0); sel = selCreateFromString(sel_48_2, 3, 3, "sel_48_2"); selaAddSel(sela48, sel, NULL, 0); pixt = selaDisplayInPix(sela48, 35, 3, 15, 4); pixWrite("/tmp/junkallsel48.png", pixt, IFF_PNG); pixDestroy(&pixt); selaDestroy(&sela48); /* Generate and display three of the 4-cc sels and their rotations */ sela4 = selaCreate(3); sel = selCreateFromString(sel_4_1, 3, 3, "sel_4_1"); sel1 = selRotateOrth(sel, 1); sel2 = selRotateOrth(sel, 2); sel3 = selRotateOrth(sel, 3); selaAddSel(sela4, sel, NULL, 0); selaAddSel(sela4, sel1, "sel_4_1_90", 0); selaAddSel(sela4, sel2, "sel_4_1_180", 0); selaAddSel(sela4, sel3, "sel_4_1_270", 0); sel = selCreateFromString(sel_4_2, 3, 3, "sel_4_2"); sel1 = selRotateOrth(sel, 1); sel2 = selRotateOrth(sel, 2); sel3 = selRotateOrth(sel, 3); selaAddSel(sela4, sel, NULL, 0); selaAddSel(sela4, sel1, "sel_4_2_90", 0); selaAddSel(sela4, sel2, "sel_4_2_180", 0); selaAddSel(sela4, sel3, "sel_4_2_270", 0); sel = selCreateFromString(sel_4_3, 3, 3, "sel_4_3"); sel1 = selRotateOrth(sel, 1); sel2 = selRotateOrth(sel, 2); sel3 = selRotateOrth(sel, 3); selaAddSel(sela4, sel, NULL, 0); selaAddSel(sela4, sel1, "sel_4_3_90", 0); selaAddSel(sela4, sel2, "sel_4_3_180", 0); selaAddSel(sela4, sel3, "sel_4_3_270", 0); pixt = selaDisplayInPix(sela4, 35, 3, 15, 4); pixWrite("/tmp/junksel4.png", pixt, IFF_PNG); pixDestroy(&pixt); selaDestroy(&sela4); /* Generate and display four of the 8-cc sels and their rotations */ sela8 = selaCreate(4); sel = selCreateFromString(sel_8_2, 3, 3, "sel_8_2"); sel1 = selRotateOrth(sel, 1); sel2 = selRotateOrth(sel, 2); sel3 = selRotateOrth(sel, 3); selaAddSel(sela8, sel, NULL, 0); selaAddSel(sela8, sel1, "sel_8_2_90", 0); selaAddSel(sela8, sel2, "sel_8_2_180", 0); selaAddSel(sela8, sel3, "sel_8_2_270", 0); sel = selCreateFromString(sel_8_3, 3, 3, "sel_8_3"); sel1 = selRotateOrth(sel, 1); sel2 = selRotateOrth(sel, 2); sel3 = selRotateOrth(sel, 3); selaAddSel(sela8, sel, NULL, 0); selaAddSel(sela8, sel1, "sel_8_3_90", 0); selaAddSel(sela8, sel2, "sel_8_3_180", 0); selaAddSel(sela8, sel3, "sel_8_3_270", 0); sel = selCreateFromString(sel_8_5, 3, 3, "sel_8_5"); sel1 = selRotateOrth(sel, 1); sel2 = selRotateOrth(sel, 2); sel3 = selRotateOrth(sel, 3); selaAddSel(sela8, sel, NULL, 0); selaAddSel(sela8, sel1, "sel_8_5_90", 0); selaAddSel(sela8, sel2, "sel_8_5_180", 0); selaAddSel(sela8, sel3, "sel_8_5_270", 0); sel = selCreateFromString(sel_8_6, 3, 3, "sel_8_6"); sel1 = selRotateOrth(sel, 1); sel2 = selRotateOrth(sel, 2); sel3 = selRotateOrth(sel, 3); selaAddSel(sela8, sel, NULL, 0); selaAddSel(sela8, sel1, "sel_8_6_90", 0); selaAddSel(sela8, sel2, "sel_8_6_180", 0); selaAddSel(sela8, sel3, "sel_8_6_270", 0); pixt = selaDisplayInPix(sela8, 35, 3, 15, 4); pixWrite("/tmp/junksel8.png", pixt, IFF_PNG); pixDestroy(&pixt); selaDestroy(&sela8); /* Test the best 4 and 8 cc thinning */ pixDisplayWrite(NULL, 0); pix = pixRead("feyn.tif"); box = boxCreate(683, 799, 970, 479); pixs = pixClipRectangle(pix, box, NULL); pixDisplayWrite(pixs, 1); pixt = pixThin(pixs, L_THIN_FG, 4, 0); pixDisplayWrite(pixt, 1); pixDestroy(&pixt); pixt = pixThin(pixs, L_THIN_BG, 4, 0); pixDisplayWrite(pixt, 1); pixDestroy(&pixt); pixt = pixThin(pixs, L_THIN_FG, 8, 0); pixDisplayWrite(pixt, 1); pixDestroy(&pixt); pixt = pixThin(pixs, L_THIN_BG, 8, 0); pixDisplayWrite(pixt, 1); pixDestroy(&pixt); /* Display tiled */ pixa = pixaReadFiles("/tmp/display", "file"); pixd = pixaDisplayTiledAndScaled(pixa, 8, 500, 1, 0, 25, 2); pixWrite("/tmp/junktiles.jpg", pixd, IFF_JFIF_JPEG); pixDestroy(&pixd); pixaDestroy(&pixa); pixDestroy(&pix); pixDestroy(&pixs); boxDestroy(&box); pixDisplayMultiple("/tmp/display/file*"); return 0; }
/*! * \brief selaAddCrossJunctions() * * \param[in] sela [optional] * \param[in] hlsize length of each line of hits from origin * \param[in] mdist distance of misses from the origin * \param[in] norient number of orientations; max of 8 * \param[in] debugflag 1 for debug output * \return sela with additional sels, or NULL on error * * <pre> * Notes: * (1) Adds hitmiss Sels for the intersection of two lines. * If the lines are very thin, they must be nearly orthogonal * to register. * (2) The number of Sels generated is equal to %norient. * (3) If %norient == 2, this generates 2 Sels of crosses, each with * two perpendicular lines of hits. One Sel has horizontal and * vertical hits; the other has hits along lines at +-45 degrees. * Likewise, if %norient == 3, this generates 3 Sels of crosses * oriented at 30 degrees with each other. * (4) It is suggested that %hlsize be chosen at least 1 greater * than %mdist. Try values of (%hlsize, %mdist) such as * (6,5), (7,6), (8,7), (9,7), etc. * </pre> */ SELA * selaAddCrossJunctions(SELA *sela, l_float32 hlsize, l_float32 mdist, l_int32 norient, l_int32 debugflag) { char name[L_BUF_SIZE]; l_int32 i, j, w, xc, yc; l_float64 pi, halfpi, radincr, radang; l_float64 angle; PIX *pixc, *pixm, *pixt; PIXA *pixa; PTA *pta1, *pta2, *pta3, *pta4; SEL *sel; PROCNAME("selaAddCrossJunctions"); if (hlsize <= 0) return (SELA *)ERROR_PTR("hlsize not > 0", procName, NULL); if (norient < 1 || norient > 8) return (SELA *)ERROR_PTR("norient not in [1, ... 8]", procName, NULL); if (!sela) { if ((sela = selaCreate(0)) == NULL) return (SELA *)ERROR_PTR("sela not made", procName, NULL); } pi = 3.1415926535; halfpi = 3.1415926535 / 2.0; radincr = halfpi / (l_float64)norient; w = (l_int32)(2.2 * (L_MAX(hlsize, mdist) + 0.5)); if (w % 2 == 0) w++; xc = w / 2; yc = w / 2; pixa = pixaCreate(norient); for (i = 0; i < norient; i++) { /* Set the don't cares */ pixc = pixCreate(w, w, 32); pixSetAll(pixc); /* Add the green lines of hits */ pixm = pixCreate(w, w, 1); radang = (l_float32)i * radincr; pta1 = generatePtaLineFromPt(xc, yc, hlsize + 1, radang); pta2 = generatePtaLineFromPt(xc, yc, hlsize + 1, radang + halfpi); pta3 = generatePtaLineFromPt(xc, yc, hlsize + 1, radang + pi); pta4 = generatePtaLineFromPt(xc, yc, hlsize + 1, radang + pi + halfpi); ptaJoin(pta1, pta2, 0, -1); ptaJoin(pta1, pta3, 0, -1); ptaJoin(pta1, pta4, 0, -1); pixRenderPta(pixm, pta1, L_SET_PIXELS); pixPaintThroughMask(pixc, pixm, 0, 0, 0x00ff0000); ptaDestroy(&pta1); ptaDestroy(&pta2); ptaDestroy(&pta3); ptaDestroy(&pta4); /* Add red misses between the lines */ for (j = 0; j < 4; j++) { angle = radang + (j - 0.5) * halfpi; pixSetPixel(pixc, xc + (l_int32)(mdist * cos(angle)), yc + (l_int32)(mdist * sin(angle)), 0xff000000); } /* Add dark green for origin */ pixSetPixel(pixc, xc, yc, 0x00550000); /* Generate the sel */ sel = selCreateFromColorPix(pixc, NULL); sprintf(name, "sel_cross_%d", i); selaAddSel(sela, sel, name, 0); if (debugflag) { pixt = pixScaleBySampling(pixc, 10.0, 10.0); pixaAddPix(pixa, pixt, L_INSERT); } pixDestroy(&pixm); pixDestroy(&pixc); } if (debugflag) { l_int32 w; lept_mkdir("lept/sel"); pixaGetPixDimensions(pixa, 0, &w, NULL, NULL); pixt = pixaDisplayTiledAndScaled(pixa, 32, w, 1, 0, 10, 2); pixWrite("/tmp/lept/sel/xsel1.png", pixt, IFF_PNG); pixDisplay(pixt, 0, 100); pixDestroy(&pixt); pixt = selaDisplayInPix(sela, 15, 2, 20, 1); pixWrite("/tmp/lept/sel/xsel2.png", pixt, IFF_PNG); pixDisplay(pixt, 500, 100); pixDestroy(&pixt); selaWriteStream(stderr, sela); } pixaDestroy(&pixa); return sela; }