/*! * dpixResizeImageData() * * Input: dpixd, dpixs * Return: 0 if OK, 1 on error */ l_int32 dpixResizeImageData(DPIX *dpixd, DPIX *dpixs) { l_int32 ws, hs, wd, hd, bytes; l_float64 *data; PROCNAME("dpixResizeImageData"); if (!dpixs) return ERROR_INT("dpixs not defined", procName, 1); if (!dpixd) return ERROR_INT("dpixd not defined", procName, 1); dpixGetDimensions(dpixs, &ws, &hs); dpixGetDimensions(dpixd, &wd, &hd); if (ws == wd && hs == hd) /* nothing to do */ return 0; dpixSetDimensions(dpixd, ws, hs); dpixSetWpl(dpixd, ws); bytes = 8 * ws * hs; data = dpixGetData(dpixd); if (data) FREE(data); if ((data = (l_float64 *)MALLOC(bytes)) == NULL) return ERROR_INT("MALLOC fail for data", procName, 1); dpixSetData(dpixd, data); return 0; }
/*! * dpixGetMinMax() * * Input: dpix * &minval (<optional return> min value) * &maxval (<optional return> max value) * Return: 0 if OK; 1 on error */ l_int32 dpixGetMinMax(DPIX *dpix, l_float64 *pminval, l_float64 *pmaxval) { l_int32 i, j, w, h, wpl; l_float64 *data, *line; l_float64 minval, maxval; PROCNAME("dpixGetMinMax"); if (!pminval && !pmaxval) return ERROR_INT("nothing to do", procName, 1); if (pminval) *pminval = 0.0; if (pmaxval) *pmaxval = 0.0; if (!dpix) return ERROR_INT("dpix not defined", procName, 1); minval = +1.0e40; maxval = -1.0e40; dpixGetDimensions(dpix, &w, &h); data = dpixGetData(dpix); wpl = dpixGetWpl(dpix); for (i = 0; i < h; i++) { line = data + i * wpl; for (j = 0; j < w; j++) { if (line[j] < minval) minval = line[j]; if (line[j] > maxval) maxval = line[j]; } } if (pminval) *pminval = minval; if (pmaxval) *pmaxval = maxval; return 0; }
/*! * dpixNormalize() * * Input: dpixd (<optional>; this can be null, equal to dpixs, * or different from dpixs) * dpixs * Return: dpixd, or null on error * * Notes: * (1) Normalize dpixs by dividing each value by the size of the * image. This is to compensate for the FFTW library returning * unnormalized DFT values. * (2) There are 3 cases: * (a) dpixd == null, ~src --> new dpixd * (b) dpixd == dpixs, ~src --> src (in-place) * (c) dpixd != dpixs, ~src --> input dpixd * (3) For clarity, if the case is known, use these patterns: * (a) dpixd = dpixNormalize(NULL, dpixs); * (b) dpixNormalize(dpixs, dpixs); * (c) dpixNormalize(dpixd, dpixs); */ DPIX * dpixNormalize(DPIX *dpixd, DPIX *dpixs) { l_int32 w, h, n, i, j, wpl; l_float64 *data, *line; PROCNAME("dpixNormalize"); if (!dpixs) return (DPIX *)ERROR_PTR("dpixs not defined", procName, NULL); /* Prepare dpixd for in-place operation */ if ((dpixd = dpixCopy(dpixd, dpixs)) == NULL) return (DPIX *)ERROR_PTR("dpixd not made", procName, NULL); dpixGetDimensions(dpixd, &w, &h); data = dpixGetData(dpixd); wpl = dpixGetWpl(dpixd); n = w * h; for (i = 0; i < h; i++) { line = data + i * wpl; for (j = 0; j < w; j++) { line[j] /= n; } } return dpixd; }
/*! * dpixCreateTemplate() * * Input: dpixs * Return: dpixd, or null on error * * Notes: * (1) Makes a DPix of the same size as the input DPix, with the * data array allocated and initialized to 0. * (2) Copies the resolution. */ DPIX * dpixCreateTemplate(DPIX *dpixs) { l_int32 w, h; DPIX *dpixd; PROCNAME("dpixCreateTemplate"); if (!dpixs) return (DPIX *)ERROR_PTR("dpixs not defined", procName, NULL); dpixGetDimensions(dpixs, &w, &h); dpixd = dpixCreate(w, h); dpixCopyResolution(dpixd, dpixs); return dpixd; }
/*! * dpixMaxDynamicRange() * * Input: dpixd (<optional>; this can be null, equal to dpixs, * or different from dpixs) * dpixs * k (maximum intensity value) * hivals (L_HI_TO_WHITE or L_HI_TO_BLACK) * Return: dpixd, or null on error * * Notes: * (1) Linearly rescale dpix values to maximize the dynamic range * within range [0, k] * (2) There are 3 cases: * (a) dpixd == null, ~src --> new dpixd * (b) dpixd == dpixs, ~src --> src (in-place) * (c) dpixd != dpixs, ~src --> input dpixd * (3) For clarity, if the case is known, use these patterns: * (a) dpixd = dpixNormalize(NULL, dpixs); * (b) dpixNormalize(dpixs, dpixs); * (c) dpixNormalize(dpixd, dpixs); * (4) Set @hivals to L_HI_TO_WHITE to convert higher intensities to * white, or L_HI_TO_BLACK to convert them to black instead. */ DPIX * dpixMaxDynamicRange(DPIX *dpixd, DPIX *dpixs, l_int32 k, l_int32 hivals) { l_int32 w, h, n, i, j, wpl; l_float64 *data, *line; l_float64 minval, maxval; PROCNAME("dpixMaxDynamicRange"); if (!dpixs) return (DPIX *)ERROR_PTR("dpixs not defined", procName, NULL); if (hivals != L_HI_TO_WHITE && hivals != L_HI_TO_BLACK) return (DPIX *)ERROR_PTR("invalid hivals", procName, NULL); /* Prepare dpixd for in-place operation */ if ((dpixd = dpixCopy(dpixd, dpixs)) == NULL) return (DPIX *)ERROR_PTR("dpixd not made", procName, NULL); dpixGetDimensions(dpixd, &w, &h); data = dpixGetData(dpixd); wpl = dpixGetWpl(dpixd); dpixGetMinMax(dpixd, &minval, &maxval); maxval -= minval; /* Prevent division by 0 */ if (!maxval) maxval += 1.0; for (i = 0; i < h; i++) { line = data + i * wpl; for (j = 0; j < w; j++) { if (hivals == L_HI_TO_WHITE) line[j] = k * ((line[j] - minval) / maxval); else line[j] = k - (k * ((line[j] - minval) / maxval)); } } return dpixd; }
/*! * dpixGetMax() * * Input: dpix * &maxval (<optional return> max value) * &xmaxloc (<optional return> x location of max) * &ymaxloc (<optional return> y location of max) * Return: 0 if OK; 1 on error */ l_int32 dpixGetMax(DPIX *dpix, l_float64 *pmaxval, l_int32 *pxmaxloc, l_int32 *pymaxloc) { l_int32 i, j, w, h, wpl, xmaxloc, ymaxloc; l_float64 *data, *line; l_float64 maxval; PROCNAME("dpixGetMax"); if (!pmaxval && !pxmaxloc && !pymaxloc) return ERROR_INT("nothing to do", procName, 1); if (pmaxval) *pmaxval = 0.0; if (pxmaxloc) *pxmaxloc = 0; if (pymaxloc) *pymaxloc = 0; if (!dpix) return ERROR_INT("dpix not defined", procName, 1); maxval = -1.0e40; xmaxloc = 0; ymaxloc = 0; dpixGetDimensions(dpix, &w, &h); data = dpixGetData(dpix); wpl = dpixGetWpl(dpix); for (i = 0; i < h; i++) { line = data + i * wpl; for (j = 0; j < w; j++) { if (line[j] > maxval) { maxval = line[j]; xmaxloc = j; ymaxloc = i; } } } if (pmaxval) *pmaxval = maxval; if (pxmaxloc) *pxmaxloc = xmaxloc; if (pymaxloc) *pymaxloc = ymaxloc; return 0; }
/*! * dpixCopy() * * Input: dpixd (<optional>; can be null, or equal to dpixs, * or different from dpixs) * dpixs * Return: dpixd, or null on error * * Notes: * (1) There are three cases: * (a) dpixd == null (makes a new dpix; refcount = 1) * (b) dpixd == dpixs (no-op) * (c) dpixd != dpixs (data copy; no change in refcount) * If the refcount of dpixd > 1, case (c) will side-effect * these handles. * (2) The general pattern of use is: * dpixd = dpixCopy(dpixd, dpixs); * This will work for all three cases. * For clarity when the case is known, you can use: * (a) dpixd = dpixCopy(NULL, dpixs); * (c) dpixCopy(dpixd, dpixs); * (3) For case (c), we check if dpixs and dpixd are the same size. * If so, the data is copied directly. * Otherwise, the data is reallocated to the correct size * and the copy proceeds. The refcount of dpixd is unchanged. * (4) This operation, like all others that may involve a pre-existing * dpixd, will side-effect any existing clones of dpixd. */ DPIX * dpixCopy(DPIX *dpixd, /* can be null */ DPIX *dpixs) { l_int32 w, h, bytes; l_float64 *datas, *datad; PROCNAME("dpixCopy"); if (!dpixs) return (DPIX *)ERROR_PTR("dpixs not defined", procName, NULL); if (dpixs == dpixd) return dpixd; /* Total bytes in image data */ dpixGetDimensions(dpixs, &w, &h); bytes = 8 * w * h; /* If we're making a new dpix ... */ if (!dpixd) { if ((dpixd = dpixCreateTemplate(dpixs)) == NULL) return (DPIX *)ERROR_PTR("dpixd not made", procName, NULL); datas = dpixGetData(dpixs); datad = dpixGetData(dpixd); memcpy((char *)datad, (char *)datas, bytes); return dpixd; } /* Reallocate image data if sizes are different */ dpixResizeImageData(dpixd, dpixs); /* Copy data */ dpixCopyResolution(dpixd, dpixs); datas = dpixGetData(dpixs); datad = dpixGetData(dpixd); memcpy((char*)datad, (char*)datas, bytes); return dpixd; }
/*! * dpixConvertToPix() * * Input: dpixs * outdepth (0, 1, 8, 16 or 32 bpp) * negvals (L_CLIP_TO_ZERO, L_TAKE_ABSVAL, * L_THRESH_NEG_TO_BLACK or L_THRESH_NEG_TO_WHITE) * errorflag (1 to output error stats; 0 otherwise) * shiftflag (L_NO_SHIFTING or L_WITH_SHIFTING) * Return: pixd, or null on error * * Notes: * (1) Use @outdepth = 0 to programmatically determine the * output depth. If no values are greater than 255, * it will set outdepth = 8; otherwise to 16 or 32. * (2) Because we are converting a float to an unsigned int * with a specified dynamic range (8, 16 or 32 bits), errors * can occur. If errorflag == TRUE, output the number * of values out of range, both negative and positive. * (3) If a pixel value is positive and out of range, clip to * the maximum value represented at the outdepth of 8, 16 * or 32 bits. * (4) Set @shiftflag to L_WITH_SHIFTING to move the DC of the * the DFT to the center of pix. * When @shiftflag == L_WITH_SHIFTING, pixd is multiplied * by pow(-1, x + y). */ PIX * dpixConvertToPix(DPIX *dpixs, l_int32 outdepth, l_int32 negvals, l_int32 errorflag, l_int32 shiftflag) { l_int32 w, h, wpls, wpld, maxval; l_int32 i, j; l_uint32 vald; l_float64 val; l_float64 *datas, *lines; l_uint32 *datad, *lined; PIX *pixd; PROCNAME("dpixConvertToPix"); if (!dpixs) return (PIX *)ERROR_PTR("dpixs not defined", procName, NULL); if (negvals != L_CLIP_TO_ZERO && negvals != L_TAKE_ABSVAL && negvals != L_THRESH_NEG_TO_BLACK && negvals != L_THRESH_NEG_TO_WHITE) return (PIX *)ERROR_PTR("invalid negvals", procName, NULL); if (outdepth != 0 && outdepth != 8 && outdepth != 16 && outdepth != 32) return (PIX *)ERROR_PTR("outdepth not in {0,8,16,32}", procName, NULL); if (shiftflag != L_NO_SHIFTING && shiftflag != L_WITH_SHIFTING) return (PIX *)ERROR_PTR("invalid shiftflag", procName, NULL); dpixGetDimensions(dpixs, &w, &h); datas = dpixGetData(dpixs); wpls = dpixGetWpl(dpixs); /* Adaptive determination of output depth */ if (outdepth == 0) { outdepth = 8; for (i = 0; i < h; i++) { lines = datas + i * wpls; for (j = 0; j < w; j++) { val = lines[j]; if (val > 65535.5) { outdepth = 32; break; } if (val > 255.5) outdepth = 16; } if (outdepth == 32) break; } } maxval = (1 << outdepth) - 1; /* Gather statistics if @errorflag = TRUE */ if (errorflag) { l_int32 negs = 0; l_int32 overvals = 0; for (i = 0; i < h; i++) { lines = datas + i * wpls; for (j = 0; j < w; j++) { val = lines[j]; if (val < 0.0) negs++; else if (val > maxval) overvals++; } } if (negs > 0) L_ERROR_INT("Number of negative values: %d", procName, negs); if (overvals > 0) L_ERROR_INT("Number of too-large values: %d", procName, overvals); } /* Make the pix and convert the data */ if ((pixd = pixCreate(w, h, outdepth)) == NULL) return (PIX *)ERROR_PTR("pixd not made", procName, NULL); datad = pixGetData(pixd); wpld = pixGetWpl(pixd); for (i = 0; i < h; i++) { lines = datas + i * wpls; lined = datad + i * wpld; for (j = 0; j < w; j++) { val = lines[j]; if (shiftflag) val *= pow(-1, i + j); if (val > 0.0) { if (negvals == L_THRESH_NEG_TO_BLACK || negvals == L_THRESH_NEG_TO_WHITE) vald = negvals == L_THRESH_NEG_TO_BLACK ? maxval : 0; else vald = (l_uint32)(val + 0.5); } else { /* val <= 0.0 */ if (negvals == L_THRESH_NEG_TO_BLACK || negvals == L_THRESH_NEG_TO_WHITE) vald = negvals == L_THRESH_NEG_TO_BLACK ? 0 : maxval; else if (negvals == L_CLIP_TO_ZERO) vald = 0; else vald = (l_uint32)(-val + 0.5); } if (vald > maxval) vald = maxval; if (outdepth == 8) SET_DATA_BYTE(lined, j, vald); else if (outdepth == 16) SET_DATA_TWO_BYTES(lined, j, vald); else /* outdepth == 32 */ SET_DATA_FOUR_BYTES(lined, j, vald); } } return pixd; }