diff --git a/README.md b/README.md index 8c8a1dfde42d0a0b348dbf747404659c64a202b9..cba8fd62b5e0990318bf6218493e530303588126 100644 --- a/README.md +++ b/README.md @@ -1,21 +1,27 @@ # 图像字符化 -## 介绍 +## 功能介绍 ## 图片转换为文本 -运行 `python img2txt.py` 读取默认输入 `data/input.jpg`,生成字符化后的文本文件。 +运行 `python img2txt.py`,生成字符化后的文本文件。 + +## 图片转换为 html + +运行 `python img2html.py`,生成字符化后的彩色 html。 ## 图片转换为图片 -运行 `python img2img.py` 读取默认输入 `data/input.jpg`,生成字符化后的黑白图片 `data/output.jpg`。`img2img_color` 生成彩色的。 +运行 `python img2img.py`,生成字符化后的黑白图片 `data/output.jpg`。`img2img_color` 生成彩色的。 加选项用指定语言 (english, german, french ...) 的字符,如` --language french`,暂不支持中日韩(见与原库差别)。 ## 更多选项 -见源码 `get_args` 部分。 +默认读取图片文件 `data/input.jpg` 作为输入,可用 `--输入` 指定其他的文件路径。 + +其他选项见源码 `get_args` 部分。 ## 环境依赖 diff --git a/img2html.py b/img2html.py new file mode 100644 index 0000000000000000000000000000000000000000..fd5d3bf266eb67434580a6d769ee66ec8a28b60f --- /dev/null +++ b/img2html.py @@ -0,0 +1,60 @@ +import argparse + +import cv2 +import numpy as np + + +def get_args(): + parser = argparse.ArgumentParser("Image to ASCII") + parser.add_argument("--输入", type=str, default="data/input.jpg", help="原图文件路径") + parser.add_argument("--output", type=str, default="data/output.html", help="生成 html 文件路径") + parser.add_argument("--mode", type=str, default="complex", choices=["simple", "complex"], + help="10 or 70 different characters") + parser.add_argument("--num_cols", type=int, default=150, help="number of character for output's width") + args = parser.parse_args() + return args + +def rgb_to_hex(rgb): + return '#{0:02x}{1:02x}{2:02x}'.format(*rgb) + +def main(opt): + if opt.mode == "simple": + 字符列表 = '@%#*+=-:. ' + else: + 字符列表 = "$@B%8&WM#*oahkbdpqwmZO0QLCJUYXzcvunxrjft/\|()1{}[]?-_+~<>i!lI;:,\"^`'. " + 字符种数 = len(字符列表) + 列数 = opt.num_cols + 图片 = cv2.imread(opt.输入) + 图片 = cv2.cvtColor(图片, cv2.COLOR_BGR2RGB) + 图高, 图宽, _ = 图片.shape + 格宽 = 图宽 / opt.num_cols + 格高 = 2 * 格宽 + 行数 = int(图高 / 格高) + if 列数 > 图宽 or 行数 > 图高: + print("Too many columns or rows. Use default setting") + 格宽 = 6 + 格高 = 12 + 列数 = int(图宽 / 格宽) + 行数 = int(图高 / 格高) + + 输出文件 = open(opt.output, 'w') + 输出文件.write('
')
+    for 行号 in range(行数):
+        for 列号 in range(列数):
+            局部图 = 图片[int(行号 * 格高) : min(int((行号 + 1) * 格高), 图高),
+                        int(列号 * 格宽) : min(int((列号 + 1) * 格宽), 图宽)]
+            局部平均颜色 = np.sum(np.sum(局部图, axis=0), axis=0) / (格高 * 格宽)
+            局部平均颜色 = tuple(局部平均颜色.astype(np.int32).tolist())
+            输出文件.write(
+                ''
+                + 字符列表[min(int(np.mean(局部图) * 字符种数 / 255), 字符种数 - 1)]
+                + '')
+            
+        输出文件.write("
") + 输出文件.write('
') + 输出文件.close() + + +if __name__ == '__main__': + opt = get_args() + main(opt) \ No newline at end of file diff --git a/img2img_color.py b/img2img_color.py index a0818a2d2ff0fd91b13988f2dd05d2ec0456703c..3d1e386f2998ee384293154bd971d0fc6c26af67 100644 --- a/img2img_color.py +++ b/img2img_color.py @@ -25,47 +25,47 @@ def get_args(): def main(opt): if opt.background == "white": - bg_code = (255, 255, 255) + 背景编码 = (255, 255, 255) else: - bg_code = (0, 0, 0) - char_list, font, 字符示例, scale = get_data(opt.language, opt.mode) - num_chars = len(char_list) - num_cols = opt.num_cols - image = cv2.imread(opt.input, cv2.IMREAD_COLOR) - image = cv2.cvtColor(image, cv2.COLOR_BGR2RGB) - height, width, _ = image.shape + 背景编码 = (0, 0, 0) + 字符列表, font, 字符示例, scale = get_data(opt.language, opt.mode) + 字符种数 = len(字符列表) + 列数 = opt.num_cols + 图片 = cv2.imread(opt.input, cv2.IMREAD_COLOR) + 图片 = cv2.cvtColor(图片, cv2.COLOR_BGR2RGB) + 图高, 图宽, _ = 图片.shape 字符宽度, 字符高度 = font.getsize(字符示例) 字符高宽比 = 字符高度/字符宽度 - cell_width = width / opt.num_cols - cell_height = 字符高宽比 * cell_width - num_rows = int(height / cell_height) - if num_cols > width or num_rows > height: + 格宽 = 图宽 / opt.num_cols + 格高 = 字符高宽比 * 格宽 + 行数 = int(图高 / 格高) + if 列数 > 图宽 or 行数 > 图高: print("Too many columns or rows. Use default setting") - cell_width = 6 - cell_height = 字符高宽比 * cell_width - num_cols = int(width / cell_width) - num_rows = int(height / cell_height) - out_width = 字符宽度 * num_cols - out_height = scale * 字符高度 * num_rows - out_image = Image.new("RGB", (out_width, out_height), bg_code) - draw = ImageDraw.Draw(out_image) - for i in range(num_rows): - for j in range(num_cols): - partial_image = image[int(i * cell_height):min(int((i + 1) * cell_height), height), - int(j * cell_width):min(int((j + 1) * cell_width), width), :] - partial_avg_color = np.sum(np.sum(partial_image, axis=0), axis=0) / (cell_height * cell_width) - partial_avg_color = tuple(partial_avg_color.astype(np.int32).tolist()) - char = char_list[min(int(np.mean(partial_image) * num_chars / 255), num_chars - 1)] - draw.text((j * 字符宽度, i * 字符高度), char, fill=partial_avg_color, font=font) + 格宽 = 6 + 格高 = 字符高宽比 * 格宽 + 列数 = int(图宽 / 格宽) + 行数 = int(图高 / 格高) + 输出宽度 = 字符宽度 * 列数 + 输出高度 = scale * 字符高度 * 行数 + 输出图片 = Image.new("RGB", (输出宽度, 输出高度), 背景编码) + draw = ImageDraw.Draw(输出图片) + for 行号 in range(行数): + for 列号 in range(列数): + 局部图 = 图片[int(行号 * 格高) : min(int((行号 + 1) * 格高), 图高), + int(列号 * 格宽) : min(int((列号 + 1) * 格宽), 图宽)] + 局部平均颜色 = np.sum(np.sum(局部图, axis=0), axis=0) / (格高 * 格宽) + 局部平均颜色 = tuple(局部平均颜色.astype(np.int32).tolist()) + 字符 = 字符列表[min(int(np.mean(局部图) * 字符种数 / 255), 字符种数 - 1)] + draw.text((列号 * 字符宽度, 行号 * 字符高度), 字符, fill=局部平均颜色, font=font) if opt.background == "white": - cropped_image = ImageOps.invert(out_image).getbbox() + cropped_image = ImageOps.invert(输出图片).getbbox() else: - cropped_image = out_image.getbbox() - out_image = out_image.crop(cropped_image) - out_image.save(opt.output) + cropped_image = 输出图片.getbbox() + 输出图片 = 输出图片.crop(cropped_image) + 输出图片.save(opt.output) if __name__ == '__main__': diff --git a/img2txt.py b/img2txt.py index 44bda99e0fd798f1ae91366eea1d8f99189319fd..0e53bcfce39c042adb11995a653de0600f5746bd 100644 --- a/img2txt.py +++ b/img2txt.py @@ -20,33 +20,33 @@ def get_args(): def main(opt): if opt.mode == "simple": - CHAR_LIST = '@%#*+=-:. ' + 字符列表 = '@%#*+=-:. ' else: - CHAR_LIST = "$@B%8&WM#*oahkbdpqwmZO0QLCJUYXzcvunxrjft/\|()1{}[]?-_+~<>i!lI;:,\"^`'. " - num_chars = len(CHAR_LIST) - num_cols = opt.num_cols - image = cv2.imread(opt.input) - image = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY) - height, width = image.shape - cell_width = width / opt.num_cols - cell_height = 2 * cell_width - num_rows = int(height / cell_height) - if num_cols > width or num_rows > height: + 字符列表 = "$@B%8&WM#*oahkbdpqwmZO0QLCJUYXzcvunxrjft/\|()1{}[]?-_+~<>i!lI;:,\"^`'. " + 字符种数 = len(字符列表) + 列数 = opt.num_cols + 图片 = cv2.imread(opt.input) + 图片 = cv2.cvtColor(图片, cv2.COLOR_BGR2GRAY) + 图高, 图宽 = 图片.shape + 格宽 = 图宽 / opt.num_cols + 格高 = 2 * 格宽 + 行数 = int(图高 / 格高) + if 列数 > 图宽 or 行数 > 图高: print("Too many columns or rows. Use default setting") - cell_width = 6 - cell_height = 12 - num_cols = int(width / cell_width) - num_rows = int(height / cell_height) - - output_file = open(opt.output, 'w') - for i in range(num_rows): - for j in range(num_cols): - output_file.write( - CHAR_LIST[min(int(np.mean(image[int(i * cell_height):min(int((i + 1) * cell_height), height), - int(j * cell_width):min(int((j + 1) * cell_width), - width)]) * num_chars / 255), num_chars - 1)]) - output_file.write("\n") - output_file.close() + 格宽 = 6 + 格高 = 12 + 列数 = int(图宽 / 格宽) + 行数 = int(图高 / 格高) + + 输出文件 = open(opt.output, 'w') + for 行号 in range(行数): + for 列号 in range(列数): + 局部图 = 图片[int(行号 * 格高) : min(int((行号 + 1) * 格高), 图高), + int(列号 * 格宽) : min(int((列号 + 1) * 格宽), 图宽)] + 输出文件.write( + 字符列表[min(int(np.mean(局部图) * 字符种数 / 255), 字符种数 - 1)]) + 输出文件.write("\n") + 输出文件.close() if __name__ == '__main__':