将图像的像素值从RGB转换为灰度(Python PIL手动实现)?

3

我正在尝试使用特定伽马校正灰度实现 - Gleam将图像像素转换为灰度。如何在PIL Python中手动完成此操作?

def tau_gamma_correct(pixel_channel):
    pixel_channel = pixel_channel**(1/2.2)
    return pixel_channel

#@param: rgb
#@result: returns grayscale value
def gleam(rgb):
    #convert rgb tuple to list
    rgblist = list(rgb)
    #gamma correct each rgb channel
    rgblist[0] = tau_gamma_correct(rgblist[0])
    rgblist[1] = tau_gamma_correct(rgblist[1])
    rgblist[2] = tau_gamma_correct(rgblist[2])
    grayscale = 1/3*(rgblist[0] + rgblist[1] + rgblist[2])
    return grayscale

# get a glob list of jpg filenames
files = glob.glob('*.jpg')
for file in files:
    file = open(file)
    filename = file.name
    image = Image.open(file)
    pix = image.load()
    width, height = image.size
    #print(width,height)
    for x in range(0, width):
        for y in range(0, height):
            rgb = pix[x,y]
            #print(rgb)
            # calc new pixel value and set to pixel
            image.mode = 'L'
            pix[x,y] = gleam(rgb)

            image.save(filename + 'gray.gleam'+'.jpg')
   file.close()

系统错误:新样式的getargs格式,但参数不是元组
我认为它仍然期望rgb元组。


尝试将 file.close() 命令向前移动 2 个缩进块,看看是否可以解决问题?我的意思是将 file.close() 命令与 open() 方法在同一缩进级别。 - ZdaR
没有帮助,问题是我不确定如何将RGB元组更改为单个灰度值。我试图更改模式,但似乎无法工作,或者可能无法更改。我会查看PIL文档。 - jsky
gleam函数不是返回介于0和255之间的整数灰度值吗?您是否想让该函数返回元组而不是整数? - ZdaR
是的,那就是我的目标。 - jsky
我想将像素值设置为灰度值,而不是RGB元组。 - jsky
3个回答

1
我发现我可以简单地建立另外一个图像:

import sys
import os
import glob
import numpy
from PIL import Image

def tau_gamma_correct(pixel_channel):
    pixel_channel = pixel_channel**(1/2.2)
    return pixel_channel

#@param: rgb
#@result: returns grayscale value
def gleam(rgb):
    #convert rgb tuple to list
    rgblist = list(rgb)
    #gamma correct each rgb channel
    rgblist[0] = tau_gamma_correct(rgblist[0])
    print('gleamed red ' + str(rgblist[0]))
    rgblist[1] = tau_gamma_correct(rgblist[1])
    print('gleamed green ' + str(rgblist[1]))
    rgblist[2] = tau_gamma_correct(rgblist[2])
    print('gleamed blue ' + str(rgblist[0]))
    grayscale = (rgblist[0] + rgblist[1] + rgblist[2])/3
    print('grayscale '+ str(grayscale))
    return grayscale

# get a glob list of jpg filenames
files = glob.glob('*.jpg')
for file in files:
    file = open(file)
    filename = file.name
    image = Image.open(file)
    pix = image.load()
    width, height = image.size
    new_image = Image.new('L', image.size)
    #pixelmatrix = [width][height]
    pixelmatrix = numpy.zeros((width, height))
    #print(width,height)
    for x in range(0, width):
        for y in range(0, height):
            rgb = pix[x,y]
            print('current pixel value: '+str(rgb))
            # calc new pixel value and set to pixel
            #print(gleam(rgb))
            gray = gleam(rgb)
            print('changing to pixel value: '+str(gray))
            pixelmatrix[x,y] = gray
            new_image.save(filename + 'gray.gleam'+'.jpg')
    new_image.putdata(pixelmatrix)
    file.close()

1
问题在于image.mode = 'L'并没有实际改变图像的类型,它只是更改了属性,因此不再准确。要更改图像的模式,您需要使用image.convert('L')创建一个新副本。

一旦您将图像设置为灰度模式,就不再需要使用元组表示像素值了。


谢谢。虽然看起来我需要处理每个像素,但对我来说,从头开始构建灰度图就足够了。也就是说,我不需要转换原始图像,我只需要灰度图像。但我在将numpy数组/矩阵数据放入图像时遇到了问题。 - jsky
@jsky,你有两个对象,new_imagenew_img,你可能只是把它们搞混了。 - Mark Ransom

0
看到 SystemError: new style getargs format but argument is not a tuple 错误,似乎需要返回一个元组,表示为:

sample_tuple = (1, 2, 3, 4)

所以我们将gleam()函数编辑为:

def gleam(rgb):
    #convert rgb tuple to list
    rgblist = list(rgb)
    #gamma correct each rgb channel
    rgblist[0] = tau_gamma_correct(rgblist[0])
    rgblist[1] = tau_gamma_correct(rgblist[1])
    rgblist[2] = tau_gamma_correct(rgblist[2])
    grayscale = 1/3*(rgblist[0] + rgblist[1] + rgblist[2])
    return (grayscale, )

请记住,当返回一个单元素元组时,需要表示为:
sample_tuple = (1, )

这是因为 (4) == 4 但是 (4, ) != 4

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接