dailenson / SDT

This repository is the official implementation of Disentangling Writer and Character Styles for Handwriting Generation (CVPR23).
MIT License
956 stars 81 forks source link

教程:如何生成自己的个性化手写文字? #43

Open dailenson opened 7 months ago

dailenson commented 7 months ago

1.数据预处理

4971704624672_ pic 首先是在白纸上写至少15个字(我自己抄了一首诗,写了28个字,没有白纸的话用别的颜色的纸应该也行),然后用扫描软件(例如夸克ocr)扫描一下,估计可以自动把背景去掉。以下是扫描后的样子:

4981704624748_ pic

然后就是手动裁剪部分啦,我用的是windows自带的画图板,有裁剪功能,直接对着图片,右键点击选择画图, 4991704624919_ pic

打开图片后,选择裁剪,裁剪的时候注意,大概贴着字裁个差不多的正方形就好(后面代码里面会自动resize成64*64),然后保存成jpg或者png都行。 5001704625174_ pic

裁完之后的样子如下图所示: 4961704599879_ pic

接着,把这些图片放到一个文件夹下面就行,假设大家放到了style_samples文件夹里面。

2.代码运行

首先按照readme里面的步骤把环境配置好,然后运行:

python user_generate.py --pretrained_model checkpoint_path --style_path style_samples

checkpoint_path要从网盘里面下载,readme里面有给下载链接,checkpoint在网盘的saved_weights/Chinese/路径下面。我测了一下,有gpu的情况下,3分钟左右就可以生成6763个中文字符,生成的字符存放在Generated/Chinese_User路径。

最后,祝大家使用愉快~如果想在word软件里面使用的话,直接百度“图像转ttf文件”即可。

zcfrank1st commented 7 months ago

点赞,我来试试

pledge42 commented 7 months ago

在Windows系统下可能会出现报错 error: (-215:Assertion failed) !ssize.empty() in function 'cv::resize' 可能是路径中有中文导致的,把生成图片的.jpg改成英文或者数字即可解决 (经过测试,样本中的.jpg文件是否是对应的中文与推演结果无关,即想省事直接随便命名, 想要中文命名不报错的方法在最后) 或者用以下代码来检查哪张图片有问题(有中文路径就会报错)

import os
import cv2
filpath='D:/CVPR2023_SDT/SDT-master/style_samples'
image_list = os.listdir(filpath)  # 读取文件夹中所有的图片
print(image_list)
i=0
for picname in image_list:
    i += 1
    img = cv2.imread((filpath + '/' + picname), 0)
    try:
        img = cv2.resize(img, (64, 64))
        print(i, picname) #打印当前成功处理的图片数量图片名称
    except :
        print(picname) #打印出有问题的图片名
        break 

带数字的图片名称是正确的,不带数字的名称是有问题的

以下是改中文的路径又不报错的方法loader.py中大概224行 把style_img = cv2.imread(self.style_path[idx], flags=0) 替换成 style_img = cv2.imdecode(np.fromfile(self.style_path[idx], dtype=np.uint8), cv2.IMREAD_GRAYSCALE) 在中文下运行不会报错 兼容中英文的检查程序就是 把 img = cv2.imread((filpath + '/' + picname), 0) 替换成 img = cv2.imdecode(np.fromfile(filpath + '/' + picname,dtype=np.uint8),-1)

zcfrank1st commented 7 months ago

点赞,我来试试

试了一下,字体不是太像。。。用了17个字做sample进行生成,会不会微调下效果会好?

pledge42 commented 7 months ago

自己的字和生成的字属于是完全没啥关系,图1自己的字,图2生成的字 是不是自己写的字不是用中文命名的原因,但是Windows系统下用中文命名的.jpg图片就会报错 image image

dailenson commented 7 months ago

点赞,我来试试

试了一下,字体不是太像。。。用了17个字做sample进行生成,会不会微调下效果会好?

可以多喂点字进去先试试,微调一下模型肯定是最好的

dailenson commented 7 months ago

自己的字和生成的字属于是完全没啥关系,图1自己的字,图2生成的字 是不是自己写的字不是用中文命名的原因,但是Windows系统下用中文命名的.jpg图片就会报错 image image

训练过程中文字的笔画宽度是均匀的。现在真实场景下,遇到的文字是有多样笔画宽度了,对模型的泛化性是个很大的挑战了。如何解决笔画宽度的问题,我们下一个工作正在弄,还需要点时间。

zcfrank1st commented 7 months ago

点赞,我来试试

试了一下,字体不是太像。。。用了17个字做sample进行生成,会不会微调下效果会好?

可以多喂点字进去先试试,微调一下模型肯定是最好的

OK

pledge42 commented 7 months ago

研究了一个晚上发现了几个问题 第一,使用user_generate.py生成的单位是106,而用test.py生成的单位却是468,都是引用了同一个.pth文件为何会这样 image image

第二,使用user_generate.py生成的字十分的潦草,即使尽力把预处理做好,虽能看出与‘test.py'确实不同 该如何达到readme中的效果 image image 我尝试过给了30个去推演,结果风格都是一笔划写的字,因为预训练模型不是同一个吗? image user_generate.py生成的 image 自己写的

dailenson commented 7 months ago

研究了一个晚上发现了几个问题 第一,使用user_generate.py生成的单位是106,而用test.py生成的单位却是468,都是引用了同一个.pth文件为何会这样 image image

第二,使用user_generate.py生成的字十分的潦草,即使尽力把预处理做好,虽能看出与‘test.py'确实不同 该如何达到readme中的效果 image image 我尝试过给了30个去推演,结果风格都是一笔划写的字,因为预训练模型不是同一个吗? image user_generate.py生成的 image 自己写的

感谢你的反馈,我这边大概分析了一下。原因感觉还是数据差异的问题,具体来说的话:我们训练时候的数据是使用的公开数据集,笔画宽度是均匀的,你的数据似乎是平板采集的,具有更加真实的笔画宽度,由于跟训练数据的分布差异过大,导致模型倾向于给出一个平均化的风格,这个平均化的风格指的是训练集所有的风格的平均。想要提高效果的话,fine-tune一下应该会好很多,可以让模型适应一下你的数据。

另外,你的第一个问题,因为user_generate.py只生成你一个人的6733个文字,所以iteration是6733/64=105.2 (64是batchsize)的大小。test.py是生成测试集中60个书写者的6733个文字,然后每个书写者采样生成500个所以iteration是60×500/64=468.75

你贴的最后一张图是SDT的一个拓展,我们引入了一个额外的装饰网络,为SDT生成的均匀笔画的文字增加了笔画宽度和颜色。

YYYYYYYen commented 7 months ago

提问:按照作者给出的python user_generate.py --pretrained_model checkpoint_path --style_path style_samples运行后,再添加图片生成出来的字和原来所生成的字的字一模一样是什么原因:)

dailenson commented 7 months ago

提问:按照作者给出的python user_generate.py --pretrained_model checkpoint_path --style_path style_samples运行后,再添加图片生成出来的字和原来所生成的字的字一模一样是什么原因:)

原来生成的字指的是什么?

13232308597 commented 7 months ago

(base) C:\Windows\System32>python user_generate.py --pretrained_model checkpoint_path --style_path style_samples python: can't open file 'C:\Windows\System32\user_generate.py': [Errno 2] No such file or directory 下载的文件里没找到有user_generate.py诶

dailenson commented 7 months ago

(base) C:\Windows\System32>python user_generate.py --pretrained_model checkpoint_path --style_path style_samples python: can't open file 'C:\Windows\System32\user_generate.py': [Errno 2] No such file or directory 下载的文件里没找到有user_generate.py诶

重新下载最新版的文件

13232308597 commented 7 months ago

G:\python38\python.exe C:\desktop\SDT-master(new)\SDT-master\user_generate.py --pretrained_model C:\desktop\CVPR2023_SDT\saved_weights\Chinese\checkpoint-iter199999.pth load pretrained model from C:\desktop\CVPR2023_SDT\saved_weights\Chinese\checkpoint-iter199999.pth 0%| | 0/106 [00:00<?, ?it/s] Traceback (most recent call last): File "C:\desktop\SDT-master(new)\SDT-master\user_generate.py", line 83, in main(opt) File "C:\desktop\SDT-master(new)\SDT-master\user_generate.py", line 55, in main preds = model.inference(img_list, char_img, 120) File "C:\desktop\SDT-master(new)\SDT-master\models\model.py", line 152, in inference batch_size, num_imgs, in_planes, h, w = style_imgs.shape ValueError: not enough values to unpack (expected 5, got 3) ChatGPT回答:根据错误信息,看起来问题出现在模型的 inference 方法中的 style_imgs.shape。错误信息表明期望的形状是 (batch_size, num_imgs, in_planes, h, w),但实际的形状是 (3,)。 这个问题可能是由于样式图片的数量不足导致的。请确保 style_samples 文件夹中至少有5张样式图片。如果没有足够的样式图片,你可以添加更多的样式图片到该文件夹中。 如果你已经确认样式图片的数量足够,并且问题仍然存在,那么可能需要检查模型的代码,确保在 inference 方法中对 style_imgs 进行正确的处理,以适应不同数量的样式图片。 我是直接在user_generate.py相同的根目录里新建的style_samples文件夹,里面放了86张png格式的图片,是哪里弄错了吗

CreeperAWA commented 7 months ago

没有英伟达显卡有办法用吗

cactusgame commented 7 months ago

请问您3分钟可以执行一遍的gpu配置是?我用T4跑一遍需要12分钟

checkpoint_path要从网盘里面下载,readme里面有给下载链接,checkpoint在网盘的saved_weights/Chinese/路径下面。我测了一下,有gpu的情况下,3分钟左右就可以生成6763个中文字符,生成的字符存放在Generated/Chinese_User路径。

dailenson commented 7 months ago

没有英伟达显卡有办法用吗

没有显卡的话就用Cpu啦,会慢一点。

dailenson commented 7 months ago

请问您3分钟可以执行一遍的gpu配置是?我用T4跑一遍需要12分钟

checkpoint_path要从网盘里面下载,readme里面有给下载链接,checkpoint在网盘的saved_weights/Chinese/路径下面。我测了一下,有gpu的情况下,3分钟左右就可以生成6763个中文字符,生成的字符存放在Generated/Chinese_User路径。

我的是RTX 3090

CreeperAWA commented 7 months ago

没有英伟达显卡有办法用吗

没有显卡的话就用 Cpu 啦,会慢一点。

能讲一下怎么用CPU吗

dailenson commented 7 months ago

没有英伟达显卡有办法用吗

没有显卡的话就用 Cpu 啦,会慢一点。

能讲一下怎么用CPU吗

我抽空整理一个cpu版本

chengtx809 commented 7 months ago

FileNotFoundError: [Errno 2] No such file or directory: 'data\CASIA_CHINESE\Chinese_content.pkl' 大佬这又是因为什么a

dailenson commented 7 months ago

FileNotFoundError: [Errno 2] No such file or directory: 'data\CASIA_CHINESE\Chinese_content.pkl' 大佬这又是因为什么a

你下载好了Chinese_content.pkl这个文件吗?

CreeperAWA commented 7 months ago

没有英伟达显卡有办法用吗

没有显卡的话就用 Cpu 啦,会慢一点。

能讲一下怎么用 CPU 吗

我抽空整理一个 cpu 版本

大佬弄好了回个话哈

chengtx809 commented 7 months ago

没有英伟达显卡有办法用吗

没有显卡的话就用 Cpu 啦,会慢一点。

能讲一下怎么用CPU吗

我抽空整理一个cpu版本

催更哈哈

13232308597 commented 7 months ago

没有英伟达显卡有办法用吗

没有显卡的话就用 Cpu 啦,会慢一点。

能讲一下怎么用 CPU 吗

我抽空整理一个 cpu 版本

大佬弄好了回个话哈

55

13232308597 commented 7 months ago

没有英伟达显卡有办法用吗

没有显卡的话就用 Cpu 啦,会慢一点。

能讲一下怎么用CPU吗

我抽空整理一个cpu版本

催更哈哈

55

chengtx809 commented 7 months ago

没有英伟达显卡有办法用吗

没有显卡的话就用 Cpu 啦,会慢一点。

能讲一下怎么用 CPU 吗

我抽空整理一个 cpu 版本

大佬弄好了回个话哈

56 我写了个教程

awei669 commented 7 months ago

FileNotFoundError: [Errno 2] No such file or directory: 'data\CASIA_CHINESE\Chinese_content.pkl' 大佬这又是因为什么a

需要重新给data重新设置一个软链接,原repo作者是链接到了他的data,首先使用命令移除掉这个软链接,unlink data,然后使用命令ln -s 被链接的文件或目录名称 链接名称将data链接到你下载数据的地方,这样做可以避免移动数据集。

以下以我的机器为例子。

image
dailenson commented 6 months ago

没有英伟达显卡有办法用吗

没有显卡的话就用 Cpu 啦,会慢一点。

能讲一下怎么用CPU吗

我抽空整理一个cpu版本

催更哈哈

哈哈哈 这两天在弄CVPR的rebuttal,31号以后弄一下

chengtx809 commented 6 months ago

没有英伟达显卡有办法用吗

没有显卡的话就用 Cpu 啦,会慢一点。

能讲一下怎么用CPU吗

我抽空整理一个cpu版本

催更哈哈

哈哈哈 这两天在弄CVPR的rebuttal,31号以后弄一下

大佬,我自己等不及已经写了一个cpu的版本哈哈 提了pr,大佬可以看看我写的还有什么问题吗

liusenb commented 6 months ago

使用如下脚本切割获取了200多手写字体(图1、图2),249个字体训练后生成的字体(图3)和手写字体差别很大,跟手写字体文件名是否有关?

import argparse
import os
import cv2
import shutil

def main(opt):
    # 膨胀腐蚀大小 即将笔画膨胀 避免将偏旁单独分割 根据图片请况自行设置
    rect_size = 16
    # 字体小于该值忽略 20*20
    ignore_min_size = 20
    # 字体大于该值忽略 100*100
    ignore_max_size = 100

    # 需要切分的图片 input/input.jpg
    input_file = opt.input_path

    # 输出文件夹 output
    output_path = opt.output_path + os.path.sep
    if not os.path.exists(output_path):
        os.makedirs(output_path)
    else:
        shutil.rmtree(output_path)
        os.makedirs(output_path)

    img = cv2.imread(input_file)

    gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
    # 二值化 根据图片情况调节灰度阈值 第二个参数灰度值表示小于该值就将其变为0
    ret, thresh = cv2.threshold(gray, 150, 255, cv2.THRESH_BINARY)
    cv2.imwrite(output_path + "thresh.jpg", thresh)
    thresh_rgb = cv2.cvtColor(thresh, cv2.COLOR_GRAY2BGR)
    # 待切分的图片 img原图 gray灰度图 thresh二值化后的灰度图 thresh_rgb二值化后转RGB
    result = thresh.copy()

    # 膨胀腐蚀 将字体笔画扩大15像素
    kernel = cv2.getStructuringElement(cv2.MORPH_RECT, (rect_size, rect_size))
    eroded = cv2.erode(thresh, kernel)
    cv2.imwrite(output_path + "eroded.jpg", eroded)

    # 轮廓检测
    contours, hierarchy = cv2.findContours(eroded, cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE)

    # 膨胀间距
    spacing = rect_size // 2 - 1
    cut_frame_color = (0, 255, 0)
    font_frame_color = (255, 0, 0)
    for c in contours:
        x, y, w, h = cv2.boundingRect(c)
        if w < ignore_min_size or h < ignore_min_size or w > ignore_max_size or h > ignore_max_size:
            continue

        font_w = w - spacing - spacing
        font_h = h - spacing - spacing

        frame_size = font_w if font_w > font_h else font_h

        # 正方形切割偏移量
        x_offset = int((frame_size - font_w) / 2)
        y_offset = int((frame_size - font_h) / 2)

        start_x = x + spacing - x_offset
        start_y = y + spacing - y_offset
        end_x = x + w - spacing + x_offset
        end_y = y + h - spacing + y_offset

        # 字体框线
        cv2.rectangle(thresh_rgb, (x + spacing, y + spacing), (x + w - spacing, y + h - spacing), font_frame_color, 1)
        # 切割框线
        cv2.rectangle(thresh_rgb, (start_x, start_y), (end_x, end_y), cut_frame_color, 1)
        # 切割
        temp = result[start_y:end_y, start_x:end_x]
        path = opt.output_path + os.path.sep + "result" + os.path.sep
        if not os.path.exists(path):
            os.makedirs(path)
        cv2.imwrite(path + str(x) + "_" + str(y) + ".jpg", temp)

    cv2.imwrite(output_path + "result.jpg", thresh_rgb)

if __name__ == '__main__':
    """Parse input arguments"""
    parser = argparse.ArgumentParser()
    parser.add_argument('--input', dest='input_path', default='input/input.jpg',
                        help='Please set the input path')
    parser.add_argument('--output', dest='output_path', default='output',
                        help='Please set the output path')
    opt = parser.parse_args()
    main(opt)

图1

图2

图3

dailenson commented 6 months ago

生成效果不满意,出现“狂草”现象的朋友,可以试试将收集的参考图像做个二值化处理再输入模型中,应该可以提升生成效果https://github.com/dailenson/SDT/issues/59#issuecomment-1963233481

CreeperAWA commented 6 months ago

用文心一言写了个图片二值化的代码( https://github.com/CreeperAWA/Binary-Image

PekoYinT commented 5 months ago

PermissionError: [Errno 13] Permission denied: 这个报错一直解决不了

PekoYinT commented 5 months ago

解决了谢谢

YZcat2023 commented 4 months ago

image

dailenson commented 4 months ago

image

这位兄弟复现的应该是目前效果最好的。详情见https://github.com/dailenson/SDT/issues/75#issuecomment-2031897517

aceliuchanghong commented 2 months ago

额外的装饰网络,为SDT生成的均匀笔画的文字增加了笔画宽度和颜色 作者大佬,这个可以解释一下吗? 额外的装饰网络,为SDT生成的均匀笔画的文字增加了笔画宽度和颜色

shurenhdsm commented 1 month ago

PermissionError: [Errno 13] 权限被拒绝:这个报错一直解决不了 同问,请问怎么解决呢