/*! * \brief pixColorSegmentClean() * * \param[in] pixs 8 bpp, colormapped * \param[in] selsize for closing * \param[in] countarray ptr to array containing the number of pixels * found in each color in the colormap * \return 0 if OK, 1 on error * * <pre> * Notes: * (1) This operation is in-place. * (2) This is phase 3 of color segmentation. It is the first * part of a two-step noise removal process. Colors with a * large population are closed first; this operation absorbs * small sets of intercolated pixels of a different color. * </pre> */ l_ok pixColorSegmentClean(PIX *pixs, l_int32 selsize, l_int32 *countarray) { l_int32 i, ncolors, val; l_uint32 val32; NUMA *na, *nasi; PIX *pixt1, *pixt2; PIXCMAP *cmap; PROCNAME("pixColorSegmentClean"); if (!pixs) return ERROR_INT("pixs not defined", procName, 1); if (pixGetDepth(pixs) != 8) return ERROR_INT("pixs not 8 bpp", procName, 1); if ((cmap = pixGetColormap(pixs)) == NULL) return ERROR_INT("cmap not found", procName, 1); if (!countarray) return ERROR_INT("countarray not defined", procName, 1); if (selsize <= 1) return 0; /* nothing to do */ /* Sort colormap indices in decreasing order of pixel population */ ncolors = pixcmapGetCount(cmap); na = numaCreate(ncolors); for (i = 0; i < ncolors; i++) numaAddNumber(na, countarray[i]); nasi = numaGetSortIndex(na, L_SORT_DECREASING); numaDestroy(&na); if (!nasi) return ERROR_INT("nasi not made", procName, 1); /* For each color, in order of decreasing population, * do a closing and absorb the added pixels. Note that * if the closing removes pixels at the border, they'll * still appear in the xor and will be properly (re)set. */ for (i = 0; i < ncolors; i++) { numaGetIValue(nasi, i, &val); pixt1 = pixGenerateMaskByValue(pixs, val, 1); pixt2 = pixCloseSafeCompBrick(NULL, pixt1, selsize, selsize); pixXor(pixt2, pixt2, pixt1); /* pixels to be added to type 'val' */ pixcmapGetColor32(cmap, val, &val32); pixSetMasked(pixs, pixt2, val32); /* add them */ pixDestroy(&pixt1); pixDestroy(&pixt2); } numaDestroy(&nasi); return 0; }
/*! * pixMorphCompSequence() * * Input: pixs * sequence (string specifying sequence) * dispsep (horizontal separation in pixels between * successive displays; use zero to suppress display) * Return: pixd, or null on error * * Notes: * (1) This does rasterop morphology on binary images, using composite * operations for extra speed on large Sels. * (2) Safe closing is used atomically. However, if you implement a * closing as a sequence with a dilation followed by an * erosion, it will not be safe, and to ensure that you have * no boundary effects you must add a border in advance and * remove it at the end. * (3) For other usage details, see the notes for pixMorphSequence(). * (4) The sequence string is formatted as follows: * - An arbitrary number of operations, each separated * by a '+' character. White space is ignored. * - Each operation begins with a case-independent character * specifying the operation: * d or D (dilation) * e or E (erosion) * o or O (opening) * c or C (closing) * r or R (rank binary reduction) * x or X (replicative binary expansion) * b or B (add a border of 0 pixels of this size) * - The args to the morphological operations are bricks of hits, * and are formatted as a.b, where a and b are horizontal and * vertical dimensions, rsp. * - The args to the reduction are a sequence of up to 4 integers, * each from 1 to 4. * - The arg to the expansion is a power of two, in the set * {2, 4, 8, 16}. */ PIX * pixMorphCompSequence(PIX *pixs, const char *sequence, l_int32 dispsep) { char *rawop, *op; l_int32 nops, i, j, nred, fact, w, h, x, y, border; l_int32 level[4]; PIX *pixt1, *pixt2; SARRAY *sa; PROCNAME("pixMorphCompSequence"); if (!pixs) return (PIX *)ERROR_PTR("pixs not defined", procName, NULL); if (!sequence) return (PIX *)ERROR_PTR("sequence not defined", procName, NULL); /* Split sequence into individual operations */ sa = sarrayCreate(0); sarraySplitString(sa, sequence, "+"); nops = sarrayGetCount(sa); if (!morphSequenceVerify(sa)) { sarrayDestroy(&sa); return (PIX *)ERROR_PTR("sequence not valid", procName, NULL); } /* Parse and operate */ border = 0; pixt1 = pixCopy(NULL, pixs); pixt2 = NULL; x = y = 0; for (i = 0; i < nops; i++) { rawop = sarrayGetString(sa, i, 0); op = stringRemoveChars(rawop, " \n\t"); switch (op[0]) { case 'd': case 'D': sscanf(&op[1], "%d.%d", &w, &h); pixt2 = pixDilateCompBrick(NULL, pixt1, w, h); pixDestroy(&pixt1); pixt1 = pixClone(pixt2); pixDestroy(&pixt2); if (dispsep > 0) { pixDisplay(pixt1, x, y); x += dispsep; } break; case 'e': case 'E': sscanf(&op[1], "%d.%d", &w, &h); pixt2 = pixErodeCompBrick(NULL, pixt1, w, h); pixDestroy(&pixt1); pixt1 = pixClone(pixt2); pixDestroy(&pixt2); if (dispsep > 0) { pixDisplay(pixt1, x, y); x += dispsep; } break; case 'o': case 'O': sscanf(&op[1], "%d.%d", &w, &h); pixOpenCompBrick(pixt1, pixt1, w, h); if (dispsep > 0) { pixDisplay(pixt1, x, y); x += dispsep; } break; case 'c': case 'C': sscanf(&op[1], "%d.%d", &w, &h); pixCloseSafeCompBrick(pixt1, pixt1, w, h); if (dispsep > 0) { pixDisplay(pixt1, x, y); x += dispsep; } break; case 'r': case 'R': nred = strlen(op) - 1; for (j = 0; j < nred; j++) level[j] = op[j + 1] - '0'; for (j = nred; j < 4; j++) level[j] = 0; pixt2 = pixReduceRankBinaryCascade(pixt1, level[0], level[1], level[2], level[3]); pixDestroy(&pixt1); pixt1 = pixClone(pixt2); pixDestroy(&pixt2); if (dispsep > 0) { pixDisplay(pixt1, x, y); x += dispsep; } break; case 'x': case 'X': sscanf(&op[1], "%d", &fact); pixt2 = pixExpandReplicate(pixt1, fact); pixDestroy(&pixt1); pixt1 = pixClone(pixt2); pixDestroy(&pixt2); if (dispsep > 0) { pixDisplay(pixt1, x, y); x += dispsep; } break; case 'b': case 'B': sscanf(&op[1], "%d", &border); pixt2 = pixAddBorder(pixt1, border, 0); pixDestroy(&pixt1); pixt1 = pixClone(pixt2); pixDestroy(&pixt2); if (dispsep > 0) { pixDisplay(pixt1, x, y); x += dispsep; } break; default: /* All invalid ops are caught in the first pass */ break; } FREE(op); } if (border > 0) { pixt2 = pixRemoveBorder(pixt1, border); pixDestroy(&pixt1); pixt1 = pixClone(pixt2); pixDestroy(&pixt2); } sarrayDestroy(&sa); return pixt1; }
l_int32 DoComparisonDwa1(L_REGPARAMS *rp, PIX *pixs, PIX *pix1, PIX *pix2, PIX *pix3, PIX *pix4, PIX *pix5, PIX *pix6, l_int32 isize) { l_int32 fact1, fact2, size; selectComposableSizes(isize, &fact1, &fact2); size = fact1 * fact2; fprintf(stderr, "..%d..", size); if (TIMING) startTimer(); pixDilateCompBrickExtendDwa(pix1, pixs, size, 1); pixDilateCompBrickExtendDwa(pix3, pixs, 1, size); pixDilateCompBrickExtendDwa(pix5, pixs, size, size); if (TIMING) fprintf(stderr, "Time Dwa: %7.3f sec\n", stopTimer()); if (TIMING) startTimer(); pixDilateCompBrick(pix2, pixs, size, 1); pixDilateCompBrick(pix4, pixs, 1, size); pixDilateCompBrick(pix6, pixs, size, size); if (TIMING) fprintf(stderr, "Time Rop: %7.3f sec\n", stopTimer()); PixCompareDwa(rp, size, "dilate", pix1, pix2, pix3, pix4, pix5, pix6); if (TIMING) startTimer(); pixErodeCompBrickExtendDwa(pix1, pixs, size, 1); pixErodeCompBrickExtendDwa(pix3, pixs, 1, size); pixErodeCompBrickExtendDwa(pix5, pixs, size, size); if (TIMING) fprintf(stderr, "Time Dwa: %7.3f sec\n", stopTimer()); if (TIMING) startTimer(); pixErodeCompBrick(pix2, pixs, size, 1); pixErodeCompBrick(pix4, pixs, 1, size); pixErodeCompBrick(pix6, pixs, size, size); if (TIMING) fprintf(stderr, "Time Rop: %7.3f sec\n", stopTimer()); PixCompareDwa(rp, size, "erode", pix1, pix2, pix3, pix4, pix5, pix6); if (TIMING) startTimer(); pixOpenCompBrickExtendDwa(pix1, pixs, size, 1); pixOpenCompBrickExtendDwa(pix3, pixs, 1, size); pixOpenCompBrickExtendDwa(pix5, pixs, size, size); if (TIMING) fprintf(stderr, "Time Dwa: %7.3f sec\n", stopTimer()); if (TIMING) startTimer(); pixOpenCompBrick(pix2, pixs, size, 1); pixOpenCompBrick(pix4, pixs, 1, size); pixOpenCompBrick(pix6, pixs, size, size); if (TIMING) fprintf(stderr, "Time Rop: %7.3f sec\n", stopTimer()); PixCompareDwa(rp, size, "open", pix1, pix2, pix3, pix4, pix5, pix6); if (TIMING) startTimer(); pixCloseCompBrickExtendDwa(pix1, pixs, size, 1); pixCloseCompBrickExtendDwa(pix3, pixs, 1, size); pixCloseCompBrickExtendDwa(pix5, pixs, size, size); if (TIMING) fprintf(stderr, "Time Dwa: %7.3f sec\n", stopTimer()); if (TIMING) startTimer(); pixCloseSafeCompBrick(pix2, pixs, size, 1); pixCloseSafeCompBrick(pix4, pixs, 1, size); pixCloseSafeCompBrick(pix6, pixs, size, size); if (TIMING) fprintf(stderr, "Time Rop: %7.3f sec\n", stopTimer()); PixCompareDwa(rp, size, "close", pix1, pix2, pix3, pix4, pix5, pix6); return 0; }
l_int32 DoComparisonDwa1(PIX *pixs, PIX *pixt1, PIX *pixt2, PIX *pixt3, PIX *pixt4, PIX *pixt5, PIX *pixt6, l_int32 isize) { l_int32 fact1, fact2, size; selectComposableSizes(isize, &fact1, &fact2); size = fact1 * fact2; fprintf(stderr, "..%d..", size); if (TIMING) startTimer(); pixDilateCompBrickExtendDwa(pixt1, pixs, size, 1); pixDilateCompBrickExtendDwa(pixt3, pixs, 1, size); pixDilateCompBrickExtendDwa(pixt5, pixs, size, size); if (TIMING) fprintf(stderr, "Time Dwa: %7.3f sec\n", stopTimer()); if (TIMING) startTimer(); pixDilateCompBrick(pixt2, pixs, size, 1); pixDilateCompBrick(pixt4, pixs, 1, size); pixDilateCompBrick(pixt6, pixs, size, size); if (TIMING) fprintf(stderr, "Time Rop: %7.3f sec\n", stopTimer()); PixCompareDwa(size, "dilate", pixt1, pixt2, pixt3, pixt4, pixt5, pixt6); if (TIMING) startTimer(); pixErodeCompBrickExtendDwa(pixt1, pixs, size, 1); pixErodeCompBrickExtendDwa(pixt3, pixs, 1, size); pixErodeCompBrickExtendDwa(pixt5, pixs, size, size); if (TIMING) fprintf(stderr, "Time Dwa: %7.3f sec\n", stopTimer()); if (TIMING) startTimer(); pixErodeCompBrick(pixt2, pixs, size, 1); pixErodeCompBrick(pixt4, pixs, 1, size); pixErodeCompBrick(pixt6, pixs, size, size); if (TIMING) fprintf(stderr, "Time Rop: %7.3f sec\n", stopTimer()); PixCompareDwa(size, "erode", pixt1, pixt2, pixt3, pixt4, pixt5, pixt6); if (TIMING) startTimer(); pixOpenCompBrickExtendDwa(pixt1, pixs, size, 1); pixOpenCompBrickExtendDwa(pixt3, pixs, 1, size); pixOpenCompBrickExtendDwa(pixt5, pixs, size, size); if (TIMING) fprintf(stderr, "Time Dwa: %7.3f sec\n", stopTimer()); if (TIMING) startTimer(); pixOpenCompBrick(pixt2, pixs, size, 1); pixOpenCompBrick(pixt4, pixs, 1, size); pixOpenCompBrick(pixt6, pixs, size, size); if (TIMING) fprintf(stderr, "Time Rop: %7.3f sec\n", stopTimer()); PixCompareDwa(size, "open", pixt1, pixt2, pixt3, pixt4, pixt5, pixt6); if (TIMING) startTimer(); pixCloseCompBrickExtendDwa(pixt1, pixs, size, 1); pixCloseCompBrickExtendDwa(pixt3, pixs, 1, size); pixCloseCompBrickExtendDwa(pixt5, pixs, size, size); if (TIMING) fprintf(stderr, "Time Dwa: %7.3f sec\n", stopTimer()); if (TIMING) startTimer(); pixCloseSafeCompBrick(pixt2, pixs, size, 1); pixCloseSafeCompBrick(pixt4, pixs, 1, size); pixCloseSafeCompBrick(pixt6, pixs, size, size); if (TIMING) fprintf(stderr, "Time Rop: %7.3f sec\n", stopTimer()); PixCompareDwa(size, "close", pixt1, pixt2, pixt3, pixt4, pixt5, pixt6); #if 0 pixWrite("/tmp/junkpixt3.png", pixt3, IFF_PNG); pixWrite("/tmp/junkpixt4.png", pixt4, IFF_PNG); pixXor(pixt3, pixt3, pixt4); pixWrite("/tmp/junkxor.png", pixt3, IFF_PNG); #endif return 0; }
/* dwa composite with morph composite */ l_int32 DoComparisonDwa4(PIX *pixs, PIX *pixt1, PIX *pixt2, PIX *pixt3, PIX *pixt4, PIX *pixt5, PIX *pixt6, l_int32 isize) { l_int32 fact1, fact2, size; selectComposableSizes(isize, &fact1, &fact2); size = fact1 * fact2; fprintf(stderr, "..%d..", size); if (TIMING) startTimer(); pixDilateCompBrickDwa(pixt1, pixs, size, 1); pixDilateCompBrickDwa(pixt3, pixs, 1, size); pixDilateCompBrickDwa(pixt5, pixs, size, size); if (TIMING) fprintf(stderr, "Time Dwa: %7.3f sec\n", stopTimer()); if (TIMING) startTimer(); pixDilateCompBrick(pixt2, pixs, size, 1); pixDilateCompBrick(pixt4, pixs, 1, size); pixDilateCompBrick(pixt6, pixs, size, size); if (TIMING) fprintf(stderr, "Time Rop: %7.3f sec\n", stopTimer()); PixCompareDwa(size, "dilate", pixt1, pixt2, pixt3, pixt4, pixt5, pixt6); /* pixDisplay(pixt1, 100, 100); */ /* pixDisplay(pixt2, 800, 100); */ if (TIMING) startTimer(); pixErodeCompBrickDwa(pixt1, pixs, size, 1); pixErodeCompBrickDwa(pixt3, pixs, 1, size); pixErodeCompBrickDwa(pixt5, pixs, size, size); if (TIMING) fprintf(stderr, "Time Dwa: %7.3f sec\n", stopTimer()); if (TIMING) startTimer(); pixErodeCompBrick(pixt2, pixs, size, 1); pixErodeCompBrick(pixt4, pixs, 1, size); pixErodeCompBrick(pixt6, pixs, size, size); if (TIMING) fprintf(stderr, "Time Rop: %7.3f sec\n", stopTimer()); PixCompareDwa(size, "erode", pixt1, pixt2, pixt3, pixt4, pixt5, pixt6); if (TIMING) startTimer(); pixOpenCompBrickDwa(pixt1, pixs, size, 1); pixOpenCompBrickDwa(pixt3, pixs, 1, size); pixOpenCompBrickDwa(pixt5, pixs, size, size); if (TIMING) fprintf(stderr, "Time Dwa: %7.3f sec\n", stopTimer()); if (TIMING) startTimer(); pixOpenCompBrick(pixt2, pixs, size, 1); pixOpenCompBrick(pixt4, pixs, 1, size); pixOpenCompBrick(pixt6, pixs, size, size); if (TIMING) fprintf(stderr, "Time Rop: %7.3f sec\n", stopTimer()); PixCompareDwa(size, "open", pixt1, pixt2, pixt3, pixt4, pixt5, pixt6); /* pixDisplay(pixt1, 100, 100); */ /* pixDisplay(pixt2, 800, 100); */ /* pixWrite("/tmp/junkpixt1.png", pixt1, IFF_PNG); */ /* pixWrite("/tmp/junkpixt2.png", pixt2, IFF_PNG); */ if (TIMING) startTimer(); pixCloseCompBrickDwa(pixt1, pixs, size, 1); pixCloseCompBrickDwa(pixt3, pixs, 1, size); pixCloseCompBrickDwa(pixt5, pixs, size, size); if (TIMING) fprintf(stderr, "Time Dwa: %7.3f sec\n", stopTimer()); if (TIMING) startTimer(); pixCloseSafeCompBrick(pixt2, pixs, size, 1); pixCloseSafeCompBrick(pixt4, pixs, 1, size); pixCloseSafeCompBrick(pixt6, pixs, size, size); if (TIMING) fprintf(stderr, "Time Rop: %7.3f sec\n", stopTimer()); PixCompareDwa(size, "close", pixt1, pixt2, pixt3, pixt4, pixt5, pixt6); return 0; }
/*! * \brief pixMorphCompSequence() * * \param[in] pixs * \param[in] sequence string specifying sequence * \param[in] dispsep controls debug display of each result in the sequence: * 0: no output * > 0: gives horizontal separation in pixels between * successive displays * < 0: pdf output; abs(dispsep) is used for naming * \return pixd, or NULL on error * * <pre> * Notes: * (1) This does rasterop morphology on binary images, using composite * operations for extra speed on large Sels. * (2) Safe closing is used atomically. However, if you implement a * closing as a sequence with a dilation followed by an * erosion, it will not be safe, and to ensure that you have * no boundary effects you must add a border in advance and * remove it at the end. * (3) For other usage details, see the notes for pixMorphSequence(). * (4) The sequence string is formatted as follows: * ~ An arbitrary number of operations, each separated * by a '+' character. White space is ignored. * ~ Each operation begins with a case-independent character * specifying the operation: * d or D (dilation) * e or E (erosion) * o or O (opening) * c or C (closing) * r or R (rank binary reduction) * x or X (replicative binary expansion) * b or B (add a border of 0 pixels of this size) * ~ The args to the morphological operations are bricks of hits, * and are formatted as a.b, where a and b are horizontal and * vertical dimensions, rsp. * ~ The args to the reduction are a sequence of up to 4 integers, * each from 1 to 4. * ~ The arg to the expansion is a power of two, in the set * {2, 4, 8, 16}. * </pre> */ PIX * pixMorphCompSequence(PIX *pixs, const char *sequence, l_int32 dispsep) { char *rawop, *op, *fname; char buf[256]; l_int32 nops, i, j, nred, fact, w, h, x, y, border, pdfout; l_int32 level[4]; PIX *pixt1, *pixt2; PIXA *pixa; SARRAY *sa; PROCNAME("pixMorphCompSequence"); if (!pixs) return (PIX *)ERROR_PTR("pixs not defined", procName, NULL); if (!sequence) return (PIX *)ERROR_PTR("sequence not defined", procName, NULL); /* Split sequence into individual operations */ sa = sarrayCreate(0); sarraySplitString(sa, sequence, "+"); nops = sarrayGetCount(sa); pdfout = (dispsep < 0) ? 1 : 0; if (!morphSequenceVerify(sa)) { sarrayDestroy(&sa); return (PIX *)ERROR_PTR("sequence not valid", procName, NULL); } /* Parse and operate */ pixa = NULL; if (pdfout) { pixa = pixaCreate(0); pixaAddPix(pixa, pixs, L_CLONE); snprintf(buf, sizeof(buf), "/tmp/seq_output_%d.pdf", L_ABS(dispsep)); fname = genPathname(buf, NULL); } border = 0; pixt1 = pixCopy(NULL, pixs); pixt2 = NULL; x = y = 0; for (i = 0; i < nops; i++) { rawop = sarrayGetString(sa, i, L_NOCOPY); op = stringRemoveChars(rawop, " \n\t"); switch (op[0]) { case 'd': case 'D': sscanf(&op[1], "%d.%d", &w, &h); pixt2 = pixDilateCompBrick(NULL, pixt1, w, h); pixSwapAndDestroy(&pixt1, &pixt2); break; case 'e': case 'E': sscanf(&op[1], "%d.%d", &w, &h); pixt2 = pixErodeCompBrick(NULL, pixt1, w, h); pixSwapAndDestroy(&pixt1, &pixt2); break; case 'o': case 'O': sscanf(&op[1], "%d.%d", &w, &h); pixOpenCompBrick(pixt1, pixt1, w, h); break; case 'c': case 'C': sscanf(&op[1], "%d.%d", &w, &h); pixCloseSafeCompBrick(pixt1, pixt1, w, h); break; case 'r': case 'R': nred = strlen(op) - 1; for (j = 0; j < nred; j++) level[j] = op[j + 1] - '0'; for (j = nred; j < 4; j++) level[j] = 0; pixt2 = pixReduceRankBinaryCascade(pixt1, level[0], level[1], level[2], level[3]); pixSwapAndDestroy(&pixt1, &pixt2); break; case 'x': case 'X': sscanf(&op[1], "%d", &fact); pixt2 = pixExpandReplicate(pixt1, fact); pixSwapAndDestroy(&pixt1, &pixt2); break; case 'b': case 'B': sscanf(&op[1], "%d", &border); pixt2 = pixAddBorder(pixt1, border, 0); pixSwapAndDestroy(&pixt1, &pixt2); break; default: /* All invalid ops are caught in the first pass */ break; } LEPT_FREE(op); /* Debug output */ if (dispsep > 0) { pixDisplay(pixt1, x, y); x += dispsep; } if (pdfout) pixaAddPix(pixa, pixt1, L_COPY); } if (border > 0) { pixt2 = pixRemoveBorder(pixt1, border); pixSwapAndDestroy(&pixt1, &pixt2); } if (pdfout) { pixaConvertToPdf(pixa, 0, 1.0, L_FLATE_ENCODE, 0, fname, fname); LEPT_FREE(fname); pixaDestroy(&pixa); } sarrayDestroy(&sa); return pixt1; }