HighCWu commited on
Commit
067ec2e
·
1 Parent(s): f53177b

init commits.

Browse files
Files changed (3) hide show
  1. README.md +1 -1
  2. app.py +204 -0
  3. requirements.txt +2 -0
README.md CHANGED
@@ -10,4 +10,4 @@ pinned: false
10
  license: mit
11
  ---
12
 
13
- Check out the configuration reference at https://huggingface.co/docs/hub/spaces#reference
 
10
  license: mit
11
  ---
12
 
13
+ Largely referenced from [this space](https://huggingface.co/spaces/dt/ascii-art)
app.py ADDED
@@ -0,0 +1,204 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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
7
+ import math
8
+ import gradio as gr
9
+
10
+ from PIL import Image, ImageFont, ImageDraw
11
+
12
+ # 70 levels of gray
13
+ gscale1 = "$@B%8&WM#*oahkbdpqwmZO0QLCJUYXzcvunxrjft/\|()1{}[]?-_+~<>i!lI;:,\"^`'. "
14
+
15
+ # 10 levels of gray
16
+ gscale2 = '@%#*+=-:. '
17
+
18
+ font = ImageFont.load_default()
19
+
20
+ def getAverageL(image):
21
+
22
+ """
23
+ Given PIL Image, return average value of grayscale value
24
+ """
25
+ # get image as numpy array
26
+ im = np.array(image)
27
+ # get shape
28
+ w,h = im.shape
29
+
30
+ # get average
31
+ return np.average(im.reshape(w*h))
32
+
33
+ def covertImageToAscii(input_img, cols, scale, moreLevels):
34
+ """
35
+ Given Image and dims (rows, cols) returns an m*n list of Images
36
+ """
37
+ # declare globals
38
+ global gscale1, gscale2
39
+
40
+ # open image and convert to grayscale
41
+ image = input_img.convert('L')
42
+
43
+ # store dimensions
44
+ # store dimensions
45
+ W, H = image.size[0], image.size[1]
46
+ print("input image dims: %d x %d" % (W, H))
47
+
48
+ # compute width of tile
49
+ w = W/cols
50
+
51
+ # compute tile height based on aspect ratio and scale
52
+ h = w/scale
53
+
54
+ # compute number of rows
55
+ rows = int(H/h)
56
+
57
+ print("cols: %d, rows: %d" % (cols, rows))
58
+ print("tile dims: %d x %d" % (w, 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
+ out_img = input_img * alpha
128
+ out_colors = out_img.sum((1,3), keepdims=True) / (alpha.sum((1,3), keepdims=True) + 1e-12)
129
+ out_img = out_colors * alpha
130
+ out_img = np.concatenate([out_img, alpha * 255], -1)
131
+ out_img = out_img.reshape((
132
+ out_img.shape[0] * out_img.shape[1],
133
+ out_img.shape[2] * out_img.shape[3],
134
+ 4
135
+ ))
136
+ out_img = np.clip(out_img, 0, 255)
137
+ out_img = np.uint8(out_img)
138
+ out_img = Image.fromarray(out_img)
139
+
140
+ our_colors = np.clip(out_colors, 0, 255)
141
+ our_colors = np.uint8(out_colors)[:,0,:,0]
142
+
143
+ return out_img, our_colors
144
+
145
+
146
+ def convertTextToHTML(our_colors, aimg):
147
+ bimg = r'''
148
+ <!DOCTYPE html>
149
+ <html>
150
+ <body>
151
+ <style>text{ font-size:8px; }</style>
152
+ <svg xmlns="http://www.w3.org/2000/svg" version="1.1" style="width: 100vw;height: 100vh;" viewBox="0, 0, 1200, 1200">
153
+ '''
154
+ for i in range(our_colors.shape[0]):
155
+ our_colors2 = our_colors[i]
156
+ aimg2 = aimg[i]
157
+ for j in range(our_colors2.shape[0]):
158
+ [r, g, b] = our_colors2[j]
159
+ p = aimg2[j]
160
+ if p == ' ': continue
161
+ aimg3 = f'<text x="{j*6}" y="{i*11}" style="fill:rgb{int(r),int(g),int(b)};">{p}</text>\n'
162
+ bimg += aimg3
163
+ bimg += r'''
164
+ </svg>
165
+
166
+ </body>
167
+ </html>
168
+ '''
169
+
170
+ return bimg
171
+
172
+
173
+ def sepia(input_img):
174
+ input_img = Image.fromarray(input_img).convert('RGB')
175
+ aimg = covertImageToAscii(input_img, 200, 6/11, True)
176
+ blank_image = Image.new(mode="RGB", size=(len(aimg[0])*6, len(aimg)*11), color=(0, 0, 0))
177
+
178
+ my_image = blank_image.copy()
179
+ image_editable = ImageDraw.Draw(my_image)
180
+
181
+ image_editable.text((0, 0), "\n".join(aimg), (255, 255, 255), font=font, spacing=0)
182
+
183
+ input_img_resize = input_img.resize((len(aimg[0])*6, len(aimg)*11), Image.BICUBIC)
184
+ w, h = input_img.size
185
+ scale = 200 * 6 / w
186
+ w = 200 * 6
187
+ h = int(round(h*scale))
188
+ input_img = input_img.resize((200 * 6, h), Image.BICUBIC)
189
+ input_img_resize.paste(input_img, (0, 0, w, h))
190
+ input_img = input_img_resize
191
+
192
+ my_image, my_colors = colorizeTextImage(input_img, my_image)
193
+ my_html = convertTextToHTML(my_colors, aimg)
194
+
195
+ return [my_image, my_html]
196
+
197
+
198
+ iface = gr.Interface(sepia,
199
+ gr.inputs.Image(),
200
+ ["image", "html"],
201
+ title = "Colorful ASCII Art",
202
+ description = "Convert an image to colorful ASCII art based on ascii character density. Copy and paste the text to a notepad to see it correctly")
203
+
204
+ iface.launch()
requirements.txt ADDED
@@ -0,0 +1,2 @@
 
 
 
1
+ Pillow
2
+ gradio