Python:规范化图像曝光

时间:2018-03-29 00:21:27

标签: python image image-processing

我正在开展一个测量和可视化图像相似性的项目。我的数据集中的图像来自书籍中的图像照片,其中一些图像的曝光率非常高或很低。例如,下面的图片来自两本不同的书;顶部的那个是底部的那个曝光重印,其中曝光看起来很好:

enter image description here enter image description here

我希望将每张图片的曝光标准化为Python。我想我可以使用以下天真的方法来做到这一点,它试图将每个像素值置于0到255之间:

from scipy.ndimage import imread
import sys

def normalize(img):
  '''
  Normalize the exposure of an image.
  @args:
    {numpy.ndarray} img: an array of image pixels with shape:
      (height, width)
  @returns:
    {numpy.ndarray} an image with shape of `img` wherein
      all values are normalized such that the min=0 and max=255
  '''
  _min = img.min()
  _max = img.max()
  return img - _min * 255 / (_max - _min)

img = imread(sys.argv[1])
normalized = normalize(img)

只有在运行之后我才意识到这种规范化只会帮助最轻值小于255或最暗值大于0的图像。

是否有一种简单的方法来标准化图像的曝光,例如上面的顶部图像?我很感激别人可以就这个问题提出的任何想法。

3 个答案:

答案 0 :(得分:6)

很难说如果没有看到更大的图片样本,它是否适合您,但您可能会发现" auto-gamma" 有用。有一个内置于 ImageMagick 和描述 - 以便您可以自己计算 - 是:

  

自动调整图像的伽玛级别。

     

计算图像的平均值,然后应用计算值   -gamma调整,以使图像中的平均颜色值达到50%。

     

这意味着任何坚实的灰色'图像变为50%灰色。

     

这适用于极少或没有极端黑暗的真实图像   和亮区,但对于大量的图像往往会失败   明亮的天空或黑暗的阴影。它也不适用于图表或   卡通像图像。

您可以在开始之前在命令行上自行尝试,并花费大量时间编写可能不起作用的内容:

convert Tribunal.jpg -auto-gamma result.png

enter image description here

您可以事先根据自己的代码执行-auto-level,也a thousand other things

convert Tribunal.jpg -auto-level -auto-gamma result.png

答案 1 :(得分:5)

Histogram equalisation对于这种事情的效果非常好。它通常对于摄影图像更好,但即使在线条艺术上也是如此,只要有一些非黑/白像素。

它也适用于彩色图像:将条带分开,分别均衡每个条带,并重新组合。

我尝试了你的示例图片:

after hist equal

使用libvips

$ vips hist_equal sample.jpg x.jpg

答案 2 :(得分:1)

我最终使用直方图规范化方法@ user894763指出的numpy实现。只需将以下内容保存为normalize.py即可调用:

python normalize.py cats.jpg

脚本:

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)

输出:

enter image description here