NAME
Image::Leptonica::Func::grayquant
VERSION
version 0.04
grayquant.c
grayquant.c
Thresholding from 8 bpp to 1 bpp
Floyd-Steinberg dithering to binary
PIX *pixDitherToBinary()
PIX *pixDitherToBinarySpec()
Simple (pixelwise) binarization with fixed threshold
PIX *pixThresholdToBinary()
Binarization with variable threshold
PIX *pixVarThresholdToBinary()
Slower implementation of Floyd-Steinberg dithering, using LUTs
PIX *pixDitherToBinaryLUT()
Generate a binary mask from pixels of particular values
PIX *pixGenerateMaskByValue()
PIX *pixGenerateMaskByBand()
Thresholding from 8 bpp to 2 bpp
Dithering to 2 bpp
PIX *pixDitherTo2bpp()
PIX *pixDitherTo2bppSpec()
Simple (pixelwise) thresholding to 2 bpp with optional cmap
PIX *pixThresholdTo2bpp()
Simple (pixelwise) thresholding from 8 bpp to 4 bpp
PIX *pixThresholdTo4bpp()
Simple (pixelwise) quantization on 8 bpp grayscale
PIX *pixThresholdOn8bpp()
Arbitrary (pixelwise) thresholding from 8 bpp to 2, 4 or 8 bpp
PIX *pixThresholdGrayArb()
Quantization tables for linear thresholds of grayscale images
l_int32 *makeGrayQuantIndexTable()
l_int32 *makeGrayQuantTargetTable()
Quantization table for arbitrary thresholding of grayscale images
l_int32 makeGrayQuantTableArb()
l_int32 makeGrayQuantColormapArb()
Thresholding from 32 bpp rgb to 1 bpp
(really color quantization, but it's better placed in this file)
PIX *pixGenerateMaskByBand32()
PIX *pixGenerateMaskByDiscr32()
Histogram-based grayscale quantization
PIX *pixGrayQuantFromHisto()
static l_int32 numaFillCmapFromHisto()
Color quantize grayscale image using existing colormap
PIX *pixGrayQuantFromCmap()
FUNCTIONS
makeGrayQuantColormapArb
l_int32 makeGrayQuantColormapArb ( PIX *pixs, l_int32 *tab, l_int32 outdepth, PIXCMAP **pcmap )
makeGrayQuantColormapArb()
Input: pixs (8 bpp)
tab (table mapping input gray level to cmap index)
outdepth (of colormap: 1, 2, 4 or 8)
&cmap (<return> colormap)
Return: 0 if OK, 1 on error
Notes:
(1) The table is a 256-entry inverse colormap: it maps input gray
level to colormap index (the bin number). It is computed
using makeGrayQuantTableArb().
(2) The colormap generated here has quantized values at the
average gray value of the pixels that are in each bin.
(3) Returns an error if there are not enough levels in the
output colormap for the number of bins. The number
of bins must not exceed 2^outdepth.
makeGrayQuantIndexTable
l_int32 * makeGrayQuantIndexTable ( l_int32 nlevels )
makeGrayQuantIndexTable()
Input: nlevels (number of output levels)
Return: table (maps input gray level to colormap index,
or null on error)
Notes:
(1) 'nlevels' is some number between 2 and 256 (typically 8 or less).
(2) The table is typically used for quantizing 2, 4 and 8 bpp
grayscale src pix, and generating a colormapped dest pix.
makeGrayQuantTableArb
l_int32 makeGrayQuantTableArb ( NUMA *na, l_int32 outdepth, l_int32 **ptab, PIXCMAP **pcmap )
makeGrayQuantTableArb()
Input: na (numa of bin boundaries)
outdepth (of colormap: 1, 2, 4 or 8)
&tab (<return> table mapping input gray level to cmap index)
&cmap (<return> colormap)
Return: 0 if OK, 1 on error
Notes:
(1) The number of bins is the count of @na + 1.
(2) The bin boundaries in na must be sorted in increasing order.
(3) The table is an inverse colormap: it maps input gray level
to colormap index (the bin number).
(4) The colormap generated here has quantized values at the
center of each bin. If you want to use the average gray
value of pixels within the bin, discard the colormap and
compute it using makeGrayQuantColormapArb().
(5) Returns an error if there are not enough levels in the
output colormap for the number of bins. The number
of bins must not exceed 2^outdepth.
makeGrayQuantTargetTable
l_int32 * makeGrayQuantTargetTable ( l_int32 nlevels, l_int32 depth )
makeGrayQuantTargetTable()
Input: nlevels (number of output levels)
depth (of dest pix, in bpp; 2, 4 or 8 bpp)
Return: table (maps input gray level to thresholded gray level,
or null on error)
Notes:
(1) nlevels is some number between 2 and 2^(depth)
(2) The table is used in two similar ways:
- for 8 bpp, it quantizes to a given number of target levels
- for 2 and 4 bpp, it thresholds to appropriate target values
that will use the full dynamic range of the dest pix.
(3) For depth = 8, the number of thresholds chosen is
('nlevels' - 1), and the 'nlevels' values stored in the
table are at the two at the extreme ends, (0, 255), plus
plus ('nlevels' - 2) values chosen at equal intervals between.
For example, for depth = 8 and 'nlevels' = 3, the two
threshold values are 3f and bf, and the three target pixel
values are 0, 7f and ff.
(4) For depth < 8, we ignore nlevels, and always use the maximum
number of levels, which is 2^(depth).
If you want nlevels < the maximum number, you should always
use a colormap.
pixDitherTo2bpp
PIX * pixDitherTo2bpp ( PIX *pixs, l_int32 cmapflag )
pixDitherTo2bpp()
Input: pixs (8 bpp)
cmapflag (1 to generate a colormap)
Return: pixd (dithered 2 bpp), or null on error
An analog of the Floyd-Steinberg error diffusion dithering
algorithm is used to "dibitize" an 8 bpp grayscale image
to 2 bpp, using equally spaced gray values of 0, 85, 170, and 255,
which are served by thresholds of 43, 128 and 213.
If cmapflag == 1, the colormap values are set to 0, 85, 170 and 255.
If a pixel has a value between 0 and 42, it is dibitized
to 0, and the excess (above 0) is added to the
three neighboring pixels, in the fractions 3/8 to (i, j+1),
3/8 to (i+1, j) and 1/4 to (i+1, j+1), truncating to 255 if
necessary. If a pixel has a value between 43 and 127, it is
dibitized to 1, and the excess (above 85) is added to the three
neighboring pixels as before. If the value is below 85, the
excess is subtracted. With a value between 128
and 212, it is dibitized to 2, with the excess on either side
of 170 distributed as before. Finally, with a value between
213 and 255, it is dibitized to 3, with the excess (below 255)
subtracted from the neighbors. We always truncate to 0 or 255.
The details can be seen in the lookup table generation.
This function differs from straight dithering in that it allows
clipping of grayscale to 0 or 255 if the values are
sufficiently close, without distribution of the excess.
This uses default values (from pix.h) to specify the range of lower
and upper values (near 0 and 255, rsp) that are clipped to black
and white without propagating the excess.
Not propagating the excess has the effect of reducing the snake
patterns in parts of the image that are nearly black or white;
however, it also prevents any attempt to reproduce gray for those values.
The implementation uses 3 lookup tables for simplicity, and
a pair of line buffers to avoid modifying pixs.
pixDitherTo2bppSpec
PIX * pixDitherTo2bppSpec ( PIX *pixs, l_int32 lowerclip, l_int32 upperclip, l_int32 cmapflag )
pixDitherTo2bppSpec()
Input: pixs (8 bpp)
lowerclip (lower clip distance to black; use 0 for default)
upperclip (upper clip distance to white; use 0 for default)
cmapflag (1 to generate a colormap)
Return: pixd (dithered 2 bpp), or null on error
Notes:
(1) See comments above in pixDitherTo2bpp() for details.
(2) The input parameters lowerclip and upperclip specify the range
of lower and upper values (near 0 and 255, rsp) that are
clipped to black and white without propagating the excess.
For that reason, lowerclip and upperclip should be small numbers.
pixDitherToBinary
PIX * pixDitherToBinary ( PIX *pixs )
pixDitherToBinary()
Input: pixs
Return: pixd (dithered binary), or null on error
The Floyd-Steinberg error diffusion dithering algorithm
binarizes an 8 bpp grayscale image to a threshold of 128.
If a pixel has a value above 127, it is binarized to white
and the excess (below 255) is subtracted from three
neighboring pixels in the fractions 3/8 to (i, j+1),
3/8 to (i+1, j) and 1/4 to (i+1,j+1), truncating to 0
if necessary. Likewise, if it the pixel has a value
below 128, it is binarized to black and the excess above 0
is added to the neighboring pixels, truncating to 255 if necessary.
This function differs from straight dithering in that it allows
clipping of grayscale to 0 or 255 if the values are
sufficiently close, without distribution of the excess.
This uses default values to specify the range of lower
and upper values (near 0 and 255, rsp) that are clipped
to black and white without propagating the excess.
Not propagating the excess has the effect of reducing the
snake patterns in parts of the image that are nearly black or white;
however, it also prevents the attempt to reproduce gray for those values.
The implementation is straightforward. It uses a pair of
line buffers to avoid changing pixs. It is about 2x faster
than the implementation using LUTs.
pixDitherToBinaryLUT
PIX * pixDitherToBinaryLUT ( PIX *pixs, l_int32 lowerclip, l_int32 upperclip )
pixDitherToBinaryLUT()
Input: pixs
lowerclip (lower clip distance to black; use -1 for default)
upperclip (upper clip distance to white; use -1 for default)
Return: pixd (dithered binary), or null on error
This implementation is deprecated. You should use pixDitherToBinary().
See comments in pixDitherToBinary()
This implementation additionally uses three lookup tables to
generate the output pixel value and the excess or deficit
carried over to the neighboring pixels.
pixDitherToBinarySpec
PIX * pixDitherToBinarySpec ( PIX *pixs, l_int32 lowerclip, l_int32 upperclip )
pixDitherToBinarySpec()
Input: pixs
lowerclip (lower clip distance to black; use 0 for default)
upperclip (upper clip distance to white; use 0 for default)
Return: pixd (dithered binary), or null on error
Notes:
(1) See comments above in pixDitherToBinary() for details.
(2) The input parameters lowerclip and upperclip specify the range
of lower and upper values (near 0 and 255, rsp) that are
clipped to black and white without propagating the excess.
For that reason, lowerclip and upperclip should be small numbers.
pixGenerateMaskByBand
PIX * pixGenerateMaskByBand ( PIX *pixs, l_int32 lower, l_int32 upper, l_int32 inband, l_int32 usecmap )
pixGenerateMaskByBand()
Input: pixs (2, 4 or 8 bpp, or colormapped)
lower, upper (two pixel values from which a range, either
between (inband) or outside of (!inband),
determines which pixels in pixs cause us to
set a 1 in the dest mask)
inband (1 for finding pixels in [lower, upper];
0 for finding pixels in [0, lower) union (upper, 255])
usecmap (1 to retain cmap values; 0 to convert to gray)
Return: pixd (1 bpp), or null on error
Notes:
(1) Generates a 1 bpp mask pixd, the same size as pixs, where
the fg pixels in the mask are those either within the specified
band (for inband == 1) or outside the specified band
(for inband == 0).
(2) If pixs is colormapped, @usecmap determines if the colormap
values are used, or if the colormap is removed to gray and
the gray values are used. For the latter, it generates
an approximate grayscale value for each pixel, and then looks
for gray pixels with the value @val.
pixGenerateMaskByBand32
PIX * pixGenerateMaskByBand32 ( PIX *pixs, l_uint32 refval, l_int32 delm, l_int32 delp )
pixGenerateMaskByBand32()
Input: pixs (32 bpp)
refval (reference rgb value)
delm (max amount below the ref value for any component)
delp (max amount above the ref value for any component)
Return: pixd (1 bpp), or null on error
Notes:
(1) Generates a 1 bpp mask pixd, the same size as pixs, where
the fg pixels in the mask are those where each component
is within -delm to +delp of the reference value.
pixGenerateMaskByDiscr32
PIX * pixGenerateMaskByDiscr32 ( PIX *pixs, l_uint32 refval1, l_uint32 refval2, l_int32 distflag )
pixGenerateMaskByDiscr32()
Input: pixs (32 bpp)
refval1 (reference rgb value)
refval2 (reference rgb value)
distflag (L_MANHATTAN_DISTANCE, L_EUCLIDEAN_DISTANCE)
Return: pixd (1 bpp), or null on error
Notes:
(1) Generates a 1 bpp mask pixd, the same size as pixs, where
the fg pixels in the mask are those where the pixel in pixs
is "closer" to refval1 than to refval2.
(2) "Closer" can be defined in several ways, such as:
- manhattan distance (L1)
- euclidean distance (L2)
- majority vote of the individual components
Here, we have a choice of L1 or L2.
pixGenerateMaskByValue
PIX * pixGenerateMaskByValue ( PIX *pixs, l_int32 val, l_int32 usecmap )
pixGenerateMaskByValue()
Input: pixs (2, 4 or 8 bpp, or colormapped)
val (of pixels for which we set 1 in dest)
usecmap (1 to retain cmap values; 0 to convert to gray)
Return: pixd (1 bpp), or null on error
Notes:
(1) @val is the pixel value that we are selecting. It can be
either a gray value or a colormap index.
(2) If pixs is colormapped, @usecmap determines if the colormap
index values are used, or if the colormap is removed to gray and
the gray values are used. For the latter, it generates
an approximate grayscale value for each pixel, and then looks
for gray pixels with the value @val.
pixGrayQuantFromCmap
PIX * pixGrayQuantFromCmap ( PIX *pixs, PIXCMAP *cmap, l_int32 mindepth )
pixGrayQuantFromCmap()
Input: pixs (8 bpp grayscale without cmap)
cmap (to quantize to; of dest pix)
mindepth (minimum depth of pixd: can be 2, 4 or 8 bpp)
Return: pixd (2, 4 or 8 bpp, colormapped), or null on error
Notes:
(1) In use, pixs is an 8 bpp grayscale image without a colormap.
If there is an existing colormap, a warning is issued and
a copy of the input pixs is returned.
pixGrayQuantFromHisto
PIX * pixGrayQuantFromHisto ( PIX *pixd, PIX *pixs, PIX *pixm, l_float32 minfract, l_int32 maxsize )
pixGrayQuantFromHisto()
Input: pixd (<optional> quantized pix with cmap; can be null)
pixs (8 bpp gray input pix; not cmapped)
pixm (<optional> mask over pixels in pixs to quantize)
minfract (minimum fraction of pixels in a set of adjacent
histo bins that causes the set to be automatically
set aside as a color in the colormap; must be
at least 0.01)
maxsize (maximum number of adjacent bins allowed to represent
a color, regardless of the population of pixels
in the bins; must be at least 2)
Return: pixd (8 bpp, cmapped), or null on error
Notes:
(1) This is useful for quantizing images with relatively few
colors, but which may have both color and gray pixels.
If there are color pixels, it is assumed that an input
rgb image has been color quantized first so that:
- pixd has a colormap describing the color pixels
- pixm is a mask over the non-color pixels in pixd
- the colormap in pixd, and the color pixels in pixd,
have been repacked to go from 0 to n-1 (n colors)
If there are no color pixels, pixd and pixm are both null,
and all pixels in pixs are quantized to gray.
(2) A 256-entry histogram is built of the gray values in pixs.
If pixm exists, the pixels contributing to the histogram are
restricted to the fg of pixm. A colormap and LUT are generated
from this histogram. We break up the array into a set
of intervals, each one constituting a color in the colormap:
An interval is identified by summing histogram bins until
either the sum equals or exceeds the @minfract of the total
number of pixels, or the span itself equals or exceeds @maxsize.
The color of each bin is always an average of the pixels
that constitute it.
(3) Note that we do not specify the number of gray colors in
the colormap. Instead, we specify two parameters that
describe the accuracy of the color assignments; this and
the actual image determine the number of resulting colors.
(4) If a mask exists and it is not the same size as pixs, make
a new mask the same size as pixs, with the original mask
aligned at the UL corners. Set all additional pixels
in the (larger) new mask set to 1, causing those pixels
in pixd to be set as gray.
(5) We estimate the total number of colors (color plus gray);
if it exceeds 255, return null.
pixThresholdGrayArb
PIX * pixThresholdGrayArb ( PIX *pixs, const char *edgevals, l_int32 outdepth, l_int32 use_average, l_int32 setblack, l_int32 setwhite )
pixThresholdGrayArb()
Input: pixs (8 bpp grayscale; can have colormap)
edgevals (string giving edge value of each bin)
outdepth (0, 2, 4 or 8 bpp; 0 is default for min depth)
use_average (1 if use the average pixel value in colormap)
setblack (1 if darkest color is set to black)
setwhite (1 if lightest color is set to white)
Return: pixd (2, 4 or 8 bpp quantized image with colormap),
or null on error
Notes:
(1) This function allows exact specification of the quantization bins.
The string @edgevals is a space-separated set of values
specifying the dividing points between output quantization bins.
These threshold values are assigned to the bin with higher
values, so that each of them is the smallest value in their bin.
(2) The output image (pixd) depth is specified by @outdepth. The
number of bins is the number of edgevals + 1. The
relation between outdepth and the number of bins is:
outdepth = 2 nbins <= 4
outdepth = 4 nbins <= 16
outdepth = 8 nbins <= 256
With @outdepth == 0, the minimum required depth for the
given number of bins is used.
The output pixd has a colormap.
(3) The last 3 args determine the specific values that go into
the colormap.
(4) For @use_average:
- if TRUE, the average value of pixels falling in the bin is
chosen as the representative gray value. Otherwise,
- if FALSE, the central value of each bin is chosen as
the representative value.
The colormap holds the representative value.
(5) For @setblack, if TRUE the darkest color is set to (0,0,0).
(6) For @setwhite, if TRUE the lightest color is set to (255,255,255).
(7) An alternative to using this function to quantize to
unequally-spaced bins is to first transform the 8 bpp pixs
using pixGammaTRC(), and follow this with pixThresholdTo4bpp().
pixThresholdOn8bpp
PIX * pixThresholdOn8bpp ( PIX *pixs, l_int32 nlevels, l_int32 cmapflag )
pixThresholdOn8bpp()
Input: pixs (8 bpp, can have colormap)
nlevels (equally spaced; must be between 2 and 256)
cmapflag (1 to build colormap; 0 otherwise)
Return: pixd (8 bpp, optionally with colormap), or null on error
Notes:
(1) Valid values for nlevels is the set {2,...,256}.
(2) Any colormap on the input pixs is removed to 8 bpp grayscale.
(3) If cmapflag == 1, a colormap of size 'nlevels' is made,
and the pixel values in pixs are replaced by their
appropriate color indices. Otherwise, the pixel values
are the actual thresholded (i.e., quantized) grayscale values.
(4) If you don't want the thresholding to be equally spaced,
first transform the input 8 bpp src using pixGammaTRC().
pixThresholdTo2bpp
PIX * pixThresholdTo2bpp ( PIX *pixs, l_int32 nlevels, l_int32 cmapflag )
pixThresholdTo2bpp()
Input: pixs (8 bpp)
nlevels (equally spaced; must be between 2 and 4)
cmapflag (1 to build colormap; 0 otherwise)
Return: pixd (2 bpp, optionally with colormap), or null on error
Notes:
(1) Valid values for nlevels is the set {2, 3, 4}.
(2) Any colormap on the input pixs is removed to 8 bpp grayscale.
(3) This function is typically invoked with cmapflag == 1.
In the situation where no colormap is desired, nlevels is
ignored and pixs is thresholded to 4 levels.
(4) The target output colors are equally spaced, with the
darkest at 0 and the lightest at 255. The thresholds are
chosen halfway between adjacent output values. A table
is built that specifies the mapping from src to dest.
(5) If cmapflag == 1, a colormap of size 'nlevels' is made,
and the pixel values in pixs are replaced by their
appropriate color indices. The number of holdouts,
4 - nlevels, will be between 0 and 2.
(6) If you don't want the thresholding to be equally spaced,
either first transform the 8 bpp src using pixGammaTRC().
or, if cmapflag == 1, after calling this function you can use
pixcmapResetColor() to change any individual colors.
(7) If a colormap is generated, it will specify (to display
programs) exactly how each level is to be represented in RGB
space. When representing text, 3 levels is far better than
2 because of the antialiasing of the single gray level,
and 4 levels (black, white and 2 gray levels) is getting
close to the perceptual quality of a (nearly continuous)
grayscale image. With 2 bpp, you can set up a colormap
and allocate from 2 to 4 levels to represent antialiased text.
Any left over colormap entries can be used for coloring regions.
For the same number of levels, the file size of a 2 bpp image
is about 10% smaller than that of a 4 bpp result for the same
number of levels. For both 2 bpp and 4 bpp, using 4 levels you
get compression far better than that of jpeg, because the
quantization to 4 levels will remove the jpeg ringing in the
background near character edges.
pixThresholdTo4bpp
PIX * pixThresholdTo4bpp ( PIX *pixs, l_int32 nlevels, l_int32 cmapflag )
pixThresholdTo4bpp()
Input: pixs (8 bpp, can have colormap)
nlevels (equally spaced; must be between 2 and 16)
cmapflag (1 to build colormap; 0 otherwise)
Return: pixd (4 bpp, optionally with colormap), or null on error
Notes:
(1) Valid values for nlevels is the set {2, ... 16}.
(2) Any colormap on the input pixs is removed to 8 bpp grayscale.
(3) This function is typically invoked with cmapflag == 1.
In the situation where no colormap is desired, nlevels is
ignored and pixs is thresholded to 16 levels.
(4) The target output colors are equally spaced, with the
darkest at 0 and the lightest at 255. The thresholds are
chosen halfway between adjacent output values. A table
is built that specifies the mapping from src to dest.
(5) If cmapflag == 1, a colormap of size 'nlevels' is made,
and the pixel values in pixs are replaced by their
appropriate color indices. The number of holdouts,
16 - nlevels, will be between 0 and 14.
(6) If you don't want the thresholding to be equally spaced,
either first transform the 8 bpp src using pixGammaTRC().
or, if cmapflag == 1, after calling this function you can use
pixcmapResetColor() to change any individual colors.
(7) If a colormap is generated, it will specify, to display
programs, exactly how each level is to be represented in RGB
space. When representing text, 3 levels is far better than
2 because of the antialiasing of the single gray level,
and 4 levels (black, white and 2 gray levels) is getting
close to the perceptual quality of a (nearly continuous)
grayscale image. Therefore, with 4 bpp, you can set up a
colormap, allocate a relatively small fraction of the 16
possible values to represent antialiased text, and use the
other colormap entries for other things, such as coloring
text or background. Two other reasons for using a small number
of gray values for antialiased text are (1) PNG compression
gets worse as the number of levels that are used is increased,
and (2) using a small number of levels will filter out most of
the jpeg ringing that is typically introduced near sharp edges
of text. This filtering is partly responsible for the improved
compression.
pixThresholdToBinary
PIX * pixThresholdToBinary ( PIX *pixs, l_int32 thresh )
pixThresholdToBinary()
Input: pixs (4 or 8 bpp)
threshold value
Return: pixd (1 bpp), or null on error
Notes:
(1) If the source pixel is less than the threshold value,
the dest will be 1; otherwise, it will be 0
pixVarThresholdToBinary
PIX * pixVarThresholdToBinary ( PIX *pixs, PIX *pixg )
pixVarThresholdToBinary()
Input: pixs (8 bpp)
pixg (8 bpp; contains threshold values for each pixel)
Return: pixd (1 bpp), or null on error
Notes:
(1) If the pixel in pixs is less than the corresponding pixel
in pixg, the dest will be 1; otherwise it will be 0.
AUTHOR
Zakariyya Mughal <zmughal@cpan.org>
COPYRIGHT AND LICENSE
This software is copyright (c) 2014 by Zakariyya Mughal.
This is free software; you can redistribute it and/or modify it under the same terms as the Perl 5 programming language system itself.