File size: 4,763 Bytes
eac4855
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
import cv2
import numpy as np
import gradio as gr
from skimage.metrics import structural_similarity as compare_ssim


def ascii_art_generator(input_image, contrast, threshold1, threshold2, ascii_chars):
    # Resize the image
    new_width = 100
    height, width = input_image.shape[:2]
    aspect_ratio = height / width
    new_height = int(aspect_ratio * new_width * 0.55)
    resized_image = cv2.resize(input_image, (new_width, int(new_height)))

    # Convert to grayscale
    gray_image = cv2.cvtColor(resized_image, cv2.COLOR_BGR2GRAY)

    # Apply transformation algorithm with user parameters
    adjusted_image = cv2.convertScaleAbs(gray_image, alpha=contrast, beta=0)
    edges = cv2.Canny(
        adjusted_image, threshold1=int(threshold1), threshold2=int(threshold2)
    )
    processed_image = cv2.bitwise_not(edges)

    # Map intensities to ASCII characters
    def pixel_to_ascii(pixel_value):
        num_chars = len(ascii_chars)
        index = int(pixel_value / 255 * (num_chars - 1))
        return ascii_chars[index]

    # Generate the ASCII art string
    ascii_art_lines = []
    for row in processed_image:
        line = "".join([pixel_to_ascii(pixel) for pixel in row])
        ascii_art_lines.append(line)
    ascii_art = "\n".join(ascii_art_lines)

    # Save the ASCII art to a text file
    with open("ascii_art.txt", "w") as f:
        f.write(ascii_art)

    # Convert processed_image to RGB format for display
    processed_image_rgb = cv2.cvtColor(processed_image, cv2.COLOR_GRAY2RGB)

    # Convert ASCII art back to image
    def ascii_to_image(ascii_art, ascii_chars):
        # Create a mapping from characters to grayscale values
        char_to_intensity = {
            char: int(i / (len(ascii_chars) - 1) * 255)
            for i, char in enumerate(ascii_chars)
        }
        ascii_lines = ascii_art.split("\n")
        height = len(ascii_lines)
        width = len(ascii_lines[0]) if height > 0 else 0
        ascii_image = np.zeros((height, width), dtype=np.uint8)
        for y, line in enumerate(ascii_lines):
            for x, char in enumerate(line):
                ascii_image[y, x] = char_to_intensity.get(char, 0)
        return ascii_image

    ascii_image = ascii_to_image(ascii_art, ascii_chars)

    # Normalize the original image
    def normalize_images(original_image, ascii_image_shape):
        resized_original = cv2.resize(
            original_image, (ascii_image_shape[1], ascii_image_shape[0])
        )
        if len(resized_original.shape) == 3:
            resized_original = cv2.cvtColor(resized_original, cv2.COLOR_BGR2GRAY)
        return resized_original

    normalized_original = normalize_images(gray_image, ascii_image.shape)

    # Calculate similarity metrics
    def calculate_mse(image1, image2):
        mse = np.mean((image1.astype("float") - image2.astype("float")) ** 2)
        return mse

    def calculate_ssim(image1, image2):
        ssim, _ = compare_ssim(image1, image2, full=True)
        return ssim

    def calculate_psnr(image1, image2):
        mse = calculate_mse(image1, image2)
        if mse == 0:
            return float("inf")
        PIXEL_MAX = 255.0
        psnr = 20 * np.log10(PIXEL_MAX / np.sqrt(mse))
        return psnr

    mse = calculate_mse(normalized_original, ascii_image)
    ssim = calculate_ssim(normalized_original, ascii_image)
    psnr = calculate_psnr(normalized_original, ascii_image)

    # Prepare metrics output
    metrics_text = f"MSE: {mse:.2f}\nSSIM: {ssim:.4f}\nPSNR: {psnr:.2f} dB"

    return ascii_art, "ascii_art.txt", processed_image_rgb, metrics_text


# Define the Gradio interface using the updated components
iface = gr.Interface(
    fn=ascii_art_generator,
    inputs=[
        gr.Image(type="numpy", label="Upload Image"),
        gr.Slider(0.5, 3.0, step=0.1, value=1.5, label="Contrast"),
        gr.Slider(0, 255, step=1, value=50, label="Edge Detection Threshold1"),
        gr.Slider(0, 255, step=1, value=150, label="Edge Detection Threshold2"),
        gr.Textbox(value="@%#*+=-:. ", label="ASCII Characters (Dark to Light)"),
    ],
    outputs=[
        gr.Textbox(label="ASCII Art"),
        gr.File(label="Download ASCII Art as Text File"),
        gr.Image(type="numpy", label="Processed Image"),
        gr.Textbox(label="Performance Metrics"),
    ],
    title="Interactive ASCII Art Generator with Performance Metric",
    description="Upload an image and adjust parameters to convert it into ASCII art. The performance metric quantifies the similarity between the original image and the ASCII art.",
    allow_flagging="never",
)

iface.launch(debug=True, share=True)