【问题标题】:Outline around non-transparent image parts围绕不透明图像部分的轮廓
【发布时间】:2019-11-19 18:46:06
【问题描述】:

我正在尝试在 PIL 中制作图像轮廓。我的目标是在任何背景(包括图像,而不仅仅是纯色)上都可以看到带有一些额外线条的文本,有点像带轮廓的电影字幕。

这里有很多答案和网络上的文字,但没有一个适合我。它们归结为:

  1. (通常用于文本)执行 for-loops 将文本放置到位置 (x+dx, y+dy) for dx, dx in range(-radius, radius + 1)

  2. 模糊图像。

  3. 制作轮廓并用粗线绘制。

  4. 边缘检测算法。

我尝试了这些,但结果的质量很差。这是一个真正需要看起来很专业的项目。

如果我在 Gimp 中执行此操作,我可能会使用“按颜色选择”工具选择图像的透明部分,然后反转选择(选择不透明的所有内容),然后扩大选择(给我很好圆角),然后稍微羽化(以获得更平滑的线条),然后在我的图像下方的图层上用纯色绘制它。

是否可以在 PIL 中做类似的事情,或者任何兼容的东西(基本上,任何可以采用 NumPy 数组“图像”的东西)?

【问题讨论】:

标签: python image-processing python-imaging-library


【解决方案1】:

很遗憾,您没有展示您的任何试验,因此人们可以看到,您的结果是什么样子才能给人留下深刻印象,您认为什么“不好”。因此,当您提到存储为 NumPy 数组的图像时,OpenCV 可能是这里的一个选项。

我将遵循上述想法的组合:

  • 生成一个与图像尺寸相同的空文本平面,并添加一个额外的 alpha 通道设置为0(不可见)。
  • 放置文本轮廓:所需的背景颜色(比如说黄色),粗细。
  • 严重模糊整个文本平面,包括 Alpha 通道。所以,你得到了你的羽毛轮廓。
  • 输入实际文本:所需的前景色(比如说黑色),正常粗细。
  • 稍微模糊整个文本平面,只是为了平滑生成的文本。 (漂亮的文字不是 OpenCV 的强项之一!)
  • 使用平面的 Alpha 通道通过图像和文本平面的线性组合生成输出。

这就是代码:

import cv2
import numpy as np

# Open image, Attention: OpenCV uses BGR ordering by default!
image = cv2.imread('path/your/image.png', cv2.IMREAD_COLOR)

# Set up text properties
loc = (250, 500)
text = 'You were the chosen one!'
c_fg = (0, 255, 255, 255)
c_bg = (0, 0, 0, 255)

# Initialize overlay text plane
overlay = np.zeros((image.shape[0], image.shape[1], 4), np.uint8)

# Put text outline, larger thickness, color of outline (here: black)
cv2.putText(overlay, text, loc, cv2.FONT_HERSHEY_COMPLEX, 1.0, c_bg, 9, cv2.LINE_AA)

# Blur text plane (including alpha channel): Heavy blur
overlay = cv2.GaussianBlur(overlay, (21, 21), sigmaX=10, sigmaY=10)

# Put text, normal thickness, color of overlay (here: yellow)
cv2.putText(overlay, text, loc, cv2.FONT_HERSHEY_COMPLEX, 1.0, c_fg, 2, cv2.LINE_AA)

# Blur text plane (inclusing alpha channel): Very slight blur
overlay = cv2.GaussianBlur(overlay, (3, 3), sigmaX=0.5, sigmaY=0.5)

# Add overlay text plane to image (channel by channel)
output = np.zeros(image.shape, np.uint8)
for i in np.arange(3):
    output[:, :, i] = image[:, :, i] * ((255 - overlay[:, :, 3]) / 255) + overlay[:, :, i] * (overlay[:, :, 3] / 255)

cv2.imshow('output', output)
cv2.waitKey(0)
cv2.destroyAllWindows()

模糊的参数是手动设置的。不同的图片和文字大小需要进一步调整。

这是一个示例输出:

即使使用类似于图像背景的前景色,文本仍然是可读的 - 至少从我的角度来看:

那么,现在最大的问题是:这个结果被认为是“坏的”吗?

希望有帮助!

【讨论】:

  • 谢谢。 imshow 在 Fedora 上对我不起作用,所以我将其替换为 imwrite。我从我的磁盘中使用了一个随机 PNG,其余代码是你的,没有改变。结果是这样的:i.imgur.com/1szgTVi.png 如您所见,模糊的背景具有清晰的像素化边缘,而前景色不存在。知道为什么吗?它是 Python 2 下的 OpenCV 3.2.0.7(不是我的选择,目前我无法迁移到 Python 3)。
  • 将 OpenCV 升级到 4.1.1.26 没有帮助。
  • @VedranŠego 一般评论:请描述您在问题中使用的环境以防止此类问题。如果我知道您使用 Python 2,我可能不会回答。一个想法,在不久阅读 Python 2 / 3 差异后:Python 2 中的整数除法似乎总是返回整数。因此,也许尝试显式强制转换以浮动以进行循环内的计算。否则,我恐怕无法再为您提供帮助了。
  • 好发现!谢谢,也很抱歉遗漏了。除了我完全忘记的除法之外,Python 2/3 的差异不应该真正影响这样的事情。它现在可以工作了,我会尝试使其适应我的项目。
猜你喜欢
  • 2012-02-24
  • 1970-01-01
  • 1970-01-01
  • 2021-12-21
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多