Нормализуйте гистограмму (яркость и контрастность) набора изображений с помощью библиотеки изображений Python (PIL) - PullRequest
10 голосов
/ 19 августа 2011

У меня есть скрипт, который использует 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 ]

6 голосов
/ 24 августа 2011

Вероятно, вы ищете утилиту, которая выполняет "растяжение гистограммы". Вот одна реализация .Я уверен, что есть другие.Я думаю, что вы хотите сохранить исходный оттенок и применить эту функцию равномерно ко всем цветным полосам.

Конечно, есть хороший шанс, что некоторые плитки будут иметь заметный разрыв в уровне, к которому они присоединяются.Однако избежание этого потребовало бы пространственной интерполяции параметров «растяжения» и является гораздо более сложным решением.(... но было бы хорошим упражнением, если в этом есть необходимость.)

Редактировать:

Вот настройка, которая сохраняет оттенок изображения:

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)
2 голосов
/ 01 июля 2016

Следующий код работает на изображениях с микроскопа (которые похожи), чтобы подготовить их до сшивания.Я использовал его на тестовом наборе из 20 изображений с приемлемыми результатами.

Функция средней яркости взята из другого Вопрос Stackoverflow .

from PIL import Image
from PIL import ImageStat
import math

# function to return average brightness of an image
# Source: /3916949/kakovy-nekotorye-metody-analiza-yarkosti-izobrazheniya-s-pomoschy-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
...