 <p>By "bias", I am assuming that you want to shift the result so that all pixel values are non-negative.</p> <p>In the notes for pixConvolve(), it says that the absolute value is taken to avoid negative output. It also says that if you wish to keep the negative values, use fpixConvolve() instead, which operates on an FPix and generates an FPix.</p> <p>If you want a biased result without clipping, it is in general necessary to do the following:</p> <ul> <li>(1) pixConvertToFpix() -- convert to an FPix</li> <li>(2) fpixConvolve() -- do the convolution on the FPix, producing an FPix</li> <li>(3) fpixGetMin() -- determine the bias required to make all values nonzero</li> <li>(4) fpixAddMultConstant() -- add the bias to the FPix</li> <li>(5) fpixGetMax() -- find the max value; if > 255, you need a 16 bpp Pix to represent it</li> <li>(6) fpixConvertToPix -- convert back to a pix</li> </ul> <p>Perhaps the leptonica maintainer (me) should bundle this up into a simple interface ;-)</p> <p>OK, here's a function, following the outline that I wrote above, that should give enough flexibility to do these convolutions.</p> <pre><code> /*! * pixConvolveWithBias() * Input: pixs (8 bpp; no colormap) * kel1 * kel2 (can be null; use if separable) * force8 (if 1, force output to 8 bpp; otherwise, determine * output depth by the dynamic range of pixel values) * &amp;bias (&lt;return&gt; applied bias) * Return: pixd (8 or 16 bpp) * * Notes: * (1) This does a convolution with either a single kernel or * a pair of separable kernels, and automatically applies whatever * bias (shift) is required so that the resulting pixel values * are non-negative. * (2) If there are no negative values in the kernel, a normalized * convolution is performed, with 8 bpp output. * (3) If there are negative values in the kernel, the pix is * converted to an fpix, the convolution is done on the fpix, and * a bias (shift) may need to be applied. * (4) If force8 == TRUE and the range of values after the convolution * is &gt; 255, the output values will be scaled to fit in * [0 ... 255]. * If force8 == FALSE, the output will be either 8 or 16 bpp, * to accommodate the dynamic range of output values without * scaling. */ PIX * pixConvolveWithBias(PIX *pixs, L_KERNEL *kel1, L_KERNEL *kel2, l_int32 force8, l_int32 *pbias) { l_int32 outdepth; l_float32 min1, min2, min, minval, maxval, range; FPIX *fpix1, *fpix2; PIX *pixd; PROCNAME("pixConvolveWithBias"); if (!pixs || pixGetDepth(pixs) != 8) return (PIX *)ERROR_PTR("pixs undefined or not 8 bpp", procName, NULL); if (pixGetColormap(pixs)) return (PIX *)ERROR_PTR("pixs has colormap", procName, NULL); if (!kel1) return (PIX *)ERROR_PTR("kel1 not defined", procName, NULL); /* Determine if negative values can be produced in convolution */ kernelGetMinMax(kel1, &amp;min1, NULL); min2 = 0.0; if (kel2) kernelGetMinMax(kel2, &amp;min2, NULL); min = L_MIN(min1, min2); if (min &gt;= 0.0) { if (!kel2) return pixConvolve(pixs, kel1, 8, 1); else return pixConvolveSep(pixs, kel1, kel2, 8, 1); } /* Bias may need to be applied; convert to fpix and convolve */ fpix1 = pixConvertToFPix(pixs, 1); if (!kel2) fpix2 = fpixConvolve(fpix1, kel1, 1); else fpix2 = fpixConvolveSep(fpix1, kel1, kel2, 1); fpixDestroy(&amp;fpix1); /* Determine the bias and the dynamic range. * If the dynamic range is &lt;= 255, just shift the values by the * bias, if any. * If the dynamic range is &gt; 255, there are two cases: * (1) the output depth is not forced to 8 bpp ==&gt; outdepth = 16 * (2) the output depth is forced to 8 ==&gt; linearly map the * pixel values to [0 ... 255]. */ fpixGetMin(fpix2, &amp;minval, NULL, NULL); fpixGetMax(fpix2, &amp;maxval, NULL, NULL); range = maxval - minval; *pbias = (minval &lt; 0.0) ? -minval : 0.0; fpixAddMultConstant(fpix2, *pbias, 1.0); /* shift: min val ==&gt; 0 */ if (range &lt;= 255 || !force8) { /* no scaling of output values */ outdepth = (range &gt; 255) ? 16 : 8; } else { /* scale output values to fit in 8 bpp */ fpixAddMultConstant(fpix2, 0.0, (255.0 / range)); outdepth = 8; } /* Convert back to pix; it won't do any clipping */ pixd = fpixConvertToPix(fpix2, outdepth, L_CLIP_TO_ZERO, 0); fpixDestroy(&amp;fpix2); return pixd; } </code></pre>