File size: 3,729 Bytes
c77c587
 
 
 
 
 
 
 
70542da
 
c77c587
70542da
c77c587
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
70542da
 
c77c587
 
 
70542da
 
 
 
 
 
 
 
c77c587
 
 
 
 
6ee4209
 
 
c77c587
70542da
c77c587
 
 
 
 
 
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
import gradio as gr
import cv2
import matplotlib.animation as animation
import matplotlib.pyplot as plt
import numpy as np
from scipy.integrate import quad_vec
from math import tau
import os
from PIL import Image
import io

def fourier_transform_drawing(input_image, frames, coefficients):
    # Convert input_image to an OpenCV image
    input_image = np.array(input_image)
    img = cv2.cvtColor(input_image, cv2.COLOR_RGB2BGR)

    # processing
    imgray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
    blurred = cv2.GaussianBlur(imgray, (7, 7), 0)

    (T, thresh) = cv2.threshold(blurred, 0, 255, cv2.THRESH_BINARY_INV | cv2.THRESH_OTSU)

    contours, _ = cv2.findContours(thresh, cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE)
    largest_contour_idx = np.argmax([len(c) for c in contours])
    verts = [tuple(coord) for coord in contours[largest_contour_idx].squeeze()]

    xs, ys = zip(*verts)
    xs = np.asarray(xs) - np.mean(xs)
    ys = - np.asarray(ys) + np.mean(ys)
    t_list = np.linspace(0, tau, len(xs))

    # Compute the Fourier coefficients
    def f(t, t_list, xs, ys):
        return np.interp(t, t_list, xs + 1j*ys)

    def compute_cn(f, n):
        coef = 1/tau*quad_vec(
            lambda t: f(t, t_list, xs, ys)*np.exp(-n*t*1j), 
            0, 
            tau, 
            limit=100, 
            full_output=False)[0]
        return coef

    N = coefficients
    coefs = [(compute_cn(f, 0), 0)] + [(compute_cn(f, j), j) for i in range(1, N+1) for j in (i, -i)]

    # animate the drawings
    fig, ax = plt.subplots()
    circles = [ax.plot([], [], 'b-')[0] for _ in range(-N, N+1)]
    circle_lines = [ax.plot([], [], 'g-')[0] for _ in range(-N, N+1)]
    drawing, = ax.plot([], [], 'r-', linewidth=2)

    ax.set_xlim(-500, 500)
    ax.set_ylim(-500, 500)
    ax.set_axis_off()
    ax.set_aspect('equal')
    fig.set_size_inches(15, 15)

    draw_x, draw_y = [], []
    
    def animate(i, coefs, time):
        t = time[i]
        coefs = [(c * np.exp(1j*(fr * tau * t)), fr) for c, fr in coefs]
        center = (0, 0)

        for c, _ in coefs:
            r = np.linalg.norm(c)
            theta = np.linspace(0, tau, 80)
            x, y = center[0] + r * np.cos(theta), center[1] + r * np.sin(theta)
            circle_lines[_].set_data([center[0], center[0]+np.real(c)], [center[1], center[1]+np.imag(c)])
            circles[_].set_data(x, y) 
            center = (center[0] + np.real(c), center[1] + np.imag(c))
        
        draw_x.append(center[0])
        draw_y.append(center[1])
        drawing.set_data(draw_x, draw_y)

    drawing_time = 1
    time = np.linspace(0, drawing_time, num=frames)    
    anim = animation.FuncAnimation(fig, animate, frames=frames, interval=5, fargs=(coefs, time)) 

    output_animation = "output.mp4"
    
    anim.save(output_animation, fps=15)
    plt.close(fig)

    # Convert the mp4 file to a GIF for display in Gradio
    os.system(f"ffmpeg -i {output_animation} -vf 'fps=10,scale=320:-1:flags=lanczos' -c:v gif -loop 0 output.gif")

    # Read the GIF and convert to PIL Image
    with open("output.gif", 'rb') as f:
        gif_image = Image.open(io.BytesIO(f.read()))

    return gif_image

# Gradio interface
interface = gr.Interface(
    fn=fourier_transform_drawing,
    inputs=[
        gr.Image(label="Input Image", sources=['upload'], type="pil"),
        gr.Slider(minimum=10, maximum=500, value=300, label="Number of Frames"),
        gr.Slider(minimum=10, maximum=500, value=300, label="Number of Coefficients")
    ],
    outputs=gr.Image(format="gif"),
    title="Fourier Transform Drawing",
    description="Upload an image and generate a Fourier Transform drawing animation."
)

if __name__ == "__main__":
    interface.launch()