Spaces:
Runtime error
Runtime error
Create app.py
Browse files
app.py
ADDED
@@ -0,0 +1,77 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
import skia
|
2 |
+
import numpy as np
|
3 |
+
import gradio as gr
|
4 |
+
|
5 |
+
def load_image(path):
|
6 |
+
return skia.Image.open(path)
|
7 |
+
|
8 |
+
def save_image(image, path):
|
9 |
+
image.save(path)
|
10 |
+
|
11 |
+
def image_to_array(image):
|
12 |
+
return np.array(image)
|
13 |
+
|
14 |
+
def array_to_image(array):
|
15 |
+
return skia.Image.fromarray(np.uint8(array))
|
16 |
+
|
17 |
+
def texture_image_with_normal(A, A_normal, B):
|
18 |
+
# Load images
|
19 |
+
A_img = load_image(A)
|
20 |
+
A_normal_img = load_image(A_normal)
|
21 |
+
B_img = load_image(B)
|
22 |
+
|
23 |
+
# Convert images to numpy arrays
|
24 |
+
A_array = image_to_array(A_img)
|
25 |
+
A_normal_array = image_to_array(A_normal_img)
|
26 |
+
B_array = image_to_array(B_img)
|
27 |
+
|
28 |
+
# Ensure all images have the same dimensions
|
29 |
+
assert A_array.shape == A_normal_array.shape == B_array.shape, "All images must have the same dimensions."
|
30 |
+
|
31 |
+
# Normalize the normal map (values should be between 0 and 1)
|
32 |
+
A_normal_array = A_normal_array / 255.0
|
33 |
+
|
34 |
+
# Create an empty array for the textured image
|
35 |
+
textured_array = np.zeros_like(A_array, dtype=np.float32)
|
36 |
+
|
37 |
+
# Texture the image B onto A based on the normal map
|
38 |
+
for y in range(A_array.shape[0]):
|
39 |
+
for x in range(A_array.shape[1]):
|
40 |
+
# Get the normal vector at this pixel
|
41 |
+
normal = A_normal_array[y, x]
|
42 |
+
|
43 |
+
# Calculate the offset based on the normal vector
|
44 |
+
offset_x = int(normal[0] * B_array.shape[1])
|
45 |
+
offset_y = int(normal[1] * B_array.shape[0])
|
46 |
+
|
47 |
+
# Calculate the new coordinates in B
|
48 |
+
new_x = (x + offset_x) % B_array.shape[1]
|
49 |
+
new_y = (y + offset_y) % B_array.shape[0]
|
50 |
+
|
51 |
+
# Apply the texture from B to A
|
52 |
+
textured_array[y, x] = B_array[new_y, new_x]
|
53 |
+
|
54 |
+
# Convert the textured array back to an image
|
55 |
+
textured_image = array_to_image(textured_array)
|
56 |
+
|
57 |
+
return textured_image
|
58 |
+
|
59 |
+
def gradio_interface(A, A_normal, B):
|
60 |
+
textured_image = texture_image_with_normal(A, A_normal, B)
|
61 |
+
return np.array(textured_image)
|
62 |
+
|
63 |
+
# Create Gradio interface
|
64 |
+
iface = gr.Interface(
|
65 |
+
fn=gradio_interface,
|
66 |
+
inputs=[
|
67 |
+
gr.inputs.Image(type="filepath", label="Image A"),
|
68 |
+
gr.inputs.Image(type="filepath", label="Normal Map A_normal"),
|
69 |
+
gr.inputs.Image(type="filepath", label="Image B")
|
70 |
+
],
|
71 |
+
outputs=gr.outputs.Image(type="numpy", label="Textured Image"),
|
72 |
+
title="Image Texturing with Normal Map",
|
73 |
+
description="Upload Image A, its Normal Map A_normal, and Image B to texture B onto A based on A_normal."
|
74 |
+
)
|
75 |
+
|
76 |
+
# Launch the interface
|
77 |
+
iface.launch()
|