Python使用特定规则将图片转换为黑白

时间:2013-05-01 20:06:22

标签: python image image-manipulation

我正在尝试分析图片。我基本上分两步完成:

  1. 将其转换为灰度图片
  2. 拍摄照片中的区域并查看它们是否更可能是白色或黑色
  3. 我的程序在大多数情况下运行良好但并非全部。这主要是因为我从未真正理解过,如何将图片转换为黑白图片。我主要复制了我发现的代码,并使其与试验和错误一起工作(这就是为什么我最终,灰度而不是黑白,因为我没有找到,如何使灰度中的每个非白色像素变为黑色)

    我正在使用PIL进行图片操作,我的图片操作主要功能如下(convert()使用一次,avgcol()用于转换图片的每个部分,我想分析)

    def convert():
        global im   
        matrix = (1.412453, 0.357580, 0.180423, 0,
               0.212671, 0.715160, 0.072169, 0,
               0.019334, 0.119193, 0.950227, 0 )
        im = im.convert("L", matrix)
    
    def avgcol(im):
        p_colors=im.getcolors()
        cnt_pix=(im.size[0])*(im.size[1])
        avgpix=0
        for i in range(len(p_colors)):
            avgpix=avgpix+p_colors[i][0]*p_colors[i][1]
        return round(avgpix/cnt_pix  , 1)
    

    我真的不知道,矩阵的作用是什么(没有找到一个解释单个值的网站)。 我现在的具体问题是,我想将绿色太多的像素转换成白色像素,但我很确定,如果这个问题得到解决,其他的东西会突然出现,所以一些基本的解释,这是怎样的完了,会很棒。 但我感谢任何指针朝着正确的方向发展。 请不要解决每个像素的循环问题。图片非常大,程序应该很快。

1 个答案:

答案 0 :(得分:2)

如果你看the documentation,你会看到一些事情。

首先,convert有一个参数版本,只需要mode

如果您只想进行RGB到灰度转换:

grey = im.convert("L")

提供矩阵的唯一原因是您不想使用默认转换。

你也可以直接转换为双层黑&白;

bw = im.convert("1")

正如文档所说:

  

转换为双层图像(模式“1”)时,源图像首先转换为黑白图像。然后将大于127的结果值设置为白色,并使图像抖动。要使用其他阈值,请使用point方法。

因此,如果您想要标准阈值和抖动,只需convert。如果您想要不同的阈值,它看起来像这样:

grey = im.convert("L")
table = [int(i>200) for i in range(256)]
bw = grey.point(table, '1')

在你的回答中,你说:

  

...如何将灰度中的每个非白色像素变为黑色

如果您的意思是“绝对纯白色以外的任何东西”为“非白色”,则不能使用point。即使您使用65536项表格convertL16point,也无法区分99.998%和100%白色,并且可以想象您的某些原始像素不是白色得到匹配错误。因此,您可能希望直接迭代原始像素(使用load函数)并手动构建新图像。


关于矩阵的作用......如果您了解矩阵数学的基础知识,那就非常简单了。 (如果你没有,我在这里无法解释,但the Wikipedia article可能是一个很好的起点。)

将每个源像素视为向量(例如,在RGBA图像中,向量<red, green, blue, alpha>。将该向量乘以矩阵,然后得到一个新向量。将其视为目标色彩空间中的像素。

例如,如果您有D65 RGBA像素,并将每个像素乘以文档中给出的4x3矩阵,则结果为CIE XYZ像素。

这意味着没有理由使用4x3矩阵转换为L.你想要的是4x1矩阵。然后,只有你不想要默认值。正如文档所说:

  

当从彩色图像到黑白时,图书馆使用ITU-R 601-2亮度变换:

L = R * 299/1000 + G * 587/1000 + B * 114/1000

...这只是(.299, .587, .114, 0)


所以,如果你想:

  

将绿色太多的像素转换为白色像素

这有些含糊不清。但至少有一种做这样的事情的方法就是过分强调绿色。例如,如果您使用(.1495, .8448 , .0057, 0),绿色将比平时计算得多(红色和蓝色要少得多)以确定亮度。


同时,在你的问题结束时:

  

请不要解决每个像素的循环问题。图片非常大,程序应该很快。

当然,在bw = grey.point([int(i>200) for i in range(256)], '1')之下的PIL命令实际上是用于循环grey中的每个像素。它只是在C而不是Python中进行循环。您可以使用Cython自己做同样的事情,或者使用numpy隐式执行,或者只使用PyPy而不是现有的Python解释器(可以将您的Python循环到JIT)几乎是C速度。)

你为什么要那样做?好吧,看看每种方式的阈值代码:

# PIL
table = [int(i>200) for i in range(256)]
bw = grey.point(table, '1')

# Python (run in PyPy) or Cython
bw = [pixel > 200 for pixel in grey]

# numpy
bw = grey > 200