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; }
static void CopyPtras(L_PTRA *papixs, L_PTRA *paboxs, L_PTRA **ppapixd, L_PTRA **ppaboxd) { l_int32 i, imax; BOX *box; PIX *pix; ptraGetMaxIndex(papixs, &imax); *ppapixd = ptraCreate(imax + 1); *ppaboxd = ptraCreate(imax + 1); for (i = 0; i <= imax; i++) { pix = pixCopy(NULL, (PIX *)ptraGetPtrToItem(papixs, i)); box = boxCopy((BOX *)ptraGetPtrToItem(paboxs, i)); ptraAdd(*ppapixd, pix); ptraAdd(*ppaboxd, box); } return; }
/*! * ptraaFlattenToPtra() * * Input: ptraa * Return: ptra, or null on error * * Notes: * (1) This 'flattens' the ptraa to a ptra, taking the items in * each ptra, in order, starting with the first ptra, etc. * (2) As a side-effect, the ptra are all removed from the ptraa * and destroyed, leaving an empty ptraa. */ L_PTRA * ptraaFlattenToPtra(L_PTRAA *paa) { l_int32 i, n; L_PTRA *pat, *pad; PROCNAME("ptraaFlattenToPtra"); if (!paa) return (L_PTRA *) ERROR_PTR("paa not defined", procName, NULL); pad = ptraCreate(0); ptraaGetSize(paa, &n); for (i = 0; i < n; i++) { pat = ptraaGetPtra(paa, i, L_REMOVE); if (!pat) continue; ptraJoin(pad, pat); ptraDestroy(&pat, FALSE, FALSE); /* they're all empty */ } return pad; }
/*! * \brief pmsCreate() * * \param[in] minsize of data chunk that can be supplied by pms * \param[in] smallest bytes of the smallest pre-allocated data chunk. * \param[in] numalloc array with the number of data chunks for each * size that are in the memory store * \param[in] logfile use for debugging; null otherwise * \return 0 if OK, 1 on error * * <pre> * Notes: * (1) This computes the size of the block of memory required * and allocates it. Each chunk starts on a 32-bit word boundary. * The chunk sizes are in powers of 2, starting at %smallest, * and the number of levels and chunks at each level is * specified by %numalloc. * (2) This is intended to manage the image data for a small number * of relatively large pix. The system malloc is expected to * handle very large numbers of small chunks efficiently. * (3) Important: set the allocators and call this function * before any pix have been allocated. Destroy all the pix * in the normal way before calling pmsDestroy(). * (4) The pms struct is stored in a static global, so this function * is not thread-safe. When used, there must be only one thread * per process. * </pre> */ l_ok pmsCreate(size_t minsize, size_t smallest, NUMA *numalloc, const char *logfile) { l_int32 nlevels, i, j, nbytes; l_int32 *alloca; l_float32 nchunks; l_uint32 *baseptr, *data; l_uint32 **firstptr; size_t *sizes; L_PIX_MEM_STORE *pms; L_PTRA *pa; L_PTRAA *paa; PROCNAME("createPMS"); if (!numalloc) return ERROR_INT("numalloc not defined", procName, 1); numaGetSum(numalloc, &nchunks); if (nchunks > 1000.0) L_WARNING("There are %.0f chunks\n", procName, nchunks); if ((pms = (L_PIX_MEM_STORE *)LEPT_CALLOC(1, sizeof(L_PIX_MEM_STORE))) == NULL) return ERROR_INT("pms not made", procName, 1); CustomPMS = pms; /* Make sure that minsize and smallest are multiples of 32 bit words */ if (minsize % 4 != 0) minsize -= minsize % 4; pms->minsize = minsize; nlevels = numaGetCount(numalloc); pms->nlevels = nlevels; if ((sizes = (size_t *)LEPT_CALLOC(nlevels, sizeof(size_t))) == NULL) return ERROR_INT("sizes not made", procName, 1); pms->sizes = sizes; if (smallest % 4 != 0) smallest += 4 - (smallest % 4); pms->smallest = smallest; for (i = 0; i < nlevels; i++) sizes[i] = smallest * (1 << i); pms->largest = sizes[nlevels - 1]; alloca = numaGetIArray(numalloc); pms->allocarray = alloca; if ((paa = ptraaCreate(nlevels)) == NULL) return ERROR_INT("paa not made", procName, 1); pms->paa = paa; for (i = 0, nbytes = 0; i < nlevels; i++) nbytes += alloca[i] * sizes[i]; pms->nbytes = nbytes; if ((baseptr = (l_uint32 *)LEPT_CALLOC(nbytes / 4, sizeof(l_uint32))) == NULL) return ERROR_INT("calloc fail for baseptr", procName, 1); pms->baseptr = baseptr; pms->maxptr = baseptr + nbytes / 4; /* just beyond the memory store */ if ((firstptr = (l_uint32 **)LEPT_CALLOC(nlevels, sizeof(l_uint32 *))) == NULL) return ERROR_INT("calloc fail for firstptr", procName, 1); pms->firstptr = firstptr; data = baseptr; for (i = 0; i < nlevels; i++) { if ((pa = ptraCreate(alloca[i])) == NULL) return ERROR_INT("pa not made", procName, 1); ptraaInsertPtra(paa, i, pa); firstptr[i] = data; for (j = 0; j < alloca[i]; j++) { ptraAdd(pa, data); data += sizes[i] / 4; } } if (logfile) { pms->memused = (l_int32 *)LEPT_CALLOC(nlevels, sizeof(l_int32)); pms->meminuse = (l_int32 *)LEPT_CALLOC(nlevels, sizeof(l_int32)); pms->memmax = (l_int32 *)LEPT_CALLOC(nlevels, sizeof(l_int32)); pms->memempty = (l_int32 *)LEPT_CALLOC(nlevels, sizeof(l_int32)); pms->logfile = stringNew(logfile); } 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; }