callsub => sub { my %hsh=@_; i_hardinvertall($hsh{image}); }
};
- $filters{autolevels} ={
+ $filters{autolevels_skew} ={
callseq => ['image','lsat','usat','skew'],
defaults => { lsat=>0.1,usat=>0.1,skew=>0.0 },
callsub => sub { my %hsh=@_; i_autolevels($hsh{image},$hsh{lsat},$hsh{usat},$hsh{skew}); }
};
+ $filters{autolevels} ={
+ callseq => ['image','lsat','usat'],
+ defaults => { lsat=>0.1,usat=>0.1 },
+ callsub => sub { my %hsh=@_; i_autolevels_mono($hsh{image},$hsh{lsat},$hsh{usat}); }
+ };
+
$filters{turbnoise} ={
callseq => ['image'],
defaults => { xo=>0.0,yo=>0.0,scale=>10.0 },
float usat
float skew
+void
+i_autolevels_mono(im,lsat,usat)
+ Imager::ImgRaw im
+ float lsat
+ float usat
+
void
i_radnoise(im,xo,yo,rscale,ascale)
Imager::ImgRaw im
}
}
+/*
+=item i_autolevels_mono(im, lsat, usat)
+
+Do autolevels, but monochromatically.
+
+=cut
+*/
+
+void
+i_autolevels_mono(i_img *im, float lsat, float usat) {
+ i_color val;
+ i_img_dim i, x, y, hist[256];
+ i_img_dim sum_lum, min_lum, max_lum;
+ i_img_dim upper_accum, lower_accum;
+ i_color *row;
+ dIMCTXim(im);
+ int adapt_channels = im->channels == 4 ? 2 : 1;
+ int color_channels = i_img_color_channels(im);
+ i_img_dim color_samples = im->xsize * color_channels;
+
+
+ im_log((aIMCTX, 1,"i_autolevels_mono(im %p, lsat %f,usat %f)\n", im, lsat,usat));
+
+ /* build the histogram in 8-bits, unless the image has a very small
+ range it should make little difference to the result */
+ sum_lum = 0;
+ for (i = 0; i < 256; i++)
+ hist[i] = 0;
+
+ row = mymalloc(im->xsize * sizeof(i_color));
+ /* create histogram for each channel */
+ for (y = 0; y < im->ysize; y++) {
+ i_color *p = row;
+ i_glin(im, 0, im->xsize, y, row);
+ if (im->channels > 2)
+ i_adapt_colors(adapt_channels, im->channels, row, im->xsize);
+ for (x = 0; x < im->xsize; x++) {
+ hist[p->channel[0]]++;
+ ++p;
+ }
+ }
+ myfree(row);
+
+ for(i = 0; i < 256; i++) {
+ sum_lum += hist[i];
+ }
+
+ min_lum = 0;
+ max_lum = 255;
+
+ lower_accum = upper_accum = 0;
+
+ for(i=0; i<256; i++) {
+ lower_accum += hist[i];
+ if (lower_accum < sum_lum * lsat)
+ min_lum = i;
+
+ upper_accum += hist[255-i];
+ if (upper_accum < sum_lum * usat)
+ max_lum = 255-i;
+ }
+
+#code im->bits <= 8
+ IM_SAMPLE_T *srow = mymalloc(color_samples * sizeof(IM_SAMPLE_T));
+#ifdef IM_EIGHT_BIT
+ IM_WORK_T low = min_lum;
+#else
+ IM_WORK_T low = min_lum / 255.0 * IM_SAMPLE_MAX;
+#endif
+ IM_WORK_T scale = 255.0 / (max_lum - min_lum);
+
+ for(y = 0; y < im->ysize; y++) {
+ IM_GSAMP(im, 0, im->xsize, y, srow, NULL, color_channels);
+ for(i = 0; i < color_samples; ++i) {
+ IM_WORK_T tmp = (srow[i] - low) * scale;
+ srow[i] = IM_LIMIT(tmp);
+ }
+ IM_PSAMP(im, 0, im->xsize, y, srow, NULL, color_channels);
+ }
+ myfree(srow);
+#/code
+}
+
/*
=item i_autolevels(im, lsat, usat, skew)
usat - fraction of pixels that will be truncated at the higher end of the spectrum
skew - not used yet
+Note: this code calculates levels and adjusts each channel separately,
+which will typically cause a color shift.
+
=cut
*/
void i_mosaic(i_img *im,i_img_dim size);
void i_watermark(i_img *im,i_img *wmark,i_img_dim tx,i_img_dim ty,int pixdiff);
void i_autolevels(i_img *im,float lsat,float usat,float skew);
+void i_autolevels_mono(i_img *im,float lsat,float usat);
void i_radnoise(i_img *im,i_img_dim xo,i_img_dim yo,double rscale,double ascale);
void i_turbnoise(i_img *im,double xo,double yo,double scale);
void i_gradgen(i_img *im, int num, i_img_dim *xo, i_img_dim *yo, i_color *ival, int dmeasure);
Filter Arguments Default value
autolevels lsat 0.1
usat 0.1
+
+ autolevels_skew lsat 0.1
+ usat 0.1
skew 0
bumpmap bump lightx lighty
=item autolevels
-scales the value of each channel so that the values in the image will
+Scales the luminosity of the image so that the luminosity will cover
+the possible range for the image. C<lsat> and C<usat> truncate the
+range by the specified fraction at the top and bottom of the range
+respectively.
+
+ # increase contrast, losing little detail
+ $img->filter(type=>"autolevels")
+ or die $img->errstr;
+
+The method used here is typically called L<Histogram
+Equalization|http://en.wikipedia.org/wiki/Histogram_equalization>.
+
+=item autolevels_skew
+
+Scales the value of each channel so that the values in the image will
cover the whole possible range for the channel. C<lsat> and C<usat>
truncate the range by the specified fraction at the top and bottom of
the range respectively.
# increase contrast per channel, losing little detail
- $img->filter(type=>"autolevels")
+ $img->filter(type=>"autolevels_skew")
or die $img->errstr;
# increase contrast, losing 20% of highlight at top and bottom range
$img->filter(type=>"autolevels", lsat=>0.2, usat=>0.2)
or die $img->errstr;
+This filter was the original C<autolevels> filter, but it's typically
+useless due to the significant color skew it can produce.
+
=item bumpmap
uses the channel C<elevation> image C<bump> as a bump map on your
#!perl -w
use strict;
use Imager qw(:handy);
-use Test::More tests => 122;
+use Test::More tests => 124;
-d "testout" or mkdir "testout";
test($imbase, {type=>'autolevels'}, 'testout/t61_autolev.ppm');
+test($imbase, {type=>'autolevels_skew'}, 'testout/t61_autoskew.ppm');
+
test($imbase, {type=>'contrast', intensity=>0.5},
'testout/t61_contrast.ppm');