Как использовать слайдер уровней гамма / средних тонов в коде для изображения в градациях серого - PullRequest
0 голосов
/ 31 января 2019

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

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

Здесь R - это красное RGB-значение пикселей в моем изображении в виде массива, H - высокоевход и L низкий вход.Я начинаю с L = 0 и H = 255 и продолжаю передавать различные значения в функцию, пока возвращаемое изображение не будет иметь медиану 127 на гистограмме.

def get_levelcorrected_image(R,H,L):

    temp=((R-L)*255.0)/(H-L)
    temp[temp<0]=0
    temp[temp>255]=255
    temp[temp==255]=0    #added this line because for some reason there were a lot of white pixels where it should have been dark
    final = temp.astype('uint8')
    return final

Я попытался найти в документации gimp формулуза ползунком гаммы, и нашел код, который был похож на это.

  if (gray)
  {
  gdouble input;
  gdouble range;
  gdouble inten;
  gdouble out_light;
  gdouble lightness;

  /* Calculate lightness value */
  lightness = GIMP_RGB_LUMINANCE (gray->r, gray->g, gray->b);

  input = gimp_levels_config_input_from_color (channel, gray);

  range = config->high_input[channel] - config->low_input[channel];
  if (range <= 0)
    goto out;

  input -= config->low_input[channel];
  if (input < 0)
    goto out;

  /* Normalize input and lightness */
  inten = input / range;
  out_light = lightness / range;

  /* See bug 622054: picking pure black or white as gamma doesn't
   * work. But we cannot compare to 0.0 or 1.0 because cpus and
   * compilers are shit. If you try to check out_light using
   * printf() it will give exact 0.0 or 1.0 anyway, probably
   * because the generated code is different and out_light doesn't
   * live in a register. That must be why the cpu/compiler mafia
   * invented epsilon and defined this shit to be the programmer's
   * responsibility.
   */
  if (out_light <= 0.0001 || out_light >= 0.9999)
    goto out;

  /* Map selected color to corresponding lightness */
  config->gamma[channel] = log (inten) / log (out_light);
  config->gamma[channel] = CLAMP (config->gamma[channel], 0.1, 10.0);
  g_object_notify (G_OBJECT (config), "gamma");

Я знаю, что значение гамма-входа должно быть между 0,1 и 10, и что это, вероятно, логарифмическая или квадратичная функция.Я не уверен, что это правильный фрагмент кода, так как он, кажется, принимает высокие, низкие и пиксельные значения и производит гамма-значение (я могу ошибаться), тогда как я хочу ввести гамма-значение и получить исправленное изображение.

Проблема в том, что хотя изображение, полученное с помощью этого метода, близко к тому, что я хочу, это не то же самое, что перемещение слайдера гаммы в фотошопе или gimp.

Я любительпри манипулировании изображениями с помощью кода, и это мой первый вопрос в StackOverFlow, поэтому, пожалуйста, прости меня за все глупости, которые я мог спросить.

1 Ответ

0 голосов
/ 31 января 2019

Я думаю, что это правильно, но, пожалуйста, тщательно попробуйте, прежде чем запускать в производство:

#!/usr/bin/env python3

import numpy as np
import math
from PIL import Image

# Load starting image and ensure greyscale. Make into Numpy array for doing maths.
im = Image.open('start.png').convert('L')
imnp = np.array(im)/255

# DEBUG: print(imnp.max())
# DEBUG: print(imnp.min())
# DEBUG: print(imnp.mean()

# Calculate new gamma
gamma=math.log(imnp.mean())/math.log(0.5) 

# Apply new gamma to image
new = ((imnp**(1/gamma))*255).astype(np.uint8)

# Convert back to PIL from Numpy and save
Image.fromarray(new).save('result.png')

Получается так:

enter image description here

в это:

enter image description here

Если ваши изображения большие, возможно, стоит сделать LUT (таблицу поиска) из 256 возможныхзначения в градациях серого и его применение вместо того, чтобы делать полномочия и тому подобное.


Или, если вам не хочется писать какой-либо Python, вы можете просто использовать ImageMagick , который установлен на большинствеLinux дистрибутивы и доступны для MacOS и Windows.Итак, просто в терминале (или командной строке в Windows):

magick input.png -auto-gamma result.png
...