Home | Works | About

ImageAdjuster Banner

ImageAdjuster


Description

ImageAdjuster is a library for Processing. It's purpose is to perform brightness, contrast, gamma and other such adjustments on images. It contains both high-level and low-level routines, and can be extended via user-defined transformations. The high-level routines allow for simple basic adjustments, while the low-level routines allow for complex and high-performance adjustments. The low-level routines are particularly well-suited to video applications where a constant adjustment is to be applied to every frame. Various adjustments may be concatenated, in much the same way that a 3-D transform matrix is, and applied in a single operation. Adjustments can be performed on an entire image or limited to a rectangular region within the image.

Download

Version 0.04: imageadjuster004.zip (280K)

Contains precompiled library, installation instructions, java docs, source code for all demos and the library itself.

Demo Applets

Intended to be studied as examples in order of increasing complexity:

demo01

01
Simple Brightness
200 x 200

demo02

02
Simple Contrast
200 x 200

demo03

03
Simple Gamma
200 x 200

demo04

04
Simple Combo
200 x 200

demo05

05
Advanced Combo
200 x 200

demo06

06
Accumulation
200 x 200

demo07

07
User Defined
Invert/Negate
200 x 200

demo08

08
User Defined
Posterize
200 x 200

demo09

09
User Defined
Advanced Posterize
200 x 200

demo10

10
Get/Set as Push/Pop
200 x 200

demo11

11
Extreme Adjusting
200 x 200

demo12

12
Animation
200 x 200


Lookup Table "Recipes"

For those using the low-level lookup table routines -- A few handy formulae to accomplish some other common image processing routines. (Negate and Posterize are already shown above in demos 7 & 8, in case you missed them) This collection is likely to change, but here's what's available so far:

lut01

LUT 01
Threshold
200 x 200

lut02

LUT 02
Solarize
200 x 200

lut03

LUT 03
Sigmoid
200 x 200


Extending The Base Class

Once you have a "recipe" that you find yourself using often, it may be beneficial to extend the base class with that operation rather than manually recreating the lookup table each time you wish to use it. Here's a quick demo of extending the base class to support the posterize() operation. The same concepts could be used to implement any of the above "recipes" or your own user-defined adjustments. (of course you could also just recompile the library source with your new functionality, but I figure that those who would take that approach are probably advanced enough to not need need a demo)

ext01

EXT 01
Posterize
200 x 200


FAQ

Q: Can't I already do this sort of stuff by manipulating the pixels array?

A: Sure, that's essentially all that this library is doing. But why reinvent the wheel? Here it is, already done for you. Plus you'll get the advantage of being able to concatenate multiple adjustments into a single operation for high-performance applications. Enjoy.

Q: Can't I already do invert/posterize like demos 7/8 with filter()?

A: Sure. Those operations are simply examples of user-defined adjustments, you may just as easily create other operations that aren't currently implemented in filter(). Or see demos 9 and 11 for uses of invert/posterize operations in combination with other operations that filter() doesn't support.

Q: Why aren't posterize/negate/threshold/solarize or any of the other "recipes" included in the base class?

A: To simplify the base class. Since not everyone will likely need all of those esoteric operations, it seemed best to build in only the most generic operations (brightness, contrast, gamma) and provide an easy mechanism to use custom lookup tables and/or extend the class as needed.

Q: Why are brightness values specified from [0..1] instead of [0..255] or the current colorMode range?

A: To maintain consistency and accuracy. While it might make sense to specify brightness adjustments in +/- [0..255], those values don't make any sense for contrast or gamma. So all values are represented internally at a scale where 1.0 equals unity. Also, limiting the range to 256 integer values unnecessarily limits accuracy - when concatenating adjustments, floating point values are used internally and thus can represent non-integer values to maintain intermediate precision, until the final rounding occurs when applying the adjustment. For example, you can easily request a brightness adjustment of 0.3 -- a value that cannot be well-represented by an integer in [0..255].

Q: Why did the code blow up when I passed it a null image?

A: To avoid cluttering the code with endless error-handling. Some of the more subtle errors are trapped or handled in some way, such as passing bad user-defined lookup tables or gamma values of 0.0 (which imply a division by zero). But assuring that valid images are passed to the routines is left as a responsibility of the user.

 

Creative Commons License

© 2006 Dave Bollinger