RedBottle13 commited on
Commit
83fd0ba
·
1 Parent(s): 0e5a89b

update app.py

Browse files
app.py ADDED
@@ -0,0 +1,138 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from PIL import Image, ImageDraw, ImageOps, ImageFilter, ImageFont
2
+ import numpy as np
3
+ import math
4
+ import gradio as gr
5
+
6
+ ##### CONSTANTS #####
7
+ # ASCII characters used to represent image pixels, reversed for better contrast in mapping
8
+ CHARS = ' .:-=+*#%@'[::-1]
9
+ # Convert the characters to a list for easier access
10
+ CHAR_ARRAY = list(CHARS)
11
+ # Number of available ASCII characters
12
+ CHAR_LEN = len(CHAR_ARRAY)
13
+
14
+ # Grayscale level for each ASCII character, determining how many shades of gray each character represents
15
+ GRAYSCALE_LEVEL = CHAR_LEN / 256
16
+
17
+ # Scaling factor to resize the image
18
+ SCALE = 0.15
19
+
20
+ # Character dimensions (width and height in pixels) used to match image aspect ratio to character aspect ratio
21
+ CHAR_W = 6
22
+ CHAR_H = 14
23
+
24
+ ##### FUNCTIONS #####
25
+ def getChar(inputInt, gamma=1.8):
26
+ """Map a grayscale pixel value to an ASCII character with gamma correction applied."""
27
+ # Adjust the input pixel intensity using gamma correction for perceptual brightness adjustment
28
+ inputInt = (inputInt / 255) ** gamma * 255
29
+ # Map the corrected pixel value to an appropriate ASCII character
30
+ return CHAR_ARRAY[math.floor(inputInt * GRAYSCALE_LEVEL)]
31
+
32
+
33
+ def load_and_preprocess_image(image):
34
+ """Resize and preprocess the input image, adjusting contrast and blurring for better ASCII conversion."""
35
+ width, height = image.size
36
+ # Resize image, adjusting aspect ratio to fit ASCII character dimensions
37
+ im = image.resize((int(SCALE * width), int(SCALE * height * (CHAR_W / CHAR_H))))
38
+
39
+ # Enhance contrast to bring out more detail in the ASCII representation
40
+ im = ImageOps.equalize(im, mask=None)
41
+
42
+ # Apply a slight blur to reduce noise and simplify pixel values
43
+ im = im.filter(ImageFilter.GaussianBlur(radius=0.5))
44
+
45
+ return im
46
+
47
+ def create_ascii_art(im):
48
+ """Convert a preprocessed image into ASCII art by mapping grayscale values to ASCII characters."""
49
+ # Convert the image to grayscale
50
+ grayscale_image = im.convert("L")
51
+ # Get the pixel values as a NumPy array for easier processing
52
+ pix = np.array(grayscale_image)
53
+ width, height = grayscale_image.size
54
+
55
+ # Create a string that holds the ASCII art, where each character represents a pixel
56
+ ascii_art = ""
57
+ for i in range(height):
58
+ for j in range(width):
59
+ # Append the corresponding ASCII character for each pixel
60
+ ascii_art += getChar(pix[i, j])
61
+ # Newline after each row to maintain image structure
62
+ ascii_art += '\n'
63
+
64
+ return ascii_art
65
+
66
+
67
+ def draw_ascii_image(ascii_art_string, char_width, char_height, font_size):
68
+ """Draw the ASCII art string onto an image."""
69
+ # Split the ASCII art string into lines
70
+ lines = ascii_art_string.split('\n')
71
+
72
+ # Determine the dimensions of the image based on the number of characters
73
+ width = max(len(line) for line in lines) # Maximum line width
74
+ height = len(lines) # Number of lines (height)
75
+
76
+ # Create a blank white image based on the ASCII art size and font size
77
+ img_width = width * char_width
78
+ img_height = height * char_height
79
+ ascii_image = Image.new("RGB", (img_width, img_height), "white")
80
+ draw = ImageDraw.Draw(ascii_image)
81
+
82
+ # Use default or custom font (Pillow's default font in this case)
83
+ font = ImageFont.load_default()
84
+ # Draw the ASCII art on the image
85
+ for i, line in enumerate(lines):
86
+ # Draw each line of the ASCII art onto the image
87
+ draw.text((0, i * char_height), line, font=font, fill="black")
88
+
89
+ return ascii_image
90
+
91
+
92
+ def process_image(image):
93
+ """Process the input image to generate both an ASCII art image and a downloadable text file."""
94
+ # Resize and preprocess the image
95
+ resized_image = load_and_preprocess_image(image)
96
+ # Generate the ASCII art as text
97
+ ascii_art = create_ascii_art(resized_image)
98
+
99
+ # Create an image from the ASCII art characters
100
+ output_image = draw_ascii_image(ascii_art, char_width=CHAR_W, char_height=CHAR_H, font_size=10)
101
+
102
+ # Save the ASCII art as a text file
103
+ ascii_txt_path = "ascii_art.txt"
104
+ with open(ascii_txt_path, "w") as text_file:
105
+ text_file.write(ascii_art)
106
+
107
+ return output_image, ascii_txt_path
108
+
109
+
110
+ ##### GRADIO INTERFACE #####
111
+ def gradio_interface(image):
112
+ """Gradio interface function to handle user input and return the ASCII art image and text file."""
113
+ ascii_image, txt_file = process_image(image)
114
+ return ascii_image, txt_file
115
+
116
+ # Set up the Gradio interface
117
+ demo = gr.Interface(
118
+ fn=gradio_interface,
119
+ inputs=gr.Image(type="pil", label="Upload an Image", height=300),
120
+ outputs=[
121
+ gr.Image(type="pil", label="ASCII Art Image", height=300),
122
+ gr.File(label="Download ASCII Art Text File", height=50),
123
+ ],
124
+ title="ASCII Art Generator",
125
+ description="Upload an image, and this tool will generate ASCII art and provide a downloadable text file of the result.",
126
+ allow_flagging="never",
127
+ examples=[
128
+ ['images/building.jpg'],
129
+ ['images/cat.webp'],
130
+ ['images/mountain.webp'],
131
+ ['images/people.jpg'],
132
+ ['images/Northeastern_seal.png'],
133
+ ['images/einstein.jpg'],
134
+ ],
135
+
136
+ )
137
+
138
+ demo.launch(share=True)
images/Northeastern_seal.png ADDED
images/building.jpg ADDED
images/cat.webp ADDED
images/einstein.jpg ADDED
images/mountain.webp ADDED
images/people.jpg ADDED
requirements.txt ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ gradio
2
+ pillow
3
+ numpy