File size: 5,329 Bytes
a74e93f
 
 
 
 
e662564
 
a74e93f
 
e662564
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
a74e93f
 
e662564
 
 
 
 
 
 
 
 
 
 
 
 
a74e93f
 
e662564
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
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
import gradio as gr
from PIL import Image, ImageOps
import numpy as np
import os
import uuid
import random
from scipy import ndimage

# Ensure there's a directory for outputs

os.makedirs("outputs", exist\_ok=True)

def make\_square(img, size=3000, fill\_color=(0, 0, 0)):
x, y = img.size
scale = size / max(x, y)
new\_size = (int(x \* scale), int(y \* scale))
img = img.resize(new\_size, Image.Resampling.LANCZOS)
new\_img = Image.new("RGB", (size, size), fill\_color)
new\_img.paste(img, ((size - new\_size\[0]) // 2, (size - new\_size\[1]) // 2))
return new\_img

def pixel\_shuffle(img\_array, block\_size=10, shuffle\_strength=0.5):
"""Shuffle pixels in blocks to create generative effect"""
height, width, channels = img\_array.shape
result = np.copy(img\_array)

```
# Create blocks for shuffling
h_blocks = height // block_size
w_blocks = width // block_size

# Create list of block coordinates
blocks = []
for i in range(h_blocks):
    for j in range(w_blocks):
        blocks.append((i, j))

# Shuffle a percentage of blocks based on strength
num_blocks_to_shuffle = int(len(blocks) * shuffle_strength)
blocks_to_shuffle = random.sample(blocks, num_blocks_to_shuffle)

# Create a shuffled version of these blocks
target_positions = blocks_to_shuffle.copy()
random.shuffle(target_positions)

# Perform the shuffling
for (src_i, src_j), (tgt_i, tgt_j) in zip(blocks_to_shuffle, target_positions):
    src_y, src_x = src_i * block_size, src_j * block_size
    tgt_y, tgt_x = tgt_i * block_size, tgt_j * block_size
    
    # Swap blocks
    temp = np.copy(result[src_y:src_y+block_size, src_x:src_x+block_size])
    result[src_y:src_y+block_size, src_x:src_x+block_size] = result[tgt_y:tgt_y+block_size, tgt_x:tgt_x+block_size]
    result[tgt_y:tgt_y+block_size, tgt_x:tgt_x+block_size] = temp

return result
```

def flow\_distortion(img\_array, strength=10):
"""Apply flow-based distortion to simulate generative models"""
height, width, channels = img\_array.shape
result = np.zeros\_like(img\_array, dtype=np.float32)

```
# Create random flow fields for x and y directions
flow_x = np.random.normal(0, strength, (height, width))
flow_y = np.random.normal(0, strength, (height, width))

# Smooth the flow fields
flow_x = ndimage.gaussian_filter(flow_x, sigma=30)
flow_y = ndimage.gaussian_filter(flow_y, sigma=30)

# Create meshgrid for coordinate mapping
y_coords, x_coords = np.meshgrid(np.arange(height), np.arange(width), indexing='ij')

# Add flow to coordinates
x_mapped = x_coords + flow_x
y_mapped = y_coords + flow_y

# Clip to ensure we stay within bounds
x_mapped = np.clip(x_mapped, 0, width-1)
y_mapped = np.clip(y_mapped, 0, height-1)

# Sample from the original image using the warped coordinates
for c in range(channels):
    result[:, :, c] = ndimage.map_coordinates(img_array[:, :, c], [y_mapped, x_mapped], order=1)

return result
```

def blend\_images\_with\_rearrangement(images, block\_size=20, shuffle\_strength=0.3, flow\_strength=5):
if len(images) < 2:
return "Upload at least two images.", None

```
try:
    # Process images
    processed = []
    for img in images:
        try:
            processed.append(make_square(Image.open(img)))
        except Exception as e:
            return f"Error processing image: {str(e)}", None
    
    # Convert images to numpy arrays
    img_arrays = [np.array(img).astype(np.float32) for img in processed]
    
    # Create a base canvas
    base = np.zeros_like(img_arrays[0])
    
    # Divide the images into a grid and randomly select pixels from different images
    height, width, _ = base.shape
    for i in range(0, height, block_size):
        for j in range(0, width, block_size):
            # Get end coordinates for the block
            end_i = min(i + block_size, height)
            end_j = min(j + block_size, width)
            
            # Randomly select which image to pull this block from
            source_img = random.choice(img_arrays)
            base[i:end_i, j:end_j] = source_img[i:end_i, j:end_j]
    
    # Apply pixel shuffling to the composite image
    base = pixel_shuffle(base, block_size, shuffle_strength)
    
    # Apply flow distortion to further randomize
    base = flow_distortion(base, flow_strength)
    
    # Blend with original images to preserve some coherence
    for img_array in img_arrays:
        base = base * 0.7 + img_array * 0.3 / len(img_arrays)
    
    final = Image.fromarray(np.uint8(np.clip(base, 0, 255)))
    
    # Save to file
    output_path = f"outputs/amalgam_{uuid.uuid4().hex[:8]}.png"
    final.save(output_path)
    
    return final, output_path
except Exception as e:
    return f"Error during blending: {str(e)}", None
```

demo = gr.Interface(
fn=blend\_images\_with\_rearrangement,
inputs=\[
gr.File(file\_types=\["image"], file\_count="multiple", label="Upload 2–5 stills"),
gr.Slider(minimum=5, maximum=100, value=20, step=5, label="Block Size (pixels)"),
gr.Slider(minimum=0.0, maximum=1.0, value=0.3, step=0.05, label="Shuffle Strength"),
gr.Slider(minimum=0, maximum=20, value=5, step=1, label="Flow Distortion")
],
outputs=\[
gr.Image(label="Generated Image"),
gr.File(label="Download Image")
],
title="Amalgamator",
description="Upload up to 5 stills. Outputs a 3000x3000 image with pixel rearrangement to create a truly generative look."
)

demo.launch()