staghado commited on
Commit
47201a2
1 Parent(s): 573c3f1

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +31 -34
app.py CHANGED
@@ -1,49 +1,40 @@
1
- import os
2
- import io
3
- import cv2
4
  import numpy as np
5
  import matplotlib.pyplot as plt
6
  import matplotlib.animation as animation
7
  from PIL import Image
 
 
8
  from math import tau
9
- from concurrent.futures import ThreadPoolExecutor
10
  import gradio as gr
 
11
 
12
  def fourier_transform_drawing(input_image, frames, coefficients, img_size, blur_kernel_size, desired_range, num_points, theta_points):
13
  # Convert PIL to OpenCV image
14
  img = cv2.cvtColor(np.array(input_image), cv2.COLOR_RGB2BGR)
15
-
16
- # Resize the image for faster processing
17
  img = cv2.resize(img, (img_size, img_size), interpolation=cv2.INTER_AREA)
18
-
19
- # Image processing
20
  imgray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
21
  blurred = cv2.GaussianBlur(imgray, (blur_kernel_size, blur_kernel_size), 0)
22
  _, thresh = cv2.threshold(blurred, 0, 255, cv2.THRESH_BINARY_INV | cv2.THRESH_OTSU)
23
  contours, _ = cv2.findContours(thresh, cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE)
24
 
25
  # find the contour with the largest area
26
- # largest_contour_idx = np.argmax([cv2.contourArea(c) for c in contours])
27
- # largest_contour = contours[largest_contour_idx]
28
 
29
- # Combine all contours
30
- def combine_all_contours(contours):
31
- combined_contour = np.array([], dtype=np.int32).reshape(0, 1, 2)
32
- for contour in contours:
33
- combined_contour = np.vstack((combined_contour, contour))
34
- return combined_contour
35
-
36
- combined_contour = combine_all_contours(contours)
37
- verts = [tuple(coord) for coord in combined_contour.squeeze()]
38
  xs, ys = np.asarray(list(zip(*verts)))
39
-
40
- # Scale the coordinates
41
  x_range, y_range = np.max(xs) - np.min(xs), np.max(ys) - np.min(ys)
42
  scale_x, scale_y = desired_range / x_range, desired_range / y_range
43
  xs = (xs - np.mean(xs)) * scale_x
44
  ys = (-ys + np.mean(ys)) * scale_y
45
 
46
- # Compute Fourier coefficients
47
  t_list = np.linspace(0, tau, len(xs))
48
  t_values = np.linspace(0, tau, num_points)
49
  f_precomputed = np.interp(t_values, t_list, xs + 1j * ys)
@@ -55,11 +46,9 @@ def fourier_transform_drawing(input_image, frames, coefficients, img_size, blur_
55
  N = coefficients
56
  indices = [0] + [j for i in range(1, N + 1) for j in (i, -i)]
57
 
58
- # Parallel computation of coefficients
59
  with ThreadPoolExecutor(max_workers=8) as executor:
60
  coefs = list(executor.map(lambda n: (compute_cn(f_precomputed, n, t_values), n), indices))
61
 
62
- # Animation setup
63
  fig, ax = plt.subplots()
64
  circles = [ax.plot([], [], 'b-')[0] for _ in range(-N, N + 1)]
65
  circle_lines = [ax.plot([], [], 'g-')[0] for _ in range(-N, N + 1)]
@@ -75,26 +64,35 @@ def fourier_transform_drawing(input_image, frames, coefficients, img_size, blur_
75
  theta = np.linspace(0, tau, theta_points)
76
  coefs_static = [(np.linalg.norm(c), fr) for c, fr in coefs]
77
 
78
- # Animation function
79
  def animate(i, coefs, time):
80
  center = (0, 0)
81
  for idx, (r, fr) in enumerate(coefs_static):
82
  c_dynamic = coefs[idx][0] * np.exp(1j * (fr * tau * time[i]))
83
  x, y = center[0] + r * np.cos(theta), center[1] + r * np.sin(theta)
84
  circle_lines[idx].set_data([center[0], center[0] + np.real(c_dynamic)], [center[1], center[1] + np.imag(c_dynamic)])
85
- circles[idx].set_data(x, y)
86
  center = (center[0] + np.real(c_dynamic), center[1] + np.imag(c_dynamic))
87
-
88
  draw_x.append(center[0])
89
  draw_y.append(center[1])
90
  drawing.set_data(draw_x[:i+1], draw_y[:i+1])
91
 
92
- # Create and save the animation
 
 
 
 
 
 
 
 
 
 
93
  anim = animation.FuncAnimation(fig, animate, frames=frames, interval=5, fargs=(coefs, np.linspace(0, 1, num=frames)))
94
- output_animation = "output.mp4"
95
- anim.save(output_animation, fps=15)
96
- plt.close(fig)
97
- return output_animation
98
 
99
  # Gradio interface setup
100
  interface = gr.Interface(
@@ -109,10 +107,9 @@ interface = gr.Interface(
109
  gr.Number(value=1000, label="Number of Points for Integration", precision=0),
110
  gr.Slider(minimum=50, maximum=500, value=80, label="Theta Points for Animation")
111
  ],
112
- outputs=gr.Video(),
113
  title="Fourier Transform Drawing",
114
  description="Upload an image and generate a Fourier Transform drawing animation.",
115
- examples=[["Fourier2.jpg", 100, 200, 224, 5, 400, 1000, 80], ["Luffy.png", 100, 100, 224, 5, 400, 1000, 80]]
116
  )
117
 
118
  if __name__ == "__main__":
 
 
 
 
1
  import numpy as np
2
  import matplotlib.pyplot as plt
3
  import matplotlib.animation as animation
4
  from PIL import Image
5
+ import io
6
+ import cv2
7
  from math import tau
 
8
  import gradio as gr
9
+ from concurrent.futures import ThreadPoolExecutor
10
 
11
  def fourier_transform_drawing(input_image, frames, coefficients, img_size, blur_kernel_size, desired_range, num_points, theta_points):
12
  # Convert PIL to OpenCV image
13
  img = cv2.cvtColor(np.array(input_image), cv2.COLOR_RGB2BGR)
 
 
14
  img = cv2.resize(img, (img_size, img_size), interpolation=cv2.INTER_AREA)
 
 
15
  imgray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
16
  blurred = cv2.GaussianBlur(imgray, (blur_kernel_size, blur_kernel_size), 0)
17
  _, thresh = cv2.threshold(blurred, 0, 255, cv2.THRESH_BINARY_INV | cv2.THRESH_OTSU)
18
  contours, _ = cv2.findContours(thresh, cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE)
19
 
20
  # find the contour with the largest area
21
+ largest_contour_idx = np.argmax([cv2.contourArea(c) for c in contours])
22
+ largest_contour = contours[largest_contour_idx]
23
 
24
+ # def combine_all_contours(contours):
25
+ # combined_contour = np.array([], dtype=np.int32).reshape(0, 1, 2)
26
+ # for contour in contours:
27
+ # combined_contour = np.vstack((combined_contour, contour))
28
+ # return combined_contour
29
+
30
+ # largest_contour = combine_all_contours(contours)
31
+ verts = [tuple(coord) for coord in largest_contour.squeeze()]
 
32
  xs, ys = np.asarray(list(zip(*verts)))
 
 
33
  x_range, y_range = np.max(xs) - np.min(xs), np.max(ys) - np.min(ys)
34
  scale_x, scale_y = desired_range / x_range, desired_range / y_range
35
  xs = (xs - np.mean(xs)) * scale_x
36
  ys = (-ys + np.mean(ys)) * scale_y
37
 
 
38
  t_list = np.linspace(0, tau, len(xs))
39
  t_values = np.linspace(0, tau, num_points)
40
  f_precomputed = np.interp(t_values, t_list, xs + 1j * ys)
 
46
  N = coefficients
47
  indices = [0] + [j for i in range(1, N + 1) for j in (i, -i)]
48
 
 
49
  with ThreadPoolExecutor(max_workers=8) as executor:
50
  coefs = list(executor.map(lambda n: (compute_cn(f_precomputed, n, t_values), n), indices))
51
 
 
52
  fig, ax = plt.subplots()
53
  circles = [ax.plot([], [], 'b-')[0] for _ in range(-N, N + 1)]
54
  circle_lines = [ax.plot([], [], 'g-')[0] for _ in range(-N, N + 1)]
 
64
  theta = np.linspace(0, tau, theta_points)
65
  coefs_static = [(np.linalg.norm(c), fr) for c, fr in coefs]
66
 
 
67
  def animate(i, coefs, time):
68
  center = (0, 0)
69
  for idx, (r, fr) in enumerate(coefs_static):
70
  c_dynamic = coefs[idx][0] * np.exp(1j * (fr * tau * time[i]))
71
  x, y = center[0] + r * np.cos(theta), center[1] + r * np.sin(theta)
72
  circle_lines[idx].set_data([center[0], center[0] + np.real(c_dynamic)], [center[1], center[1] + np.imag(c_dynamic)])
73
+ circles[idx].set_data(x, y)
74
  center = (center[0] + np.real(c_dynamic), center[1] + np.imag(c_dynamic))
75
+
76
  draw_x.append(center[0])
77
  draw_y.append(center[1])
78
  drawing.set_data(draw_x[:i+1], draw_y[:i+1])
79
 
80
+ # Capture and yield the current plot as an image
81
+ buf = io.BytesIO()
82
+ plt.savefig(buf, format='png', bbox_inches='tight')
83
+ buf.seek(0)
84
+ yield np.array(Image.open(buf))
85
+
86
+ # Generate and yield images
87
+ for frame in range(frames):
88
+ yield from animate(frame, coefs, np.linspace(0, 1, num=frames))
89
+
90
+ # Generate final animation
91
  anim = animation.FuncAnimation(fig, animate, frames=frames, interval=5, fargs=(coefs, np.linspace(0, 1, num=frames)))
92
+ buf = io.BytesIO()
93
+ anim.save(buf, format='gif', fps=15)
94
+ buf.seek(0)
95
+ yield buf
96
 
97
  # Gradio interface setup
98
  interface = gr.Interface(
 
107
  gr.Number(value=1000, label="Number of Points for Integration", precision=0),
108
  gr.Slider(minimum=50, maximum=500, value=80, label="Theta Points for Animation")
109
  ],
110
+ outputs=["image", "file"],
111
  title="Fourier Transform Drawing",
112
  description="Upload an image and generate a Fourier Transform drawing animation.",
 
113
  )
114
 
115
  if __name__ == "__main__":