Skip to content

Commit 23e164f

Browse files
committed
add conversion scripts for colors
1 parent d291919 commit 23e164f

File tree

2 files changed

+170
-0
lines changed

2 files changed

+170
-0
lines changed

img2img_color.py

Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,73 @@
1+
"""
2+
@author: Viet Nguyen <[email protected]>
3+
"""
4+
import argparse
5+
6+
import cv2
7+
import numpy as np
8+
from PIL import Image, ImageFont, ImageDraw, ImageOps
9+
10+
11+
def get_args():
12+
parser = argparse.ArgumentParser("Image to ASCII")
13+
parser.add_argument("--input", type=str, default="data/input.jpg", help="Path to input image")
14+
parser.add_argument("--output", type=str, default="data/output.jpg", help="Path to output text file")
15+
parser.add_argument("--mode", type=str, default="complex", choices=["simple", "complex"],
16+
help="10 or 70 different characters")
17+
parser.add_argument("--background", type=str, default="black", choices=["black", "white"],
18+
help="background's color")
19+
parser.add_argument("--num_cols", type=int, default=200, help="number of character for output's width")
20+
parser.add_argument("--scale", type=int, default=2, help="upsize output")
21+
args = parser.parse_args()
22+
return args
23+
24+
25+
def main(opt):
26+
if opt.mode == "simple":
27+
CHAR_LIST = '@%#*+=-:. '
28+
else:
29+
CHAR_LIST = "$@B%8&WM#*oahkbdpqwmZO0QLCJUYXzcvunxrjft/\|()1{}[]?-_+~<>i!lI;:,\"^`'. "
30+
if opt.background == "white":
31+
bg_code = (255, 255, 255)
32+
else:
33+
bg_code = (0, 0, 0)
34+
font = ImageFont.truetype("fonts/DejaVuSansMono-Bold.ttf", size=10 * opt.scale)
35+
num_chars = len(CHAR_LIST)
36+
num_cols = opt.num_cols
37+
image = cv2.imread(opt.input, cv2.IMREAD_COLOR)
38+
image = cv2.cvtColor(image, cv2.COLOR_BGR2RGB)
39+
height, width, _ = image.shape
40+
cell_width = width / opt.num_cols
41+
cell_height = 2 * cell_width
42+
num_rows = int(height / cell_height)
43+
if num_cols > width or num_rows > height:
44+
print("Too many columns or rows. Use default setting")
45+
cell_width = 6
46+
cell_height = 12
47+
num_cols = int(width / cell_width)
48+
num_rows = int(height / cell_height)
49+
char_width, char_height = font.getsize("A")
50+
out_width = char_width * num_cols
51+
out_height = 2 * char_height * num_rows
52+
out_image = Image.new("RGB", (out_width, out_height), bg_code)
53+
draw = ImageDraw.Draw(out_image)
54+
for i in range(num_rows):
55+
for j in range(num_cols):
56+
partial_image = image[int(i * cell_height):min(int((i + 1) * cell_height), height),
57+
int(j * cell_width):min(int((j + 1) * cell_width), width), :]
58+
partial_avg_color = np.sum(np.sum(partial_image, axis=0), axis=0) / (cell_height * cell_width)
59+
partial_avg_color = tuple(partial_avg_color.astype(np.int32).tolist())
60+
char = CHAR_LIST[min(int(np.mean(partial_image) * num_chars / 255), num_chars - 1)]
61+
draw.text((j * char_width, i * char_height), char, fill=partial_avg_color, font=font)
62+
63+
if opt.background == "white":
64+
cropped_image = ImageOps.invert(out_image).getbbox()
65+
else:
66+
cropped_image = out_image.getbbox()
67+
out_image = out_image.crop(cropped_image)
68+
out_image.save(opt.output)
69+
70+
71+
if __name__ == '__main__':
72+
opt = get_args()
73+
main(opt)

video2video_color.py

Lines changed: 97 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,97 @@
1+
"""
2+
@author: Viet Nguyen <[email protected]>
3+
"""
4+
import argparse
5+
6+
import cv2
7+
import numpy as np
8+
from PIL import Image, ImageFont, ImageDraw, ImageOps
9+
10+
11+
def get_args():
12+
parser = argparse.ArgumentParser("Image to ASCII")
13+
parser.add_argument("--input", type=str, default="data/input.mp4", help="Path to input video")
14+
parser.add_argument("--output", type=str, default="data/output.mp4", help="Path to output video")
15+
parser.add_argument("--mode", type=str, default="complex", choices=["simple", "complex"],
16+
help="10 or 70 different characters")
17+
parser.add_argument("--background", type=str, default="black", choices=["black", "white"],
18+
help="background's color")
19+
parser.add_argument("--num_cols", type=int, default=100, help="number of character for output's width")
20+
parser.add_argument("--scale", type=int, default=1, help="upsize output")
21+
parser.add_argument("--fps", type=int, default=0, help="frame per second")
22+
parser.add_argument("--overlay_ratio", type=float, default=0.2, help="Overlay width ratio")
23+
args = parser.parse_args()
24+
return args
25+
26+
27+
def main(opt):
28+
if opt.mode == "simple":
29+
CHAR_LIST = '@%#*+=-:. '
30+
else:
31+
CHAR_LIST = "$@B%8&WM#*oahkbdpqwmZO0QLCJUYXzcvunxrjft/\|()1{}[]?-_+~<>i!lI;:,\"^`'. "
32+
if opt.background == "white":
33+
bg_code = (255, 255, 255)
34+
else:
35+
bg_code = (0, 0, 0)
36+
font = ImageFont.truetype("fonts/DejaVuSansMono-Bold.ttf", size=int(10 * opt.scale))
37+
cap = cv2.VideoCapture(opt.input)
38+
if opt.fps == 0:
39+
fps = int(cap.get(cv2.CAP_PROP_FPS))
40+
else:
41+
fps = opt.fps
42+
num_chars = len(CHAR_LIST)
43+
num_cols = opt.num_cols
44+
while cap.isOpened():
45+
flag, frame = cap.read()
46+
if flag:
47+
image = frame
48+
else:
49+
break
50+
height, width, _ = image.shape
51+
cell_width = width / opt.num_cols
52+
cell_height = 2 * cell_width
53+
num_rows = int(height / cell_height)
54+
if num_cols > width or num_rows > height:
55+
print("Too many columns or rows. Use default setting")
56+
cell_width = 6
57+
cell_height = 12
58+
num_cols = int(width / cell_width)
59+
num_rows = int(height / cell_height)
60+
char_width, char_height = font.getsize("A")
61+
out_width = char_width * num_cols
62+
out_height = 2 * char_height * num_rows
63+
out_image = Image.new("RGB", (out_width, out_height), bg_code)
64+
draw = ImageDraw.Draw(out_image)
65+
for i in range(num_rows):
66+
for j in range(num_cols):
67+
partial_image = image[int(i * cell_height):min(int((i + 1) * cell_height), height),
68+
int(j * cell_width):min(int((j + 1) * cell_width), width), :]
69+
partial_avg_color = np.sum(np.sum(partial_image, axis=0), axis=0) / (cell_height * cell_width)
70+
partial_avg_color = tuple(partial_avg_color.astype(np.int32).tolist())
71+
char = CHAR_LIST[min(int(np.mean(partial_image) * num_chars / 255), num_chars - 1)]
72+
draw.text((j * char_width, i * char_height), char, fill=partial_avg_color, font=font)
73+
74+
if opt.background == "white":
75+
cropped_image = ImageOps.invert(out_image).getbbox()
76+
else:
77+
cropped_image = out_image.getbbox()
78+
out_image = out_image.crop(cropped_image)
79+
out_image = np.array(out_image)
80+
try:
81+
out
82+
except:
83+
out = cv2.VideoWriter(opt.output, cv2.VideoWriter_fourcc(*"XVID"), fps,
84+
((out_image.shape[1], out_image.shape[0])))
85+
86+
if opt.overlay_ratio:
87+
height, width, _ = out_image.shape
88+
overlay = cv2.resize(frame, (int(width * opt.overlay_ratio), int(height * opt.overlay_ratio)))
89+
out_image[height - int(height * opt.overlay_ratio):, width - int(width * opt.overlay_ratio):, :] = overlay
90+
out.write(out_image)
91+
cap.release()
92+
out.release()
93+
94+
95+
if __name__ == '__main__':
96+
opt = get_args()
97+
main(opt)

0 commit comments

Comments
 (0)