From: Tony Cook Date: Sun, 21 Feb 2016 00:45:43 +0000 (+1100) Subject: [rt #111871] re-work autolevels X-Git-Tag: v1.004_001~23 X-Git-Url: http://git.imager.perl.org/imager.git/commitdiff_plain/aef782f2f3bdef30991a1782e5c00b70dbcaba77 [rt #111871] re-work autolevels - avoid an off-by-one error when calculating the minimum and maximum levels from the histogram - optimize 8-bit images by using a lookup table instead of doing a floating point multiply for each sample --- diff --git a/MANIFEST b/MANIFEST index e8dd2560..41825da4 100644 --- a/MANIFEST +++ b/MANIFEST @@ -360,6 +360,7 @@ t/350-font/030-ttoo.t OO level FT1 tests t/350-font/040-ttstd.t Standard font tests for TT t/350-font/100-texttools.t Test text wrapping t/400-filter/010-filters.t Consolidated filter tests (needs to split) +t/400-filter/020-autolevels.t Test the autolevels filter t/450-api/100-inline.t Inline::C integration and API t/450-api/110-inlinectx.t context APIs t/850-thread/010-base.t Test wrt to perl threads diff --git a/filters.im b/filters.im index 081072f2..ee4f5d8a 100644 --- a/filters.im +++ b/filters.im @@ -696,34 +696,47 @@ i_autolevels_mono(i_img *im, float lsat, float usat) { } min_lum = 0; - max_lum = 255; - - lower_accum = upper_accum = 0; - - for(i=0; i<256; i++) { - lower_accum += hist[i]; + lower_accum = 0; + for (i = 0; i < 256; ++i) { if (lower_accum < sum_lum * lsat) min_lum = i; + lower_accum += hist[i]; + } - upper_accum += hist[255-i]; + max_lum = 255; + upper_accum = 0; + for(i = 255; i >= 0; i--) { if (upper_accum < sum_lum * usat) - max_lum = 255-i; + max_lum = i; + upper_accum += hist[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; + i_sample_t lookup[256]; #else IM_WORK_T low = min_lum / 255.0 * IM_SAMPLE_MAX; #endif double scale = 255.0 / (max_lum - min_lum); +#ifdef IM_EIGHT_BIT + for (i = 0; i < 256; ++i) { + IM_WORK_T tmp = (i - low) * scale; + lookup[i] = IM_LIMIT(tmp); + } +#endif + 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) { +#ifdef IM_EIGHT_BIT + srow[i] = lookup[srow[i]]; +#else IM_WORK_T tmp = (srow[i] - low) * scale; srow[i] = IM_LIMIT(tmp); +#endif } IM_PSAMP(im, 0, im->xsize, y, srow, NULL, color_channels); } diff --git a/t/400-filter/020-autolevels.t b/t/400-filter/020-autolevels.t new file mode 100644 index 00000000..c8f3f951 --- /dev/null +++ b/t/400-filter/020-autolevels.t @@ -0,0 +1,38 @@ +#!perl -w +use strict; +use Imager; +use Test::More tests => 4; +use Imager::Test qw(is_image); + +-d "testout" or mkdir "testout"; + +Imager->open_log(log => "testout/filters-autolev.log"); + +my $base = Imager->new(xsize => 10, ysize => 10); +$base->box(filled => 1, xmax => 4, color => "404040"); +$base->box(filled => 1, xmin => 5, color => "C0C0C0"); + +{ + my $cmp = Imager->new(xsize => 10, ysize => 10); + $cmp->box(filled => 1, xmax => 4, color => "#000"); + $cmp->box(filled => 1, xmin => 5, color => "#FFF"); + + { + my $work = $base->copy; + #$work->write(file => "testout/autolevel-base.ppm"); + ok($work->filter(type => "autolevels"), "default autolevels"); + #$work->write(file => "testout/autolevel-filtered.ppm"); + #$cmp->write(file => "testout/autolevel-cmp.ppm"); + is_image($work, $cmp, "check we got expected image"); + } + + { + my $work = $base->to_rgb_double; + ok($work->filter(type => "autolevels"), "default autolevels (double)"); + is_image($work, $cmp, "check we got expected image"); + $work->write(file => "testout/autolevel-filtered.ppm", pnm_write_wide_data => 1); + } +} + + +Imager->close_log;