void Java_com_example_ocr_Pixa_nativeMergeAndReplacePix(JNIEnv *env, jclass clazz, jint nativePixa, jint indexA, jint indexB) { PIXA *pixa = (PIXA *) nativePixa; l_int32 op; l_int32 x, y, w, h; l_int32 dx, dy, dw, dh; PIX *pixs, *pixd; BOX *boxA, *boxB, *boxd; boxA = pixaGetBox(pixa, indexA, L_CLONE); boxB = pixaGetBox(pixa, indexB, L_CLONE); boxd = boxBoundingRegion(boxA, boxB); boxGetGeometry(boxd, &x, &y, &w, &h); pixd = pixCreate(w, h, 1); op = PIX_SRC | PIX_DST; pixs = pixaGetPix(pixa, indexA, L_CLONE); boxGetGeometry(boxA, &dx, &dy, &dw, &dh); pixRasterop(pixd, dx - x, dy - y, dw, dh, op, pixs, 0, 0); pixDestroy(&pixs); boxDestroy(&boxA); pixs = pixaGetPix(pixa, indexB, L_CLONE); boxGetGeometry(boxB, &dx, &dy, &dw, &dh); pixRasterop(pixd, dx - x, dy - y, dw, dh, op, pixs, 0, 0); pixDestroy(&pixs); boxDestroy(&boxB); pixaReplacePix(pixa, indexA, pixd, boxd); }
/*! * pixAddWithIndicator() * * Input: pixs (1 bpp pix from which components are added; in-place) * pixa (of connected components, some of which will be put * into pixs) * na (numa indicator: add components corresponding to 1s) * Return: 0 if OK, 1 on error * * Notes: * (1) This complements pixRemoveWithIndicator(). Here, the selected * components are added to pixs. */ l_int32 pixAddWithIndicator(PIX *pixs, PIXA *pixa, NUMA *na) { l_int32 i, n, ival, x, y, w, h; BOX *box; PIX *pix; PROCNAME("pixAddWithIndicator"); if (!pixs) return ERROR_INT("pixs not defined", procName, 1); if (!pixa) return ERROR_INT("pixa not defined", procName, 1); if (!na) return ERROR_INT("na not defined", procName, 1); n = pixaGetCount(pixa); if (n != numaGetCount(na)) return ERROR_INT("pixa and na sizes not equal", procName, 1); for (i = 0; i < n; i++) { numaGetIValue(na, i, &ival); if (ival == 1) { pix = pixaGetPix(pixa, i, L_CLONE); box = pixaGetBox(pixa, i, L_CLONE); boxGetGeometry(box, &x, &y, &w, &h); pixRasterop(pixs, x, y, w, h, PIX_SRC | PIX_DST, pix, 0, 0); boxDestroy(&box); pixDestroy(&pix); } } return 0; }
static void MakePtrasFromPixa(PIXA *pixa, L_PTRA **ppapix, L_PTRA **ppabox, l_int32 copyflag) { l_int32 i, n; BOX *box; PIX *pix; L_PTRA *papix, *pabox; n = pixaGetCount(pixa); papix = ptraCreate(n); pabox = ptraCreate(n); for (i = 0; i < n; i++) { pix = pixaGetPix(pixa, i, copyflag); box = pixaGetBox(pixa, i, copyflag); ptraAdd(papix, pix); ptraAdd(pabox, box); } *ppapix = papix; *ppabox = pabox; return; }
jint Java_com_example_ocr_Pixa_nativeGetBox(JNIEnv *env, jclass clazz, jint nativePixa, jint index) { PIXA *pixa = (PIXA *) nativePixa; BOX *box = pixaGetBox(pixa, (l_int32) index, L_CLONE); return (jint) box; }
jlong Java_com_googlecode_leptonica_android_Pixa_nativeGetBox(JNIEnv *env, jclass clazz, jlong nativePixa, jint index) { PIXA *pixa = (PIXA *) nativePixa; BOX *box = pixaGetBox(pixa, (l_int32) index, L_CLONE); return (jlong) box; }
/*! * pixaClipToPix() * * Input: pixas * pixs * Return: pixad, or null on error * * Notes: * (1) This is intended for use in situations where pixas * was originally generated from the input pixs. * (2) Returns a pixad where each pix in pixas is ANDed * with its associated region of the input pixs. This * region is specified by the the box that is associated * with the pix. * (3) In a typical application of this function, pixas has * a set of region masks, so this generates a pixa of * the parts of pixs that correspond to each region * mask component, along with the bounding box for * the region. */ PIXA * pixaClipToPix(PIXA *pixas, PIX *pixs) { l_int32 i, n; BOX *box; PIX *pix, *pixc; PIXA *pixad; PROCNAME("pixaClipToPix"); if (!pixas) return (PIXA *)ERROR_PTR("pixas not defined", procName, NULL); if (!pixs) return (PIXA *)ERROR_PTR("pixs not defined", procName, NULL); n = pixaGetCount(pixas); if ((pixad = pixaCreate(n)) == NULL) return (PIXA *)ERROR_PTR("pixad not made", procName, NULL); for (i = 0; i < n; i++) { pix = pixaGetPix(pixas, i, L_CLONE); box = pixaGetBox(pixas, i, L_COPY); pixc = pixClipRectangle(pixs, box, NULL); pixAnd(pixc, pixc, pix); pixaAddPix(pixad, pixc, L_INSERT); pixaAddBox(pixad, box, L_INSERT); pixDestroy(&pix); } return pixad; }
/*! * pixaSortByIndex() * * Input: pixas * naindex (na that maps from the new pixa to the input pixa) * copyflag (L_COPY, L_CLONE) * Return: pixad (sorted), or null on error */ PIXA * pixaSortByIndex(PIXA *pixas, NUMA *naindex, l_int32 copyflag) { l_int32 i, n, index; BOX *box; PIX *pix; PIXA *pixad; PROCNAME("pixaSortByIndex"); if (!pixas) return (PIXA *)ERROR_PTR("pixas not defined", procName, NULL); if (!naindex) return (PIXA *)ERROR_PTR("naindex not defined", procName, NULL); if (copyflag != L_CLONE && copyflag != L_COPY) return (PIXA *)ERROR_PTR("invalid copyflag", procName, NULL); n = pixaGetCount(pixas); pixad = pixaCreate(n); for (i = 0; i < n; i++) { numaGetIValue(naindex, i, &index); pix = pixaGetPix(pixas, index, copyflag); box = pixaGetBox(pixas, index, copyflag); pixaAddPix(pixad, pix, L_INSERT); pixaAddBox(pixad, box, L_INSERT); } return pixad; }
jint Java_com_googlecode_leptonica_android_Pixa_nativeGetBox(JNIEnv *env, jclass clazz, jint nativePixa, jint index) { LOGV(__FUNCTION__); PIXA *pixa = (PIXA *) nativePixa; BOX *box = pixaGetBox(pixa, (l_int32) index, L_CLONE); return (jint) box; }
/*! * pixaAddBorderGeneral() * * Input: pixad (can be null or equal to pixas) * pixas (containing pix of all depths; colormap ok) * left, right, top, bot (number of pixels added) * val (value of added border pixels) * Return: pixad (with border added to each pix), including on error * * Notes: * (1) For binary images: * white: val = 0 * black: val = 1 * For grayscale images: * white: val = 2 ** d - 1 * black: val = 0 * For rgb color images: * white: val = 0xffffff00 * black: val = 0 * For colormapped images, use 'index' found this way: * white: pixcmapGetRankIntensity(cmap, 1.0, &index); * black: pixcmapGetRankIntensity(cmap, 0.0, &index); * (2) For in-place replacement of each pix with a bordered version, * use @pixad = @pixas. To make a new pixa, use @pixad = NULL. * (3) In both cases, the boxa has sides adjusted as if it were * expanded by the border. */ PIXA * pixaAddBorderGeneral(PIXA *pixad, PIXA *pixas, l_int32 left, l_int32 right, l_int32 top, l_int32 bot, l_uint32 val) { l_int32 i, n, nbox; BOX *box; BOXA *boxad; PIX *pixs, *pixd; PROCNAME("pixaAddBorderGeneral"); if (!pixas) return (PIXA *)ERROR_PTR("pixas not defined", procName, pixad); if (left < 0 || right < 0 || top < 0 || bot < 0) return (PIXA *)ERROR_PTR("negative border added!", procName, pixad); if (pixad && (pixad != pixas)) return (PIXA *)ERROR_PTR("pixad defined but != pixas", procName, pixad); n = pixaGetCount(pixas); if (!pixad) pixad = pixaCreate(n); for (i = 0; i < n; i++) { pixs = pixaGetPix(pixas, i, L_CLONE); pixd = pixAddBorderGeneral(pixs, left, right, top, bot, val); if (pixad == pixas) /* replace */ pixaReplacePix(pixad, i, pixd, NULL); else pixaAddPix(pixad, pixd, L_INSERT); pixDestroy(&pixs); } nbox = pixaGetBoxaCount(pixas); boxad = pixaGetBoxa(pixad, L_CLONE); for (i = 0; i < nbox; i++) { if ((box = pixaGetBox(pixas, i, L_COPY)) == NULL) { L_WARNING_INT("box %d not found", procName, i); break; } boxAdjustSides(box, box, -left, right, -top, bot); if (pixad == pixas) /* replace */ boxaReplaceBox(boxad, i, box); else boxaAddBox(boxad, box, L_INSERT); } boxaDestroy(&boxad); return pixad; }
/*! * pixaCopy() * * Input: pixas * copyflag: * L_COPY makes a new pixa and copies each pix and each box * L_CLONE gives a new ref-counted handle to the input pixa * L_COPY_CLONE makes a new pixa and inserts clones of * all pix and boxes * Return: new pixa, or null on error * * Note: see pix.h for description of the copy types. */ PIXA * pixaCopy(PIXA *pixa, l_int32 copyflag) { l_int32 i; BOX *boxc; PIX *pixc; PIXA *pixac; PROCNAME("pixaCopy"); if (!pixa) return (PIXA *)ERROR_PTR("pixa not defined", procName, NULL); if (copyflag == L_CLONE) { pixaChangeRefcount(pixa, 1); return pixa; } if (copyflag != L_COPY && copyflag != L_COPY_CLONE) return (PIXA *)ERROR_PTR("invalid copyflag", procName, NULL); if ((pixac = pixaCreate(pixa->n)) == NULL) return (PIXA *)ERROR_PTR("pixac not made", procName, NULL); for (i = 0; i < pixa->n; i++) { if (copyflag == L_COPY) { pixc = pixaGetPix(pixa, i, L_COPY); boxc = pixaGetBox(pixa, i, L_COPY); } else { /* copy-clone */ pixc = pixaGetPix(pixa, i, L_CLONE); boxc = pixaGetBox(pixa, i, L_CLONE); } pixaAddPix(pixac, pixc, L_INSERT); pixaAddBox(pixac, boxc, L_INSERT); } return pixac; }
/*! * pixaSort2dByIndex() * * Input: pixas * naa (numaa that maps from the new pixaa to the input pixas) * copyflag (L_CLONE or L_COPY) * Return: pixaa (sorted), or null on error */ PIXAA * pixaSort2dByIndex(PIXA *pixas, NUMAA *naa, l_int32 copyflag) { l_int32 pixtot, ntot, i, j, n, nn, index; BOX *box; NUMA *na; PIX *pix; PIXA *pixa; PIXAA *pixaa; PROCNAME("pixaSort2dByIndex"); if (!pixas) return (PIXAA *)ERROR_PTR("pixas not defined", procName, NULL); if (!naa) return (PIXAA *)ERROR_PTR("naindex not defined", procName, NULL); /* Check counts */ ntot = numaaGetNumberCount(naa); pixtot = pixaGetCount(pixas); if (ntot != pixtot) return (PIXAA *)ERROR_PTR("element count mismatch", procName, NULL); n = numaaGetCount(naa); pixaa = pixaaCreate(n); for (i = 0; i < n; i++) { na = numaaGetNuma(naa, i, L_CLONE); nn = numaGetCount(na); pixa = pixaCreate(nn); for (j = 0; j < nn; j++) { numaGetIValue(na, j, &index); pix = pixaGetPix(pixas, index, copyflag); box = pixaGetBox(pixas, index, copyflag); pixaAddPix(pixa, pix, L_INSERT); pixaAddBox(pixa, box, L_INSERT); } pixaaAddPixa(pixaa, pixa, L_INSERT); numaDestroy(&na); } return pixaa; }
/*! * pixaaFlattenToPixa() * * Input: pixaa * &naindex (<optional return> the pixa index in the pixaa) * copyflag (L_COPY or L_CLONE) * Return: pixa, or null on error * * Notes: * (1) This 'flattens' the pixaa to a pixa, taking the pix in * order in the first pixa, then the second, etc. * (2) If &naindex is defined, we generate a Numa that gives, for * each pix in the pixaa, the index of the pixa to which it belongs. */ PIXA * pixaaFlattenToPixa(PIXAA *pixaa, NUMA **pnaindex, l_int32 copyflag) { l_int32 i, j, m, n; BOX *box; NUMA *naindex; PIX *pix; PIXA *pixa, *pixat; PROCNAME("pixaaFlattenToPixa"); if (pnaindex) *pnaindex = NULL; if (!pixaa) return (PIXA *)ERROR_PTR("pixaa not defined", procName, NULL); if (copyflag != L_COPY && copyflag != L_CLONE) return (PIXA *)ERROR_PTR("invalid copyflag", procName, NULL); if (pnaindex) { naindex = numaCreate(0); *pnaindex = naindex; } n = pixaaGetCount(pixaa); pixa = pixaCreate(n); for (i = 0; i < n; i++) { pixat = pixaaGetPixa(pixaa, i, L_CLONE); m = pixaGetCount(pixat); for (j = 0; j < m; j++) { pix = pixaGetPix(pixat, j, copyflag); box = pixaGetBox(pixat, j, copyflag); pixaAddPix(pixa, pix, L_INSERT); pixaAddBox(pixa, box, L_INSERT); if (pnaindex) numaAddNumber(naindex, i); /* save 'row' number */ } pixaDestroy(&pixat); } return pixa; }
/*! * pixaSelectWithIndicator() * * Input: pixas * na (indicator numa) * &changed (<optional return> 1 if changed; 0 if clone returned) * Return: pixad, or null on error * * Notes: * (1) Returns a pixa clone if no components are removed. * (2) Uses pix and box clones in the new pixa. * (3) The indicator numa has values 0 (ignore) and 1 (accept). */ PIXA * pixaSelectWithIndicator(PIXA *pixas, NUMA *na, l_int32 *pchanged) { l_int32 i, n, ival, nsave; BOX *box; PIX *pixt; PIXA *pixad; PROCNAME("pixaSelectWithIndicator"); if (!pixas) return (PIXA *)ERROR_PTR("pixas not defined", procName, NULL); if (!na) return (PIXA *)ERROR_PTR("na not defined", procName, NULL); nsave = 0; n = numaGetCount(na); for (i = 0; i < n; i++) { numaGetIValue(na, i, &ival); if (ival == 1) nsave++; } if (nsave == n) { if (pchanged) *pchanged = FALSE; return pixaCopy(pixas, L_CLONE); } if (pchanged) *pchanged = TRUE; pixad = pixaCreate(nsave); for (i = 0; i < n; i++) { numaGetIValue(na, i, &ival); if (ival == 0) continue; pixt = pixaGetPix(pixas, i, L_CLONE); box = pixaGetBox(pixas, i, L_CLONE); pixaAddPix(pixad, pixt, L_INSERT); pixaAddBox(pixad, box, L_INSERT); } return pixad; }
/*! * pixaGetBoxGeometry() * * Input: pixa * index (to the index-th box) * &x, &y, &w, &h (<optional return>; each can be null) * Return: 0 if OK, 1 on error */ l_int32 pixaGetBoxGeometry(PIXA *pixa, l_int32 index, l_int32 *px, l_int32 *py, l_int32 *pw, l_int32 *ph) { BOX *box; PROCNAME("pixaGetBoxGeometry"); if (!pixa) return ERROR_INT("pixa not defined", procName, 1); if (index < 0 || index >= pixa->n) return ERROR_INT("index not valid", procName, 1); if ((box = pixaGetBox(pixa, index, L_CLONE)) == NULL) return ERROR_INT("box not found!", procName, 1); boxGetGeometry(box, px, py, pw, ph); boxDestroy(&box); return 0; }
main(int argc, char **argv) { l_int32 i, n; l_float32 pi, angle, val; BOX *box; BOXA *boxa, *boxa1, *boxa2; NUMA *na1, *na2; PIX *pix, *pix1, *pix2, *pix3, *pixd; PIXA *pixa1, *pixa2, *pixa3, *pixa4; static char mainName[] = "inserttest"; #if 1 pi = 3.1415926535; na1 = numaCreate(500); for (i = 0; i < 500; i++) { angle = 0.02293 * i * pi; val = (l_float32)sin(angle); numaAddNumber(na1, val); } numaWrite("/tmp/junknuma1", na1); na2 = numaCopy(na1); n = numaGetCount(na2); for (i = 0; i < n; i++) { numaGetFValue(na2, i, &val); numaRemoveNumber(na2, i); numaInsertNumber(na2, i, val); } numaWrite("/tmp/junknuma2", na2); numaDestroy(&na1); numaDestroy(&na2); #endif #if 1 pix1 = pixRead("feyn.tif"); box = boxCreate(1138, 1666, 1070, 380); pix2 = pixClipRectangle(pix1, box, NULL); boxDestroy(&box); boxa1 = pixConnComp(pix2, NULL, 8); boxaWrite("/tmp/junkboxa1", boxa1); boxa2 = boxaCopy(boxa1, L_COPY); n = boxaGetCount(boxa2); for (i = 0; i < n; i++) { box = boxaGetBox(boxa2, i, L_COPY); boxaRemoveBox(boxa2, i); boxaInsertBox(boxa2, i, box); } boxaWrite("/tmp/junkboxa2", boxa2); pixDestroy(&pix1); pixDestroy(&pix2); boxaDestroy(&boxa1); boxaDestroy(&boxa2); #endif #if 1 pix1 = pixRead("feyn.tif"); box = boxCreate(1138, 1666, 1070, 380); pix2 = pixClipRectangle(pix1, box, NULL); boxDestroy(&box); boxa = pixConnComp(pix2, &pixa1, 8); boxaDestroy(&boxa); pixaWrite("/tmp/junkpixa1", pixa1); pixa2 = pixaCopy(pixa1, L_COPY); n = pixaGetCount(pixa2); /* Remove and insert each one */ for (i = 0; i < n; i++) { pix = pixaGetPix(pixa2, i, L_COPY); box = pixaGetBox(pixa2, i, L_COPY); pixaRemovePix(pixa2, i); pixaInsertPix(pixa2, i, pix, box); } pixaWrite("/tmp/junkpixa2", pixa2); /* Move the last to the beginning; do it n times */ pixa3 = pixaCopy(pixa2, L_COPY); for (i = 0; i < n; i++) { pix = pixaGetPix(pixa3, n - 1, L_CLONE); box = pixaGetBox(pixa3, n - 1, L_CLONE); pixaInsertPix(pixa3, 0, pix, box); pixaRemovePix(pixa3, n); } pixaWrite("/tmp/junkpixa3", pixa3); /* Move the first one to the end; do it n times */ pixa4 = pixaCopy(pixa3, L_COPY); for (i = 0; i < n; i++) { pix = pixaGetPix(pixa4, 0, L_CLONE); box = pixaGetBox(pixa4, 0, L_CLONE); pixaInsertPix(pixa4, n, pix, box); /* make sure insert works at end */ pixaRemovePix(pixa4, 0); } pixaWrite("/tmp/junkpixa4", pixa4); pixDestroy(&pix1); pixDestroy(&pix2); pixaDestroy(&pixa1); pixaDestroy(&pixa2); pixaDestroy(&pixa3); pixaDestroy(&pixa4); #endif return 0; }
int main(int argc, char **argv) { l_int32 i, n; l_float32 pi, angle, val; BOX *box; BOXA *boxa, *boxa1, *boxa2; NUMA *na1, *na2; PIX *pix, *pix1, *pix2; PIXA *pixa1, *pixa2, *pixa3, *pixa4; L_REGPARAMS *rp; if (regTestSetup(argc, argv, &rp)) return 1; lept_rmfile("/tmp/regout/insert3.ba"); lept_rmfile("/tmp/regout/insert4.ba"); lept_rmfile("/tmp/regout/insert6.pa"); lept_rmfile("/tmp/regout/insert7.pa"); lept_rmfile("/tmp/regout/insert9.pa"); lept_rmfile("/tmp/regout/insert10.pa"); /* ----------------- Test numa operations -------------------- */ pi = 3.1415926535; na1 = numaCreate(500); for (i = 0; i < 500; i++) { angle = 0.02293 * i * pi; val = (l_float32)sin(angle); numaAddNumber(na1, val); } numaWrite("/tmp/regout/insert0.na", na1); na2 = numaCopy(na1); n = numaGetCount(na2); for (i = 0; i < n; i++) { numaGetFValue(na2, i, &val); numaRemoveNumber(na2, i); numaInsertNumber(na2, i, val); } numaWrite("/tmp/regout/insert1.na", na2); regTestCheckFile(rp, "/tmp/regout/insert0.na"); /* 0 */ regTestCheckFile(rp, "/tmp/regout/insert1.na"); /* 1 */ regTestCompareFiles(rp, 0, 1); /* 2 */ numaDestroy(&na1); numaDestroy(&na2); /* ----------------- Test boxa operations -------------------- */ pix1 = pixRead("feyn.tif"); box = boxCreate(1138, 1666, 1070, 380); pix2 = pixClipRectangle(pix1, box, NULL); boxDestroy(&box); boxa1 = pixConnComp(pix2, NULL, 8); boxaWrite("/tmp/regout/insert3.ba", boxa1); boxa2 = boxaCopy(boxa1, L_COPY); n = boxaGetCount(boxa2); for (i = 0; i < n; i++) { boxaRemoveBoxAndSave(boxa2, i, &box); boxaInsertBox(boxa2, i, box); } boxaWrite("/tmp/regout/insert4.ba", boxa2); regTestCheckFile(rp, "/tmp/regout/insert3.ba"); /* 3 */ regTestCheckFile(rp, "/tmp/regout/insert4.ba"); /* 4 */ regTestCompareFiles(rp, 3, 4); /* 5 */ pixDestroy(&pix1); pixDestroy(&pix2); boxaDestroy(&boxa1); boxaDestroy(&boxa2); /* ----------------- Test pixa operations -------------------- */ pix1 = pixRead("feyn.tif"); box = boxCreate(1138, 1666, 1070, 380); pix2 = pixClipRectangle(pix1, box, NULL); boxDestroy(&box); boxa = pixConnComp(pix2, &pixa1, 8); boxaDestroy(&boxa); pixaWrite("/tmp/regout/insert6.pa", pixa1); regTestCheckFile(rp, "/tmp/regout/insert6.pa"); /* 6 */ pixDestroy(&pix1); pixDestroy(&pix2); /* Remove and insert each one */ pixa2 = pixaCopy(pixa1, L_COPY); n = pixaGetCount(pixa2); for (i = 0; i < n; i++) { pixaRemovePixAndSave(pixa2, i, &pix, &box); pixaInsertPix(pixa2, i, pix, box); } pixaWrite("/tmp/regout/insert7.pa", pixa2); regTestCheckFile(rp, "/tmp/regout/insert7.pa"); /* 7 */ regTestCompareFiles(rp, 6, 7); /* 8 */ /* Move the last to the beginning; do it n times */ pixa3 = pixaCopy(pixa2, L_COPY); for (i = 0; i < n; i++) { pix = pixaGetPix(pixa3, n - 1, L_CLONE); box = pixaGetBox(pixa3, n - 1, L_CLONE); pixaInsertPix(pixa3, 0, pix, box); pixaRemovePix(pixa3, n); } pixaWrite("/tmp/regout/insert9.pa", pixa3); regTestCheckFile(rp, "/tmp/regout/insert9.pa"); /* 9 */ /* Move the first one to the end; do it n times */ pixa4 = pixaCopy(pixa3, L_COPY); for (i = 0; i < n; i++) { pix = pixaGetPix(pixa4, 0, L_CLONE); box = pixaGetBox(pixa4, 0, L_CLONE); pixaInsertPix(pixa4, n, pix, box); /* make sure insert works at end */ pixaRemovePix(pixa4, 0); } pixaWrite("/tmp/regout/insert10.pa", pixa4); regTestCheckFile(rp, "/tmp/regout/insert10.pa"); /* 10 */ regTestCompareFiles(rp, 9, 10); /* 11 */ pixaDestroy(&pixa1); pixaDestroy(&pixa2); pixaDestroy(&pixa3); pixaDestroy(&pixa4); return regTestCleanup(rp); }
int main(int argc, char **argv) { l_int32 i, n, w, h, nactual, imax; BOX *box; BOXA *boxa; PIX *pixs, *pixd, *pix; PIXA *pixas, *pixat, *pixac; L_PTRA *papix, *pabox, *papix2, *pabox2; static char mainName[] = "ptra1_reg"; if (argc != 1) return ERROR_INT(" Syntax: ptra1_reg", mainName, 1); setLeptDebugOK(1); pixac = pixaCreate(0); if ((pixs = pixRead("lucasta.1.300.tif")) == NULL) return ERROR_INT("pixs not made", mainName, 1); pixGetDimensions(pixs, &w, &h, NULL); boxa = pixConnComp(pixs, &pixas, 8); pixDestroy(&pixs); boxaDestroy(&boxa); n = pixaGetCount(pixas); /* Fill ptras with clones and reconstruct */ fprintf(stderr, "Fill with clones and reconstruct\n"); MakePtrasFromPixa(pixas, &papix, &pabox, L_CLONE); pixat = ReconstructPixa(papix, pabox, CHOOSE_RECON); ptraDestroy(&papix, 0, 1); ptraDestroy(&pabox, 0, 1); DisplayResult(pixac, &pixat, w, h, 1); /* Remove every other one for the first half; * with compaction at each removal */ fprintf(stderr, "Remove every other in 1st half, with compaction\n"); MakePtrasFromPixa(pixas, &papix, &pabox, L_COPY); for (i = 0; i < n / 2; i++) { if (i % 2 == 0) { pix = (PIX *)ptraRemove(papix, i, L_COMPACTION); box = (BOX *)ptraRemove(pabox, i, L_COMPACTION); pixDestroy(&pix); boxDestroy(&box); } } pixat = ReconstructPixa(papix, pabox, CHOOSE_RECON); ptraDestroy(&papix, 0, 1); ptraDestroy(&pabox, 0, 1); DisplayResult(pixac, &pixat, w, h, 0); /* Remove every other one for the entire set, * but without compaction at each removal */ fprintf(stderr, "Remove every other in 1st half, without & then with compaction\n"); MakePtrasFromPixa(pixas, &papix, &pabox, L_COPY); for (i = 0; i < n; i++) { if (i % 2 == 0) { pix = (PIX *)ptraRemove(papix, i, L_NO_COMPACTION); box = (BOX *)ptraRemove(pabox, i, L_NO_COMPACTION); pixDestroy(&pix); boxDestroy(&box); } } ptraCompactArray(papix); /* now do the compaction */ ptraCompactArray(pabox); pixat = ReconstructPixa(papix, pabox, CHOOSE_RECON); ptraDestroy(&papix, 0, 1); ptraDestroy(&pabox, 0, 1); DisplayResult(pixac, &pixat, w, h, 0); /* Fill ptras using insert at head, and reconstruct */ fprintf(stderr, "Insert at head and reconstruct\n"); papix = ptraCreate(n); pabox = ptraCreate(n); for (i = 0; i < n; i++) { pix = pixaGetPix(pixas, i, L_CLONE); box = pixaGetBox(pixas, i, L_CLONE); ptraInsert(papix, 0, pix, L_MIN_DOWNSHIFT); ptraInsert(pabox, 0, box, L_FULL_DOWNSHIFT); } pixat = ReconstructPixa(papix, pabox, CHOOSE_RECON); ptraDestroy(&papix, 0, 1); ptraDestroy(&pabox, 0, 1); DisplayResult(pixac, &pixat, w, h, 1); /* Reverse the arrays by swapping */ fprintf(stderr, "Reverse by swapping\n"); MakePtrasFromPixa(pixas, &papix, &pabox, L_CLONE); for (i = 0; i < n / 2; i++) { ptraSwap(papix, i, n - i - 1); ptraSwap(pabox, i, n - i - 1); } ptraCompactArray(papix); /* already compact; shouldn't do anything */ ptraCompactArray(pabox); pixat = ReconstructPixa(papix, pabox, CHOOSE_RECON); ptraDestroy(&papix, 0, 1); ptraDestroy(&pabox, 0, 1); DisplayResult(pixac, &pixat, w, h, 0); /* Remove at the top of the array and push the hole to the end * by neighbor swapping (!). This is O(n^2), so it's not a * recommended way to copy a ptra. [joke] */ fprintf(stderr, "Remove at top, pushing hole to end by swapping -- O(n^2)\n"); MakePtrasFromPixa(pixas, &papix, &pabox, L_CLONE); papix2 = ptraCreate(0); pabox2 = ptraCreate(0); while (1) { ptraGetActualCount(papix, &nactual); if (nactual == 0) break; ptraGetMaxIndex(papix, &imax); pix = (PIX *)ptraRemove(papix, 0, L_NO_COMPACTION); box = (BOX *)ptraRemove(pabox, 0, L_NO_COMPACTION); ptraAdd(papix2, pix); ptraAdd(pabox2, box); for (i = 1; i <= imax; i++) { ptraSwap(papix, i - 1, i); ptraSwap(pabox, i - 1, i); } } ptraCompactArray(papix); /* should be empty */ ptraCompactArray(pabox); /* ditto */ pixat = ReconstructPixa(papix, pabox, CHOOSE_RECON); ptraDestroy(&papix, 0, 1); ptraDestroy(&pabox, 0, 1); DisplayResult(pixac, &pixat, w, h, 1); /* nothing there */ pixat = ReconstructPixa(papix2, pabox2, CHOOSE_RECON); ptraDestroy(&papix2, 0, 1); ptraDestroy(&pabox2, 0, 1); DisplayResult(pixac, &pixat, w, h, 0); /* Remove and insert one position above, allowing minimum downshift. * If you specify L_AUTO_DOWNSHIFT, because there is only 1 hole, * it will do a full downshift at each insert. This is a * situation where the heuristic (expected number of holes) * fails to do the optimal thing. */ fprintf(stderr, "Remove and insert one position above (min downshift)\n"); MakePtrasFromPixa(pixas, &papix, &pabox, L_CLONE); for (i = 1; i < n; i++) { pix = (PIX *)ptraRemove(papix, i, L_NO_COMPACTION); box = (BOX *)ptraRemove(pabox, i, L_NO_COMPACTION); ptraInsert(papix, i - 1, pix, L_MIN_DOWNSHIFT); ptraInsert(pabox, i - 1, box, L_MIN_DOWNSHIFT); } pixat = ReconstructPixa(papix, pabox, CHOOSE_RECON); ptraDestroy(&papix, 0, 1); ptraDestroy(&pabox, 0, 1); DisplayResult(pixac, &pixat, w, h, 1); /* Remove and insert one position above, but this time * forcing a full downshift at each step. */ fprintf(stderr, "Remove and insert one position above (full downshift)\n"); MakePtrasFromPixa(pixas, &papix, &pabox, L_CLONE); for (i = 1; i < n; i++) { pix = (PIX *)ptraRemove(papix, i, L_NO_COMPACTION); box = (BOX *)ptraRemove(pabox, i, L_NO_COMPACTION); ptraInsert(papix, i - 1, pix, L_AUTO_DOWNSHIFT); ptraInsert(pabox, i - 1, box, L_AUTO_DOWNSHIFT); } /* ptraCompactArray(papix); ptraCompactArray(pabox); */ pixat = ReconstructPixa(papix, pabox, CHOOSE_RECON); ptraDestroy(&papix, 0, 1); ptraDestroy(&pabox, 0, 1); DisplayResult(pixac, &pixat, w, h, 0); pixd = pixaDisplay(pixac, 0, 0); pixDisplay(pixd, 100, 100); pixWrite("/tmp/junkptra1.png", pixd, IFF_PNG); pixDestroy(&pixd); pixaDestroy(&pixac); pixaDestroy(&pixas); return 0; }
int main(int argc, char **argv) { l_int32 w, h, d, w2, h2, i, ncols, ret; l_float32 angle, conf; BOX *box; BOXA *boxa, *boxa2; PIX *pix, *pixs, *pixb, *pixb2, *pixd; PIX *pix1, *pix2, *pix3, *pix4, *pix5, *pix6; PIXA *pixam; /* mask with a single component over each column */ PIXA *pixac, *pixad, *pixat; PIXAA *pixaa, *pixaa2; SEL *selsplit; static char mainName[] = "arabic_lines"; if (argc != 1) return ERROR_INT(" Syntax: arabic_lines", mainName, 1); pixDisplayWrite(NULL, -1); /* init debug output */ /* Binarize input */ pixs = pixRead("arabic.png"); pixGetDimensions(pixs, &w, &h, &d); pix = pixConvertTo1(pixs, 128); /* Deskew */ pixb = pixFindSkewAndDeskew(pix, 1, &angle, &conf); pixDestroy(&pix); fprintf(stderr, "Skew angle: %7.2f degrees; %6.2f conf\n", angle, conf); pixDisplayWrite(pixb, 1); /* Use full image morphology to find columns, at 2x reduction. This only works for very simple layouts where each column of text extends the full height of the input image. */ pixb2 = pixReduceRankBinary2(pixb, 2, NULL); pix1 = pixMorphCompSequence(pixb2, "c5.500", 0); boxa = pixConnComp(pix1, &pixam, 8); ncols = boxaGetCount(boxa); fprintf(stderr, "Num columns: %d\n", ncols); pixDisplayWrite(pix1, 1); /* Use selective region-based morphology to get the textline mask. */ pixad = pixaMorphSequenceByRegion(pixb2, pixam, "c100.3", 0, 0); pixGetDimensions(pixb2, &w2, &h2, NULL); pix2 = pixaDisplay(pixad, w2, h2); pixDisplayWrite(pix2, 1); pixDestroy(&pix2); /* Some of the lines may be touching, so use a HMT to split the lines in each column, and use a pixaa to save the results. */ selsplit = selCreateFromString(seltext, 17, 7, "selsplit"); pixaa = pixaaCreate(ncols); for (i = 0; i < ncols; i++) { pix3 = pixaGetPix(pixad, i, L_CLONE); box = pixaGetBox(pixad, i, L_COPY); pix4 = pixHMT(NULL, pix3, selsplit); pixXor(pix4, pix4, pix3); boxa2 = pixConnComp(pix4, &pixac, 8); pixaaAddPixa(pixaa, pixac, L_INSERT); pixaaAddBox(pixaa, box, L_INSERT); pix5 = pixaDisplayRandomCmap(pixac, 0, 0); pixDisplayWrite(pix5, 1); fprintf(stderr, "Num textlines in col %d: %d\n", i, boxaGetCount(boxa2)); pixDestroy(&pix5); pixDestroy(&pix3); pixDestroy(&pix4); boxaDestroy(&boxa2); } /* Visual output */ ret = system("gthumb /tmp/display/file* &"); pixat = pixaReadFiles("/tmp/display", "file"); pix5 = selDisplayInPix(selsplit, 31, 2); pixaAddPix(pixat, pix5, L_INSERT); pix6 = pixaDisplayTiledAndScaled(pixat, 32, 400, 3, 0, 35, 3); pixWrite("/tmp/result.png", pix6, IFF_PNG); pixaDestroy(&pixat); pixDestroy(&pix6); /* Test pixaa I/O */ pixaaWrite("/tmp/pixaa", pixaa); pixaa2 = pixaaRead("/tmp/pixaa"); pixaaWrite("/tmp/pixaa2", pixaa2); /* Test pixaa display */ pixd = pixaaDisplay(pixaa, w2, h2); pixWrite("/tmp/textlines.png", pixd, IFF_PNG); pixDestroy(&pixd); /* Cleanup */ pixDestroy(&pixb2); pixDestroy(&pix1); pixaDestroy(&pixam); pixaDestroy(&pixad); pixaaDestroy(&pixaa); pixaaDestroy(&pixaa2); boxaDestroy(&boxa); selDestroy(&selsplit); pixDestroy(&pixs); pixDestroy(&pixb); return 0; }
main(int argc, char **argv) { char *filein, *fileout; l_int32 w, h, d, w2, h2, i, ncols; l_float32 angle, conf; BOX *box; BOXA *boxa, *boxas, *boxad, *boxa2; NUMA *numa; PIX *pixs, *pixt, *pixb, *pixb2, *pixd; PIX *pixtlm, *pixvws; PIX *pixt1, *pixt2, *pixt3, *pixt4, *pixt5, *pixt6; PIXA *pixam, *pixac, *pixad, *pixat; PIXAA *pixaa, *pixaa2; PTA *pta; SEL *selsplit; static char mainName[] = "textlinemask"; if (argc != 3) exit(ERROR_INT(" Syntax: textlinemask filein fileout", mainName, 1)); filein = argv[1]; fileout = argv[2]; pixDisplayWrite(NULL, -1); /* init debug output */ if ((pixs = pixRead(filein)) == NULL) return ERROR_INT("pixs not made", mainName, 1); pixGetDimensions(pixs, &w, &h, &d); /* Binarize input */ if (d == 8) pixt = pixThresholdToBinary(pixs, 128); else if (d == 1) pixt = pixClone(pixs); else { fprintf(stderr, "depth is %d\n", d); exit(1); } /* Deskew */ pixb = pixFindSkewAndDeskew(pixt, 1, &angle, &conf); pixDestroy(&pixt); fprintf(stderr, "Skew angle: %7.2f degrees; %6.2f conf\n", angle, conf); pixDisplayWrite(pixb, DEBUG_OUTPUT); #if 1 /* Use full image morphology to find columns, at 2x reduction. * This only works for very simple layouts where each column * of text extends the full height of the input image. * pixam has a pix component over each column. */ pixb2 = pixReduceRankBinary2(pixb, 2, NULL); pixt1 = pixMorphCompSequence(pixb2, "c5.500", 0); boxa = pixConnComp(pixt1, &pixam, 8); ncols = boxaGetCount(boxa); fprintf(stderr, "Num columns: %d\n", ncols); pixDisplayWrite(pixt1, DEBUG_OUTPUT); /* Use selective region-based morphology to get the textline mask. */ pixad = pixaMorphSequenceByRegion(pixb2, pixam, "c100.3", 0, 0); pixGetDimensions(pixb2, &w2, &h2, NULL); if (DEBUG_OUTPUT) { pixt2 = pixaDisplay(pixad, w2, h2); pixDisplayWrite(pixt2, DEBUG_OUTPUT); pixDestroy(&pixt2); } /* Some of the lines may be touching, so use a HMT to split the * lines in each column, and use a pixaa to save the results. */ selsplit = selCreateFromString(seltext, 17, 7, "selsplit"); pixaa = pixaaCreate(ncols); for (i = 0; i < ncols; i++) { pixt3 = pixaGetPix(pixad, i, L_CLONE); box = pixaGetBox(pixad, i, L_COPY); pixt4 = pixHMT(NULL, pixt3, selsplit); pixXor(pixt4, pixt4, pixt3); boxa2 = pixConnComp(pixt4, &pixac, 8); pixaaAddPixa(pixaa, pixac, L_INSERT); pixaaAddBox(pixaa, box, L_INSERT); if (DEBUG_OUTPUT) { pixt5 = pixaDisplayRandomCmap(pixac, 0, 0); pixDisplayWrite(pixt5, DEBUG_OUTPUT); fprintf(stderr, "Num textlines in col %d: %d\n", i, boxaGetCount(boxa2)); pixDestroy(&pixt5); } pixDestroy(&pixt3); pixDestroy(&pixt4); boxaDestroy(&boxa2); } /* Visual output */ if (DEBUG_OUTPUT) { pixDisplayMultiple("/tmp/junk_write_display*"); pixat = pixaReadFiles("/tmp", "junk_write_display"); pixt5 = selDisplayInPix(selsplit, 31, 2); pixaAddPix(pixat, pixt5, L_INSERT); pixt6 = pixaDisplayTiledAndScaled(pixat, 32, 400, 3, 0, 35, 3); pixWrite(fileout, pixt6, IFF_PNG); pixaDestroy(&pixat); pixDestroy(&pixt6); } /* Test pixaa I/O */ pixaaWrite("/tmp/junkpixaa", pixaa); pixaa2 = pixaaRead("/tmp/junkpixaa"); pixaaWrite("/tmp/junkpixaa2", pixaa2); /* Test pixaa display */ pixd = pixaaDisplay(pixaa, w2, h2); pixWrite("/tmp/junkdisplay", pixd, IFF_PNG); pixDestroy(&pixd); /* Cleanup */ pixDestroy(&pixb2); pixDestroy(&pixt1); pixaDestroy(&pixam); pixaDestroy(&pixad); pixaaDestroy(&pixaa); pixaaDestroy(&pixaa2); boxaDestroy(&boxa); selDestroy(&selsplit); #endif #if 0 /* Use the baseline finder; not really what is needed */ numa = pixFindBaselines(pixb, &pta, 1); #endif #if 0 /* Use the textline mask function; parameters are not quite right */ pixb2 = pixReduceRankBinary2(pixb, 2, NULL); pixtlm = pixGenTextlineMask(pixb2, &pixvws, NULL, 1); pixDisplay(pixtlm, 0, 100); pixDisplay(pixvws, 500, 100); pixDestroy(&pixb2); pixDestroy(&pixtlm); pixDestroy(&pixvws); #endif #if 0 /* Use the Breuel whitespace partition method; slow and we would * still need to work to extract the fg regions. */ pixb2 = pixReduceRankBinary2(pixb, 2, NULL); boxas = pixConnComp(pixb2, NULL, 8); boxad = boxaGetWhiteblocks(boxas, NULL, L_SORT_BY_HEIGHT, 3, 0.1, 200, 0.2, 0); pixd = pixDrawBoxa(pixb2, boxad, 7, 0xe0708000); pixDisplay(pixd, 100, 500); pixDestroy(&pixb2); pixDestroy(&pixd); boxaDestroy(&boxas); boxaDestroy(&boxad); #endif #if 0 /* Use morphology to find columns and then selective * region-based morphology to get the textline mask. * This is for display; we really want to get a pixa of the * specific textline masks. */ startTimer(); pixb2 = pixReduceRankBinary2(pixb, 2, NULL); pixt1 = pixMorphCompSequence(pixb2, "c5.500", 0); /* column mask */ pixt2 = pixMorphSequenceByRegion(pixb2, pixt1, "c100.3", 8, 0, 0, &boxa); fprintf(stderr, "time = %7.3f sec\n", stopTimer()); pixDisplay(pixt1, 100, 500); pixDisplay(pixt2, 800, 500); pixDestroy(&pixb2); pixDestroy(&pixt1); pixDestroy(&pixt2); boxaDestroy(&boxa); #endif pixDestroy(&pixs); pixDestroy(&pixb); exit(0); }