RedBottle13 commited on
Commit
55f1779
·
1 Parent(s): 6d7e9fd

add SII evaluation metric

Browse files
Files changed (4) hide show
  1. app.py +61 -37
  2. images/Northeastern_seal.png +0 -0
  3. images/cartoon.png +0 -0
  4. requirements.txt +2 -0
app.py CHANGED
@@ -2,6 +2,8 @@ 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
@@ -14,9 +16,6 @@ CHAR_LEN = len(CHAR_ARRAY)
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.2
19
-
20
  # Target number of characters per row
21
  TARGET_WIDTH = 200
22
 
@@ -24,7 +23,7 @@ TARGET_WIDTH = 200
24
  CHAR_W = 6
25
  CHAR_H = 14
26
 
27
- ##### FUNCTIONS #####
28
  def getChar(inputInt, gamma=1.8):
29
  """Map a grayscale pixel value to an ASCII character with gamma correction applied."""
30
  # Adjust the input pixel intensity using gamma correction for perceptual brightness adjustment
@@ -33,25 +32,11 @@ def getChar(inputInt, gamma=1.8):
33
  return CHAR_ARRAY[math.floor(inputInt * GRAYSCALE_LEVEL)]
34
 
35
 
36
- # def load_and_preprocess_image(image):
37
- # """Resize and preprocess the input image, adjusting contrast and blurring for better ASCII conversion."""
38
- # width, height = image.size
39
- # # Resize image, adjusting aspect ratio to fit ASCII character dimensions
40
- # im = image.resize((int(SCALE * width), int(SCALE * height * (CHAR_W / CHAR_H))))
41
-
42
- # # Enhance contrast to bring out more detail in the ASCII representation
43
- # im = ImageOps.equalize(im, mask=None)
44
-
45
- # # Apply a slight blur to reduce noise and simplify pixel values
46
- # im = im.filter(ImageFilter.GaussianBlur(radius=0.5))
47
-
48
- # return im
49
-
50
  def load_and_preprocess_image(image):
51
  """Resize and preprocess the input image, adjusting contrast and blurring for better ASCII conversion."""
52
  width, height = image.size
53
 
54
- # Calculate the scaling factor to match the target character width (300 characters per row)
55
  scale_factor = TARGET_WIDTH / width
56
 
57
  # Resize the image, maintaining the aspect ratio considering the character dimensions
@@ -88,15 +73,14 @@ def create_ascii_art(im):
88
 
89
  return ascii_art
90
 
91
-
92
  def draw_ascii_image(ascii_art_string, char_width, char_height, font_size):
93
  """Draw the ASCII art string onto an image."""
94
  # Split the ASCII art string into lines
95
  lines = ascii_art_string.split('\n')
96
 
97
  # Determine the dimensions of the image based on the number of characters
98
- width = max(len(line) for line in lines) # Maximum line width
99
- height = len(lines) # Number of lines (height)
100
 
101
  # Create a blank white image based on the ASCII art size and font size
102
  img_width = width * char_width
@@ -114,50 +98,90 @@ def draw_ascii_image(ascii_art_string, char_width, char_height, font_size):
114
  return ascii_image
115
 
116
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
117
  def process_image(image):
118
  """Process the input image to generate both an ASCII art image and a downloadable text file."""
119
- # Resize and preprocess the image
120
  resized_image = load_and_preprocess_image(image)
121
- # Generate the ASCII art as text
122
  ascii_art = create_ascii_art(resized_image)
123
 
124
- # Create an image from the ASCII art characters
125
  output_image = draw_ascii_image(ascii_art, char_width=CHAR_W, char_height=CHAR_H, font_size=10)
126
-
 
 
 
 
 
 
127
  # Save the ASCII art as a text file
128
  ascii_txt_path = "ascii_art.txt"
129
  with open(ascii_txt_path, "w") as text_file:
130
  text_file.write(ascii_art)
131
 
132
- return output_image, ascii_txt_path
 
 
133
 
134
 
135
  ##### GRADIO INTERFACE #####
136
  def gradio_interface(image):
137
- """Gradio interface function to handle user input and return the ASCII art image and text file."""
138
- ascii_image, txt_file = process_image(image)
139
- return ascii_image, txt_file
140
 
141
- # Set up the Gradio interface
142
  demo = gr.Interface(
143
- fn=gradio_interface,
144
  inputs=gr.Image(type="pil", label="Upload an Image", height=300),
145
  outputs=[
146
  gr.Image(type="pil", label="ASCII Art Image", height=300),
147
  gr.File(label="Download ASCII Art Text File", height=50),
 
148
  ],
149
- title="ASCII Art Generator",
150
- description="Upload an image, and this tool will generate ASCII art and provide a downloadable text file of the result.",
151
  allow_flagging="never",
152
- examples=[
153
  ['images/building.jpg'],
154
  ['images/cat.webp'],
155
  ['images/dog.jpg'],
156
  ['images/people.jpg'],
157
- ['images/Northeastern_seal.png'],
158
  ['images/einstein.jpg'],
159
  ],
160
-
161
  )
162
 
 
163
  demo.launch()
 
2
  import numpy as np
3
  import math
4
  import gradio as gr
5
+ from skimage.metrics import structural_similarity as ssim
6
+ import cv2
7
 
8
  ##### CONSTANTS #####
9
  # ASCII characters used to represent image pixels, reversed for better contrast in mapping
 
16
  # Grayscale level for each ASCII character, determining how many shades of gray each character represents
17
  GRAYSCALE_LEVEL = CHAR_LEN / 256
18
 
 
 
 
19
  # Target number of characters per row
20
  TARGET_WIDTH = 200
21
 
 
23
  CHAR_W = 6
24
  CHAR_H = 14
25
 
26
+ ##### ASCII ART GENERATION #####
27
  def getChar(inputInt, gamma=1.8):
28
  """Map a grayscale pixel value to an ASCII character with gamma correction applied."""
29
  # Adjust the input pixel intensity using gamma correction for perceptual brightness adjustment
 
32
  return CHAR_ARRAY[math.floor(inputInt * GRAYSCALE_LEVEL)]
33
 
34
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
35
  def load_and_preprocess_image(image):
36
  """Resize and preprocess the input image, adjusting contrast and blurring for better ASCII conversion."""
37
  width, height = image.size
38
 
39
+ # Calculate the scaling factor to match the target character width
40
  scale_factor = TARGET_WIDTH / width
41
 
42
  # Resize the image, maintaining the aspect ratio considering the character dimensions
 
73
 
74
  return ascii_art
75
 
 
76
  def draw_ascii_image(ascii_art_string, char_width, char_height, font_size):
77
  """Draw the ASCII art string onto an image."""
78
  # Split the ASCII art string into lines
79
  lines = ascii_art_string.split('\n')
80
 
81
  # Determine the dimensions of the image based on the number of characters
82
+ width = max(len(line) for line in lines)
83
+ height = len(lines)
84
 
85
  # Create a blank white image based on the ASCII art size and font size
86
  img_width = width * char_width
 
98
  return ascii_image
99
 
100
 
101
+ ##### EVALUATION #####
102
+ def ascii_to_image(ascii_art, width, height):
103
+ """Convert ASCII art back to an image by mapping characters to grayscale values."""
104
+ char_to_gray = {c: int((i / CHAR_LEN) * 255) for i, c in enumerate(CHAR_ARRAY)}
105
+ ascii_lines = ascii_art.split('\n')
106
+
107
+ # Create an empty numpy array to store the pixel values
108
+ ascii_image = np.zeros((height, width), dtype=np.uint8)
109
+
110
+ for i, line in enumerate(ascii_lines):
111
+ if i >= height:
112
+ break
113
+ for j, char in enumerate(line):
114
+ if j >= width:
115
+ break
116
+ ascii_image[i, j] = char_to_gray.get(char, 255) # Default to white if character not in mapping
117
+
118
+ return Image.fromarray(ascii_image)
119
+
120
+ def calculate_ssi(original_image, ascii_art_image):
121
+ """Calculate Structural Similarity Index (SSI) between the original and reconstructed images."""
122
+ original_image = original_image.convert("L")
123
+
124
+ # Resize the original image to match the dimensions of the ASCII art image
125
+ original_image_resized = original_image.resize(ascii_art_image.size)
126
+
127
+ # Convert both images to NumPy arrays
128
+ original_array = np.array(original_image_resized)
129
+ ascii_array = np.array(ascii_art_image)
130
+
131
+ # Calculate SSI
132
+ ssi_value, _ = ssim(original_array, ascii_array, full=True)
133
+ return ssi_value
134
+
135
+
136
+ ##### MAIN FUNCTION FOR GRADIO INTERFACE #####
137
  def process_image(image):
138
  """Process the input image to generate both an ASCII art image and a downloadable text file."""
 
139
  resized_image = load_and_preprocess_image(image)
 
140
  ascii_art = create_ascii_art(resized_image)
141
 
 
142
  output_image = draw_ascii_image(ascii_art, char_width=CHAR_W, char_height=CHAR_H, font_size=10)
143
+
144
+ # Convert the ASCII art back into an image for SSI comparison
145
+ ascii_art_image = ascii_to_image(ascii_art, resized_image.width, resized_image.height)
146
+
147
+ # Calculate SSI between the original and ASCII art image
148
+ ssi_value = calculate_ssi(image, ascii_art_image)
149
+
150
  # Save the ASCII art as a text file
151
  ascii_txt_path = "ascii_art.txt"
152
  with open(ascii_txt_path, "w") as text_file:
153
  text_file.write(ascii_art)
154
 
155
+ print(f"Structural Similarity Index (SSI): {ssi_value}")
156
+
157
+ return output_image, ascii_txt_path, ssi_value
158
 
159
 
160
  ##### GRADIO INTERFACE #####
161
  def gradio_interface(image):
162
+ ascii_image, txt_file, ssi_value = process_image(image)
163
+ return ascii_image, txt_file, ssi_value
 
164
 
 
165
  demo = gr.Interface(
166
+ fn=gradio_interface,
167
  inputs=gr.Image(type="pil", label="Upload an Image", height=300),
168
  outputs=[
169
  gr.Image(type="pil", label="ASCII Art Image", height=300),
170
  gr.File(label="Download ASCII Art Text File", height=50),
171
+ gr.Textbox(label="SSI Value")
172
  ],
173
+ title="ASCII Art Generator with SSI Metric",
174
+ description="Upload an image, generate ASCII art, and calculate the Structural Similarity Index (SSI).",
175
  allow_flagging="never",
176
+ examples=[
177
  ['images/building.jpg'],
178
  ['images/cat.webp'],
179
  ['images/dog.jpg'],
180
  ['images/people.jpg'],
181
+ ['images/cartoon.png'],
182
  ['images/einstein.jpg'],
183
  ],
 
184
  )
185
 
186
+
187
  demo.launch()
images/Northeastern_seal.png DELETED
Binary file (367 kB)
 
images/cartoon.png ADDED
requirements.txt CHANGED
@@ -1,3 +1,5 @@
1
  gradio==4.44.0
2
  pillow==9.3.0
3
  numpy==1.23.4
 
 
 
1
  gradio==4.44.0
2
  pillow==9.3.0
3
  numpy==1.23.4
4
+ scikit-image==0.19.3
5
+ opencv-python==4.9.0.80