如何在灰度图像代码中使用级别 gamma/mid-tones 滑块

How to use levels gamma/mid-tones slider through code for grayscale image

我有一张灰度图像,我想对其应用伽玛校正。手动调整 photoshop 级别中的中间滑块,而不触及黑点或白点,直到直方图的中值达到 127 或接近它的某个位置。我想通过 python.

做同样的事情

我寻找一个将伽马值作为输入并生成输出图像的公式。然而,我只找到了一个调整低值和高值而不是伽玛(或中间调)的。

在这里,R 是我图像中像素的 RGB 红色值,作为一个 numpy 数组,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 文档中搜索 gamma 滑块背后的公式,并找到了一个看起来像这样的代码。

  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");

我知道 gamma 输入值应该在 0.1 到 10 之间,而且它可能是对数函数或二次函数。我不确定这是否是正确的代码片段,因为它似乎采用高、低和像素值并产生伽玛值(我可能弄错了),而我想输入伽玛值并获得校正后的图像。

问题是虽然用这种方法生成的图像接近我想要的,但它与在 photoshop 或 gimp 中移动 gamma 滑块不同。

我是使用代码进行图像处理的业余爱好者,这是我在 Whosebug 的第一个问题,所以请原谅我提出的任何愚蠢问题。

我认为这是正确的,但请在投入生产之前彻底尝试:

#!/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')

变成这样:

进入这个:

如果您的图像很大,可能值得为 256 个可能的灰度值制作一个 LUT(查找 Table)并应用它,而不是做一些幂等操作。


或者,如果您不想编写任何 Python,您可以只使用安装在大多数 Linux 发行版上的 ImageMagick适用于 macOS 和 Windows。所以,就在终端(或 Windows 上的命令提示符):

magick input.png -auto-gamma result.png