Нормализуйте гистограмму (яркость и контрастность) набора изображений с помощью библиотеки изображений Python (PIL)
У меня есть скрипт, который использует Google Maps API для загрузки последовательности спутниковых изображений квадратного размера одинакового размера и создает PDF. Изображения должны быть повернуты заранее, и я уже делаю это, используя PIL.
Я заметил, что из-за различных условий освещенности и рельефа некоторые изображения слишком яркие, другие слишком темные, и полученный PDF-файл получается немного уродливым с неидеальными условиями чтения "в поле" (что является бэккантри катание на горных велосипедах, где я хочу иметь распечатанный эскиз конкретных перекрестков).
(РЕДАКТИРОВАТЬ) Тогда цель состоит в том, чтобы все изображения имели одинаковую видимую яркость и контраст. Таким образом, слишком яркие изображения должны быть затемнены, а темные должны быть осветлены. (кстати, я когда-то использовал imagemagick autocontrast
, или же auto-gamma
, или же equalize
, или же autolevel
или что-то в этом роде, с интересными результатами на медицинских снимках, но не знаю, как это сделать в PIL).
Я уже использовал некоторые исправления изображений после преобразования в оттенки серого (у меня был принтер в оттенках серого некоторое время назад), но результаты также были не очень хорошими. Вот мой код в градациях серого:
#!/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
Этот код работает независимо для каждого изображения. Интересно, будет ли лучше сначала проанализировать все изображения, а затем "нормализовать" их визуальные свойства (контраст, яркость, гамма и т. Д.).
Кроме того, я думаю, что было бы необходимо выполнить некоторый анализ изображения (гистограмма?), Чтобы применить пользовательскую коррекцию в зависимости от каждого изображения, а не одинаковую коррекцию для всех из них (хотя любая функция "улучшения" неявно учитывает начальные условия).
У кого-нибудь была такая проблема и / или есть ли хорошая альтернатива для этого с цветными изображениями (без оттенков серого)?
Любая помощь будет оценена, спасибо за чтение!
2 ответа
Вероятно, вы ищете утилиту, которая выполняет "растяжение гистограммы". Вот одна из реализаций. Я уверен, что есть другие. Я думаю, что вы хотите сохранить исходный оттенок и применить эту функцию равномерно по всем цветным полосам.
Конечно, есть хороший шанс, что некоторые из плиток будут иметь заметный разрыв в уровне, на котором они соединяются. Однако избежание этого потребовало бы пространственной интерполяции параметров "растяжения" и является гораздо более сложным решением. (... но было бы хорошим упражнением, если есть такая необходимость.)
Редактировать:
Вот твик, который сохраняет оттенок изображения:
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)
Следующий код работает с изображениями с микроскопа (которые похожи), чтобы подготовить их перед сшиванием. Я использовал его на тестовом наборе из 20 изображений с приемлемыми результатами.
Функция усреднения яркости - из другого вопроса Stackru.
from PIL import Image
from PIL import ImageStat
import math
# function to return average brightness of an image
# Source: https://stackru.com/questions/3490727/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 r g b 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
В этот момент значения "коррекции" (т.е. разница между значением и средним значением) сохраняются в deltaList. В следующем разделе это исправление применяется ко всем изображениям по одному.
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 r g b values for the i x j 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