stzhao's picture
Update app.py
a54495c verified
import skia
import numpy as np
import gradio as gr
def load_image(path):
"""Load an image from the given path using Skia."""
return skia.Image.open(path)
def save_image(image, path):
"""Save the given image to the specified path."""
image.save(path)
def image_to_array(image):
"""Convert a Skia image to a numpy array."""
return np.array(image)
def array_to_image(array):
"""Convert a numpy array to a Skia image."""
return skia.Image.fromarray(np.uint8(array))
def texture_image_with_normal(A, A_normal, B):
"""Texture image B onto image A based on the normal map A_normal."""
# Load images
A_img = load_image(A)
A_normal_img = load_image(A_normal)
B_img = load_image(B)
# Convert images to numpy arrays
A_array = image_to_array(A_img)
A_normal_array = image_to_array(A_normal_img)
B_array = image_to_array(B_img)
# Ensure all images have the same dimensions
assert A_array.shape == A_normal_array.shape == B_array.shape, "All images must have the same dimensions."
# Normalize the normal map (values should be between 0 and 1)
A_normal_array = A_normal_array / 255.0
# Create an empty array for the textured image
textured_array = np.zeros_like(A_array, dtype=np.float32)
# Texture the image B onto A based on the normal map
for y in range(A_array.shape[0]):
for x in range(A_array.shape[1]):
# Get the normal vector at this pixel
normal = A_normal_array[y, x]
# Calculate the offset based on the normal vector
offset_x = int(normal[0] * B_array.shape[1])
offset_y = int(normal[1] * B_array.shape[0])
# Calculate the new coordinates in B
new_x = (x + offset_x) % B_array.shape[1]
new_y = (y + offset_y) % B_array.shape[0]
# Apply the texture from B to A
textured_array[y, x] = B_array[new_y, new_x]
# Convert the textured array back to an image
textured_image = array_to_image(textured_array)
return textured_image
def gradio_interface(A, A_normal, B):
"""Gradio interface function to texture images."""
textured_image = texture_image_with_normal(A, A_normal, B)
return np.array(textured_image)
# Define example inputs
examples = [
["examples/image_A_1.png", "examples/image_A_normal_1.png", "examples/image_B_1.png"],
["examples/image_A_2.png", "examples/image_A_normal_2.png", "examples/image_B_2.png"],
["examples/image_A_3.png", "examples/image_A_normal_3.png", "examples/image_B_3.png"]
]
# Create Gradio interface
iface = gr.Interface(
fn=gradio_interface,
inputs=[
gr.Image(type="filepath", label="Image A"),
gr.Image(type="filepath", label="Normal Map A_normal"),
gr.Image(type="filepath", label="Image B")
],
outputs=gr.Image(type="numpy", label="Textured Image"),
title="Image Texturing with Normal Map",
description="Upload Image A, its Normal Map A_normal, and Image B to texture B onto A based on A_normal.",
examples=examples
)
# Launch the interface
iface.launch()