前言
最近沉迷武侠小说和武侠网络游戏,被里边的武学招式深深的吸引住了。武侠小说还好,整个江湖世界由作者搭建而起,主角也在起稿之后定了下来。且不说独一无二,但是武侠小说里但主角大多拥有被人无法获得的独特心法和极为给力的招式。但武侠网络游戏不同。虽然每个在线玩家在剧情当中能够体会到主角的感觉,但是每个玩家并不是独一无二的。他们有着同样的技能图标,有着同样的武学名称。有人会说,就算这些都一样,但是不同的手法和反应速度,每个玩家也会不同。我就在想,可不可以使用某些方法,让程序自动生成武侠网易的技能图标和武学名称呢?
起手式—仙人指路
既然是武学名称,那自然是由汉字组成。我去搜索了以下,找到了一个十分完备的汉字库,没错,那就是新华字典。这个仓库包含了14032 条歇后语,16142个汉字,264434个词语,31648个成语。没错,我们总共才有16142个汉字,可以用一张图像随意进行范围覆盖。用多大的图像呢?我们来算算:128*128=16384。好巧啊,常用的128*128图像正好能够对所有汉字进行全覆盖。那就这么决定了,使用128*128的图像作为汉字的载体。到这里有人要问了,为啥要用图像来承载所有汉字?目前我的想法是:
- 可以将武学图标和武学名称统一到这张图像上。
- 目前来看深度学习在可以很好的处理图像中的某些问题。
第一式—浑水摸鱼
直接下载下来的新华字典较为的冗余,但我们只需要其中但汉字,故我们需要对这个数据库做一个数据的提取。我们先来看看汉字库的json文件
{
"word": "吖",
"oldword": "吖",
"strokes": "6",
"pinyin": "ā",
"radicals": "口",
"explanation": "喊叫天~地。\n 形容喊叫的声音高声叫~~。\n\n 吖ā[吖啶黄](-dìnghuáng)〈名〉一种注射剂。\n ────────────────—\n \n 吖yā 1.呼;喊。",
"more": "吖 a 部首 口 部首笔画 03 总笔画 06 吖2\nyā\n喊,呼喊 [cry]\n不索你没来由这般叫天吖地。--高文秀《黑旋风》\n吖\nyā\n喊声\n则听得巡院家高声的叫吖吖。--张国宾《合汗衫》\n另见ā\n吖1\nā\n--外国语的音译,主要用于有机化学。如吖嗪\n吖啶\nādìng\n[acridine] 一种无色晶状微碱性三环化合物c13h9n,存在于煤焦油的粗蒽馏分中,是制造染料和药物(如吖啶黄素和奎吖因)的重要母体化合物\n吖1\nyā ㄧㄚˉ\n(1)\n喊叫天~地。\n(2)\n形容喊叫的声音高声叫~~。\n郑码jui,u5416,gbkdfb9\n笔画数6,部首口,笔顺编号251432\n吖2\nā ㄚˉ\n叹词,相当于呵”。\n郑码jui,u5416,gbkdfb9\n笔画数6,部首口,笔顺编号251432"
},
可以看出,汉字的json拥有着非常丰富的信息,但是呢,我们只需要其中的word字段。为了方便,我们可以使用python来提取这个字段,并构成一个新的json文件。
import json
# 读取json文件
f = open("word.json", encoding='utf-8')
# 加载
setting = json.load(f)
# 初始化字典
img2word = {}
word2img = {}
# 遍历json
for idx in range(len(setting)):
# 取得word字段对应的内容
word = setting[idx]['word']
# 将内容保存到该字典,键为idx
img2word[idx] = word
# 将idx保存到该字典,键为内容
word2img[word] = idx
# 把两个字典写入文件
with open("img2word1.json","w") as f:
json.dump(img2word,f)
with open("word2img2.json","w") as f:
json.dump(word2img,f)
可以看出,有了json模块,读取json文件和构建新的json文件简直是小菜一碟。
完成这一步后,我们就得到了待会需要用到的汉字数据。
第二式—水中捞月
通过第一式我们得到了两个字典文件,一个用标号可以索引到内容,另一个使用内容可以索引到标号。故在第二式开始前,需要将这两个字典文件读取到内存中。
f_img = open("img2word.json", encoding='utf-8')
f_word = open("word2img.json", encoding='utf-8')
# 由标号索引到内容
self.img2word = json.load(f_img)
# 由内容索引到标号
self.word2img = json.load(f_word)
有了这两个数据后,我们就可以展现乾坤大挪移和吸星大法
第三式—乾坤大挪移
该功法主要使用图像和上述提到的字典来构建一个方法,那个方法的作用在于将文字储存到图像当中
# 短语转图像
# str为武学名称
def word2img_func(str):
# 构建一副空图像
word_img = np.zeros((128,128,3),dtype=np.float)
for idx, item in enumerate(str):
# 通过汉字来索引到idx
img_idx = self.word2img[item]
# 将idx分解为行列值
row, col = img_idx//128, img_idx%128
# 设置该位置为有值
word_img[row, col, 0] = 1
if word_img[row, col, 1] == 0:
# 在该位置添加上武学的名称顺序
word_img[row, col, 1] = idx+1
else:
# 当出现重复汉字时
word_img[row, col, 1] = word_img[row, col, 1]*10+(idx+1)
return word_img
在上述代码中,主要就是将文字的标号按行列进行分解,然后用图像的第一纬度记录是否存在文字,用图像的第二位度记录该文字处在武学名称的第几位。下面我们来使用这段代码看看生成的图像是什么样的
skill = '降龙十八掌'
word_img = word2img_func(skill)
cv2.imwrite('test.png', word_img)
没错,就是一篇漆黑!我们仅仅只是把十分稀少的数据放入图片中,并没有做其他操作,因此,这张还是这么黑。
第四式—吸星大法
接下来,就是从图像中解析出武学名称。其实这就是很简单的,从一个矩阵中,取出数值为一的坐标,再用坐标来构建原始的idx,最后使用idx来索引到内容。
# 图像转短语
def img2word_func(img):
# 取得数据大于0到行列坐标
rows, cols = np.where(img[:,:,0]>0)
word_dic = {}
for row, col in zip(rows, cols):
# 构建idx
word_idx = row*128+col
ord_idx = img[row, col, 1]
while ord_idx>10:
# 依次通过idx取出数据
word_dic[ord_idx%10] = self.img2word[str(word_idx)]
ord_idx //= 10
word_dic[ord_idx] = self.img2word[str(word_idx)]
# 使用idx进行排序,保证武学名称不出错
word_dic = sorted(word_dic.items(), key=lambda d:d[0])
return word_dic
然后我们进行调用来查看效果
cv2.imread('test.png')
word = app.img2word_func(word_img)
print(word)
到这里,基础功能就完成了,接下来就是如何生成一个较为好看的武学图标,并从武学图标中提取出全新的武学。