File size: 3,116 Bytes
7eb82c5
 
 
 
 
a54495c
7eb82c5
 
 
a54495c
7eb82c5
 
 
a54495c
7eb82c5
 
 
a54495c
7eb82c5
 
 
a54495c
7eb82c5
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
a54495c
7eb82c5
 
 
5f7749e
 
 
 
 
 
 
7eb82c5
 
 
 
29af960
 
 
7eb82c5
29af960
7eb82c5
5f7749e
 
7eb82c5
 
 
 
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
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()