我去年没事干干过这个, 计算字体聚类.
㬺幐(U+3B3A, U+5E50)
墫壿(U+58AB, U+58FF)
鬬鬭(U+9B2C, U+9B2D)
晚晩(U+665A, U+6669)
凉凉(U+51C9, U+F979) 我以后也要用这个词.
先随手创建一个文件夹, 然后新建一个 notebook.
选择 CJK 区 "㐀(U+3400)" 到" 龥(U+9FA5)"共 27558 个字.
有汉字有繁体字, 可能有异体字, 这个范围应该没有日语字...
字号 25 号, 字体使用混合字体 YaHei Consolas Hybrid, 对中文来说就是微软雅黑
all=StringPartition[FromCharacterCode[Range@@ToCharacterCode["㐀龥"]],1];
toImg=Rasterize@Style[#,FontSize->25,FontFamily->"YaHei Consolas Hybrid"]&;
然后用异步渲染把字都渲染出来.
并行策略选择了 Coarsest Grained, 适用于每个单元执行时间相近的情况.
虽然我也不知道并行快还是不并行快......
但是这样写就算内核突然崩溃了下次不用从头跑, 比较安全...
$now=Now
$here=DirectoryName@NotebookFileName[];
Exporter[num_]:=Block[
{name=$here<>ToString@num<>".png"},
If[FileExistsQ@name,Return[]];
Export[name,toImg@FromCharacterCode[num]]
];
ParallelMap[Exporter,Range@@ToCharacterCode["㐀龥"],Method->"CoarsestGrained"];
Now - $now
然后去上课, 上完课回来肯定就好了
渲染完洗一下内存, 再全部读进来, 关了重开也行...
然后随手选个聚类算法呗, 参数靠魔法...
瞎算了几次, 发现一个比较稳的方法.
可以分批次训练, 每批 2000 个字,聚类半径设为 10.
一起跑实在太慢了, 然后考虑到制字表的时候也是相似的字放在一起的, 应该不会出现大问题...
或者可以用快速聚类, 大约 1 分钟, 进行一个初步的空白区域大小划分.
然后再细致的对划分二次聚类, 毕竟聚类这个复杂度是超线性的, 划分一下虽然要算多算一次, 但还是有加速效果的...
$now=Now
$here=DirectoryName@NotebookFileName[];
all=Association[#->Import[#]&/@FileNames["*.png",$here]];
pat=Select[FindClusters[all,
Method->{"NeighborhoodContraction","NeighborhoodRadius"->10}],
Length@#>1&];
try1=Select[FindClusters[Association[#],
Method->{"NeighborhoodContraction","NeighborhoodRadius"->10}],
Length@#>1&]&/@Map[#->all[#]&,pat,{2}];
DeleteDuplicates/@Map[all,Flatten[try1,1],{2}]
Now-$now
然后去上另一节课, 上完差不多就能出图了, like this!
效果不够好, 基本上都是偏旁不同, 那就三次聚类呗, 现在已经只有 1690 个字了....
try2 = Select[
FindClusters[Association[Map[# -> all[#] &, Flatten[try1]]],
Method -> {"NeighborhoodContraction", "NeighborhoodRadius" -> 4}],
Length@# > 1 &]; Map[all, try2, {2}]
缺字会被垒到一起, 很迷, 还有就是异体字太多
我本来是想用机械智障造字....
构造一个 GAN, 生产者生产随机像素, 监督者来判别这个字存不存在...
然而...好像效果不咋的, 都没法通过我这个人的图灵测试, 毕竟.......
有噪点的都是新造的字啊....GG