Normalize the histogram (brightness and contrast) of an image set using the Python Image Library (PIL)

I have a script that uses the Google Maps API to load a sequence of images with a square satellite of equal size and creates a PDF file. Images need to be rotated in advance, and I'm already doing this with PIL.

I noticed that due to different lighting conditions and terrain, some images are too bright, others are too dark, and the resulting pdf ends up a little ugly, with less than ideal reading conditions "in the field" (which is a backcountry mountain bike where I want to have printed sketch of specific intersections).

(EDIT) The goal is to make all images equally pronounced and contrasting. Thus, images that are too bright should be darkened, and dark ones should be illuminated. (by the way, I once used imagemagick autocontrast , or auto-gamma , or equalize , or autolevel , or something like that, with interesting results in medical images, but I don’t know how to make any of them in PIL).

I already used some image adjustments after converting to grayscale (with a grayscale printer), but the results were not good either. Here is my grayscale code:

 #!/usr/bin/python def myEqualize(im) im=im.convert('L') contr = ImageEnhance.Contrast(im) im = contr.enhance(0.3) bright = ImageEnhance.Brightness(im) im = bright.enhance(2) #im.show() return im 

This code works independently for each image. I wonder if it would be better to first analyze all the images, and then "normalize" their visual properties (contrast, brightness, gamma, etc.).

In addition, I think that it would be necessary to perform some analysis on the image (histogram?) In order to apply custom correction depending on each image, and not equal correction for all of them (although any “gain” function implicitly considers the initial conventions )

Has anyone had such a problem and / or had a good alternative to do this with color images (no shades of gray)?

Any help would be appreciated, thanks for reading!

+8
python image-processing python-imaging-library contrast brightness
source share
2 answers

What you are probably looking for is a utility that performs "histogram stretch". Here is one implementation . I am sure there are others. I think you want to keep the original hue and apply this function evenly in all color ranges.

Of course, there is a good chance that some of the fragments will have a noticeable gap in the level at which they join. However, avoiding this is due to spatial interpolation of the “stretch” parameters and is a much more attractive solution. (... but it would be a good exercise, if necessary.)

Edit:

Here is a setting that preserves the hue of the image:

 import operator def equalize(im): h = im.convert("L").histogram() lut = [] for b in range(0, len(h), 256): # step size step = reduce(operator.add, h[b:b+256]) / 255 # create equalization lookup table n = 0 for i in range(256): lut.append(n / step) n = n + h[i+b] # map image through lookup table return im.point(lut*im.layers) 
+4
source share

The following code works with microscope images (which are similar) to prepare them before stitching. I used it on a test set of 20 images with reasonable results.

The average luminance function is another question. Question about the stop stream .

 from PIL import Image from PIL import ImageStat import math # function to return average brightness of an image # Source: /questions/365004/what-are-some-methods-to-analyze-image-brightness-using-python def brightness(im_file): im = Image.open(im_file) stat = ImageStat.Stat(im) r,g,b = stat.mean return math.sqrt(0.241*(r**2) + 0.691*(g**2) + 0.068*(b**2)) #this is a way of averaging the rgb values to derive "human-visible" brightness myList = [0.0] deltaList = [0.0] b = 0.0 num_images = 20 # number of images # loop to auto-generate image names and run prior function for i in range(1, num_images + 1): # for loop runs from image number 1 thru 20 a = str(i) if len(a) == 1: a = '0' + str(i) # to follow the naming convention of files - 01.jpg, 02.jpg... 11.jpg etc. image_name = 'twenty/' + a + '.jpg' myList.append(brightness(image_name)) avg_brightness = sum(myList[1:])/num_images print myList print avg_brightness for i in range(1, num_images + 1): deltaList.append(i) deltaList[i] = avg_brightness - myList[i] print deltaList 

At this point, the “correction” values ​​(i.e. the difference between the value and the average value) are stored in deltaList. The next section applies this correction to all images one by one.

 for k in range(1, num_images + 1): # for loop runs from image number 1 thru 20 a = str(k) if len(a) == 1: a = '0' + str(k) # to follow the naming convention of files - 01.jpg, 02.jpg... 11.jpg etc. image_name = 'twenty/' + a + '.jpg' img_file = Image.open(image_name) img_file = img_file.convert('RGB') # converts image to RGB format pixels = img_file.load() # creates the pixel map for i in range (img_file.size[0]): for j in range (img_file.size[1]): r, g, b = img_file.getpixel((i,j)) # extracts rgb values for the ixj th pixel pixels[i,j] = (r+int(deltaList[k]), g+int(deltaList[k]), b+int(deltaList[k])) # re-creates the image j = str(k) new_image_name = 'twenty/' +'image' + j + '.jpg' # creates a new filename img_file.save(new_image_name) # saves output to new file name 
+1
source share

All Articles