我正在开展一个测量和可视化图像相似性的项目。我的数据集中的图像来自书籍中的图像照片,其中一些图像的曝光率非常高或很低。例如,下面的图片来自两本不同的书;顶部的那个是底部的那个曝光重印,其中曝光看起来很好:
我希望将每张图片的曝光标准化为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的图像。
是否有一种简单的方法来标准化图像的曝光,例如上面的顶部图像?我很感激别人可以就这个问题提出的任何想法。
答案 0 :(得分:6)
很难说如果没有看到更大的图片样本,它是否适合您,但您可能会发现" auto-gamma" 有用。有一个内置于 ImageMagick 和描述 - 以便您可以自己计算 - 是:
自动调整图像的伽玛级别。
计算图像的平均值,然后应用计算值 -gamma调整,以使图像中的平均颜色值达到50%。
这意味着任何坚实的灰色'图像变为50%灰色。
这适用于极少或没有极端黑暗的真实图像 和亮区,但对于大量的图像往往会失败 明亮的天空或黑暗的阴影。它也不适用于图表或 卡通像图像。
您可以在开始之前在命令行上自行尝试,并花费大量时间编写可能不起作用的内容:
convert Tribunal.jpg -auto-gamma result.png
您可以事先根据自己的代码执行-auto-level
,也a thousand other things:
convert Tribunal.jpg -auto-level -auto-gamma result.png
答案 1 :(得分:5)
Histogram equalisation对于这种事情的效果非常好。它通常对于摄影图像更好,但即使在线条艺术上也是如此,只要有一些非黑/白像素。
它也适用于彩色图像:将条带分开,分别均衡每个条带,并重新组合。
我尝试了你的示例图片:
使用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)
输出: