I want to adjust the colour levels of an image in python. I can use any python library that can easily be installed on my Ubuntu desktop. I want to do the same as ImageMagick's -level
( http://www.imagemagick.org/www/command-line-options.html#level ). PIL (Python Image Library) doesn't seem to have it. I have been calling convert
on the image and then reading in the file back again, but that seems wasteful. Is there a better / faster way?
views:
58answers:
2
+2
A:
Why not use PythonMagick? It's a Python interface to Image Magick.
Niki Yoshiuchi
2010-06-23 21:17:03
+2
A:
If I understood correctly the -level
option of ImageMagick, then the level_image
function I provide should do what you want.
Two things to note:
- the speed definitely can be improved
- it currently only works with RGB images
- the algorithm goes through the HSV colorspace, and affects only the V (brightness) component
The code:
import colorsys
class Level(object):
def __init__(self, minv, maxv, gamma):
self.minv= minv/255.0
self.maxv= maxv/255.0
self._interval= self.maxv - self.minv
self._invgamma= 1.0/gamma
def new_level(self, value):
if value <= self.minv: return 0.0
if value >= self.maxv: return 1.0
return ((value - self.minv)/self._interval)**self._invgamma
def convert_and_level(self, band_values):
h, s, v= colorsys.rgb_to_hsv(*(i/255.0 for i in band_values))
new_v= self.new_level(v)
return tuple(int(255*i)
for i
in colorsys.hsv_to_rgb(h, s, new_v))
def level_image(image, minv=0, maxv=255, gamma=1.0):
"""Level the brightness of image (a PIL.Image instance)
All values ≤ minv will become 0
All values ≥ maxv will become 255
gamma controls the curve for all values between minv and maxv"""
if image.mode != "RGB":
raise ValueError("this works with RGB images only")
new_image= image.copy()
leveller= Level(minv, maxv, gamma)
levelled_data= [
leveller.convert_and_level(data)
for data in image.getdata()]
new_image.putdata(levelled_data)
return new_image
If there is some way to do the RGB→HSV conversion (and vice versa) using PIL, then one can split into the H, S, V bands, use the .point
method of the V band and convert back to RGB, speeding up the process by a lot; however, I haven't found such a way.
ΤΖΩΤΖΙΟΥ
2010-06-26 20:32:52