Python: Normalize image exposure

后端 未结 3 550
梦谈多话
梦谈多话 2021-02-06 04:38

I\'m working on a project to measure and visualize image similarity. The images in my dataset come from photographs of images in books, some of which have very high or low expos

相关标签:
3条回答
  • 2021-02-06 05:20

    Histogram equalisation works surprisingly well for this kind of thing. It's usually better for photographic images, but it's helpful even on line art, as long as there are some non-black/white pixels.

    It works well for colour images too: split the bands up, equalize each one separately, and recombine.

    I tried on your sample image:

    Using libvips:

    $ vips hist_equal sample.jpg x.jpg
    

    Or from Python with pyvips:

    x = pyvips.Image.new_from_file("sample.jpg")
    x = x.hist_equal()
    x.write_to_file("x.jpg")
    
    0 讨论(0)
  • 2021-02-06 05:34

    I ended up using a numpy implementation of the histogram normalization method @user894763 pointed out. Just save the below as normalize.py then you can call:

    python normalize.py cats.jpg

    Script:

    import numpy as np
    from scipy.misc import imsave
    from scipy.ndimage import imread
    import sys
    
    def get_histogram(img):
      '''
      calculate the normalized histogram of an image
      '''
      height, width = img.shape
      hist = [0.0] * 256
      for i in range(height):
        for j in range(width):
          hist[img[i, j]]+=1
      return np.array(hist)/(height*width)
    
    def get_cumulative_sums(hist):
      '''
      find the cumulative sum of a numpy array
      '''
      return [sum(hist[:i+1]) for i in range(len(hist))]
    
    def normalize_histogram(img):
      # calculate the image histogram
      hist = get_histogram(img)
      # get the cumulative distribution function
      cdf = np.array(get_cumulative_sums(hist))
      # determine the normalization values for each unit of the cdf
      sk = np.uint8(255 * cdf)
      # normalize the normalization values
      height, width = img.shape
      Y = np.zeros_like(img)
      for i in range(0, height):
        for j in range(0, width):
          Y[i, j] = sk[img[i, j]]
      # optionally, get the new histogram for comparison
      new_hist = get_histogram(Y)
      # return the transformed image
      return Y
    
    img = imread(sys.argv[1])
    normalized = normalize_histogram(img)
    imsave(sys.argv[1] + '-normalized.jpg', normalized)
    

    Output:

    0 讨论(0)
  • 2021-02-06 05:37

    It's very hard to say if it will work for you without seeing a larger sample of your images, but you may find an "auto-gamma" useful. There is one built into ImageMagick and the description - so that you can calculate it yourself - is:

    Automagically adjust gamma level of image.

    This calculates the mean values of an image, then applies a calculated -gamma adjustment so that the mean color in the image will get a value of 50%.

    This means that any solid 'gray' image becomes 50% gray.

    This works well for real-life images with little or no extreme dark and light areas, but tend to fail for images with large amounts of bright sky or dark shadows. It also does not work well for diagrams or cartoon like images.

    You can try it out yourself on the command line very simply before you go and spend a lot of time coding something that may not work:

    convert Tribunal.jpg -auto-gamma result.png
    

    You can do -auto-level as per your own code beforehand, and a thousand other things too:

    convert Tribunal.jpg -auto-level -auto-gamma result.png
    
    0 讨论(0)
提交回复
热议问题