HighCWu commited on
Commit
21ac65e
1 Parent(s): 0f58ae5

add video generator.

Browse files
Files changed (5) hide show
  1. app.py +2 -3
  2. app_video.py +188 -0
  3. packages.txt +3 -0
  4. requirements.txt +4 -1
  5. test_video.py +182 -0
app.py CHANGED
@@ -1,9 +1,6 @@
1
  '''
2
  Refer to https://huggingface.co/spaces/dt/ascii-art/blob/main/app.py
3
  '''
4
- import os
5
- os.system("pip install gradio==2.9b23")
6
-
7
  # Python code to convert an image to ASCII image.
8
  import sys, random, argparse
9
  import numpy as np
@@ -127,6 +124,8 @@ def colorizeTextImage(input_img, text_img):
127
  3
128
  ))
129
  alpha = np.float32(text_img)[...,:1] / 255
 
 
130
  out_img = input_img * alpha
131
  out_colors = out_img.sum((1,3), keepdims=True) / (alpha.sum((1,3), keepdims=True) + 1e-12)
132
  out_img = out_colors * alpha
 
1
  '''
2
  Refer to https://huggingface.co/spaces/dt/ascii-art/blob/main/app.py
3
  '''
 
 
 
4
  # Python code to convert an image to ASCII image.
5
  import sys, random, argparse
6
  import numpy as np
 
124
  3
125
  ))
126
  alpha = np.float32(text_img)[...,:1] / 255
127
+ alpha[alpha < 0.125] = 0
128
+ alpha[alpha >= 0.125] = 1
129
  out_img = input_img * alpha
130
  out_colors = out_img.sum((1,3), keepdims=True) / (alpha.sum((1,3), keepdims=True) + 1e-12)
131
  out_img = out_colors * alpha
app_video.py ADDED
@@ -0,0 +1,188 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ '''
2
+ Refer to https://huggingface.co/spaces/dt/ascii-art/blob/main/app.py
3
+ '''
4
+
5
+ # Python code to convert an image to ASCII image.
6
+ import sys, random, argparse
7
+ import numpy as np
8
+ import math
9
+ import base64
10
+ from PIL import Image, ImageFont, ImageDraw
11
+ from moviepy.editor import *
12
+ from tqdm.auto import tqdm
13
+
14
+ import gradio as gr
15
+
16
+ # 70 levels of gray
17
+ gscale1 = "$@B%8&WM#*oahkbdpqwmZO0QLCJUYXzcvunxrjft/\|()1{}[]?-_+~<>i!lI;:,\"^`'. "
18
+
19
+ # 10 levels of gray
20
+ gscale2 = '@%#*+=-:. '
21
+
22
+ font = ImageFont.load_default()
23
+
24
+ def getAverageL(image):
25
+
26
+ """
27
+ Given PIL Image, return average value of grayscale value
28
+ """
29
+ # get image as numpy array
30
+ im = np.array(image)
31
+ # get shape
32
+ w,h = im.shape
33
+
34
+ # get average
35
+ return np.average(im.reshape(w*h))
36
+
37
+ def covertImageToAscii(input_img, cols, scale, moreLevels):
38
+ """
39
+ Given Image and dims (rows, cols) returns an m*n list of Images
40
+ """
41
+ # declare globals
42
+ global gscale1, gscale2
43
+
44
+ # open image and convert to grayscale
45
+ image = input_img.convert('L')
46
+
47
+ # store dimensions
48
+ # store dimensions
49
+ W, H = image.size[0], image.size[1]
50
+
51
+ # compute width of tile
52
+ w = W/cols
53
+
54
+ # compute tile height based on aspect ratio and scale
55
+ h = w/scale
56
+
57
+ # compute number of rows
58
+ rows = int(H/h)
59
+
60
+ # check if image size is too small
61
+ if cols > W or rows > H:
62
+ print("Image too small for specified cols!")
63
+ exit(0)
64
+
65
+ # ascii image is a list of character strings
66
+ aimg = []
67
+ # generate list of dimensions
68
+ for j in range(rows):
69
+ y1 = int(j*h)
70
+ y2 = int((j+1)*h)
71
+
72
+ # correct last tile
73
+ if j == rows-1:
74
+ y2 = H
75
+
76
+ # append an empty string
77
+ aimg.append("")
78
+
79
+ for i in range(cols):
80
+
81
+ # crop image to tile
82
+ x1 = int(i*w)
83
+ x2 = int((i+1)*w)
84
+
85
+ # correct last tile
86
+ if i == cols-1:
87
+ x2 = W
88
+
89
+ # crop image to extract tile
90
+ img = image.crop((x1, y1, x2, y2))
91
+
92
+ # get average luminance
93
+ avg = int(getAverageL(img))
94
+
95
+ # look up ascii char
96
+ if moreLevels:
97
+ gsval = gscale1[int((avg*69)/255)]
98
+ else:
99
+ gsval = gscale2[int((avg*9)/255)]
100
+
101
+ # append ascii char to string
102
+ aimg[j] += gsval
103
+
104
+ # return txt image
105
+ return aimg
106
+
107
+
108
+ def colorizeTextImage(input_img, text_img):
109
+ input_img = np.asarray(input_img)
110
+ input_img = input_img.reshape((
111
+ input_img.shape[0]//11,
112
+ 11,
113
+ input_img.shape[1]//6,
114
+ 6,
115
+ 3
116
+ ))
117
+ input_img = np.float32(input_img)
118
+ text_img = np.asarray(text_img)
119
+ text_img = text_img.reshape((
120
+ input_img.shape[0],
121
+ 11,
122
+ input_img.shape[2],
123
+ 6,
124
+ 3
125
+ ))
126
+ alpha = np.float32(text_img)[...,:1] / 255
127
+ alpha[alpha < 0.125] = 0
128
+ alpha[alpha >= 0.125] = 1
129
+ out_img = input_img * alpha
130
+ out_colors = out_img.sum((1,3), keepdims=True) / (alpha.sum((1,3), keepdims=True) + 1e-12)
131
+ out_img = out_colors * alpha
132
+ out_img = out_img.reshape((
133
+ out_img.shape[0] * out_img.shape[1],
134
+ out_img.shape[2] * out_img.shape[3],
135
+ 3
136
+ ))
137
+ out_img = np.clip(out_img, 0, 255)
138
+ out_img = np.uint8(out_img)
139
+
140
+ return out_img
141
+
142
+
143
+ def sepia(input_img, no_colors=False):
144
+ input_img = Image.fromarray(input_img).convert('RGB')
145
+ aimg = covertImageToAscii(input_img, 200, 6/11, True)
146
+ blank_image = Image.new(mode="RGB", size=(len(aimg[0])*6, len(aimg)*11), color=(0, 0, 0))
147
+
148
+ my_image = blank_image.copy()
149
+ image_editable = ImageDraw.Draw(my_image)
150
+
151
+ image_editable.text((0, 0), "\n".join(aimg), (255, 255, 255), font=font, spacing=0)
152
+ if no_colors:
153
+ return np.asarray(my_image)
154
+
155
+ input_img_resize = input_img.resize((len(aimg[0])*6, len(aimg)*11), Image.BICUBIC)
156
+ w, h = input_img.size
157
+ scale = 200 * 6 / w
158
+ w = 200 * 6
159
+ h = int(round(h*scale))
160
+ input_img = input_img.resize((200 * 6, h), Image.BICUBIC)
161
+ input_img_resize.paste(input_img, (0, 0, w, h))
162
+ input_img = input_img_resize
163
+
164
+ my_image = colorizeTextImage(input_img, my_image)
165
+
166
+ return my_image
167
+
168
+
169
+ def sepia_video(video_file, no_colors=False):
170
+ clip = VideoFileClip(video_file)
171
+ audioclip = clip.audio
172
+ frames = int(clip.fps * clip.duration)
173
+ imgs = []
174
+ for i in tqdm(range(frames)):
175
+ imgs.append(sepia(clip.get_frame(i/clip.fps), no_colors))
176
+ video = ImageSequenceClip(imgs, fps=clip.fps)
177
+ video = video.set_audio(audioclip)
178
+ video.write_videofile("out.mp4", fps=clip.fps)
179
+
180
+ return "out.mp4"
181
+
182
+ iface = gr.Interface(sepia_video,
183
+ [gr.Video(format=None), gr.Checkbox(label="No Colors")],
184
+ "video",
185
+ title = "Colorful ASCII Art",
186
+ description = "Convert an image to colorful ASCII art based on ascii character density. Click the first output text to download the generated svg.")
187
+
188
+ iface.launch()
packages.txt ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ ffmpeg
2
+ liblzma-dev
3
+ libsndfile1
requirements.txt CHANGED
@@ -1 +1,4 @@
1
- Pillow
 
 
 
 
1
+ moviepy
2
+ Pillow
3
+ gradio==3.0.5
4
+ tqdm
test_video.py ADDED
@@ -0,0 +1,182 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ '''
2
+ Refer to https://huggingface.co/spaces/dt/ascii-art/blob/main/app.py
3
+ '''
4
+
5
+ # Python code to convert an image to ASCII image.
6
+ import sys, random, argparse
7
+ import numpy as np
8
+ import math
9
+ import base64
10
+ from PIL import Image, ImageFont, ImageDraw
11
+ from moviepy.editor import *
12
+ from tqdm.auto import tqdm
13
+
14
+ import gradio as gr
15
+
16
+ # 70 levels of gray
17
+ gscale1 = "$@B%8&WM#*oahkbdpqwmZO0QLCJUYXzcvunxrjft/\|()1{}[]?-_+~<>i!lI;:,\"^`'. "
18
+
19
+ # 10 levels of gray
20
+ gscale2 = '@%#*+=-:. '
21
+
22
+ font = ImageFont.load_default()
23
+
24
+ def getAverageL(image):
25
+
26
+ """
27
+ Given PIL Image, return average value of grayscale value
28
+ """
29
+ # get image as numpy array
30
+ im = np.array(image)
31
+ # get shape
32
+ w,h = im.shape
33
+
34
+ # get average
35
+ return np.average(im.reshape(w*h))
36
+
37
+ def covertImageToAscii(input_img, cols, scale, moreLevels):
38
+ """
39
+ Given Image and dims (rows, cols) returns an m*n list of Images
40
+ """
41
+ # declare globals
42
+ global gscale1, gscale2
43
+
44
+ # open image and convert to grayscale
45
+ image = input_img.convert('L')
46
+
47
+ # store dimensions
48
+ # store dimensions
49
+ W, H = image.size[0], image.size[1]
50
+
51
+ # compute width of tile
52
+ w = W/cols
53
+
54
+ # compute tile height based on aspect ratio and scale
55
+ h = w/scale
56
+
57
+ # compute number of rows
58
+ rows = int(H/h)
59
+
60
+ # check if image size is too small
61
+ if cols > W or rows > H:
62
+ print("Image too small for specified cols!")
63
+ exit(0)
64
+
65
+ # ascii image is a list of character strings
66
+ aimg = []
67
+ # generate list of dimensions
68
+ for j in range(rows):
69
+ y1 = int(j*h)
70
+ y2 = int((j+1)*h)
71
+
72
+ # correct last tile
73
+ if j == rows-1:
74
+ y2 = H
75
+
76
+ # append an empty string
77
+ aimg.append("")
78
+
79
+ for i in range(cols):
80
+
81
+ # crop image to tile
82
+ x1 = int(i*w)
83
+ x2 = int((i+1)*w)
84
+
85
+ # correct last tile
86
+ if i == cols-1:
87
+ x2 = W
88
+
89
+ # crop image to extract tile
90
+ img = image.crop((x1, y1, x2, y2))
91
+
92
+ # get average luminance
93
+ avg = int(getAverageL(img))
94
+
95
+ # look up ascii char
96
+ if moreLevels:
97
+ gsval = gscale1[int((avg*69)/255)]
98
+ else:
99
+ gsval = gscale2[int((avg*9)/255)]
100
+
101
+ # append ascii char to string
102
+ aimg[j] += gsval
103
+
104
+ # return txt image
105
+ return aimg
106
+
107
+
108
+ def colorizeTextImage(input_img, text_img):
109
+ input_img = np.asarray(input_img)
110
+ input_img = input_img.reshape((
111
+ input_img.shape[0]//11,
112
+ 11,
113
+ input_img.shape[1]//6,
114
+ 6,
115
+ 3
116
+ ))
117
+ input_img = np.float32(input_img)
118
+ text_img = np.asarray(text_img)
119
+ text_img = text_img.reshape((
120
+ input_img.shape[0],
121
+ 11,
122
+ input_img.shape[2],
123
+ 6,
124
+ 3
125
+ ))
126
+ alpha = np.float32(text_img)[...,:1] / 255
127
+ alpha[alpha < 0.125] = 0
128
+ alpha[alpha >= 0.125] = 1
129
+ out_img = input_img * alpha
130
+ out_colors = out_img.sum((1,3), keepdims=True) / (alpha.sum((1,3), keepdims=True) + 1e-12)
131
+ out_img = out_colors * alpha
132
+ out_img = out_img.reshape((
133
+ out_img.shape[0] * out_img.shape[1],
134
+ out_img.shape[2] * out_img.shape[3],
135
+ 3
136
+ ))
137
+ out_img = np.clip(out_img, 0, 255)
138
+ out_img = np.uint8(out_img)
139
+
140
+ return out_img
141
+
142
+
143
+ def sepia(input_img, no_colors=False):
144
+ input_img = Image.fromarray(input_img).convert('RGB')
145
+ aimg = covertImageToAscii(input_img, 200, 6/11, True)
146
+ blank_image = Image.new(mode="RGB", size=(len(aimg[0])*6, len(aimg)*11), color=(0, 0, 0))
147
+
148
+ my_image = blank_image.copy()
149
+ image_editable = ImageDraw.Draw(my_image)
150
+
151
+ image_editable.text((0, 0), "\n".join(aimg), (255, 255, 255), font=font, spacing=0)
152
+ if no_colors:
153
+ return np.asarray(my_image)
154
+
155
+ input_img_resize = input_img.resize((len(aimg[0])*6, len(aimg)*11), Image.BICUBIC)
156
+ w, h = input_img.size
157
+ scale = 200 * 6 / w
158
+ w = 200 * 6
159
+ h = int(round(h*scale))
160
+ input_img = input_img.resize((200 * 6, h), Image.BICUBIC)
161
+ input_img_resize.paste(input_img, (0, 0, w, h))
162
+ input_img = input_img_resize
163
+
164
+ my_image = colorizeTextImage(input_img, my_image)
165
+
166
+ return my_image
167
+
168
+
169
+ def sepia_video(video_file, no_colors=False):
170
+ clip = VideoFileClip(video_file)
171
+ audioclip = clip.audio
172
+ frames = int(clip.fps * clip.duration)
173
+ imgs = []
174
+ for i in tqdm(range(frames)):
175
+ imgs.append(sepia(clip.get_frame(i/clip.fps), no_colors))
176
+ video = ImageSequenceClip(imgs, fps=clip.fps)
177
+ video = video.set_audio(audioclip)
178
+ video.write_videofile("out.mp4", fps=clip.fps)
179
+
180
+ return "out.mp4"
181
+
182
+ sepia_video("input.mp4", no_colors=False)