ODL 有text_phantom,它通过一些花里胡哨的方式做到了这一点。
为了给您一个简化的实现,您可以使用该PIL
库。具体来说,您需要决定图像大小和字体大小,然后就相当简单了。
from PIL import Image, ImageDraw, ImageFont
import numpy as np
def text_phantom(text, size):
# Availability is platform dependent
font = 'arial'
# Create font
pil_font = ImageFont.truetype(font + ".ttf", size=size // len(text),
encoding="unic")
text_width, text_height = pil_font.getsize(text)
# create a blank canvas with extra space between lines
canvas = Image.new('RGB', [size, size], (255, 255, 255))
# draw the text onto the canvas
draw = ImageDraw.Draw(canvas)
offset = ((size - text_width) // 2,
(size - text_height) // 2)
white = "#000000"
draw.text(offset, text, font=pil_font, fill=white)
# Convert the canvas into an array with values in [0, 1]
return (255 - np.asarray(canvas)) / 255.0
Run Code Online (Sandbox Code Playgroud)
例如,这给出了:
import matplotlib.pyplot as plt
plt.imshow(text_phantom('A', 100))
plt.imshow(text_phantom('Longer text', 100))
Run Code Online (Sandbox Code Playgroud)
我实现了自己的绘图函数,称为text_draw_np(...)
,它使用 PIL 库将任何文本(不仅是单个字母,甚至是多行)绘制到 numpy RGB 数组。它支持文本的着色和拉伸(更改纵横比),还支持可选的间隙(文本周围的空白)删除功能。
要使用下一个代码安装一次 pip 模块python -m pip install pillow numpy matplotlib
,这里绘图功能本身不需要 matplotlib,它仅用于测试。
用法/测试的示例见代码末尾,就在我的函数之后。代码之后还有以不同颜色、字体大小、宽度/高度和拉伸绘制不同字母/文本的示例。
绘制一个或多个字母的最简单用例是这个result_numpy_array = text_draw_np('ABC', height = 200)
,这里生成的图像的高度是 200 像素。
函数接受下一个参数:
text
- Python字符串,可以是一个字母,也可以是多个字母,甚至是多行('\n'
里面有字母来分割行)。font
- 包含字体的文件的文件名或路径(字符串)。字体可以是任何 TrueType 字体,默认情况下我使用路径中的默认 Windows 字体 Arial c:/windows/fonts/arial.ttf
,在 Linux/MacOS 上您应该更正此路径,您也可能想从互联网下载一些免费的 TrueType 字体,例如从这里下载。也可能支持其他格式,所有 FreeType 库都支持,但需要单行修改代码PIL.ImageFont.truetype(...)
。fontsize
- 要使用的字体大小,大小以给定字体文件特定的单位表示。您只能指定fontsize
或width
/之一height
。width
/ height
- 以像素为单位指定,如果同时指定,则绘制的文本将被拉伸以填充给定的宽度/高度。如果您仅指定其中任何一个(另一个是“无”),则将自动计算另一个以保持宽高比,并且文本将不拉伸。remove_gaps
- 如果此参数为True
,则文本(背景)周围的额外空格将被删除。大多数字体都有额外的空格,例如小字母m
顶部空间较多,大写字母T
顶部空间较少。需要这个空间,以便所有字母具有相同的高度,多行文本也需要空间,以便在行之间有一些空间。如果remove_gaps为False
(默认),则空间将保留在字体字形给定的数量内。color
- 前景色(默认为'black'
),bg
- 背景色(默认为'white'
),两者都可以是常见的颜色字符串名称(如'red'
// 'green'
)'blue'
,也可以是 RGB 元组(如(0, 255, 0)
绿色)。def text_draw_np(text, *, width = None, height = None, fontsize = None, font = 'c:/windows/fonts/arial.ttf', bg = (255, 255, 255), color = (0, 0, 0), remove_gaps = False, cache = {}):
import math, numpy as np, PIL.Image, PIL.ImageDraw, PIL.ImageFont, PIL.ImageColor
def get_font(fname, size):
key = ('font', fname, size)
if key not in cache:
cache[key] = PIL.ImageFont.truetype(fname, size = size, encoding = 'unic')
return cache[key]
def text_size(text, font):
if 'tsd' not in cache:
cache['tsi'] = PIL.Image.new('RGB', (1, 1))
cache['tsd'] = PIL.ImageDraw.Draw(cache['tsi'])
return cache['tsd'].textsize(text, font)
if fontsize is not None:
pil_font = get_font(font, fontsize)
text_width, text_height = text_size(text, pil_font)
width, height = text_width, text_height
else:
pil_font = get_font(font, 24)
text_width, text_height = text_size(text, pil_font)
assert width is not None or height is not None, (width, height)
width, height = math.ceil(width) if width is not None else None, math.ceil(height) if height is not None else None
pil_font = get_font(font, math.ceil(1.2 * 24 * max(
([width / text_width] if width is not None else []) +
([height / text_height] if height is not None else [])
)))
text_width, text_height = text_size(text, pil_font)
if width is None:
width = math.ceil(height * text_width / text_height)
if height is None:
height = math.ceil(width * text_height / text_width)
canvas = PIL.Image.new('RGB', (text_width, text_height), bg)
draw = PIL.ImageDraw.Draw(canvas)
draw.text((0, 0), text, font = pil_font, fill = color)
if remove_gaps:
a = np.asarray(canvas)
bg_rgb = PIL.ImageColor.getrgb(bg)
b = np.zeros_like(a)
b[:, :, 0] = bg_rgb[0]; b[:, :, 1] = bg_rgb[1]; b[:, :, 2] = bg_rgb[2]
t0 = np.any((a != b).reshape(a.shape[0], -1), axis = -1)
top, bot = np.flatnonzero(t0)[0], np.flatnonzero(t0)[-1]
t0 = np.any((a != b).transpose(1, 0, 2).reshape(a.shape[1], -1), axis = -1)
lef, rig = np.flatnonzero(t0)[0], np.flatnonzero(t0)[-1]
a = a[top : bot, lef : rig]
canvas = PIL.Image.fromarray(a)
canvas = canvas.resize((width, height), PIL.Image.LANCZOS)
return np.asarray(canvas)
import matplotlib.pyplot as plt, matplotlib
fig, axs = plt.subplots(3, 3, constrained_layout = True)
axs[0, 0].imshow(text_draw_np('A', height = 500), interpolation = 'lanczos')
axs[0, 1].imshow(text_draw_np('B', height = 500, color = 'white', bg = 'black'), interpolation = 'lanczos')
axs[0, 2].imshow(text_draw_np('0 Stretch,No-Gaps!', width = 500, height = 500, color = 'green', bg = 'magenta', remove_gaps = True), interpolation = 'lanczos')
axs[1, 0].imshow(text_draw_np('1 Stretch,No-Gaps!', width = 1500, height = 100, color = 'blue', bg = 'yellow', remove_gaps = True), interpolation = 'lanczos')
axs[1, 1].imshow(text_draw_np('2 Stretch,With-Gaps', width = 500, height = 200, color = 'red', bg = 'gray'), interpolation = 'lanczos')
axs[1, 2].imshow(text_draw_np('3 By-Height-300', height = 300, color = 'black', bg = 'lightgray'), interpolation = 'lanczos')
axs[2, 0].imshow(text_draw_np('4 By-FontSize-40', fontsize = 40, color = 'purple', bg = 'lightblue'), interpolation = 'lanczos')
axs[2, 1].imshow(text_draw_np(''.join([(chr(i) + ('' if (j + 1) % 7 != 0 else '\n')) for j, i in enumerate(range(ord('A'), ord('Z') + 1))]),
fontsize = 40, font = 'c:/windows/fonts/cour.ttf'), interpolation = 'lanczos')
axs[2, 2].imshow(text_draw_np(''.join([(chr(i) + ('' if (j + 1) % 16 != 0 else '\n')) for j, i in enumerate(range(32, 128))]),
fontsize = 40, font = 'c:/windows/fonts/cour.ttf'), interpolation = 'lanczos')
#plt.tight_layout(pad = 0.05, w_pad = 0.05, h_pad = 0.05)
plt.show()
Run Code Online (Sandbox Code Playgroud)
输出: