使用粗糙灰度算法的问题?

问题描述 投票:60回答:7

所以我正在设计一些使用pythonPIL编辑照片的程序,其中一个是将图像转换为灰度(我避免使用PIL中的任何函数)。

我使用的算法很简单:对于每个像素(颜色深度为24),我计算了RGB值的平均值,并将RGB值设置为此平均值。

我的程序生成的灰度图像似乎准确,但我想知道我是否使用了正确的算法,我遇到this answer一个问题,似乎'正确'的算法是计算0.299 R + 0.587 G + 0.114 B

我决定将我的程序与这个算法进行比较。我使用我的程序生成了一个灰度图像,另一个(使用相同的输入)来自a website online'image to grayscale'的顶级Google结果)。

在我的肉眼看来,它们似乎完全相同,如果有任何变化,我看不到它。但是,我决定使用this website'compare two images online'的谷歌搜索结果)来比较我的灰度图像。事实证明,在像素的深处,它们有轻微的变化,但没有一个人乍一看是可感知的(差异可以被发现,但通常只有当图像相互叠加或在几毫秒之间切换时) 。

我的问题(第一个是主要问题):

  1. 使用我的“粗糙”灰度算法有什么缺点吗?
  2. 有没有人有任何输入图像,我的灰度算法会产生一个明显不同的图像与“正确”的图像?
  3. 是否有任何颜色/ RGB组合,我的算法也无法正常工作?

我的关键代码(如果需要):

def greyScale(pixelTuple):
    return tuple([round(sum(pixelTuple) / 3)] * 3)

'正确'的算法(似乎重量很重):

def greyScale(pixelTuple):
    return tuple([round(0.299 * pixelTuple[0] + 0.587 * pixelTuple[1] + 0.114 * pixelTuple[2])] * 3)

我的输入图片:My input image

我的算法产生的灰度图像:The greyscale image my algorithm produces

“正确”的灰度图像:The greyscale image which is 'correct'

当在线比较灰度图像时(突出显示红色是差异,使用10%的模糊):qazxsw poi

尽管上面突出显示了像素的变化,但上面的灰度图像看起来几乎完全相同(至少对我而言)。

另外,关于我的第一个问题,如果有人感兴趣,When the greyscale images are compared online (highlighted red are the differences, using a fuzz of 10%)已经对转换为灰度的不同算法做了一些分析,并且还有一些自定义算法。

编辑:

为了回应@ Szulat的回答,我的算法实际上生成了这个图像(忽略了糟糕的裁剪,原始图像有三个圆圈,但我只需要第一个):

this site

如果人们想知道转换为灰度的原因是什么(因为看起来算法取决于目的),我只是在This is what my algorithm **actually** produces制作一些简单的照片编辑工具,这样我就可以使用迷你Photoshop并且不要需要依靠互联网来应用过滤器和效果。

赏金的原因:这里的不同答案涵盖了不同的事物,这些都是相关的和有用的。这使得选择接受哪个答案变得非常困难。我已经开始获得赏金,因为我喜欢这里列出的一些答案,但也因为有一个答案涵盖了我对这个问题所需要的一切,这很好。

python algorithm python-imaging-library image-conversion image-comparison
7个回答
46
投票

这些图像看起来非常相似,但是你的眼睛可以区分它们,特别是如果你用一个代替另一个:

python

例如,您可以注意到背景中的花在平均转换中看起来更亮。

并不是说平均三个频道有任何本质上“坏”的东西。这个公式的原因是我们不能同等地感知红色,绿色和蓝色,因此它们对灰度图像中强度的贡献应该不相同;因为我们更强烈地感知绿色,所以绿色像素在灰度级上应该看起来更亮。然而,enter image description here没有独特的完美转换为灰度,因为我们看到的颜色,并且在任何情况下每个人的视觉都略有不同,所以任何公式都会尝试进行近似,因此对于大多数人来说像素强度感觉“正确”。


42
投票

最明显的例子:

  1. 原版的
  2. 在Gimp中去饱和(亮度模式 - 这是你的算法所做的)
  3. 在Gimp中去饱和(亮度模式 - 这是我们的眼睛所做的)

as commented by Mark

所以,不要平均RGB。平均RGB是完全错误的!

(好吧,你是对的,平均可能在一些不起眼的应用程序中有效,即使当RGB值被视为颜色时它没有物理或生理意义。顺便说一句,加权平均的“常规”方式也是错误的因为伽玛,一个更微妙的方式。应首先将sRGB线性化,然后将最终结果转换回sRGB(这相当于检索Lab颜色空间中的L分量))


19
投票

您可以使用任何转换方程,比例,线性。你找到的那个:

gimp desaturate: lightness vs luminosity

基于平均人眼“平均”原色(R,G,B)感知灵敏度(至少对于它创建的时间段和人口/ HW;记住这些标准是在LED,TFT等之前创建的。屏幕)。

你正在与几个问题作斗争:

  1. 我们的眼睛不一样 所有人都不会以同样的方式感知颜色。性别之间存在重大差异,区域之间也存在较小差异;甚至一代人和年龄都发挥了作用。因此,即使平均值也应该被视为“平均值”。 我们对可见光谱中的光强度有不同的敏感性。最敏感的颜色是绿色(因此它的重量最高)。但是I = 0.299 R + 0.587 G + 0.114 B 峰值对于不同的人可以处于不同的波长(像我一样,我将它们移动了一点,导致识别某些波长的差异,如某些色调的Aqua - 有些人认为它们是绿色的,有些甚至是蓝色的,即使它们都没有任何颜色失明残疾或其他)。
  2. 监视器不使用相同的波长,也不使用光谱色散 因此,如果您使用2个不同的显示器,它们可能会使用略微不同的波长用于R,G,B甚至不同宽度的光谱滤波器(XYZ curve)。是的,他们应该由HW“标准化”,但这与使用标准化波长不同。它类似于使用RGB与白噪声光谱光源的问题。
  3. 监控线性度 人类没有看到线性尺度:我们通常是对数/指数(取决于你如何看待它)所以是的我们可以用HW(甚至SW)对其进行标准化,但问题是如果我们对一个人进行线性化则意味着我们会损坏它是另一个。

如果将所有这些结合在一起,您可以使用平均值......或特殊(和昂贵)设备来衡量/标准化某些标准或针对校准人员(取决于行业)。

但这在家庭条件下要处理得太多,所以留下所有这些用于工业,并像世界上大多数人一样使用“平均”的权重......幸运的是我们的大脑可以处理它,因为除非你开始比较两个图像,否则你看不出差异并排或动画:)。所以我(会)这样做:

just use a spectroscope and see

8
投票

有许多不同的转换为灰度的方法,虽然使用不同的输入彩色图像可能更容易看到差异,但它们确实给出了不同的结果。

正如我们在灰度中看不到的那样,“最佳”方法在某种程度上取决于应用程序,并且在某种程度上取决于旁观者。

您提到的替代公式是基于人眼对绿色调的变化更敏感,因此给予它们更大的权重 - 类似于相机中的拜耳阵列,其中每个红色和蓝色的像素有2个绿色像素。 I = 0.299 R + 0.587 G + 0.114 B R = I G = I B = I


8
投票

Luminance有很多公式,取决于R,G,B颜色的原色:

Wiki - Bayer array

这都是因为我们的眼睛对蓝色比对红色的敏感度低于对绿色的敏感度。

话虽如此,你可能正在计算Luma,而不是Luminance,所以无论如何公式都是错误的。对于恒亮度,您必须转换为线性光

Rec.601/NTSC: Y = 0.299*R + 0.587*G + 0.114*B , 

Rec.709/EBU:  Y = 0.213*R + 0.715*G + 0.072*B , 

Rec.2020/UHD: Y = 0.263*R + 0.678*G + 0.059*B . 

应用亮度公式,并转换回伽玛域

R = R' ^ 2.4 , G = G' ^ 2.4 , B = B' ^ 2.4 , 

此外,考虑将3D颜色空间转换为1D数量会丢失2/3的信息,这可能会在下一个处理步骤中咬你。根据问题,有时不同的公式更好,如V = MAX(R,G,B)(来自HSV颜色空间)。

我怎么知道?我是Poynton博士的追随者和朋友。


5
投票

提供的答案已经足够,但我想以不同的方式讨论这个主题。

自从我学习数字绘画以来,我更常使用HSV。

在绘画过程中使用HSV更加可控,但保持简短,主要是S:饱和度将颜色与光的概念分开。并且将S转为0,已经是“计算机”灰度图像。

Y' = Y ^ (1/2.4) . 

这种方法真正保留了原始颜色的“明亮”。但是,不考虑人眼如何处理数据。


1
投票

在回答您的主要问题时,使用任何单一灰度测量都存在缺点。这取决于你想要的图像。例如,如果您在白色背景上有彩色文本,如果您想使文本突出,您可以使用最小值r,g,b值作为度量。但是,如果彩色背景上有黑色文本,则可以使用相同结果的最大值。在我的软件中,我提供了最大,最小或中值的选项供用户选择。连续色调图像的结果也很有启发性。在回应要求更多细节的评论时,像素的代码低于(没有任何防御措施)。

from PIL import Image
import colorsys

def togrey(img):
    if isinstance(img,Image.Image):
        r,g,b = img.split()
        R = []
        G = []
        B = [] 
        for rd,gn,bl in zip(r.getdata(),g.getdata(),b.getdata()) :
            h,s,v = colorsys.rgb_to_hsv(rd/255.,gn/255.,bl/255.)
            s = 0
            _r,_g,_b = colorsys.hsv_to_rgb(h,s,v)
            R.append(int(_r*255.))
            G.append(int(_g*255.))
            B.append(int(_b*255.))
        r.putdata(R)
        g.putdata(G)
        b.putdata(B)
        return Image.merge('RGB',(r,g,b))
    else:
        return None

a = Image.open('../a.jpg')
b = togrey(a)
b.save('../b.jpg')
© www.soinside.com 2019 - 2024. All rights reserved.