/*!
* pixRotateAMColorFast()
*
* Input: pixs
* angle (radians; clockwise is positive)
* colorval (e.g., 0 to bring in BLACK, 0xffffff00 for WHITE)
* Return: pixd, or null on error
*
* Notes:
* (1) This rotates a color image about the image center.
* (2) A positive angle gives a clockwise rotation.
* (3) It uses area mapping, dividing each pixel into
* 16 subpixels.
* (4) It is about 10% to 20% faster than the more accurate linear
* interpolation function pixRotateAMColor(),
* which uses 256 subpixels.
* (5) For some reason it shifts the image center.
* No attempt is made to rotate the alpha component.
*
* *** Warning: implicit assumption about RGB component ordering ***
*/
PIX *
pixRotateAMColorFast(PIX *pixs,
l_float32 angle,
l_uint32 colorval)
{
l_int32 w, h, wpls, wpld;
l_uint32 *datas, *datad;
PIX *pixd;
PROCNAME("pixRotateAMColorFast");
if (!pixs)
return (PIX *)ERROR_PTR("pixs not defined", procName, NULL);
if (pixGetDepth(pixs) != 32)
return (PIX *)ERROR_PTR("pixs must be 32 bpp", procName, NULL);
if (L_ABS(angle) < MIN_ANGLE_TO_ROTATE)
return pixClone(pixs);
pixGetDimensions(pixs, &w, &h, NULL);
datas = pixGetData(pixs);
wpls = pixGetWpl(pixs);
pixd = pixCreateTemplate(pixs);
datad = pixGetData(pixd);
wpld = pixGetWpl(pixd);
rotateAMColorFastLow(datad, w, h, wpld, datas, wpls, angle, colorval);
return pixd;
}
// Helper to remove an enclosing circle from an image.
// If there isn't one, then the image will most likely get badly mangled.
// The returned pix must be pixDestroyed after use. NULL may be returned
// if the image doesn't meet the trivial conditions that it uses to determine
// success.
static Pix* RemoveEnclosingCircle(Pix* pixs) {
Pix* pixsi = pixInvert(NULL, pixs);
Pix* pixc = pixCreateTemplate(pixs);
pixSetOrClearBorder(pixc, 1, 1, 1, 1, PIX_SET);
pixSeedfillBinary(pixc, pixc, pixsi, 4);
pixInvert(pixc, pixc);
pixDestroy(&pixsi);
Pix* pixt = pixAnd(NULL, pixs, pixc);
l_int32 max_count;
pixCountConnComp(pixt, 8, &max_count);
// The count has to go up before we start looking for the minimum.
l_int32 min_count = MAX_INT32;
Pix* pixout = NULL;
for (int i = 1; i < kMaxCircleErosions; i++) {
pixDestroy(&pixt);
pixErodeBrick(pixc, pixc, 3, 3);
pixt = pixAnd(NULL, pixs, pixc);
l_int32 count;
pixCountConnComp(pixt, 8, &count);
if (i == 1 || count > max_count) {
max_count = count;
min_count = count;
} else if (i > 1 && count < min_count) {
min_count = count;
pixDestroy(&pixout);
pixout = pixCopy(NULL, pixt); // Save the best.
} else if (count >= min_count) {
break; // We have passed by the best.
}
}
pixDestroy(&pixt);
pixDestroy(&pixc);
return pixout;
}
/*!
* pixFHMTGen_1()
*
* Input: pixd (usual 3 choices: null, == pixs, != pixs)
* pixs (1 bpp)
* sel name
* Return: pixd
*
* Notes:
* (1) This is a dwa implementation of the hit-miss transform
* on pixs by the sel.
* (2) The sel must be limited in size to not more than 31 pixels
* about the origin. It must have at least one hit, and it
* can have any number of misses.
* (3) This handles all required setting of the border pixels
* before erosion and dilation.
*/
PIX *
pixFHMTGen_1(PIX *pixd,
PIX *pixs,
char *selname)
{
l_int32 i, index, found, w, h, wpls, wpld;
l_uint32 *datad, *datas, *datat;
PIX *pixt;
PROCNAME("pixFHMTGen_1");
if (!pixs)
return (PIX *)ERROR_PTR("pixs not defined", procName, pixd);
if (pixGetDepth(pixs) != 1)
return (PIX *)ERROR_PTR("pixs must be 1 bpp", procName, pixd);
found = FALSE;
for (i = 0; i < NUM_SELS_GENERATED; i++) {
if (strcmp(selname, SEL_NAMES[i]) == 0) {
found = TRUE;
index = i;
break;
}
}
if (found == FALSE)
return (PIX *)ERROR_PTR("sel index not found", procName, pixd);
if (!pixd) {
if ((pixd = pixCreateTemplate(pixs)) == NULL)
return (PIX *)ERROR_PTR("pixd not made", procName, NULL);
}
else /* for in-place or pre-allocated */
pixResizeImageData(pixd, pixs);
wpls = pixGetWpl(pixs);
wpld = pixGetWpl(pixd);
/* The images must be surrounded with 32 additional border
* pixels, that we'll read from. We fabricate a "proper"
* image as the subimage within the border, having the
* following parameters: */
w = pixGetWidth(pixs) - 64;
h = pixGetHeight(pixs) - 64;
datas = pixGetData(pixs) + 32 * wpls + 1;
datad = pixGetData(pixd) + 32 * wpld + 1;
if (pixd == pixs) { /* need temp image if in-place */
if ((pixt = pixCopy(NULL, pixs)) == NULL)
return (PIX *)ERROR_PTR("pixt not made", procName, pixd);
datat = pixGetData(pixt) + 32 * wpls + 1;
fhmtgen_low_1(datad, w, h, wpld, datat, wpls, index);
pixDestroy(&pixt);
}
else { /* not in-place */
fhmtgen_low_1(datad, w, h, wpld, datas, wpls, index);
}
return pixd;
}
/*!
* pixAdaptiveMeanFilter()
*
* Input: pixs (8 bpp grayscale)
* wc, hc (half width/height of convolution kernel)
* varn (value of overall noise variance)
* Return: pixd (8 bpp, filtered image)
*
* Notes:
* (1) The filter reduces gaussian noise, achieving results similar
* to the arithmetic and geometric mean filters but avoiding the
* considerable image blurring effect introduced by those filters.
* (2) The filter can be expressed mathematically by:
* f'(x, y) = g(x, y) - varN / varL * [ g(x, y) - meanL ]
* where:
* -- g(x, y) is the pixel at the center of local region S of
* width (2 * wc + 1) and height (2 * wh + 1)
* -- varN and varL are the overall noise variance (given in input)
* and local variance of S, respectively
* -- meanL is the local mean of S
* (3) Typically @varn is estimated by studying the PDFs produced by
* the camera or equipment sensors.
*/
PIX *
pixAdaptiveMeanFilter(PIX *pixs,
l_int32 wc,
l_int32 hc,
l_float32 varn)
{
l_int32 i, j, w, h, d, wplt, wpld, wincr, hincr;
l_uint32 val;
l_uint32 *datat, *datad, *linet, *lined;
l_float32 norm, meanl, varl, ratio;
PIX *pixt, *pixd;
PROCNAME("pixAdaptiveMeanFilter");
if (!pixs)
return (PIX *)ERROR_PTR("pixs not defined", procName, NULL);
pixGetDimensions(pixs, &w, &h, &d);
if (d != 8)
return (PIX *)ERROR_PTR("pixs not 8 bpp", procName, NULL);
if (wc < 1 || hc < 1)
return (PIX *)ERROR_PTR("wc and hc not >= 1", procName, NULL);
/* Add wc to each side, and hc to top and bottom of the image,
* mirroring for accuracy and to avoid special-casing the boundary. */
if ((pixt = pixAddMirroredBorder(pixs, wc, wc, hc, hc)) == NULL)
return (PIX *)ERROR_PTR("pixt not made", procName, NULL);
/* Place the filter center at (0, 0). This is just a
* convenient location, because it allows us to perform
* the filtering over x:(0 ... w - 1) and y:(0 ... h - 1). */
pixd = pixCreateTemplate(pixs);
wplt = pixGetWpl(pixt);
wpld = pixGetWpl(pixd);
datat = pixGetData(pixt);
datad = pixGetData(pixd);
wincr = 2 * wc + 1;
hincr = 2 * hc + 1;
norm = 1.0 / (wincr * hincr);
for (i = 0; i < h; i++) {
linet = datat + (i + hc) * wplt;
lined = datad + i * wpld;
for (j = 0; j < w; j++) {
/* Calculate mean intensity value */
meanl = calculateLocalMeanLow(datat, wplt, wincr, hincr, i, j);
/* Calculate local variance */
varl = calculateLocalVarianceLow(datat, wplt, wincr, hincr, i, j, meanl);
/* Account for special case in which varN is more than varL */
ratio = (varn > varl) ? 1 : varn / varl;
val = GET_DATA_BYTE(linet, j + wc);
SET_DATA_BYTE(lined, j, (l_uint8) (val - ratio * (val - meanl)));
}
}
pixDestroy(&pixt);
return pixd;
}
开发者ID:Hurricane86,项目名称:ipl,代码行数:80,代码来源:spatial.c
示例8: pixSelectByWidthHeightRatio
/*!
* 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;
}
}
/*!
* 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;
}
请发表评论