Python中如何在图像上勾勒轮廓

6

我一直在使用PIL Image。

我试图在图像上绘制文本。我希望这个文本像大多数网络迷因一样有一个黑色的轮廓。我尝试通过在前面的字母后面绘制一个更大字体的阴影字母来实现这一点。我已经相应地调整了阴影的x和y位置。但是阴影有点偏差。前面的字母应该正好位于阴影字母的中间,但事实并非如此。问号在水平方向上肯定没有居中,所有的字母在垂直方向上都太低了。轮廓看起来也不好看。

enter image description here


下面是生成上面图片的最小可重现示例。

字体链接

原始图像链接

from PIL import Image, ImageDraw, ImageFont
    
    caption = "Why is the text slightly off?"
    img = Image.open('./example-img.jpg')
    d = ImageDraw.Draw(img)
    x, y = 10, 400
    font = ImageFont.truetype(font='./impact.ttf', size=50)
    shadowFont = ImageFont.truetype(font='./impact.ttf', size=60)
    for idx in range(0, len(caption)):
        char = caption[idx]
        w, h = font.getsize(char)
        sw, sh = shadowFont.getsize(char)  # shadow width, shadow height
        sx = x - ((sw - w) / 2)  # Shadow x
        sy = y - ((sh - h) / 2)  # Shadow y
        # print(x,y,sx,sy,w,h,sw,sh)
        d.text((sx, sy), char, fill="black", font=shadowFont)  # Drawing the text
        d.text((x, y), char, fill=(255,255,255), font=font)  # Drawing the text
        x += w + 5
    
    img.save('example-output.jpg')


另一种方法 包括在主要文本后面用黑色文本在略高,略低,略左和略右的位置重复绘制文本,但是如下所示,这些也不是最优的方案:

enter image description here

生成上面图片的代码:

    from PIL import Image, ImageDraw, ImageFont
    
    caption = "Why does the Y and i look weird?"
    x, y = 10, 400
    font = ImageFont.truetype(font='./impact.ttf', size=60)
    img = Image.open('./example-img.jpg')
    d = ImageDraw.Draw(img)
    shadowColor = (0, 0, 0)
    thickness = 4
    d.text((x - thickness, y - thickness), caption, font=font, fill=shadowColor, thick=thickness)
    d.text((x + thickness, y - thickness), caption, font=font, fill=shadowColor, thick=thickness)
    d.text((x - thickness, y + thickness), caption, font=font, fill=shadowColor, thick=thickness)
    d.text((x + thickness, y + thickness), caption, font=font, fill=shadowColor, thick=thickness)
    d.text((x, y), caption, spacing=4, fill=(255, 255, 255), font=font)  # Drawing the text
    img.save('example-output.jpg')


看起来像是这个的重复:https://dev59.com/NlgR5IYBdhLWcg3wO7U0 - jdaz
@jdaz 那里的答案使用了我列出的第二种方法,这不是最优解决方案。 - Sam
3个回答

13

我不知道从哪个版本开始,但大约一年前,Pillow添加了文本描边功能。如果最近没有更新过,你可能需要更新它。使用示例,stroke_width为2:

from PIL import Image, ImageDraw, ImageFont

caption = 'I need to update my Pillow'
img = Image.open('./example-img.jpg')
d = ImageDraw.Draw(img)
font = ImageFont.truetype('impact.ttf', size=50)
d.text((10, 400), caption, fill='white', font=font,
       stroke_width=2, stroke_fill='black')
img.save('example-output.jpg')

3
你可以使用mathlibplot文本 Stroke 特效,该特效使用了PIL
例如:
import matplotlib.pyplot as plt
import matplotlib.patheffects as path_effects
import matplotlib.image as mpimg

fig = plt.figure(figsize=(7, 5))
fig.figimage(mpimg.imread('seal.jpg'))
text = fig.text(0.5, 0.1, 'This text stands out because of\n'
                          'its black border.', color='white',
                          ha='center', va='center', size=30)
text.set_path_effects([path_effects.Stroke(linewidth=3, foreground='black'),
                       path_effects.Normal()])
plt.savefig('meme.png')

结果: result

你能否提供一个示例,展示如何将其绘制到图像上而不是绘制成图表? - Sam
@Sam 我添加了一个例子 - Yann

1
正如@Abang指出的那样,使用stroke_width和stroke_fill。

了解更多详情的链接

代码:

from PIL import Image, ImageDraw, ImageFont

caption = 'Ans: stroke_width & stroke_fill'
img = Image.open('./example-img.jpg')
d = ImageDraw.Draw(img)
font = ImageFont.truetype('impact.ttf', size=50)
d.text((60, 400), caption, fill='white', font=font, spacing = 4, align = 'center',
       stroke_width=4, stroke_fill='black')
img.save('example-output.jpg')

enter image description here


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