【问题标题】:Residual white pixels in transparent background from PIL来自 PIL 的透明背景中的残留白色像素
【发布时间】:2016-12-29 18:14:25
【问题描述】:

我使用了另一个 stackoverflow 帖子中的以下代码

from PIL import Image as image

img = image.open('output.png')
img = img.convert("RGBA")
datas = img.getdata()

newData = []
for item in datas:
    if item[0] == 255 and item[1] == 255 and item[2] == 255:
        newData.append((255, 255, 255, 0))
    else:
        newData.append(item)

img.putdata(newData)
img.save("img2.png", "PNG")

将我的 png 的背景转换为透明。但是,当我尝试在透明图像下方的 powerpoint 中添加一些形状时,它仍然有一些残留的白色像素。有谁知道如何解决这个问题?

【问题讨论】:

  • 你想和我打赌,那些不是实际上是白色像素?
  • 这实际上与编程无关,而是与基本的数字图像概念有关(一方面,别名)。这些像素不是白色的,在一些图像查看器/编辑器中打开图像,缩放并检查它们。

标签: python png python-imaging-library


【解决方案1】:

那些像素完全是“白色”。您正在测试并从图像中移除的颜色,其值为#FFFFFF。但是那些倾斜的线条被严重抗锯齿,从背景的纯白色“褪色”到线条中心的纯色。

这可以在放大一点​​点时看到:

您可以降低何时使像素完全透明的阈值:

if item[0] > 240 and item[1] > 240 and item[2] > 240:
    newData.append((255, 255, 255, 0))
else:
    newData.append(item)

但无论你怎么做,你总是会在线条周围看到明显更亮的像素,或者 - 当只匹配中心“线条”颜色时完全 - 像素断开,不再像原来的线条了。

但没有理由对 PNG 图像使用是/否蒙版! PNG 支持全 8 位透明度,因此您可以使“实心”中心线完全不透明,纯白色完全透明,并使逐渐变暗的像素在这些值之间渐变。

如果您知道用于绘制线条的确切原始颜色,则此方法效果最佳。用 Adob​​e PhotoShop 测量它,我得到类似 #818695 的东西。将这些值插入您的程序并将“色调”(朝向白色)调整为透明度,向整个可能范围展平,我建议使用以下代码:

from PIL import Image as image

img = image.open('input.png')
img = img.convert("RGBA")
datas = img.getdata()

retain = (0x81,0x86,0x95)
retain_gray = (39*retain[0] + 50*retain[1] + 11*retain[2])

newData = []
for item in datas:
    if item[0] > retain[0] and item[1] > retain[1] and item[2] > retain[2]:
      # convert to grayscale
      val = 39*item[0] + 50*item[1] + 11*item[2]
      # invert
      val = 25500 - val;
      # difference with 'retain'
      val = retain_gray - val
      # scale down
      val = 255*val/retain_gray
      # invert to act as transparency
      transp = 255-val
      # apply transparency to original 'full' color value
      newData.append((retain[0], retain[1], retain[2], transp ))
    else:
      newData.append(item)

img.putdata(newData)
img.save("output.png", "PNG")
print "done"

它本质上所做的是将输入图像转换为灰度,对其进行缩放(因为从最暗到最亮的比例应该在 0..255 的完整透明度范围内),然后将其用作“透明”字节。结果比您的开/关方法要好得多:

【讨论】:

  • 这不是一个完美的解决方案,因为像素颜色已经根据其透明度进行了混合。您需要将像素值设置为retain[0], retain[1], retain[2], transp 而不是item[0], item[1], item[2], transp
  • @MarkRansom:用柔软的鸡毛掸子把我打倒。这确实是一个明显的改进! (Mark 的观察是 添加 透明度使像素更亮,因此您需要从原始像素中“移除”亮度 - 已经很亮了! - 像素。这应该会再次导致(假定的)原始颜色。 )
猜你喜欢
  • 1970-01-01
  • 2014-08-21
  • 1970-01-01
  • 2012-09-21
  • 2013-04-03
  • 2012-07-26
  • 1970-01-01
  • 2010-10-20
  • 2015-06-22
相关资源
最近更新 更多