首页 > 解决方案 > 使用 Jetson.utils.cudaFont.OverlayText() 函数时,如何处理非典型英语的字母?

问题描述

我正在尝试制作一个检测对象然后将对象名称翻译成丹麦语的程序,但是当将翻译文本覆盖在图像本身上时,英语中找不到的字母,例如Æ,Ø和Å,总是出现非常糟糕(例如 fængsel 显示为 fÃ|ngsel)。在命令行中,我打印出我放入函数参数中的文本,它在命令提示符下很好,但在覆盖在图像上时很糟糕。

我正在使用 python 3 并拥有 Nvidia Jetson nano。

这是在图像上覆盖不正确文本的行。

font.OverlayText(img, width, height, "{:05.2f}% {:s}".format(confidence * 100, translateText(class_desc, "da")), 5, 5, font.White, font.Gray40)

translateText() 是一个单独的函数,您可以在其中输入要翻译的文本和语言,它会返回一个我检查过的字符串是否正确

字体定义为

font = jetson.utils.cudaFont()

标签: pythonnvidia-jetson-nano

解决方案


您正在输入cudafontUTF-8 编码的文本。查看源代码,似乎没有任何东西可以处理 UTF-8 - 甚至,如果我没看错的话,也没有任何东西可以将字体中的自然字形顺序重新编码为常规编码:

char c = str[n];
if( c < FirstGlyph || c > LastGlyph )
    continue;

c -= FirstGlyph;
... now c will hold glyph data for a character

(来自函数int4 cudaFont::TextExtents

这意味着该库在其字符处理方面严重受损。

在以下上下文中,字形仅表示“可以与现有字符或字符组合相关联的特定图像(即,连字“fi”是表示两个字符“f”和“i”的单个字形). 字体还必须定义一种编码(内置的,通过某种约定,例如 PostScript Type 1 字体,或者,在 TrueType/OpenType 字体的情况下,在它们的cmap表中定义)以将字符代码与其正确的字形相关联.

CUDA 的默认字体 DejaVu Sans 和 DejaVu Sans Mono 是 TrueType 字体并且确实包含一个cmap表格,因此它们的字形在物理上可以是任意随机顺序——这取决于字体设计者的判断。一种字体可以首先列出它的所有 A 字形,然后是所有 B 字形,依此类推,或者按字面上的任何顺序列出。如果字体包含 Latin-1 的编码表,则该表将在相应字形的字符代码A和字体的字形位置之间进行转换。如果相同的字体还包含完全不同的编码,例如 EBCDIC,它自己的代码A(不是基于 ASCII,因此不是“通常的”0x41,而是 0xC1)仍将指向字体中的相同A 字形

做什么cudafont完全是另一回事。它假定至少基本 ASCII的字形完全按照该顺序出现,从字体中的第一个字形开始。这意味着除了字体设计者强加的字形顺序之外,您不能使用任何其他字形顺序。此外,由于cudafont将字符代码限制为仅 8 位,因此您无法访问 6,107 (DejaVu Sans) 和 3,309 (DejaVu Sans Mono) 字符中的任何字符,ASCII 代码 256 之前范围内的字符除外。

我简要浏览了字形集,在我看来它们是按Unicode 顺序排列的。现在,幸运的是(对于cudafonts 程序员),这确实意味着前 95 个字符是按 ASCII 顺序排列的。

不幸的是我的西欧读者(通常对 Latin-1 边界之外的任何东西都不感兴趣)——下一个仍然遵循常见的ISO/IEC 8859-1顺序,但是按照惯例,缺少从 0x7F 到 0x9F 的范围。在基于原始 Latin-1 的 Unicode Latin-1 Supplement 中,这些代码表示控制代码并且没有字形表示。

这仍然意味着您无法将 Python 的默认 UTF-8 编码字符串输入其中,但除了纯 ASCII 之外,您无法指示 Python 将您的文本编码为 Latin-1。Python可以对其进行编码:

text = 'fængsel'
print (text)
print (text.encode('latin-1'))

fængsel
b'f\xe6ngsel'

但由于缺少范围,显示的字符在列表中仅出现 33 个字形:ć.

解决方案:中间缺少 33 个字符,因此您可以调整(现在)二进制字符串内容以再次匹配物理字形顺序:

btext = bytes([c if c <= 0x7f else c-33 for c in text.encode('latin-1')])
print (btext)

b'f\xc5ngsel'

并且字符串应该(理论上)最终呈现您的fængsel.

任何想要访问超出此修复范围的字形的假设用户都不走运,直到cudafont更新为 (a) 正确使用字体的编码,以及 (b) 支持完整的 Unicode 范围而不是char仅支持 s。至少它得到了一个简短的提及stb_truetype.h

// Todo:
// 非 MS cmaps


推荐阅读