mirror of http://192.168.1.51:8099/lmh188/twain3.0
2468 lines
73 KiB
C
2468 lines
73 KiB
C
|
/*====================================================================*
|
||
|
- Copyright (C) 2001 Leptonica. All rights reserved.
|
||
|
-
|
||
|
- Redistribution and use in source and binary forms, with or without
|
||
|
- modification, are permitted provided that the following conditions
|
||
|
- are met:
|
||
|
- 1. Redistributions of source code must retain the above copyright
|
||
|
- notice, this list of conditions and the following disclaimer.
|
||
|
- 2. Redistributions in binary form must reproduce the above
|
||
|
- copyright notice, this list of conditions and the following
|
||
|
- disclaimer in the documentation and/or other materials
|
||
|
- provided with the distribution.
|
||
|
-
|
||
|
- THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||
|
- ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||
|
- LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||
|
- A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL ANY
|
||
|
- CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||
|
- EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||
|
- PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||
|
- PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
|
||
|
- OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||
|
- NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||
|
- SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||
|
*====================================================================*/
|
||
|
|
||
|
/*!
|
||
|
* \file fpix2.c
|
||
|
* <pre>
|
||
|
*
|
||
|
* ------------------------------------------
|
||
|
* This file has these FPix utilities:
|
||
|
* ~ interconversions with pix, fpix, dpix
|
||
|
* ~ min and max values
|
||
|
* ~ integer scaling
|
||
|
* ~ arithmetic operations
|
||
|
* ~ set all
|
||
|
* ~ border functions
|
||
|
* ~ simple rasterop (source --> dest)
|
||
|
* ~ geometric transforms
|
||
|
* ------------------------------------------
|
||
|
*
|
||
|
* Interconversions between Pix, FPix and DPix
|
||
|
* FPIX *pixConvertToFPix()
|
||
|
* DPIX *pixConvertToDPix()
|
||
|
* PIX *fpixConvertToPix()
|
||
|
* PIX *fpixDisplayMaxDynamicRange() [useful for debugging]
|
||
|
* DPIX *fpixConvertToDPix()
|
||
|
* PIX *dpixConvertToPix()
|
||
|
* FPIX *dpixConvertToFPix()
|
||
|
*
|
||
|
* Min/max value
|
||
|
* l_int32 fpixGetMin()
|
||
|
* l_int32 fpixGetMax()
|
||
|
* l_int32 dpixGetMin()
|
||
|
* l_int32 dpixGetMax()
|
||
|
*
|
||
|
* Integer scaling
|
||
|
* FPIX *fpixScaleByInteger()
|
||
|
* DPIX *dpixScaleByInteger()
|
||
|
*
|
||
|
* Arithmetic operations
|
||
|
* FPIX *fpixLinearCombination()
|
||
|
* l_int32 fpixAddMultConstant()
|
||
|
* DPIX *dpixLinearCombination()
|
||
|
* l_int32 dpixAddMultConstant()
|
||
|
*
|
||
|
* Set all
|
||
|
* l_int32 fpixSetAllArbitrary()
|
||
|
* l_int32 dpixSetAllArbitrary()
|
||
|
*
|
||
|
* FPix border functions
|
||
|
* FPIX *fpixAddBorder()
|
||
|
* FPIX *fpixRemoveBorder()
|
||
|
* FPIX *fpixAddMirroredBorder()
|
||
|
* FPIX *fpixAddContinuedBorder()
|
||
|
* FPIX *fpixAddSlopeBorder()
|
||
|
*
|
||
|
* FPix simple rasterop
|
||
|
* l_int32 fpixRasterop()
|
||
|
*
|
||
|
* FPix rotation by multiples of 90 degrees
|
||
|
* FPIX *fpixRotateOrth()
|
||
|
* FPIX *fpixRotate180()
|
||
|
* FPIX *fpixRotate90()
|
||
|
* FPIX *fpixFlipLR()
|
||
|
* FPIX *fpixFlipTB()
|
||
|
*
|
||
|
* FPix affine and projective interpolated transforms
|
||
|
* FPIX *fpixAffinePta()
|
||
|
* FPIX *fpixAffine()
|
||
|
* FPIX *fpixProjectivePta()
|
||
|
* FPIX *fpixProjective()
|
||
|
* l_int32 linearInterpolatePixelFloat()
|
||
|
*
|
||
|
* Thresholding to 1 bpp Pix
|
||
|
* PIX *fpixThresholdToPix()
|
||
|
*
|
||
|
* Generate function from components
|
||
|
* FPIX *pixComponentFunction()
|
||
|
* </pre>
|
||
|
*/
|
||
|
|
||
|
#include <string.h>
|
||
|
#include "allheaders.h"
|
||
|
|
||
|
/*--------------------------------------------------------------------*
|
||
|
* FPix <--> Pix conversions *
|
||
|
*--------------------------------------------------------------------*/
|
||
|
/*!
|
||
|
* \brief pixConvertToFPix()
|
||
|
*
|
||
|
* \param[in] pixs 1, 2, 4, 8, 16 or 32 bpp
|
||
|
* \param[in] ncomps number of components: 3 for RGB, 1 otherwise
|
||
|
* \return fpix, or NULL on error
|
||
|
*
|
||
|
* <pre>
|
||
|
* Notes:
|
||
|
* (1) If colormapped, remove to grayscale.
|
||
|
* (2) If 32 bpp and %ncomps == 3, this is RGB; convert to luminance.
|
||
|
* In all other cases the src image is treated as having a single
|
||
|
* component of pixel values.
|
||
|
* </pre>
|
||
|
*/
|
||
|
FPIX *
|
||
|
pixConvertToFPix(PIX *pixs,
|
||
|
l_int32 ncomps)
|
||
|
{
|
||
|
l_int32 w, h, d, i, j, val, wplt, wpld;
|
||
|
l_uint32 uval;
|
||
|
l_uint32 *datat, *linet;
|
||
|
l_float32 *datad, *lined;
|
||
|
PIX *pixt;
|
||
|
FPIX *fpixd;
|
||
|
|
||
|
PROCNAME("pixConvertToFPix");
|
||
|
|
||
|
if (!pixs)
|
||
|
return (FPIX *)ERROR_PTR("pixs not defined", procName, NULL);
|
||
|
|
||
|
/* Convert to a single component */
|
||
|
if (pixGetColormap(pixs))
|
||
|
pixt = pixRemoveColormap(pixs, REMOVE_CMAP_TO_GRAYSCALE);
|
||
|
else if (pixGetDepth(pixs) == 32 && ncomps == 3)
|
||
|
pixt = pixConvertRGBToLuminance(pixs);
|
||
|
else
|
||
|
pixt = pixClone(pixs);
|
||
|
pixGetDimensions(pixt, &w, &h, &d);
|
||
|
if (d != 1 && d != 2 && d != 4 && d != 8 && d != 16 && d != 32) {
|
||
|
pixDestroy(&pixt);
|
||
|
return (FPIX *)ERROR_PTR("invalid depth", procName, NULL);
|
||
|
}
|
||
|
|
||
|
if ((fpixd = fpixCreate(w, h)) == NULL) {
|
||
|
pixDestroy(&pixt);
|
||
|
return (FPIX *)ERROR_PTR("fpixd not made", procName, NULL);
|
||
|
}
|
||
|
datat = pixGetData(pixt);
|
||
|
wplt = pixGetWpl(pixt);
|
||
|
datad = fpixGetData(fpixd);
|
||
|
wpld = fpixGetWpl(fpixd);
|
||
|
for (i = 0; i < h; i++) {
|
||
|
linet = datat + i * wplt;
|
||
|
lined = datad + i * wpld;
|
||
|
if (d == 1) {
|
||
|
for (j = 0; j < w; j++) {
|
||
|
val = GET_DATA_BIT(linet, j);
|
||
|
lined[j] = (l_float32)val;
|
||
|
}
|
||
|
} else if (d == 2) {
|
||
|
for (j = 0; j < w; j++) {
|
||
|
val = GET_DATA_DIBIT(linet, j);
|
||
|
lined[j] = (l_float32)val;
|
||
|
}
|
||
|
} else if (d == 4) {
|
||
|
for (j = 0; j < w; j++) {
|
||
|
val = GET_DATA_QBIT(linet, j);
|
||
|
lined[j] = (l_float32)val;
|
||
|
}
|
||
|
} else if (d == 8) {
|
||
|
for (j = 0; j < w; j++) {
|
||
|
val = GET_DATA_BYTE(linet, j);
|
||
|
lined[j] = (l_float32)val;
|
||
|
}
|
||
|
} else if (d == 16) {
|
||
|
for (j = 0; j < w; j++) {
|
||
|
val = GET_DATA_TWO_BYTES(linet, j);
|
||
|
lined[j] = (l_float32)val;
|
||
|
}
|
||
|
} else { /* d == 32 */
|
||
|
for (j = 0; j < w; j++) {
|
||
|
uval = GET_DATA_FOUR_BYTES(linet, j);
|
||
|
lined[j] = (l_float32)uval;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
pixDestroy(&pixt);
|
||
|
return fpixd;
|
||
|
}
|
||
|
|
||
|
|
||
|
/*!
|
||
|
* \brief pixConvertToDPix()
|
||
|
*
|
||
|
* \param[in] pixs 1, 2, 4, 8, 16 or 32 bpp
|
||
|
* \param[in] ncomps number of components: 3 for RGB, 1 otherwise
|
||
|
* \return dpix, or NULL on error
|
||
|
*
|
||
|
* <pre>
|
||
|
* Notes:
|
||
|
* (1) If colormapped, remove to grayscale.
|
||
|
* (2) If 32 bpp and %ncomps == 3, this is RGB; convert to luminance.
|
||
|
* In all other cases the src image is treated as having a single
|
||
|
* component of pixel values.
|
||
|
* </pre>
|
||
|
*/
|
||
|
DPIX *
|
||
|
pixConvertToDPix(PIX *pixs,
|
||
|
l_int32 ncomps)
|
||
|
{
|
||
|
l_int32 w, h, d, i, j, val, wplt, wpld;
|
||
|
l_uint32 uval;
|
||
|
l_uint32 *datat, *linet;
|
||
|
l_float64 *datad, *lined;
|
||
|
PIX *pixt;
|
||
|
DPIX *dpixd;
|
||
|
|
||
|
PROCNAME("pixConvertToDPix");
|
||
|
|
||
|
if (!pixs)
|
||
|
return (DPIX *)ERROR_PTR("pixs not defined", procName, NULL);
|
||
|
|
||
|
/* Convert to a single component */
|
||
|
if (pixGetColormap(pixs))
|
||
|
pixt = pixRemoveColormap(pixs, REMOVE_CMAP_TO_GRAYSCALE);
|
||
|
else if (pixGetDepth(pixs) == 32 && ncomps == 3)
|
||
|
pixt = pixConvertRGBToLuminance(pixs);
|
||
|
else
|
||
|
pixt = pixClone(pixs);
|
||
|
pixGetDimensions(pixt, &w, &h, &d);
|
||
|
if (d != 1 && d != 2 && d != 4 && d != 8 && d != 16 && d != 32) {
|
||
|
pixDestroy(&pixt);
|
||
|
return (DPIX *)ERROR_PTR("invalid depth", procName, NULL);
|
||
|
}
|
||
|
|
||
|
if ((dpixd = dpixCreate(w, h)) == NULL) {
|
||
|
pixDestroy(&pixt);
|
||
|
return (DPIX *)ERROR_PTR("dpixd not made", procName, NULL);
|
||
|
}
|
||
|
datat = pixGetData(pixt);
|
||
|
wplt = pixGetWpl(pixt);
|
||
|
datad = dpixGetData(dpixd);
|
||
|
wpld = dpixGetWpl(dpixd);
|
||
|
for (i = 0; i < h; i++) {
|
||
|
linet = datat + i * wplt;
|
||
|
lined = datad + i * wpld;
|
||
|
if (d == 1) {
|
||
|
for (j = 0; j < w; j++) {
|
||
|
val = GET_DATA_BIT(linet, j);
|
||
|
lined[j] = (l_float64)val;
|
||
|
}
|
||
|
} else if (d == 2) {
|
||
|
for (j = 0; j < w; j++) {
|
||
|
val = GET_DATA_DIBIT(linet, j);
|
||
|
lined[j] = (l_float64)val;
|
||
|
}
|
||
|
} else if (d == 4) {
|
||
|
for (j = 0; j < w; j++) {
|
||
|
val = GET_DATA_QBIT(linet, j);
|
||
|
lined[j] = (l_float64)val;
|
||
|
}
|
||
|
} else if (d == 8) {
|
||
|
for (j = 0; j < w; j++) {
|
||
|
val = GET_DATA_BYTE(linet, j);
|
||
|
lined[j] = (l_float64)val;
|
||
|
}
|
||
|
} else if (d == 16) {
|
||
|
for (j = 0; j < w; j++) {
|
||
|
val = GET_DATA_TWO_BYTES(linet, j);
|
||
|
lined[j] = (l_float64)val;
|
||
|
}
|
||
|
} else { /* d == 32 */
|
||
|
for (j = 0; j < w; j++) {
|
||
|
uval = GET_DATA_FOUR_BYTES(linet, j);
|
||
|
lined[j] = (l_float64)uval;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
pixDestroy(&pixt);
|
||
|
return dpixd;
|
||
|
}
|
||
|
|
||
|
|
||
|
/*!
|
||
|
* \brief fpixConvertToPix()
|
||
|
*
|
||
|
* \param[in] fpixs
|
||
|
* \param[in] outdepth 0, 8, 16 or 32 bpp
|
||
|
* \param[in] negvals L_CLIP_TO_ZERO, L_TAKE_ABSVAL
|
||
|
* \param[in] errorflag 1 to output error stats; 0 otherwise
|
||
|
* \return pixd, or NULL on error
|
||
|
*
|
||
|
* <pre>
|
||
|
* 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.
|
||
|
* </pre>
|
||
|
*/
|
||
|
PIX *
|
||
|
fpixConvertToPix(FPIX *fpixs,
|
||
|
l_int32 outdepth,
|
||
|
l_int32 negvals,
|
||
|
l_int32 errorflag)
|
||
|
{
|
||
|
l_int32 w, h, i, j, wpls, wpld;
|
||
|
l_uint32 vald, maxval;
|
||
|
l_float32 val;
|
||
|
l_float32 *datas, *lines;
|
||
|
l_uint32 *datad, *lined;
|
||
|
PIX *pixd;
|
||
|
|
||
|
PROCNAME("fpixConvertToPix");
|
||
|
|
||
|
if (!fpixs)
|
||
|
return (PIX *)ERROR_PTR("fpixs not defined", procName, NULL);
|
||
|
if (negvals != L_CLIP_TO_ZERO && negvals != L_TAKE_ABSVAL)
|
||
|
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);
|
||
|
|
||
|
fpixGetDimensions(fpixs, &w, &h);
|
||
|
datas = fpixGetData(fpixs);
|
||
|
wpls = fpixGetWpl(fpixs);
|
||
|
|
||
|
/* Adaptive determination of output depth */
|
||
|
if (outdepth == 0) {
|
||
|
outdepth = 8;
|
||
|
for (i = 0; i < h && outdepth < 32; i++) {
|
||
|
lines = datas + i * wpls;
|
||
|
for (j = 0; j < w && outdepth < 32; j++) {
|
||
|
if (lines[j] > 65535.5)
|
||
|
outdepth = 32;
|
||
|
else if (lines[j] > 255.5)
|
||
|
outdepth = 16;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
if (outdepth == 8)
|
||
|
maxval = 0xff;
|
||
|
else if (outdepth == 16)
|
||
|
maxval = 0xffff;
|
||
|
else /* outdepth == 32 */
|
||
|
maxval = 0xffffffff;
|
||
|
|
||
|
/* 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("Number of negative values: %d\n", procName, negs);
|
||
|
if (overvals > 0)
|
||
|
L_ERROR("Number of too-large values: %d\n", 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 (val >= 0.0)
|
||
|
vald = (l_uint32)(val + 0.5);
|
||
|
else if (negvals == L_CLIP_TO_ZERO) /* and val < 0.0 */
|
||
|
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;
|
||
|
}
|
||
|
|
||
|
|
||
|
/*!
|
||
|
* \brief fpixDisplayMaxDynamicRange()
|
||
|
*
|
||
|
* \param[in] fpixs
|
||
|
* \return pixd 8 bpp, or NULL on error
|
||
|
*/
|
||
|
PIX *
|
||
|
fpixDisplayMaxDynamicRange(FPIX *fpixs)
|
||
|
{
|
||
|
l_uint8 dval;
|
||
|
l_int32 i, j, w, h, wpls, wpld;
|
||
|
l_float32 factor, sval, maxval;
|
||
|
l_float32 *lines, *datas;
|
||
|
l_uint32 *lined, *datad;
|
||
|
PIX *pixd;
|
||
|
|
||
|
PROCNAME("fpixDisplayMaxDynamicRange");
|
||
|
|
||
|
if (!fpixs)
|
||
|
return (PIX *)ERROR_PTR("fpixs not defined", procName, NULL);
|
||
|
|
||
|
fpixGetDimensions(fpixs, &w, &h);
|
||
|
datas = fpixGetData(fpixs);
|
||
|
wpls = fpixGetWpl(fpixs);
|
||
|
|
||
|
maxval = 0.0;
|
||
|
for (i = 0; i < h; i++) {
|
||
|
lines = datas + i * wpls;
|
||
|
for (j = 0; j < w; j++) {
|
||
|
sval = *(lines + j);
|
||
|
if (sval > maxval)
|
||
|
maxval = sval;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
pixd = pixCreate(w, h, 8);
|
||
|
if (maxval == 0.0)
|
||
|
return pixd; /* all pixels are 0 */
|
||
|
|
||
|
datad = pixGetData(pixd);
|
||
|
wpld = pixGetWpl(pixd);
|
||
|
factor = 255. / maxval;
|
||
|
for (i = 0; i < h; i++) {
|
||
|
lines = datas + i * wpls;
|
||
|
lined = datad + i * wpld;
|
||
|
for (j = 0; j < w; j++) {
|
||
|
sval = *(lines + j);
|
||
|
if (sval < 0.0) sval = 0.0;
|
||
|
dval = (l_uint8)(factor * sval + 0.5);
|
||
|
SET_DATA_BYTE(lined, j, dval);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
return pixd;
|
||
|
}
|
||
|
|
||
|
|
||
|
/*!
|
||
|
* \brief fpixConvertToDPix()
|
||
|
*
|
||
|
* \param[in] fpix
|
||
|
* \return dpix, or NULL on error
|
||
|
*/
|
||
|
DPIX *
|
||
|
fpixConvertToDPix(FPIX *fpix)
|
||
|
{
|
||
|
l_int32 w, h, i, j, wpls, wpld;
|
||
|
l_float32 val;
|
||
|
l_float32 *datas, *lines;
|
||
|
l_float64 *datad, *lined;
|
||
|
DPIX *dpix;
|
||
|
|
||
|
PROCNAME("fpixConvertToDPix");
|
||
|
|
||
|
if (!fpix)
|
||
|
return (DPIX *)ERROR_PTR("fpix not defined", procName, NULL);
|
||
|
|
||
|
fpixGetDimensions(fpix, &w, &h);
|
||
|
if ((dpix = dpixCreate(w, h)) == NULL)
|
||
|
return (DPIX *)ERROR_PTR("dpix not made", procName, NULL);
|
||
|
|
||
|
datas = fpixGetData(fpix);
|
||
|
datad = dpixGetData(dpix);
|
||
|
wpls = fpixGetWpl(fpix);
|
||
|
wpld = dpixGetWpl(dpix); /* 8 byte words */
|
||
|
for (i = 0; i < h; i++) {
|
||
|
lines = datas + i * wpls;
|
||
|
lined = datad + i * wpld;
|
||
|
for (j = 0; j < w; j++) {
|
||
|
val = lines[j];
|
||
|
lined[j] = val;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
return dpix;
|
||
|
}
|
||
|
|
||
|
|
||
|
/*!
|
||
|
* \brief dpixConvertToPix()
|
||
|
*
|
||
|
* \param[in] dpixs
|
||
|
* \param[in] outdepth 0, 8, 16 or 32 bpp
|
||
|
* \param[in] negvals L_CLIP_TO_ZERO, L_TAKE_ABSVAL
|
||
|
* \param[in] errorflag 1 to output error stats; 0 otherwise
|
||
|
* \return pixd, or NULL on error
|
||
|
*
|
||
|
* <pre>
|
||
|
* 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.
|
||
|
* </pre>
|
||
|
*/
|
||
|
PIX *
|
||
|
dpixConvertToPix(DPIX *dpixs,
|
||
|
l_int32 outdepth,
|
||
|
l_int32 negvals,
|
||
|
l_int32 errorflag)
|
||
|
{
|
||
|
l_int32 w, h, i, j, wpls, wpld, maxval;
|
||
|
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)
|
||
|
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);
|
||
|
|
||
|
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 && outdepth < 32; i++) {
|
||
|
lines = datas + i * wpls;
|
||
|
for (j = 0; j < w && outdepth < 32; j++) {
|
||
|
if (lines[j] > 65535.5)
|
||
|
outdepth = 32;
|
||
|
else if (lines[j] > 255.5)
|
||
|
outdepth = 16;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
maxval = 0xff;
|
||
|
if (outdepth == 16)
|
||
|
maxval = 0xffff;
|
||
|
else /* outdepth == 32 */
|
||
|
maxval = 0xffffffff;
|
||
|
|
||
|
/* 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("Number of negative values: %d\n", procName, negs);
|
||
|
if (overvals > 0)
|
||
|
L_ERROR("Number of too-large values: %d\n", 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 (val >= 0.0) {
|
||
|
vald = (l_uint32)(val + 0.5);
|
||
|
} else { /* val < 0.0 */
|
||
|
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;
|
||
|
}
|
||
|
|
||
|
|
||
|
/*!
|
||
|
* \brief dpixConvertToFPix()
|
||
|
*
|
||
|
* \param[in] dpix
|
||
|
* \return fpix, or NULL on error
|
||
|
*/
|
||
|
FPIX *
|
||
|
dpixConvertToFPix(DPIX *dpix)
|
||
|
{
|
||
|
l_int32 w, h, i, j, wpls, wpld;
|
||
|
l_float64 val;
|
||
|
l_float32 *datad, *lined;
|
||
|
l_float64 *datas, *lines;
|
||
|
FPIX *fpix;
|
||
|
|
||
|
PROCNAME("dpixConvertToFPix");
|
||
|
|
||
|
if (!dpix)
|
||
|
return (FPIX *)ERROR_PTR("dpix not defined", procName, NULL);
|
||
|
|
||
|
dpixGetDimensions(dpix, &w, &h);
|
||
|
if ((fpix = fpixCreate(w, h)) == NULL)
|
||
|
return (FPIX *)ERROR_PTR("fpix not made", procName, NULL);
|
||
|
|
||
|
datas = dpixGetData(dpix);
|
||
|
datad = fpixGetData(fpix);
|
||
|
wpls = dpixGetWpl(dpix); /* 8 byte words */
|
||
|
wpld = fpixGetWpl(fpix);
|
||
|
for (i = 0; i < h; i++) {
|
||
|
lines = datas + i * wpls;
|
||
|
lined = datad + i * wpld;
|
||
|
for (j = 0; j < w; j++) {
|
||
|
val = lines[j];
|
||
|
lined[j] = (l_float32)val;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
return fpix;
|
||
|
}
|
||
|
|
||
|
|
||
|
|
||
|
/*--------------------------------------------------------------------*
|
||
|
* Min/max value *
|
||
|
*--------------------------------------------------------------------*/
|
||
|
/*!
|
||
|
* \brief fpixGetMin()
|
||
|
*
|
||
|
* \param[in] fpix
|
||
|
* \param[out] pminval [optional] min value
|
||
|
* \param[out] pxminloc [optional] x location of min
|
||
|
* \param[out] pyminloc [optional] y location of min
|
||
|
* \return 0 if OK; 1 on error
|
||
|
*/
|
||
|
l_ok
|
||
|
fpixGetMin(FPIX *fpix,
|
||
|
l_float32 *pminval,
|
||
|
l_int32 *pxminloc,
|
||
|
l_int32 *pyminloc)
|
||
|
{
|
||
|
l_int32 i, j, w, h, wpl, xminloc, yminloc;
|
||
|
l_float32 *data, *line;
|
||
|
l_float32 minval;
|
||
|
|
||
|
PROCNAME("fpixGetMin");
|
||
|
|
||
|
if (!pminval && !pxminloc && !pyminloc)
|
||
|
return ERROR_INT("no return val requested", procName, 1);
|
||
|
if (pminval) *pminval = 0.0;
|
||
|
if (pxminloc) *pxminloc = 0;
|
||
|
if (pyminloc) *pyminloc = 0;
|
||
|
if (!fpix)
|
||
|
return ERROR_INT("fpix not defined", procName, 1);
|
||
|
|
||
|
minval = +1.0e20;
|
||
|
xminloc = 0;
|
||
|
yminloc = 0;
|
||
|
fpixGetDimensions(fpix, &w, &h);
|
||
|
data = fpixGetData(fpix);
|
||
|
wpl = fpixGetWpl(fpix);
|
||
|
for (i = 0; i < h; i++) {
|
||
|
line = data + i * wpl;
|
||
|
for (j = 0; j < w; j++) {
|
||
|
if (line[j] < minval) {
|
||
|
minval = line[j];
|
||
|
xminloc = j;
|
||
|
yminloc = i;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if (pminval) *pminval = minval;
|
||
|
if (pxminloc) *pxminloc = xminloc;
|
||
|
if (pyminloc) *pyminloc = yminloc;
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
|
||
|
/*!
|
||
|
* \brief fpixGetMax()
|
||
|
*
|
||
|
* \param[in] fpix
|
||
|
* \param[out] pmaxval [optional] max value
|
||
|
* \param[out] pxmaxloc [optional] x location of max
|
||
|
* \param[out] pymaxloc [optional] y location of max
|
||
|
* \return 0 if OK; 1 on error
|
||
|
*/
|
||
|
l_ok
|
||
|
fpixGetMax(FPIX *fpix,
|
||
|
l_float32 *pmaxval,
|
||
|
l_int32 *pxmaxloc,
|
||
|
l_int32 *pymaxloc)
|
||
|
{
|
||
|
l_int32 i, j, w, h, wpl, xmaxloc, ymaxloc;
|
||
|
l_float32 *data, *line;
|
||
|
l_float32 maxval;
|
||
|
|
||
|
PROCNAME("fpixGetMax");
|
||
|
|
||
|
if (!pmaxval && !pxmaxloc && !pymaxloc)
|
||
|
return ERROR_INT("no return val requested", procName, 1);
|
||
|
if (pmaxval) *pmaxval = 0.0;
|
||
|
if (pxmaxloc) *pxmaxloc = 0;
|
||
|
if (pymaxloc) *pymaxloc = 0;
|
||
|
if (!fpix)
|
||
|
return ERROR_INT("fpix not defined", procName, 1);
|
||
|
|
||
|
maxval = -1.0e20;
|
||
|
xmaxloc = 0;
|
||
|
ymaxloc = 0;
|
||
|
fpixGetDimensions(fpix, &w, &h);
|
||
|
data = fpixGetData(fpix);
|
||
|
wpl = fpixGetWpl(fpix);
|
||
|
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;
|
||
|
}
|
||
|
|
||
|
|
||
|
/*!
|
||
|
* \brief dpixGetMin()
|
||
|
*
|
||
|
* \param[in] dpix
|
||
|
* \param[out] pminval [optional] min value
|
||
|
* \param[out] pxminloc [optional] x location of min
|
||
|
* \param[out] pyminloc [optional] y location of min
|
||
|
* \return 0 if OK; 1 on error
|
||
|
*/
|
||
|
l_ok
|
||
|
dpixGetMin(DPIX *dpix,
|
||
|
l_float64 *pminval,
|
||
|
l_int32 *pxminloc,
|
||
|
l_int32 *pyminloc)
|
||
|
{
|
||
|
l_int32 i, j, w, h, wpl, xminloc, yminloc;
|
||
|
l_float64 *data, *line;
|
||
|
l_float64 minval;
|
||
|
|
||
|
PROCNAME("dpixGetMin");
|
||
|
|
||
|
if (!pminval && !pxminloc && !pyminloc)
|
||
|
return ERROR_INT("no return val requested", procName, 1);
|
||
|
if (pminval) *pminval = 0.0;
|
||
|
if (pxminloc) *pxminloc = 0;
|
||
|
if (pyminloc) *pyminloc = 0;
|
||
|
if (!dpix)
|
||
|
return ERROR_INT("dpix not defined", procName, 1);
|
||
|
|
||
|
minval = +1.0e300;
|
||
|
xminloc = 0;
|
||
|
yminloc = 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] < minval) {
|
||
|
minval = line[j];
|
||
|
xminloc = j;
|
||
|
yminloc = i;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if (pminval) *pminval = minval;
|
||
|
if (pxminloc) *pxminloc = xminloc;
|
||
|
if (pyminloc) *pyminloc = yminloc;
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
|
||
|
/*!
|
||
|
* \brief dpixGetMax()
|
||
|
*
|
||
|
* \param[in] dpix
|
||
|
* \param[out] pmaxval [optional] max value
|
||
|
* \param[out] pxmaxloc [optional] x location of max
|
||
|
* \param[out] pymaxloc [optional] y location of max
|
||
|
* \return 0 if OK; 1 on error
|
||
|
*/
|
||
|
l_ok
|
||
|
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("no return val requested", 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.0e20;
|
||
|
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;
|
||
|
}
|
||
|
|
||
|
|
||
|
/*--------------------------------------------------------------------*
|
||
|
* Special integer scaling *
|
||
|
*--------------------------------------------------------------------*/
|
||
|
/*!
|
||
|
* \brief fpixScaleByInteger()
|
||
|
*
|
||
|
* \param[in] fpixs typically low resolution
|
||
|
* \param[in] factor integer scaling factor
|
||
|
* \return fpixd interpolated result, or NULL on error
|
||
|
*
|
||
|
* <pre>
|
||
|
* Notes:
|
||
|
* (1) The width wd of fpixd is related to ws of fpixs by:
|
||
|
* wd = factor * (ws - 1) + 1 (and ditto for the height)
|
||
|
* We avoid special-casing boundary pixels in the interpolation
|
||
|
* by constructing fpixd by inserting (factor - 1) interpolated
|
||
|
* pixels between each pixel in fpixs. Then
|
||
|
* wd = ws + (ws - 1) * (factor - 1) (same as above)
|
||
|
* This also has the advantage that if we subsample by %factor,
|
||
|
* throwing out all the interpolated pixels, we regain the
|
||
|
* original low resolution fpix.
|
||
|
* </pre>
|
||
|
*/
|
||
|
FPIX *
|
||
|
fpixScaleByInteger(FPIX *fpixs,
|
||
|
l_int32 factor)
|
||
|
{
|
||
|
l_int32 i, j, k, m, ws, hs, wd, hd, wpls, wpld;
|
||
|
l_float32 val0, val1, val2, val3;
|
||
|
l_float32 *datas, *datad, *lines, *lined, *fract;
|
||
|
FPIX *fpixd;
|
||
|
|
||
|
PROCNAME("fpixScaleByInteger");
|
||
|
|
||
|
if (!fpixs)
|
||
|
return (FPIX *)ERROR_PTR("fpixs not defined", procName, NULL);
|
||
|
|
||
|
fpixGetDimensions(fpixs, &ws, &hs);
|
||
|
wd = factor * (ws - 1) + 1;
|
||
|
hd = factor * (hs - 1) + 1;
|
||
|
fpixd = fpixCreate(wd, hd);
|
||
|
datas = fpixGetData(fpixs);
|
||
|
datad = fpixGetData(fpixd);
|
||
|
wpls = fpixGetWpl(fpixs);
|
||
|
wpld = fpixGetWpl(fpixd);
|
||
|
fract = (l_float32 *)LEPT_CALLOC(factor, sizeof(l_float32));
|
||
|
for (i = 0; i < factor; i++)
|
||
|
fract[i] = i / (l_float32)factor;
|
||
|
for (i = 0; i < hs - 1; i++) {
|
||
|
lines = datas + i * wpls;
|
||
|
for (j = 0; j < ws - 1; j++) {
|
||
|
val0 = lines[j];
|
||
|
val1 = lines[j + 1];
|
||
|
val2 = lines[wpls + j];
|
||
|
val3 = lines[wpls + j + 1];
|
||
|
for (k = 0; k < factor; k++) { /* rows of sub-block */
|
||
|
lined = datad + (i * factor + k) * wpld;
|
||
|
for (m = 0; m < factor; m++) { /* cols of sub-block */
|
||
|
lined[j * factor + m] =
|
||
|
val0 * (1.0 - fract[m]) * (1.0 - fract[k]) +
|
||
|
val1 * fract[m] * (1.0 - fract[k]) +
|
||
|
val2 * (1.0 - fract[m]) * fract[k] +
|
||
|
val3 * fract[m] * fract[k];
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/* Do the right-most column of fpixd, skipping LR corner */
|
||
|
for (i = 0; i < hs - 1; i++) {
|
||
|
lines = datas + i * wpls;
|
||
|
val0 = lines[ws - 1];
|
||
|
val1 = lines[wpls + ws - 1];
|
||
|
for (k = 0; k < factor; k++) {
|
||
|
lined = datad + (i * factor + k) * wpld;
|
||
|
lined[wd - 1] = val0 * (1.0 - fract[k]) + val1 * fract[k];
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/* Do the bottom-most row of fpixd */
|
||
|
lines = datas + (hs - 1) * wpls;
|
||
|
lined = datad + (hd - 1) * wpld;
|
||
|
for (j = 0; j < ws - 1; j++) {
|
||
|
val0 = lines[j];
|
||
|
val1 = lines[j + 1];
|
||
|
for (m = 0; m < factor; m++)
|
||
|
lined[j * factor + m] = val0 * (1.0 - fract[m]) + val1 * fract[m];
|
||
|
lined[wd - 1] = lines[ws - 1]; /* LR corner */
|
||
|
}
|
||
|
|
||
|
LEPT_FREE(fract);
|
||
|
return fpixd;
|
||
|
}
|
||
|
|
||
|
|
||
|
/*!
|
||
|
* \brief dpixScaleByInteger()
|
||
|
*
|
||
|
* \param[in] dpixs typically low resolution
|
||
|
* \param[in] factor integer scaling factor
|
||
|
* \return dpixd interpolated result, or NULL on error
|
||
|
*
|
||
|
* <pre>
|
||
|
* Notes:
|
||
|
* (1) The width wd of dpixd is related to ws of dpixs by:
|
||
|
* wd = factor * (ws - 1) + 1 (and ditto for the height)
|
||
|
* We avoid special-casing boundary pixels in the interpolation
|
||
|
* by constructing fpixd by inserting (factor - 1) interpolated
|
||
|
* pixels between each pixel in fpixs. Then
|
||
|
* wd = ws + (ws - 1) * (factor - 1) (same as above)
|
||
|
* This also has the advantage that if we subsample by %factor,
|
||
|
* throwing out all the interpolated pixels, we regain the
|
||
|
* original low resolution dpix.
|
||
|
* </pre>
|
||
|
*/
|
||
|
DPIX *
|
||
|
dpixScaleByInteger(DPIX *dpixs,
|
||
|
l_int32 factor)
|
||
|
{
|
||
|
l_int32 i, j, k, m, ws, hs, wd, hd, wpls, wpld;
|
||
|
l_float64 val0, val1, val2, val3;
|
||
|
l_float64 *datas, *datad, *lines, *lined, *fract;
|
||
|
DPIX *dpixd;
|
||
|
|
||
|
PROCNAME("dpixScaleByInteger");
|
||
|
|
||
|
if (!dpixs)
|
||
|
return (DPIX *)ERROR_PTR("dpixs not defined", procName, NULL);
|
||
|
|
||
|
dpixGetDimensions(dpixs, &ws, &hs);
|
||
|
wd = factor * (ws - 1) + 1;
|
||
|
hd = factor * (hs - 1) + 1;
|
||
|
dpixd = dpixCreate(wd, hd);
|
||
|
datas = dpixGetData(dpixs);
|
||
|
datad = dpixGetData(dpixd);
|
||
|
wpls = dpixGetWpl(dpixs);
|
||
|
wpld = dpixGetWpl(dpixd);
|
||
|
fract = (l_float64 *)LEPT_CALLOC(factor, sizeof(l_float64));
|
||
|
for (i = 0; i < factor; i++)
|
||
|
fract[i] = i / (l_float64)factor;
|
||
|
for (i = 0; i < hs - 1; i++) {
|
||
|
lines = datas + i * wpls;
|
||
|
for (j = 0; j < ws - 1; j++) {
|
||
|
val0 = lines[j];
|
||
|
val1 = lines[j + 1];
|
||
|
val2 = lines[wpls + j];
|
||
|
val3 = lines[wpls + j + 1];
|
||
|
for (k = 0; k < factor; k++) { /* rows of sub-block */
|
||
|
lined = datad + (i * factor + k) * wpld;
|
||
|
for (m = 0; m < factor; m++) { /* cols of sub-block */
|
||
|
lined[j * factor + m] =
|
||
|
val0 * (1.0 - fract[m]) * (1.0 - fract[k]) +
|
||
|
val1 * fract[m] * (1.0 - fract[k]) +
|
||
|
val2 * (1.0 - fract[m]) * fract[k] +
|
||
|
val3 * fract[m] * fract[k];
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/* Do the right-most column of dpixd, skipping LR corner */
|
||
|
for (i = 0; i < hs - 1; i++) {
|
||
|
lines = datas + i * wpls;
|
||
|
val0 = lines[ws - 1];
|
||
|
val1 = lines[wpls + ws - 1];
|
||
|
for (k = 0; k < factor; k++) {
|
||
|
lined = datad + (i * factor + k) * wpld;
|
||
|
lined[wd - 1] = val0 * (1.0 - fract[k]) + val1 * fract[k];
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/* Do the bottom-most row of dpixd */
|
||
|
lines = datas + (hs - 1) * wpls;
|
||
|
lined = datad + (hd - 1) * wpld;
|
||
|
for (j = 0; j < ws - 1; j++) {
|
||
|
val0 = lines[j];
|
||
|
val1 = lines[j + 1];
|
||
|
for (m = 0; m < factor; m++)
|
||
|
lined[j * factor + m] = val0 * (1.0 - fract[m]) + val1 * fract[m];
|
||
|
lined[wd - 1] = lines[ws - 1]; /* LR corner */
|
||
|
}
|
||
|
|
||
|
LEPT_FREE(fract);
|
||
|
return dpixd;
|
||
|
}
|
||
|
|
||
|
|
||
|
/*--------------------------------------------------------------------*
|
||
|
* Arithmetic operations *
|
||
|
*--------------------------------------------------------------------*/
|
||
|
/*!
|
||
|
* \brief fpixLinearCombination()
|
||
|
*
|
||
|
* \param[in] fpixd [optional] this can be null, equal to fpixs1, or
|
||
|
* different from fpixs1
|
||
|
* \param[in] fpixs1 can be equal to fpixd
|
||
|
* \param[in] fpixs2
|
||
|
* \param[in] a, b multiplication factors on fpixs1 and fpixs2, rsp.
|
||
|
* \return fpixd always
|
||
|
*
|
||
|
* <pre>
|
||
|
* Notes:
|
||
|
* (1) Computes pixelwise linear combination: a * src1 + b * src2
|
||
|
* (2) Alignment is to UL corner.
|
||
|
* (3) There are 3 cases. The result can go to a new dest,
|
||
|
* in-place to fpixs1, or to an existing input dest:
|
||
|
* * fpixd == null: (src1 + src2) --> new fpixd
|
||
|
* * fpixd == fpixs1: (src1 + src2) --> src1 (in-place)
|
||
|
* * fpixd != fpixs1: (src1 + src2) --> input fpixd
|
||
|
* (4) fpixs2 must be different from both fpixd and fpixs1.
|
||
|
* </pre>
|
||
|
*/
|
||
|
FPIX *
|
||
|
fpixLinearCombination(FPIX *fpixd,
|
||
|
FPIX *fpixs1,
|
||
|
FPIX *fpixs2,
|
||
|
l_float32 a,
|
||
|
l_float32 b)
|
||
|
{
|
||
|
l_int32 i, j, ws, hs, w, h, wpls, wpld;
|
||
|
l_float32 *datas, *datad, *lines, *lined;
|
||
|
|
||
|
PROCNAME("fpixLinearCombination");
|
||
|
|
||
|
if (!fpixs1)
|
||
|
return (FPIX *)ERROR_PTR("fpixs1 not defined", procName, fpixd);
|
||
|
if (!fpixs2)
|
||
|
return (FPIX *)ERROR_PTR("fpixs2 not defined", procName, fpixd);
|
||
|
if (fpixs1 == fpixs2)
|
||
|
return (FPIX *)ERROR_PTR("fpixs1 == fpixs2", procName, fpixd);
|
||
|
if (fpixs2 == fpixd)
|
||
|
return (FPIX *)ERROR_PTR("fpixs2 == fpixd", procName, fpixd);
|
||
|
|
||
|
if (fpixs1 != fpixd)
|
||
|
fpixd = fpixCopy(fpixd, fpixs1);
|
||
|
|
||
|
datas = fpixGetData(fpixs2);
|
||
|
datad = fpixGetData(fpixd);
|
||
|
wpls = fpixGetWpl(fpixs2);
|
||
|
wpld = fpixGetWpl(fpixd);
|
||
|
fpixGetDimensions(fpixs2, &ws, &hs);
|
||
|
fpixGetDimensions(fpixd, &w, &h);
|
||
|
w = L_MIN(ws, w);
|
||
|
h = L_MIN(hs, h);
|
||
|
for (i = 0; i < h; i++) {
|
||
|
lines = datas + i * wpls;
|
||
|
lined = datad + i * wpld;
|
||
|
for (j = 0; j < w; j++)
|
||
|
lined[j] = a * lined[j] + b * lines[j];
|
||
|
}
|
||
|
|
||
|
return fpixd;
|
||
|
}
|
||
|
|
||
|
|
||
|
/*!
|
||
|
* \brief fpixAddMultConstant()
|
||
|
*
|
||
|
* \param[in] fpix
|
||
|
* \param[in] addc use 0.0 to skip the operation
|
||
|
* \param[in] multc use 1.0 to skip the operation
|
||
|
* \return 0 if OK, 1 on error
|
||
|
*
|
||
|
* <pre>
|
||
|
* Notes:
|
||
|
* (1) This is an in-place operation.
|
||
|
* (2) It can be used to multiply each pixel by a constant,
|
||
|
* and also to add a constant to each pixel. Multiplication
|
||
|
* is done first.
|
||
|
* </pre>
|
||
|
*/
|
||
|
l_ok
|
||
|
fpixAddMultConstant(FPIX *fpix,
|
||
|
l_float32 addc,
|
||
|
l_float32 multc)
|
||
|
{
|
||
|
l_int32 i, j, w, h, wpl;
|
||
|
l_float32 *line, *data;
|
||
|
|
||
|
PROCNAME("fpixAddMultConstant");
|
||
|
|
||
|
if (!fpix)
|
||
|
return ERROR_INT("fpix not defined", procName, 1);
|
||
|
|
||
|
if (addc == 0.0 && multc == 1.0)
|
||
|
return 0;
|
||
|
|
||
|
fpixGetDimensions(fpix, &w, &h);
|
||
|
data = fpixGetData(fpix);
|
||
|
wpl = fpixGetWpl(fpix);
|
||
|
for (i = 0; i < h; i++) {
|
||
|
line = data + i * wpl;
|
||
|
if (addc == 0.0) {
|
||
|
for (j = 0; j < w; j++)
|
||
|
line[j] *= multc;
|
||
|
} else if (multc == 1.0) {
|
||
|
for (j = 0; j < w; j++)
|
||
|
line[j] += addc;
|
||
|
} else {
|
||
|
for (j = 0; j < w; j++) {
|
||
|
line[j] = multc * line[j] + addc;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
|
||
|
/*!
|
||
|
* \brief dpixLinearCombination()
|
||
|
*
|
||
|
* \param[in] dpixd [optional] this can be null, equal to dpixs1, or
|
||
|
* different from dpixs1
|
||
|
* \param[in] dpixs1 can be equal to dpixd
|
||
|
* \param[in] dpixs2
|
||
|
* \param[in] a, b multiplication factors on dpixs1 and dpixs2, rsp.
|
||
|
* \return dpixd always
|
||
|
*
|
||
|
* <pre>
|
||
|
* Notes:
|
||
|
* (1) Computes pixelwise linear combination: a * src1 + b * src2
|
||
|
* (2) Alignment is to UL corner.
|
||
|
* (3) There are 3 cases. The result can go to a new dest,
|
||
|
* in-place to dpixs1, or to an existing input dest:
|
||
|
* * dpixd == null: (src1 + src2) --> new dpixd
|
||
|
* * dpixd == dpixs1: (src1 + src2) --> src1 (in-place)
|
||
|
* * dpixd != dpixs1: (src1 + src2) --> input dpixd
|
||
|
* (4) dpixs2 must be different from both dpixd and dpixs1.
|
||
|
* </pre>
|
||
|
*/
|
||
|
DPIX *
|
||
|
dpixLinearCombination(DPIX *dpixd,
|
||
|
DPIX *dpixs1,
|
||
|
DPIX *dpixs2,
|
||
|
l_float32 a,
|
||
|
l_float32 b)
|
||
|
{
|
||
|
l_int32 i, j, ws, hs, w, h, wpls, wpld;
|
||
|
l_float64 *datas, *datad, *lines, *lined;
|
||
|
|
||
|
PROCNAME("dpixLinearCombination");
|
||
|
|
||
|
if (!dpixs1)
|
||
|
return (DPIX *)ERROR_PTR("dpixs1 not defined", procName, dpixd);
|
||
|
if (!dpixs2)
|
||
|
return (DPIX *)ERROR_PTR("dpixs2 not defined", procName, dpixd);
|
||
|
if (dpixs1 == dpixs2)
|
||
|
return (DPIX *)ERROR_PTR("dpixs1 == dpixs2", procName, dpixd);
|
||
|
if (dpixs2 == dpixd)
|
||
|
return (DPIX *)ERROR_PTR("dpixs2 == dpixd", procName, dpixd);
|
||
|
|
||
|
if (dpixs1 != dpixd)
|
||
|
dpixd = dpixCopy(dpixd, dpixs1);
|
||
|
|
||
|
datas = dpixGetData(dpixs2);
|
||
|
datad = dpixGetData(dpixd);
|
||
|
wpls = dpixGetWpl(dpixs2);
|
||
|
wpld = dpixGetWpl(dpixd);
|
||
|
dpixGetDimensions(dpixs2, &ws, &hs);
|
||
|
dpixGetDimensions(dpixd, &w, &h);
|
||
|
w = L_MIN(ws, w);
|
||
|
h = L_MIN(hs, h);
|
||
|
for (i = 0; i < h; i++) {
|
||
|
lines = datas + i * wpls;
|
||
|
lined = datad + i * wpld;
|
||
|
for (j = 0; j < w; j++)
|
||
|
lined[j] = a * lined[j] + b * lines[j];
|
||
|
}
|
||
|
|
||
|
return dpixd;
|
||
|
}
|
||
|
|
||
|
|
||
|
/*!
|
||
|
* \brief dpixAddMultConstant()
|
||
|
*
|
||
|
* \param[in] dpix
|
||
|
* \param[in] addc use 0.0 to skip the operation
|
||
|
* \param[in] multc use 1.0 to skip the operation
|
||
|
* \return 0 if OK, 1 on error
|
||
|
*
|
||
|
* <pre>
|
||
|
* Notes:
|
||
|
* (1) This is an in-place operation.
|
||
|
* (2) It can be used to multiply each pixel by a constant,
|
||
|
* and also to add a constant to each pixel. Multiplication
|
||
|
* is done first.
|
||
|
* </pre>
|
||
|
*/
|
||
|
l_ok
|
||
|
dpixAddMultConstant(DPIX *dpix,
|
||
|
l_float64 addc,
|
||
|
l_float64 multc)
|
||
|
{
|
||
|
l_int32 i, j, w, h, wpl;
|
||
|
l_float64 *line, *data;
|
||
|
|
||
|
PROCNAME("dpixAddMultConstant");
|
||
|
|
||
|
if (!dpix)
|
||
|
return ERROR_INT("dpix not defined", procName, 1);
|
||
|
|
||
|
if (addc == 0.0 && multc == 1.0)
|
||
|
return 0;
|
||
|
|
||
|
dpixGetDimensions(dpix, &w, &h);
|
||
|
data = dpixGetData(dpix);
|
||
|
wpl = dpixGetWpl(dpix);
|
||
|
for (i = 0; i < h; i++) {
|
||
|
line = data + i * wpl;
|
||
|
if (addc == 0.0) {
|
||
|
for (j = 0; j < w; j++)
|
||
|
line[j] *= multc;
|
||
|
} else if (multc == 1.0) {
|
||
|
for (j = 0; j < w; j++)
|
||
|
line[j] += addc;
|
||
|
} else {
|
||
|
for (j = 0; j < w; j++)
|
||
|
line[j] = multc * line[j] + addc;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
|
||
|
/*--------------------------------------------------------------------*
|
||
|
* Set all *
|
||
|
*--------------------------------------------------------------------*/
|
||
|
/*!
|
||
|
* \brief fpixSetAllArbitrary()
|
||
|
*
|
||
|
* \param[in] fpix
|
||
|
* \param[in] inval to set at each pixel
|
||
|
* \return 0 if OK, 1 on error
|
||
|
*/
|
||
|
l_ok
|
||
|
fpixSetAllArbitrary(FPIX *fpix,
|
||
|
l_float32 inval)
|
||
|
{
|
||
|
l_int32 i, j, w, h;
|
||
|
l_float32 *data, *line;
|
||
|
|
||
|
PROCNAME("fpixSetAllArbitrary");
|
||
|
|
||
|
if (!fpix)
|
||
|
return ERROR_INT("fpix not defined", procName, 1);
|
||
|
|
||
|
fpixGetDimensions(fpix, &w, &h);
|
||
|
data = fpixGetData(fpix);
|
||
|
for (i = 0; i < h; i++) {
|
||
|
line = data + i * w;
|
||
|
for (j = 0; j < w; j++)
|
||
|
*(line + j) = inval;
|
||
|
}
|
||
|
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
|
||
|
/*!
|
||
|
* \brief dpixSetAllArbitrary()
|
||
|
*
|
||
|
* \param[in] dpix
|
||
|
* \param[in] inval to set at each pixel
|
||
|
* \return 0 if OK, 1 on error
|
||
|
*/
|
||
|
l_ok
|
||
|
dpixSetAllArbitrary(DPIX *dpix,
|
||
|
l_float64 inval)
|
||
|
{
|
||
|
l_int32 i, j, w, h;
|
||
|
l_float64 *data, *line;
|
||
|
|
||
|
PROCNAME("dpixSetAllArbitrary");
|
||
|
|
||
|
if (!dpix)
|
||
|
return ERROR_INT("dpix not defined", procName, 1);
|
||
|
|
||
|
dpixGetDimensions(dpix, &w, &h);
|
||
|
data = dpixGetData(dpix);
|
||
|
for (i = 0; i < h; i++) {
|
||
|
line = data + i * w;
|
||
|
for (j = 0; j < w; j++)
|
||
|
*(line + j) = inval;
|
||
|
}
|
||
|
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
|
||
|
/*--------------------------------------------------------------------*
|
||
|
* Border functions *
|
||
|
*--------------------------------------------------------------------*/
|
||
|
/*!
|
||
|
* \brief fpixAddBorder()
|
||
|
*
|
||
|
* \param[in] fpixs
|
||
|
* \param[in] left, right, top, bot pixels on each side to be added
|
||
|
* \return fpixd, or NULL on error
|
||
|
*
|
||
|
* <pre>
|
||
|
* Notes:
|
||
|
* (1) Adds border of '0' 32-bit pixels
|
||
|
* </pre>
|
||
|
*/
|
||
|
FPIX *
|
||
|
fpixAddBorder(FPIX *fpixs,
|
||
|
l_int32 left,
|
||
|
l_int32 right,
|
||
|
l_int32 top,
|
||
|
l_int32 bot)
|
||
|
{
|
||
|
l_int32 ws, hs, wd, hd;
|
||
|
FPIX *fpixd;
|
||
|
|
||
|
PROCNAME("fpixAddBorder");
|
||
|
|
||
|
if (!fpixs)
|
||
|
return (FPIX *)ERROR_PTR("fpixs not defined", procName, NULL);
|
||
|
|
||
|
if (left <= 0 && right <= 0 && top <= 0 && bot <= 0)
|
||
|
return fpixCopy(NULL, fpixs);
|
||
|
fpixGetDimensions(fpixs, &ws, &hs);
|
||
|
wd = ws + left + right;
|
||
|
hd = hs + top + bot;
|
||
|
if ((fpixd = fpixCreate(wd, hd)) == NULL)
|
||
|
return (FPIX *)ERROR_PTR("fpixd not made", procName, NULL);
|
||
|
|
||
|
fpixCopyResolution(fpixd, fpixs);
|
||
|
fpixRasterop(fpixd, left, top, ws, hs, fpixs, 0, 0);
|
||
|
return fpixd;
|
||
|
}
|
||
|
|
||
|
|
||
|
/*!
|
||
|
* \brief fpixRemoveBorder()
|
||
|
*
|
||
|
* \param[in] fpixs
|
||
|
* \param[in] left, right, top, bot pixels on each side to be removed
|
||
|
* \return fpixd, or NULL on error
|
||
|
*/
|
||
|
FPIX *
|
||
|
fpixRemoveBorder(FPIX *fpixs,
|
||
|
l_int32 left,
|
||
|
l_int32 right,
|
||
|
l_int32 top,
|
||
|
l_int32 bot)
|
||
|
{
|
||
|
l_int32 ws, hs, wd, hd;
|
||
|
FPIX *fpixd;
|
||
|
|
||
|
PROCNAME("fpixRemoveBorder");
|
||
|
|
||
|
if (!fpixs)
|
||
|
return (FPIX *)ERROR_PTR("fpixs not defined", procName, NULL);
|
||
|
|
||
|
if (left <= 0 && right <= 0 && top <= 0 && bot <= 0)
|
||
|
return fpixCopy(NULL, fpixs);
|
||
|
fpixGetDimensions(fpixs, &ws, &hs);
|
||
|
wd = ws - left - right;
|
||
|
hd = hs - top - bot;
|
||
|
if (wd <= 0 || hd <= 0)
|
||
|
return (FPIX *)ERROR_PTR("width & height not both > 0", procName, NULL);
|
||
|
if ((fpixd = fpixCreate(wd, hd)) == NULL)
|
||
|
return (FPIX *)ERROR_PTR("fpixd not made", procName, NULL);
|
||
|
|
||
|
fpixCopyResolution(fpixd, fpixs);
|
||
|
fpixRasterop(fpixd, 0, 0, wd, hd, fpixs, left, top);
|
||
|
return fpixd;
|
||
|
}
|
||
|
|
||
|
|
||
|
|
||
|
/*!
|
||
|
* \brief fpixAddMirroredBorder()
|
||
|
*
|
||
|
* \param[in] fpixs
|
||
|
* \param[in] left, right, top, bot pixels on each side to be added
|
||
|
* \return fpixd, or NULL on error
|
||
|
*
|
||
|
* <pre>
|
||
|
* Notes:
|
||
|
* (1) See pixAddMirroredBorder() for situations of usage.
|
||
|
* </pre>
|
||
|
*/
|
||
|
FPIX *
|
||
|
fpixAddMirroredBorder(FPIX *fpixs,
|
||
|
l_int32 left,
|
||
|
l_int32 right,
|
||
|
l_int32 top,
|
||
|
l_int32 bot)
|
||
|
{
|
||
|
l_int32 i, j, w, h;
|
||
|
FPIX *fpixd;
|
||
|
|
||
|
PROCNAME("fpixAddMirroredBorder");
|
||
|
|
||
|
if (!fpixs)
|
||
|
return (FPIX *)ERROR_PTR("fpixs not defined", procName, NULL);
|
||
|
|
||
|
fpixd = fpixAddBorder(fpixs, left, right, top, bot);
|
||
|
fpixGetDimensions(fpixs, &w, &h);
|
||
|
for (j = 0; j < left; j++)
|
||
|
fpixRasterop(fpixd, left - 1 - j, top, 1, h,
|
||
|
fpixd, left + j, top);
|
||
|
for (j = 0; j < right; j++)
|
||
|
fpixRasterop(fpixd, left + w + j, top, 1, h,
|
||
|
fpixd, left + w - 1 - j, top);
|
||
|
for (i = 0; i < top; i++)
|
||
|
fpixRasterop(fpixd, 0, top - 1 - i, left + w + right, 1,
|
||
|
fpixd, 0, top + i);
|
||
|
for (i = 0; i < bot; i++)
|
||
|
fpixRasterop(fpixd, 0, top + h + i, left + w + right, 1,
|
||
|
fpixd, 0, top + h - 1 - i);
|
||
|
|
||
|
return fpixd;
|
||
|
}
|
||
|
|
||
|
|
||
|
/*!
|
||
|
* \brief fpixAddContinuedBorder()
|
||
|
*
|
||
|
* \param[in] fpixs
|
||
|
* \param[in] left, right, top, bot pixels on each side to be added
|
||
|
* \return fpixd, or NULL on error
|
||
|
*
|
||
|
* <pre>
|
||
|
* Notes:
|
||
|
* (1) This adds pixels on each side whose values are equal to
|
||
|
* the value on the closest boundary pixel.
|
||
|
* </pre>
|
||
|
*/
|
||
|
FPIX *
|
||
|
fpixAddContinuedBorder(FPIX *fpixs,
|
||
|
l_int32 left,
|
||
|
l_int32 right,
|
||
|
l_int32 top,
|
||
|
l_int32 bot)
|
||
|
{
|
||
|
l_int32 i, j, w, h;
|
||
|
FPIX *fpixd;
|
||
|
|
||
|
PROCNAME("fpixAddContinuedBorder");
|
||
|
|
||
|
if (!fpixs)
|
||
|
return (FPIX *)ERROR_PTR("fpixs not defined", procName, NULL);
|
||
|
|
||
|
fpixd = fpixAddBorder(fpixs, left, right, top, bot);
|
||
|
fpixGetDimensions(fpixs, &w, &h);
|
||
|
for (j = 0; j < left; j++)
|
||
|
fpixRasterop(fpixd, j, top, 1, h, fpixd, left, top);
|
||
|
for (j = 0; j < right; j++)
|
||
|
fpixRasterop(fpixd, left + w + j, top, 1, h, fpixd, left + w - 1, top);
|
||
|
for (i = 0; i < top; i++)
|
||
|
fpixRasterop(fpixd, 0, i, left + w + right, 1, fpixd, 0, top);
|
||
|
for (i = 0; i < bot; i++)
|
||
|
fpixRasterop(fpixd, 0, top + h + i, left + w + right, 1,
|
||
|
fpixd, 0, top + h - 1);
|
||
|
|
||
|
return fpixd;
|
||
|
}
|
||
|
|
||
|
|
||
|
/*!
|
||
|
* \brief fpixAddSlopeBorder()
|
||
|
*
|
||
|
* \param[in] fpixs
|
||
|
* \param[in] left, right, top, bot pixels on each side to be added
|
||
|
* \return fpixd, or NULL on error
|
||
|
*
|
||
|
* <pre>
|
||
|
* Notes:
|
||
|
* (1) This adds pixels on each side whose values have a normal
|
||
|
* derivative equal to the normal derivative at the boundary
|
||
|
* of fpixs.
|
||
|
* </pre>
|
||
|
*/
|
||
|
FPIX *
|
||
|
fpixAddSlopeBorder(FPIX *fpixs,
|
||
|
l_int32 left,
|
||
|
l_int32 right,
|
||
|
l_int32 top,
|
||
|
l_int32 bot)
|
||
|
{
|
||
|
l_int32 i, j, w, h, fullw, fullh;
|
||
|
l_float32 val1, val2, del;
|
||
|
FPIX *fpixd;
|
||
|
|
||
|
PROCNAME("fpixAddSlopeBorder");
|
||
|
|
||
|
if (!fpixs)
|
||
|
return (FPIX *)ERROR_PTR("fpixs not defined", procName, NULL);
|
||
|
|
||
|
fpixd = fpixAddBorder(fpixs, left, right, top, bot);
|
||
|
fpixGetDimensions(fpixs, &w, &h);
|
||
|
|
||
|
/* Left */
|
||
|
for (i = top; i < top + h; i++) {
|
||
|
fpixGetPixel(fpixd, left, i, &val1);
|
||
|
fpixGetPixel(fpixd, left + 1, i, &val2);
|
||
|
del = val1 - val2;
|
||
|
for (j = 0; j < left; j++)
|
||
|
fpixSetPixel(fpixd, j, i, val1 + del * (left - j));
|
||
|
}
|
||
|
|
||
|
/* Right */
|
||
|
fullw = left + w + right;
|
||
|
for (i = top; i < top + h; i++) {
|
||
|
fpixGetPixel(fpixd, left + w - 1, i, &val1);
|
||
|
fpixGetPixel(fpixd, left + w - 2, i, &val2);
|
||
|
del = val1 - val2;
|
||
|
for (j = left + w; j < fullw; j++)
|
||
|
fpixSetPixel(fpixd, j, i, val1 + del * (j - left - w + 1));
|
||
|
}
|
||
|
|
||
|
/* Top */
|
||
|
for (j = 0; j < fullw; j++) {
|
||
|
fpixGetPixel(fpixd, j, top, &val1);
|
||
|
fpixGetPixel(fpixd, j, top + 1, &val2);
|
||
|
del = val1 - val2;
|
||
|
for (i = 0; i < top; i++)
|
||
|
fpixSetPixel(fpixd, j, i, val1 + del * (top - i));
|
||
|
}
|
||
|
|
||
|
/* Bottom */
|
||
|
fullh = top + h + bot;
|
||
|
for (j = 0; j < fullw; j++) {
|
||
|
fpixGetPixel(fpixd, j, top + h - 1, &val1);
|
||
|
fpixGetPixel(fpixd, j, top + h - 2, &val2);
|
||
|
del = val1 - val2;
|
||
|
for (i = top + h; i < fullh; i++)
|
||
|
fpixSetPixel(fpixd, j, i, val1 + del * (i - top - h + 1));
|
||
|
}
|
||
|
|
||
|
return fpixd;
|
||
|
}
|
||
|
|
||
|
|
||
|
/*--------------------------------------------------------------------*
|
||
|
* Simple rasterop *
|
||
|
*--------------------------------------------------------------------*/
|
||
|
/*!
|
||
|
* \brief fpixRasterop()
|
||
|
*
|
||
|
* \param[in] fpixd dest fpix
|
||
|
* \param[in] dx x val of UL corner of dest rectangle
|
||
|
* \param[in] dy y val of UL corner of dest rectangle
|
||
|
* \param[in] dw width of dest rectangle
|
||
|
* \param[in] dh height of dest rectangle
|
||
|
* \param[in] fpixs src fpix
|
||
|
* \param[in] sx x val of UL corner of src rectangle
|
||
|
* \param[in] sy y val of UL corner of src rectangle
|
||
|
* \return 0 if OK; 1 on error.
|
||
|
*
|
||
|
* <pre>
|
||
|
* Notes:
|
||
|
* (1) This is similar in structure to pixRasterop(), except
|
||
|
* it only allows copying from the source into the destination.
|
||
|
* For that reason, no op code is necessary. Additionally,
|
||
|
* all pixels are 32 bit words (float values), which makes
|
||
|
* the copy very simple.
|
||
|
* (2) Clipping of both src and dest fpix are done automatically.
|
||
|
* (3) This allows in-place copying, without checking to see if
|
||
|
* the result is valid: use for in-place with caution!
|
||
|
* </pre>
|
||
|
*/
|
||
|
l_ok
|
||
|
fpixRasterop(FPIX *fpixd,
|
||
|
l_int32 dx,
|
||
|
l_int32 dy,
|
||
|
l_int32 dw,
|
||
|
l_int32 dh,
|
||
|
FPIX *fpixs,
|
||
|
l_int32 sx,
|
||
|
l_int32 sy)
|
||
|
{
|
||
|
l_int32 fsw, fsh, fdw, fdh, dhangw, shangw, dhangh, shangh;
|
||
|
l_int32 i, j, wpls, wpld;
|
||
|
l_float32 *datas, *datad, *lines, *lined;
|
||
|
|
||
|
PROCNAME("fpixRasterop");
|
||
|
|
||
|
if (!fpixs)
|
||
|
return ERROR_INT("fpixs not defined", procName, 1);
|
||
|
if (!fpixd)
|
||
|
return ERROR_INT("fpixd not defined", procName, 1);
|
||
|
|
||
|
/* -------------------------------------------------------- *
|
||
|
* Clip to maximum rectangle with both src and dest *
|
||
|
* -------------------------------------------------------- */
|
||
|
fpixGetDimensions(fpixs, &fsw, &fsh);
|
||
|
fpixGetDimensions(fpixd, &fdw, &fdh);
|
||
|
|
||
|
/* First clip horizontally (sx, dx, dw) */
|
||
|
if (dx < 0) {
|
||
|
sx -= dx; /* increase sx */
|
||
|
dw += dx; /* reduce dw */
|
||
|
dx = 0;
|
||
|
}
|
||
|
if (sx < 0) {
|
||
|
dx -= sx; /* increase dx */
|
||
|
dw += sx; /* reduce dw */
|
||
|
sx = 0;
|
||
|
}
|
||
|
dhangw = dx + dw - fdw; /* rect overhang of dest to right */
|
||
|
if (dhangw > 0)
|
||
|
dw -= dhangw; /* reduce dw */
|
||
|
shangw = sx + dw - fsw; /* rect overhang of src to right */
|
||
|
if (shangw > 0)
|
||
|
dw -= shangw; /* reduce dw */
|
||
|
|
||
|
/* Then clip vertically (sy, dy, dh) */
|
||
|
if (dy < 0) {
|
||
|
sy -= dy; /* increase sy */
|
||
|
dh += dy; /* reduce dh */
|
||
|
dy = 0;
|
||
|
}
|
||
|
if (sy < 0) {
|
||
|
dy -= sy; /* increase dy */
|
||
|
dh += sy; /* reduce dh */
|
||
|
sy = 0;
|
||
|
}
|
||
|
dhangh = dy + dh - fdh; /* rect overhang of dest below */
|
||
|
if (dhangh > 0)
|
||
|
dh -= dhangh; /* reduce dh */
|
||
|
shangh = sy + dh - fsh; /* rect overhang of src below */
|
||
|
if (shangh > 0)
|
||
|
dh -= shangh; /* reduce dh */
|
||
|
|
||
|
/* if clipped entirely, quit */
|
||
|
if ((dw <= 0) || (dh <= 0))
|
||
|
return 0;
|
||
|
|
||
|
/* -------------------------------------------------------- *
|
||
|
* Copy block of data *
|
||
|
* -------------------------------------------------------- */
|
||
|
datas = fpixGetData(fpixs);
|
||
|
datad = fpixGetData(fpixd);
|
||
|
wpls = fpixGetWpl(fpixs);
|
||
|
wpld = fpixGetWpl(fpixd);
|
||
|
datas += sy * wpls + sx; /* at UL corner of block */
|
||
|
datad += dy * wpld + dx; /* at UL corner of block */
|
||
|
for (i = 0; i < dh; i++) {
|
||
|
lines = datas + i * wpls;
|
||
|
lined = datad + i * wpld;
|
||
|
for (j = 0; j < dw; j++) {
|
||
|
*lined = *lines;
|
||
|
lines++;
|
||
|
lined++;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
|
||
|
/*--------------------------------------------------------------------*
|
||
|
* Rotation by multiples of 90 degrees *
|
||
|
*--------------------------------------------------------------------*/
|
||
|
/*!
|
||
|
* \brief fpixRotateOrth()
|
||
|
*
|
||
|
* \param[in] fpixs
|
||
|
* \param[in] quads 0-3; number of 90 degree cw rotations
|
||
|
* \return fpixd, or NULL on error
|
||
|
*/
|
||
|
FPIX *
|
||
|
fpixRotateOrth(FPIX *fpixs,
|
||
|
l_int32 quads)
|
||
|
{
|
||
|
PROCNAME("fpixRotateOrth");
|
||
|
|
||
|
if (!fpixs)
|
||
|
return (FPIX *)ERROR_PTR("fpixs not defined", procName, NULL);
|
||
|
if (quads < 0 || quads > 3)
|
||
|
return (FPIX *)ERROR_PTR("quads not in {0,1,2,3}", procName, NULL);
|
||
|
|
||
|
if (quads == 0)
|
||
|
return fpixCopy(NULL, fpixs);
|
||
|
else if (quads == 1)
|
||
|
return fpixRotate90(fpixs, 1);
|
||
|
else if (quads == 2)
|
||
|
return fpixRotate180(NULL, fpixs);
|
||
|
else /* quads == 3 */
|
||
|
return fpixRotate90(fpixs, -1);
|
||
|
}
|
||
|
|
||
|
|
||
|
/*!
|
||
|
* \brief fpixRotate180()
|
||
|
*
|
||
|
* \param[in] fpixd [optional] can be null, equal to fpixs,
|
||
|
* or different from fpixs
|
||
|
* \param[in] fpixs
|
||
|
* \return fpixd, or NULL on error
|
||
|
*
|
||
|
* <pre>
|
||
|
* Notes:
|
||
|
* (1) This does a 180 rotation of the image about the center,
|
||
|
* which is equivalent to a left-right flip about a vertical
|
||
|
* line through the image center, followed by a top-bottom
|
||
|
* flip about a horizontal line through the image center.
|
||
|
* (2) There are 3 cases for input:
|
||
|
* (a) fpixd == null (creates a new fpixd)
|
||
|
* (b) fpixd == fpixs (in-place operation)
|
||
|
* (c) fpixd != fpixs (existing fpixd)
|
||
|
* (3) For clarity, use these three patterns, respectively:
|
||
|
* (a) fpixd = fpixRotate180(NULL, fpixs);
|
||
|
* (b) fpixRotate180(fpixs, fpixs);
|
||
|
* (c) fpixRotate180(fpixd, fpixs);
|
||
|
* </pre>
|
||
|
*/
|
||
|
FPIX *
|
||
|
fpixRotate180(FPIX *fpixd,
|
||
|
FPIX *fpixs)
|
||
|
{
|
||
|
PROCNAME("fpixRotate180");
|
||
|
|
||
|
if (!fpixs)
|
||
|
return (FPIX *)ERROR_PTR("fpixs not defined", procName, NULL);
|
||
|
|
||
|
/* Prepare pixd for in-place operation */
|
||
|
if ((fpixd = fpixCopy(fpixd, fpixs)) == NULL)
|
||
|
return (FPIX *)ERROR_PTR("fpixd not made", procName, NULL);
|
||
|
|
||
|
fpixFlipLR(fpixd, fpixd);
|
||
|
fpixFlipTB(fpixd, fpixd);
|
||
|
return fpixd;
|
||
|
}
|
||
|
|
||
|
|
||
|
/*!
|
||
|
* \brief fpixRotate90()
|
||
|
*
|
||
|
* \param[in] fpixs
|
||
|
* \param[in] direction 1 = clockwise; -1 = counter-clockwise
|
||
|
* \return fpixd, or NULL on error
|
||
|
*
|
||
|
* <pre>
|
||
|
* 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).
|
||
|
* </pre>
|
||
|
*/
|
||
|
FPIX *
|
||
|
fpixRotate90(FPIX *fpixs,
|
||
|
l_int32 direction)
|
||
|
{
|
||
|
l_int32 i, j, wd, hd, wpls, wpld;
|
||
|
l_float32 *datas, *datad, *lines, *lined;
|
||
|
FPIX *fpixd;
|
||
|
|
||
|
PROCNAME("fpixRotate90");
|
||
|
|
||
|
if (!fpixs)
|
||
|
return (FPIX *)ERROR_PTR("fpixs not defined", procName, NULL);
|
||
|
if (direction != 1 && direction != -1)
|
||
|
return (FPIX *)ERROR_PTR("invalid direction", procName, NULL);
|
||
|
|
||
|
fpixGetDimensions(fpixs, &hd, &wd);
|
||
|
if ((fpixd = fpixCreate(wd, hd)) == NULL)
|
||
|
return (FPIX *)ERROR_PTR("fpixd not made", procName, NULL);
|
||
|
fpixCopyResolution(fpixd, fpixs);
|
||
|
|
||
|
datas = fpixGetData(fpixs);
|
||
|
wpls = fpixGetWpl(fpixs);
|
||
|
datad = fpixGetData(fpixd);
|
||
|
wpld = fpixGetWpl(fpixd);
|
||
|
if (direction == 1) { /* clockwise */
|
||
|
for (i = 0; i < hd; i++) {
|
||
|
lined = datad + i * wpld;
|
||
|
lines = datas + (wd - 1) * wpls;
|
||
|
for (j = 0; j < wd; j++) {
|
||
|
lined[j] = lines[i];
|
||
|
lines -= wpls;
|
||
|
}
|
||
|
}
|
||
|
} else { /* ccw */
|
||
|
for (i = 0; i < hd; i++) {
|
||
|
lined = datad + i * wpld;
|
||
|
lines = datas;
|
||
|
for (j = 0; j < wd; j++) {
|
||
|
lined[j] = lines[hd - 1 - i];
|
||
|
lines += wpls;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
return fpixd;
|
||
|
}
|
||
|
|
||
|
|
||
|
/*!
|
||
|
* \brief pixFlipLR()
|
||
|
*
|
||
|
* \param[in] fpixd [optional] can be null, equal to fpixs,
|
||
|
* or different from fpixs
|
||
|
* \param[in] fpixs
|
||
|
* \return fpixd, or NULL on error
|
||
|
*
|
||
|
* <pre>
|
||
|
* Notes:
|
||
|
* (1) This does a left-right flip of the image, which is
|
||
|
* equivalent to a rotation out of the plane about a
|
||
|
* vertical line through the image center.
|
||
|
* (2) There are 3 cases for input:
|
||
|
* (a) fpixd == null (creates a new fpixd)
|
||
|
* (b) fpixd == fpixs (in-place operation)
|
||
|
* (c) fpixd != fpixs (existing fpixd)
|
||
|
* (3) For clarity, use these three patterns, respectively:
|
||
|
* (a) fpixd = fpixFlipLR(NULL, fpixs);
|
||
|
* (b) fpixFlipLR(fpixs, fpixs);
|
||
|
* (c) fpixFlipLR(fpixd, fpixs);
|
||
|
* (4) If an existing fpixd is not the same size as fpixs, the
|
||
|
* image data will be reallocated.
|
||
|
* </pre>
|
||
|
*/
|
||
|
FPIX *
|
||
|
fpixFlipLR(FPIX *fpixd,
|
||
|
FPIX *fpixs)
|
||
|
{
|
||
|
l_int32 i, j, w, h, wpl, bpl;
|
||
|
l_float32 *line, *data, *buffer;
|
||
|
|
||
|
PROCNAME("fpixFlipLR");
|
||
|
|
||
|
if (!fpixs)
|
||
|
return (FPIX *)ERROR_PTR("fpixs not defined", procName, NULL);
|
||
|
|
||
|
fpixGetDimensions(fpixs, &w, &h);
|
||
|
|
||
|
/* Prepare fpixd for in-place operation */
|
||
|
if ((fpixd = fpixCopy(fpixd, fpixs)) == NULL)
|
||
|
return (FPIX *)ERROR_PTR("fpixd not made", procName, NULL);
|
||
|
|
||
|
data = fpixGetData(fpixd);
|
||
|
wpl = fpixGetWpl(fpixd); /* 4-byte words */
|
||
|
bpl = 4 * wpl;
|
||
|
if ((buffer = (l_float32 *)LEPT_CALLOC(wpl, sizeof(l_float32))) == NULL) {
|
||
|
fpixDestroy(&fpixd);
|
||
|
return (FPIX *)ERROR_PTR("buffer not made", procName, NULL);
|
||
|
}
|
||
|
for (i = 0; i < h; i++) {
|
||
|
line = data + i * wpl;
|
||
|
memcpy(buffer, line, bpl);
|
||
|
for (j = 0; j < w; j++)
|
||
|
line[j] = buffer[w - 1 - j];
|
||
|
}
|
||
|
LEPT_FREE(buffer);
|
||
|
return fpixd;
|
||
|
}
|
||
|
|
||
|
|
||
|
/*!
|
||
|
* \brief fpixFlipTB()
|
||
|
*
|
||
|
* \param[in] fpixd [optional] can be null, equal to fpixs,
|
||
|
* or different from fpixs
|
||
|
* \param[in] fpixs
|
||
|
* \return fpixd, or NULL on error
|
||
|
*
|
||
|
* <pre>
|
||
|
* Notes:
|
||
|
* (1) This does a top-bottom flip of the image, which is
|
||
|
* equivalent to a rotation out of the plane about a
|
||
|
* horizontal line through the image center.
|
||
|
* (2) There are 3 cases for input:
|
||
|
* (a) fpixd == null (creates a new fpixd)
|
||
|
* (b) fpixd == fpixs (in-place operation)
|
||
|
* (c) fpixd != fpixs (existing fpixd)
|
||
|
* (3) For clarity, use these three patterns, respectively:
|
||
|
* (a) fpixd = fpixFlipTB(NULL, fpixs);
|
||
|
* (b) fpixFlipTB(fpixs, fpixs);
|
||
|
* (c) fpixFlipTB(fpixd, fpixs);
|
||
|
* (4) If an existing fpixd is not the same size as fpixs, the
|
||
|
* image data will be reallocated.
|
||
|
* </pre>
|
||
|
*/
|
||
|
FPIX *
|
||
|
fpixFlipTB(FPIX *fpixd,
|
||
|
FPIX *fpixs)
|
||
|
{
|
||
|
l_int32 i, k, h, h2, wpl, bpl;
|
||
|
l_float32 *linet, *lineb, *data, *buffer;
|
||
|
|
||
|
PROCNAME("fpixFlipTB");
|
||
|
|
||
|
if (!fpixs)
|
||
|
return (FPIX *)ERROR_PTR("fpixs not defined", procName, NULL);
|
||
|
|
||
|
/* Prepare fpixd for in-place operation */
|
||
|
if ((fpixd = fpixCopy(fpixd, fpixs)) == NULL)
|
||
|
return (FPIX *)ERROR_PTR("fpixd not made", procName, NULL);
|
||
|
|
||
|
data = fpixGetData(fpixd);
|
||
|
wpl = fpixGetWpl(fpixd);
|
||
|
fpixGetDimensions(fpixd, NULL, &h);
|
||
|
if ((buffer = (l_float32 *)LEPT_CALLOC(wpl, sizeof(l_float32))) == NULL) {
|
||
|
fpixDestroy(&fpixd);
|
||
|
return (FPIX *)ERROR_PTR("buffer not made", procName, NULL);
|
||
|
}
|
||
|
h2 = h / 2;
|
||
|
bpl = 4 * wpl;
|
||
|
for (i = 0, k = h - 1; i < h2; i++, k--) {
|
||
|
linet = data + i * wpl;
|
||
|
lineb = data + k * wpl;
|
||
|
memcpy(buffer, linet, bpl);
|
||
|
memcpy(linet, lineb, bpl);
|
||
|
memcpy(lineb, buffer, bpl);
|
||
|
}
|
||
|
LEPT_FREE(buffer);
|
||
|
return fpixd;
|
||
|
}
|
||
|
|
||
|
|
||
|
/*--------------------------------------------------------------------*
|
||
|
* Affine and projective interpolated transforms *
|
||
|
*--------------------------------------------------------------------*/
|
||
|
/*!
|
||
|
* \brief fpixAffinePta()
|
||
|
*
|
||
|
* \param[in] fpixs 8 bpp
|
||
|
* \param[in] ptad 4 pts of final coordinate space
|
||
|
* \param[in] ptas 4 pts of initial coordinate space
|
||
|
* \param[in] border size of extension with constant normal derivative
|
||
|
* \param[in] inval value brought in; typ. 0
|
||
|
* \return fpixd, or NULL on error
|
||
|
*
|
||
|
* <pre>
|
||
|
* Notes:
|
||
|
* (1) If %border > 0, all four sides are extended by that distance,
|
||
|
* and removed after the transformation is finished. Pixels
|
||
|
* that would be brought in to the trimmed result from outside
|
||
|
* the extended region are assigned %inval. The purpose of
|
||
|
* extending the image is to avoid such assignments.
|
||
|
* (2) On the other hand, you may want to give all pixels that
|
||
|
* are brought in from outside fpixs a specific value. In that
|
||
|
* case, set %border == 0.
|
||
|
* </pre>
|
||
|
*/
|
||
|
FPIX *
|
||
|
fpixAffinePta(FPIX *fpixs,
|
||
|
PTA *ptad,
|
||
|
PTA *ptas,
|
||
|
l_int32 border,
|
||
|
l_float32 inval)
|
||
|
{
|
||
|
l_float32 *vc;
|
||
|
PTA *ptas2, *ptad2;
|
||
|
FPIX *fpixs2, *fpixd, *fpixd2;
|
||
|
|
||
|
PROCNAME("fpixAffinePta");
|
||
|
|
||
|
if (!fpixs)
|
||
|
return (FPIX *)ERROR_PTR("fpixs not defined", procName, NULL);
|
||
|
if (!ptas)
|
||
|
return (FPIX *)ERROR_PTR("ptas not defined", procName, NULL);
|
||
|
if (!ptad)
|
||
|
return (FPIX *)ERROR_PTR("ptad not defined", procName, NULL);
|
||
|
|
||
|
/* If a border is to be added, also translate the ptas */
|
||
|
if (border > 0) {
|
||
|
ptas2 = ptaTransform(ptas, border, border, 1.0, 1.0);
|
||
|
ptad2 = ptaTransform(ptad, border, border, 1.0, 1.0);
|
||
|
fpixs2 = fpixAddSlopeBorder(fpixs, border, border, border, border);
|
||
|
} else {
|
||
|
ptas2 = ptaClone(ptas);
|
||
|
ptad2 = ptaClone(ptad);
|
||
|
fpixs2 = fpixClone(fpixs);
|
||
|
}
|
||
|
|
||
|
/* Get backwards transform from dest to src, and apply it */
|
||
|
getAffineXformCoeffs(ptad2, ptas2, &vc);
|
||
|
fpixd2 = fpixAffine(fpixs2, vc, inval);
|
||
|
fpixDestroy(&fpixs2);
|
||
|
ptaDestroy(&ptas2);
|
||
|
ptaDestroy(&ptad2);
|
||
|
LEPT_FREE(vc);
|
||
|
|
||
|
if (border == 0)
|
||
|
return fpixd2;
|
||
|
|
||
|
/* Remove the added border */
|
||
|
fpixd = fpixRemoveBorder(fpixd2, border, border, border, border);
|
||
|
fpixDestroy(&fpixd2);
|
||
|
return fpixd;
|
||
|
}
|
||
|
|
||
|
|
||
|
/*!
|
||
|
* \brief fpixAffine()
|
||
|
*
|
||
|
* \param[in] fpixs 8 bpp
|
||
|
* \param[in] vc vector of 8 coefficients for projective transformation
|
||
|
* \param[in] inval value brought in; typ. 0
|
||
|
* \return fpixd, or NULL on error
|
||
|
*/
|
||
|
FPIX *
|
||
|
fpixAffine(FPIX *fpixs,
|
||
|
l_float32 *vc,
|
||
|
l_float32 inval)
|
||
|
{
|
||
|
l_int32 i, j, w, h, wpld;
|
||
|
l_float32 val;
|
||
|
l_float32 *datas, *datad, *lined;
|
||
|
l_float32 x, y;
|
||
|
FPIX *fpixd;
|
||
|
|
||
|
PROCNAME("fpixAffine");
|
||
|
|
||
|
if (!fpixs)
|
||
|
return (FPIX *)ERROR_PTR("fpixs not defined", procName, NULL);
|
||
|
fpixGetDimensions(fpixs, &w, &h);
|
||
|
if (!vc)
|
||
|
return (FPIX *)ERROR_PTR("vc not defined", procName, NULL);
|
||
|
|
||
|
datas = fpixGetData(fpixs);
|
||
|
fpixd = fpixCreateTemplate(fpixs);
|
||
|
fpixSetAllArbitrary(fpixd, inval);
|
||
|
datad = fpixGetData(fpixd);
|
||
|
wpld = fpixGetWpl(fpixd);
|
||
|
|
||
|
/* Iterate over destination pixels */
|
||
|
for (i = 0; i < h; i++) {
|
||
|
lined = datad + i * wpld;
|
||
|
for (j = 0; j < w; j++) {
|
||
|
/* Compute float src pixel location corresponding to (i,j) */
|
||
|
affineXformPt(vc, j, i, &x, &y);
|
||
|
linearInterpolatePixelFloat(datas, w, h, x, y, inval, &val);
|
||
|
*(lined + j) = val;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
return fpixd;
|
||
|
}
|
||
|
|
||
|
|
||
|
/*!
|
||
|
* \brief fpixProjectivePta()
|
||
|
*
|
||
|
* \param[in] fpixs 8 bpp
|
||
|
* \param[in] ptad 4 pts of final coordinate space
|
||
|
* \param[in] ptas 4 pts of initial coordinate space
|
||
|
* \param[in] border size of extension with constant normal derivative
|
||
|
* \param[in] inval value brought in; typ. 0
|
||
|
* \return fpixd, or NULL on error
|
||
|
*
|
||
|
* <pre>
|
||
|
* Notes:
|
||
|
* (1) If %border > 0, all four sides are extended by that distance,
|
||
|
* and removed after the transformation is finished. Pixels
|
||
|
* that would be brought in to the trimmed result from outside
|
||
|
* the extended region are assigned %inval. The purpose of
|
||
|
* extending the image is to avoid such assignments.
|
||
|
* (2) On the other hand, you may want to give all pixels that
|
||
|
* are brought in from outside fpixs a specific value. In that
|
||
|
* case, set %border == 0.
|
||
|
* </pre>
|
||
|
*/
|
||
|
FPIX *
|
||
|
fpixProjectivePta(FPIX *fpixs,
|
||
|
PTA *ptad,
|
||
|
PTA *ptas,
|
||
|
l_int32 border,
|
||
|
l_float32 inval)
|
||
|
{
|
||
|
l_float32 *vc;
|
||
|
PTA *ptas2, *ptad2;
|
||
|
FPIX *fpixs2, *fpixd, *fpixd2;
|
||
|
|
||
|
PROCNAME("fpixProjectivePta");
|
||
|
|
||
|
if (!fpixs)
|
||
|
return (FPIX *)ERROR_PTR("fpixs not defined", procName, NULL);
|
||
|
if (!ptas)
|
||
|
return (FPIX *)ERROR_PTR("ptas not defined", procName, NULL);
|
||
|
if (!ptad)
|
||
|
return (FPIX *)ERROR_PTR("ptad not defined", procName, NULL);
|
||
|
|
||
|
/* If a border is to be added, also translate the ptas */
|
||
|
if (border > 0) {
|
||
|
ptas2 = ptaTransform(ptas, border, border, 1.0, 1.0);
|
||
|
ptad2 = ptaTransform(ptad, border, border, 1.0, 1.0);
|
||
|
fpixs2 = fpixAddSlopeBorder(fpixs, border, border, border, border);
|
||
|
} else {
|
||
|
ptas2 = ptaClone(ptas);
|
||
|
ptad2 = ptaClone(ptad);
|
||
|
fpixs2 = fpixClone(fpixs);
|
||
|
}
|
||
|
|
||
|
/* Get backwards transform from dest to src, and apply it */
|
||
|
getProjectiveXformCoeffs(ptad2, ptas2, &vc);
|
||
|
fpixd2 = fpixProjective(fpixs2, vc, inval);
|
||
|
fpixDestroy(&fpixs2);
|
||
|
ptaDestroy(&ptas2);
|
||
|
ptaDestroy(&ptad2);
|
||
|
LEPT_FREE(vc);
|
||
|
|
||
|
if (border == 0)
|
||
|
return fpixd2;
|
||
|
|
||
|
/* Remove the added border */
|
||
|
fpixd = fpixRemoveBorder(fpixd2, border, border, border, border);
|
||
|
fpixDestroy(&fpixd2);
|
||
|
return fpixd;
|
||
|
}
|
||
|
|
||
|
|
||
|
/*!
|
||
|
* \brief fpixProjective()
|
||
|
*
|
||
|
* \param[in] fpixs 8 bpp
|
||
|
* \param[in] vc vector of 8 coefficients for projective transform
|
||
|
* \param[in] inval value brought in; typ. 0
|
||
|
* \return fpixd, or NULL on error
|
||
|
*/
|
||
|
FPIX *
|
||
|
fpixProjective(FPIX *fpixs,
|
||
|
l_float32 *vc,
|
||
|
l_float32 inval)
|
||
|
{
|
||
|
l_int32 i, j, w, h, wpld;
|
||
|
l_float32 val;
|
||
|
l_float32 *datas, *datad, *lined;
|
||
|
l_float32 x, y;
|
||
|
FPIX *fpixd;
|
||
|
|
||
|
PROCNAME("fpixProjective");
|
||
|
|
||
|
if (!fpixs)
|
||
|
return (FPIX *)ERROR_PTR("fpixs not defined", procName, NULL);
|
||
|
fpixGetDimensions(fpixs, &w, &h);
|
||
|
if (!vc)
|
||
|
return (FPIX *)ERROR_PTR("vc not defined", procName, NULL);
|
||
|
|
||
|
datas = fpixGetData(fpixs);
|
||
|
fpixd = fpixCreateTemplate(fpixs);
|
||
|
fpixSetAllArbitrary(fpixd, inval);
|
||
|
datad = fpixGetData(fpixd);
|
||
|
wpld = fpixGetWpl(fpixd);
|
||
|
|
||
|
/* Iterate over destination pixels */
|
||
|
for (i = 0; i < h; i++) {
|
||
|
lined = datad + i * wpld;
|
||
|
for (j = 0; j < w; j++) {
|
||
|
/* Compute float src pixel location corresponding to (i,j) */
|
||
|
projectiveXformPt(vc, j, i, &x, &y);
|
||
|
linearInterpolatePixelFloat(datas, w, h, x, y, inval, &val);
|
||
|
*(lined + j) = val;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
return fpixd;
|
||
|
}
|
||
|
|
||
|
|
||
|
/*!
|
||
|
* \brief linearInterpolatePixelFloat()
|
||
|
*
|
||
|
* \param[in] datas ptr to beginning of float image data
|
||
|
* \param[in] w, h dimensions of image
|
||
|
* \param[in] x, y floating pt location for evaluation
|
||
|
* \param[in] inval float value brought in from the outside when the
|
||
|
* input x,y location is outside the image
|
||
|
* \param[out] pval interpolated float value
|
||
|
* \return 0 if OK, 1 on error
|
||
|
*
|
||
|
* <pre>
|
||
|
* Notes:
|
||
|
* (1) This is a standard linear interpolation function. It is
|
||
|
* equivalent to area weighting on each component, and
|
||
|
* avoids "jaggies" when rendering sharp edges.
|
||
|
* </pre>
|
||
|
*/
|
||
|
l_ok
|
||
|
linearInterpolatePixelFloat(l_float32 *datas,
|
||
|
l_int32 w,
|
||
|
l_int32 h,
|
||
|
l_float32 x,
|
||
|
l_float32 y,
|
||
|
l_float32 inval,
|
||
|
l_float32 *pval)
|
||
|
{
|
||
|
l_int32 xpm, ypm, xp, yp, xf, yf;
|
||
|
l_float32 v00, v01, v10, v11;
|
||
|
l_float32 *lines;
|
||
|
|
||
|
PROCNAME("linearInterpolatePixelFloat");
|
||
|
|
||
|
if (!pval)
|
||
|
return ERROR_INT("&val not defined", procName, 1);
|
||
|
*pval = inval;
|
||
|
if (!datas)
|
||
|
return ERROR_INT("datas not defined", procName, 1);
|
||
|
|
||
|
/* Skip if off the edge */
|
||
|
if (x < 0.0 || y < 0.0 || x > w - 2.0 || y > h - 2.0)
|
||
|
return 0;
|
||
|
|
||
|
xpm = (l_int32)(16.0 * x + 0.5);
|
||
|
ypm = (l_int32)(16.0 * y + 0.5);
|
||
|
xp = xpm >> 4;
|
||
|
yp = ypm >> 4;
|
||
|
xf = xpm & 0x0f;
|
||
|
yf = ypm & 0x0f;
|
||
|
|
||
|
#if DEBUG
|
||
|
if (xf < 0 || yf < 0)
|
||
|
fprintf(stderr, "xp = %d, yp = %d, xf = %d, yf = %d\n", xp, yp, xf, yf);
|
||
|
#endif /* DEBUG */
|
||
|
|
||
|
/* Interpolate by area weighting. */
|
||
|
lines = datas + yp * w;
|
||
|
v00 = (16.0 - xf) * (16.0 - yf) * (*(lines + xp));
|
||
|
v10 = xf * (16.0 - yf) * (*(lines + xp + 1));
|
||
|
v01 = (16.0 - xf) * yf * (*(lines + w + xp));
|
||
|
v11 = (l_float32)(xf) * yf * (*(lines + w + xp + 1));
|
||
|
*pval = (v00 + v01 + v10 + v11) / 256.0;
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
|
||
|
/*--------------------------------------------------------------------*
|
||
|
* Thresholding to 1 bpp Pix *
|
||
|
*--------------------------------------------------------------------*/
|
||
|
/*!
|
||
|
* \brief fpixThresholdToPix()
|
||
|
*
|
||
|
* \param[in] fpix
|
||
|
* \param[in] thresh
|
||
|
* \return pixd 1 bpp, or NULL on error
|
||
|
*
|
||
|
* <pre>
|
||
|
* Notes:
|
||
|
* (1) For all values of fpix that are <= thresh, sets the pixel
|
||
|
* in pixd to 1.
|
||
|
* </pre>
|
||
|
*/
|
||
|
PIX *
|
||
|
fpixThresholdToPix(FPIX *fpix,
|
||
|
l_float32 thresh)
|
||
|
{
|
||
|
l_int32 i, j, w, h, wpls, wpld;
|
||
|
l_float32 *datas, *lines;
|
||
|
l_uint32 *datad, *lined;
|
||
|
PIX *pixd;
|
||
|
|
||
|
PROCNAME("fpixThresholdToPix");
|
||
|
|
||
|
if (!fpix)
|
||
|
return (PIX *)ERROR_PTR("fpix not defined", procName, NULL);
|
||
|
|
||
|
fpixGetDimensions(fpix, &w, &h);
|
||
|
datas = fpixGetData(fpix);
|
||
|
wpls = fpixGetWpl(fpix);
|
||
|
pixd = pixCreate(w, h, 1);
|
||
|
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++) {
|
||
|
if (lines[j] <= thresh)
|
||
|
SET_DATA_BIT(lined, j);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
return pixd;
|
||
|
}
|
||
|
|
||
|
|
||
|
/*--------------------------------------------------------------------*
|
||
|
* Generate function from components *
|
||
|
*--------------------------------------------------------------------*/
|
||
|
/*!
|
||
|
* \brief pixComponentFunction()
|
||
|
*
|
||
|
* \param[in] pix 32 bpp rgb
|
||
|
* \param[in] rnum, gnum, bnum coefficients for numerator
|
||
|
* \param[in] rdenom, gdenom, bdenom coefficients for denominator
|
||
|
* \return fpixd, or NULL on error
|
||
|
*
|
||
|
* <pre>
|
||
|
* Notes:
|
||
|
* (1) This stores a function of the component values of each
|
||
|
* input pixel in %fpixd.
|
||
|
* (2) The function is a ratio of linear combinations of component values.
|
||
|
* There are two special cases for denominator coefficients:
|
||
|
* (a) The denominator is 1.0: input 0 for all denominator coefficients
|
||
|
* (b) Only one component is used in the denominator: input 1.0
|
||
|
* for that denominator component and 0.0 for the other two.
|
||
|
* (3) If the denominator is 0, multiply by an arbitrary number that
|
||
|
* is much larger than 1. Choose 256 "arbitrarily".
|
||
|
*
|
||
|
* </pre>
|
||
|
*/
|
||
|
FPIX *
|
||
|
pixComponentFunction(PIX *pix,
|
||
|
l_float32 rnum,
|
||
|
l_float32 gnum,
|
||
|
l_float32 bnum,
|
||
|
l_float32 rdenom,
|
||
|
l_float32 gdenom,
|
||
|
l_float32 bdenom)
|
||
|
{
|
||
|
l_int32 i, j, w, h, wpls, wpld, rval, gval, bval, zerodenom, onedenom;
|
||
|
l_float32 fnum, fdenom;
|
||
|
l_uint32 *datas, *lines;
|
||
|
l_float32 *datad, *lined, *recip;
|
||
|
FPIX *fpixd;
|
||
|
|
||
|
PROCNAME("pixComponentFunction");
|
||
|
|
||
|
if (!pix || pixGetDepth(pix) != 32)
|
||
|
return (FPIX *)ERROR_PTR("pix undefined or not 32 bpp", procName, NULL);
|
||
|
|
||
|
pixGetDimensions(pix, &w, &h, NULL);
|
||
|
datas = pixGetData(pix);
|
||
|
wpls = pixGetWpl(pix);
|
||
|
fpixd = fpixCreate(w, h);
|
||
|
datad = fpixGetData(fpixd);
|
||
|
wpld = fpixGetWpl(fpixd);
|
||
|
zerodenom = (rdenom == 0.0 && gdenom == 0.0 && bdenom == 0.0) ? 1: 0;
|
||
|
onedenom = ((rdenom == 1.0 && gdenom == 0.0 && bdenom == 0.0) ||
|
||
|
(rdenom == 0.0 && gdenom == 1.0 && bdenom == 0.0) ||
|
||
|
(rdenom == 0.0 && gdenom == 0.0 && bdenom == 1.0)) ? 1 : 0;
|
||
|
recip = NULL;
|
||
|
if (onedenom) {
|
||
|
recip = (l_float32 *)LEPT_CALLOC(256, sizeof(l_float32));
|
||
|
recip[0] = 256; /* arbitrary large number */
|
||
|
for (i = 1; i < 256; i++)
|
||
|
recip[i] = 1.0 / (l_float32)i;
|
||
|
}
|
||
|
for (i = 0; i < h; i++) {
|
||
|
lines = datas + i * wpls;
|
||
|
lined = datad + i * wpld;
|
||
|
if (zerodenom) {
|
||
|
for (j = 0; j < w; j++) {
|
||
|
extractRGBValues(lines[j], &rval, &gval, &bval);
|
||
|
lined[j] = rnum * rval + gnum * gval + bnum * bval;
|
||
|
}
|
||
|
} else if (onedenom && rdenom == 1.0) {
|
||
|
for (j = 0; j < w; j++) {
|
||
|
extractRGBValues(lines[j], &rval, &gval, &bval);
|
||
|
lined[j]
|
||
|
= recip[rval] * (rnum * rval + gnum * gval + bnum * bval);
|
||
|
}
|
||
|
} else if (onedenom && gdenom == 1.0) {
|
||
|
for (j = 0; j < w; j++) {
|
||
|
extractRGBValues(lines[j], &rval, &gval, &bval);
|
||
|
lined[j]
|
||
|
= recip[gval] * (rnum * rval + gnum * gval + bnum * bval);
|
||
|
}
|
||
|
} else if (onedenom && bdenom == 1.0) {
|
||
|
for (j = 0; j < w; j++) {
|
||
|
extractRGBValues(lines[j], &rval, &gval, &bval);
|
||
|
lined[j]
|
||
|
= recip[bval] * (rnum * rval + gnum * gval + bnum * bval);
|
||
|
}
|
||
|
} else { /* general case */
|
||
|
for (j = 0; j < w; j++) {
|
||
|
extractRGBValues(lines[j], &rval, &gval, &bval);
|
||
|
fnum = rnum * rval + gnum * gval + bnum * bval;
|
||
|
fdenom = rdenom * rval + gdenom * gval + bdenom * bval;
|
||
|
lined[j] = (fdenom == 0) ? 256.0 * fnum : fnum / fdenom;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
LEPT_FREE(recip);
|
||
|
return fpixd;
|
||
|
}
|