/* Reconstruction without compaction */ static PIXA * ReconstructPixa1(L_PTRA *papix, L_PTRA *pabox) { l_int32 i, imax, nactual; BOX *box; PIX *pix; PIXA *pixat; ptraGetMaxIndex(papix, &imax); ptraGetActualCount(papix, &nactual); fprintf(stderr, "Before removal: imax = %4d, actual = %4d\n", imax, nactual); pixat = pixaCreate(imax + 1); for (i = 0; i <= imax; i++) { pix = (PIX *)ptraRemove(papix, i, L_NO_COMPACTION); box = (BOX *)ptraRemove(pabox, i, L_NO_COMPACTION); if (pix) pixaAddPix(pixat, pix, L_INSERT); if (box) pixaAddBox(pixat, box, L_INSERT); } ptraGetMaxIndex(papix, &imax); ptraGetActualCount(papix, &nactual); fprintf(stderr, "After removal: imax = %4d, actual = %4d\n\n", imax, nactual); return pixat; }
/* Reconstruction with compaction */ static PIXA * ReconstructPixa2(L_PTRA *papix, L_PTRA *pabox) { l_int32 i, imax, nactual; BOX *box; PIX *pix; PIXA *pixat; ptraGetMaxIndex(papix, &imax); ptraGetActualCount(papix, &nactual); fprintf(stderr, "Before removal: imax = %4d, actual = %4d\n", imax, nactual); /* Remove half */ pixat = pixaCreate(imax + 1); for (i = 0; i <= imax; i++) { if (i % 2 == 0) { pix = (PIX *)ptraRemove(papix, i, L_NO_COMPACTION); box = (BOX *)ptraRemove(pabox, i, L_NO_COMPACTION); if (pix) pixaAddPix(pixat, pix, L_INSERT); if (box) pixaAddBox(pixat, box, L_INSERT); } } /* Compact */ ptraGetMaxIndex(papix, &imax); ptraGetActualCount(papix, &nactual); fprintf(stderr, "Before compaction: imax = %4d, actual = %4d\n", imax, nactual); ptraCompactArray(papix); ptraCompactArray(pabox); ptraGetMaxIndex(papix, &imax); ptraGetActualCount(papix, &nactual); fprintf(stderr, "After compaction: imax = %4d, actual = %4d\n", imax, nactual); /* Remove the rest (and test compaction with removal) */ while (1) { ptraGetActualCount(papix, &nactual); if (nactual == 0) break; pix = (PIX *)ptraRemove(papix, 0, L_COMPACTION); box = (BOX *)ptraRemove(pabox, 0, L_COMPACTION); pixaAddPix(pixat, pix, L_INSERT); pixaAddBox(pixat, box, L_INSERT); } ptraGetMaxIndex(papix, &imax); ptraGetActualCount(papix, &nactual); fprintf(stderr, "After removal: imax = %4d, actual = %4d\n\n", imax, nactual); return pixat; }
/*! * ptraDestroy() * * Input: &ptra (<to be nulled>) * freeflag (TRUE to free each remaining item in the array) * warnflag (TRUE to warn if any remaining items are not destroyed) * Return: void * * Notes: * (1) If @freeflag == TRUE, frees each item in the array. * (2) If @freeflag == FALSE and warnflag == TRUE, and there are * items on the array, this gives a warning and destroys the array. * If these items are not owned elsewhere, this will cause * a memory leak of all the items that were on the array. * So if the items are not owned elsewhere and require their * own destroy function, they must be destroyed before the ptra. * (3) If warnflag == FALSE, no warnings will be issued. This is * useful if the items are owned elsewhere, such as a * PixMemoryStore(). * (4) To destroy the ptra, we destroy the ptr array, then * the ptra, and then null the contents of the input ptr. */ void ptraDestroy(L_PTRA **ppa, l_int32 freeflag, l_int32 warnflag) { l_int32 i, nactual; void *item; L_PTRA *pa; PROCNAME("ptraDestroy"); if (ppa == NULL) { L_WARNING("ptr address is NULL\n", procName); return; } if ((pa = *ppa) == NULL) return; ptraGetActualCount(pa, &nactual); if (nactual > 0) { if (freeflag) { for (i = 0; i <= pa->imax; i++) { if ((item = ptraRemove(pa, i, L_NO_COMPACTION)) != NULL) FREE(item); } } else if (warnflag) { L_WARNING("potential memory leak of %d items in ptra\n", procName, nactual); } } FREE(pa->array); FREE(pa); *ppa = NULL; return; }
/*! * ptraRemoveLast() * * Input: ptra * Return: item, or null on error or if the array is empty */ void * ptraRemoveLast(L_PTRA *pa) { l_int32 imax; PROCNAME("ptraRemoveLast"); if (!pa) return (void *) ERROR_PTR("pa not defined", procName, NULL); /* Remove the last item in the array. No compaction is required. */ ptraGetMaxIndex(pa, &imax); if (imax >= 0) return ptraRemove(pa, imax, L_NO_COMPACTION); else /* empty */ return NULL; }
/*! * ptraJoin() * * Input: ptra1 (add to this one) * ptra2 (appended to ptra1, and emptied of items; can be null) * Return: 0 if OK, 1 on error */ l_int32 ptraJoin(L_PTRA *pa1, L_PTRA *pa2) { l_int32 i, imax; void *item; PROCNAME("ptraJoin"); if (!pa1) return ERROR_INT("pa1 not defined", procName, 1); if (!pa2) return 0; ptraGetMaxIndex(pa2, &imax); for (i = 0; i <= imax; i++) { item = ptraRemove(pa2, i, L_NO_COMPACTION); ptraAdd(pa1, item); } return 0; }
/*! * ptraSwap() * * Input: ptra * index1 * index2 * Return: 0 if OK, 1 on error */ l_int32 ptraSwap(L_PTRA *pa, l_int32 index1, l_int32 index2) { l_int32 imax; void *item; PROCNAME("ptraSwap"); if (!pa) return ERROR_INT("pa not defined", procName, 1); if (index1 == index2) return 0; ptraGetMaxIndex(pa, &imax); if (index1 < 0 || index1 > imax || index2 < 0 || index2 > imax) return ERROR_INT("invalid index: not in [0 ... imax]", procName, 1); item = ptraRemove(pa, index1, L_NO_COMPACTION); item = ptraReplace(pa, index2, item, FALSE); ptraInsert(pa, index1, item, L_MIN_DOWNSHIFT); return 0; }
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; }