/*! * pixSelectByWidthHeightRatio() * * Input: pixs (1 bpp) * thresh (threshold ratio of width/height) * connectivity (4 or 8) * type (L_SELECT_IF_LT, L_SELECT_IF_GT, * L_SELECT_IF_LTE, L_SELECT_IF_GTE) * &changed (<optional return> 1 if changed; 0 if clone returned) * Return: pixd, or null on error * * Notes: * (1) The args specify constraints on the width-to-height ratio * for components that are kept. * (2) If unchanged, returns a copy of pixs. Otherwise, * returns a new pix with the filtered components. * (3) This filters components based on the width-to-height ratios. * (4) Use L_SELECT_IF_LT or L_SELECT_IF_LTE to save components * with less than the threshold ratio, and * L_SELECT_IF_GT or L_SELECT_IF_GTE to remove them. */ PIX * pixSelectByWidthHeightRatio(PIX *pixs, l_float32 thresh, l_int32 connectivity, l_int32 type, l_int32 *pchanged) { l_int32 w, h, empty, changed, count; BOXA *boxa; PIX *pixd; PIXA *pixas, *pixad; PROCNAME("pixSelectByWidthHeightRatio"); if (!pixs) return (PIX *)ERROR_PTR("pixs not defined", procName, NULL); if (connectivity != 4 && connectivity != 8) return (PIX *)ERROR_PTR("connectivity not 4 or 8", procName, NULL); if (type != L_SELECT_IF_LT && type != L_SELECT_IF_GT && type != L_SELECT_IF_LTE && type != L_SELECT_IF_GTE) return (PIX *)ERROR_PTR("invalid type", procName, NULL); if (pchanged) *pchanged = FALSE; /* Check if any components exist */ pixZero(pixs, &empty); if (empty) return pixCopy(NULL, pixs); /* Filter components */ boxa = pixConnComp(pixs, &pixas, connectivity); pixad = pixaSelectByWidthHeightRatio(pixas, thresh, type, &changed); boxaDestroy(&boxa); pixaDestroy(&pixas); /* Render the result */ if (!changed) { pixaDestroy(&pixad); return pixCopy(NULL, pixs); } else { if (pchanged) *pchanged = TRUE; pixGetDimensions(pixs, &w, &h, NULL); count = pixaGetCount(pixad); if (count == 0) /* return empty pix */ pixd = pixCreateTemplate(pixs); else { pixd = pixaDisplay(pixad, w, h); pixCopyResolution(pixd, pixs); pixCopyColormap(pixd, pixs); pixCopyText(pixd, pixs); pixCopyInputFormat(pixd, pixs); } pixaDestroy(&pixad); return pixd; } }
/*! * pixTransferAllData() * * Input: pixd (must be different from pixs) * &pixs (will be nulled if refcount goes to 0) * copytext (1 to copy the text field; 0 to skip) * copyformat (1 to copy the informat field; 0 to skip) * Return: 0 if OK, 1 on error * * Notes: * (1) This does a complete data transfer from pixs to pixd, * followed by the destruction of pixs (refcount permitting). * (2) If the refcount of pixs is 1, pixs is destroyed. Otherwise, * the data in pixs is copied (rather than transferred) to pixd. * (3) This operation, like all others with a pre-existing pixd, * will side-effect any existing clones of pixd. The pixd * refcount does not change. * (4) When might you use this? Suppose you have an in-place Pix * function (returning void) with the typical signature: * void function-inplace(PIX *pix, ...) * where "..." are non-pointer input parameters, and suppose * further that you sometimes want to return an arbitrary Pix * in place of the input Pix. There are two ways you can do this: * (a) The straightforward way is to change the function * signature to take the address of the Pix ptr: * void function-inplace(PIX **ppix, ...) { * PIX *pixt = function-makenew(*ppix); * pixDestroy(ppix); * *ppix = pixt; * return; * } * Here, the input and returned pix are different, as viewed * by the calling function, and the inplace function is * expected to destroy the input pix to avoid a memory leak. * (b) Keep the signature the same and use pixTransferAllData() * to return the new Pix in the input Pix struct: * void function-inplace(PIX *pix, ...) { * PIX *pixt = function-makenew(pix); * pixTransferAllData(pix, &pixt); // pixt is destroyed * return; * } * Here, the input and returned pix are the same, as viewed * by the calling function, and the inplace function must * never destroy the input pix, because the calling function * maintains an unchanged handle to it. */ l_int32 pixTransferAllData(PIX *pixd, PIX **ppixs, l_int32 copytext, l_int32 copyformat) { l_int32 nbytes; PIX *pixs; PROCNAME("pixTransferAllData"); if (!ppixs) return ERROR_INT("&pixs not defined", procName, 1); if ((pixs = *ppixs) == NULL) return ERROR_INT("pixs not defined", procName, 1); if (!pixd) return ERROR_INT("pixd not defined", procName, 1); if (pixs == pixd) /* no-op */ return ERROR_INT("pixd == pixs", procName, 1); if (pixGetRefcount(pixs) == 1) { /* transfer the data, cmap, text */ pixFreeData(pixd); /* dealloc any existing data */ pixSetData(pixd, pixGetData(pixs)); /* transfer new data from pixs */ pixs->data = NULL; /* pixs no longer owns data */ pixSetColormap(pixd, pixGetColormap(pixs)); /* frees old; sets new */ pixs->colormap = NULL; /* pixs no longer owns colormap */ if (copytext) { pixSetText(pixd, pixGetText(pixs)); pixSetText(pixs, NULL); } } else { /* preserve pixs by making a copy of the data, cmap, text */ pixResizeImageData(pixd, pixs); nbytes = 4 * pixGetWpl(pixs) * pixGetHeight(pixs); memcpy((char *)pixGetData(pixd), (char *)pixGetData(pixs), nbytes); pixCopyColormap(pixd, pixs); if (copytext) pixCopyText(pixd, pixs); } pixCopyResolution(pixd, pixs); pixCopyDimensions(pixd, pixs); if (copyformat) pixCopyInputFormat(pixd, pixs); /* This will destroy pixs if data was transferred; * otherwise, it just decrements its refcount. */ pixDestroy(ppixs); return 0; }
/*! * pixCopy() * * Input: pixd (<optional>; can be null, or equal to pixs, * or different from pixs) * pixs * Return: pixd, or null on error * * Notes: * (1) There are three cases: * (a) pixd == null (makes a new pix; refcount = 1) * (b) pixd == pixs (no-op) * (c) pixd != pixs (data copy; no change in refcount) * If the refcount of pixd > 1, case (c) will side-effect * these handles. * (2) The general pattern of use is: * pixd = pixCopy(pixd, pixs); * This will work for all three cases. * For clarity when the case is known, you can use: * (a) pixd = pixCopy(NULL, pixs); * (c) pixCopy(pixd, pixs); * (3) For case (c), we check if pixs and pixd are the same * size (w,h,d). If so, the data is copied directly. * Otherwise, the data is reallocated to the correct size * and the copy proceeds. The refcount of pixd is unchanged. * (4) This operation, like all others that may involve a pre-existing * pixd, will side-effect any existing clones of pixd. */ PIX * pixCopy(PIX *pixd, /* can be null */ PIX *pixs) { l_int32 bytes; l_uint32 *datas, *datad; PROCNAME("pixCopy"); if (!pixs) return (PIX *)ERROR_PTR("pixs not defined", procName, NULL); if (pixs == pixd) return pixd; /* Total bytes in image data */ bytes = 4 * pixGetWpl(pixs) * pixGetHeight(pixs); /* If we're making a new pix ... */ if (!pixd) { if ((pixd = pixCreateTemplate(pixs)) == NULL) return (PIX *)ERROR_PTR("pixd not made", procName, NULL); datas = pixGetData(pixs); datad = pixGetData(pixd); memcpy((char *)datad, (char *)datas, bytes); return pixd; } /* Reallocate image data if sizes are different */ if (pixResizeImageData(pixd, pixs) == 1) return (PIX *)ERROR_PTR("reallocation of data failed", procName, NULL); /* Copy non-image data fields */ pixCopyColormap(pixd, pixs); pixCopyResolution(pixd, pixs); pixCopyInputFormat(pixd, pixs); pixCopyText(pixd, pixs); /* Copy image data */ datas = pixGetData(pixs); datad = pixGetData(pixd); memcpy((char*)datad, (char*)datas, bytes); return pixd; }
/*! * pixCreateTemplateNoInit() * * Input: pixs * Return: pixd, or null on error * * Notes: * (1) Makes a Pix of the same size as the input Pix, with * the data array allocated but not initialized to 0. * (2) Copies the other fields, including colormap if it exists. */ PIX * pixCreateTemplateNoInit(PIX *pixs) { l_int32 w, h, d; PIX *pixd; PROCNAME("pixCreateTemplateNoInit"); if (!pixs) return (PIX *)ERROR_PTR("pixs not defined", procName, NULL); pixGetDimensions(pixs, &w, &h, &d); if ((pixd = pixCreateNoInit(w, h, d)) == NULL) return (PIX *)ERROR_PTR("pixd not made", procName, NULL); pixCopyResolution(pixd, pixs); pixCopyColormap(pixd, pixs); pixCopyText(pixd, pixs); pixCopyInputFormat(pixd, pixs); return pixd; }
/*! * pixRotate90() * * Input: pixs (all depths) * direction (1 = clockwise, -1 = counter-clockwise) * Return: pixd, or null on error * * Notes: * (1) This does a 90 degree rotation of the image about the center, * either cw or ccw, returning a new pix. * (2) The direction must be either 1 (cw) or -1 (ccw). */ PIX * pixRotate90(PIX *pixs, l_int32 direction) { l_int32 wd, hd, d, wpls, wpld; l_uint32 *datas, *datad; PIX *pixd; PROCNAME("pixRotate90"); if (!pixs) return (PIX *)ERROR_PTR("pixs not defined", procName, NULL); d = pixGetDepth(pixs); if (d != 1 && d != 2 && d != 4 && d != 8 && d != 16 && d != 32) return (PIX *)ERROR_PTR("pixs not in {1,2,4,8,16,32} bpp", procName, NULL); if (direction != 1 && direction != -1) return (PIX *)ERROR_PTR("invalid direction", procName, NULL); hd = pixGetWidth(pixs); wd = pixGetHeight(pixs); if ((pixd = pixCreate(wd, hd, d)) == NULL) return (PIX *)ERROR_PTR("pixd not made", procName, NULL); pixCopyColormap(pixd, pixs); pixCopyResolution(pixd, pixs); pixCopyInputFormat(pixd, pixs); datas = pixGetData(pixs); wpls = pixGetWpl(pixs); datad = pixGetData(pixd); wpld = pixGetWpl(pixd); rotate90Low(datad, wd, hd, d, wpld, datas, wpls, direction); return pixd; }