File size: 7,505 Bytes
aec5cde f4daba4 9d84578 aec5cde 9d84578 501be52 9d84578 9ec4178 95cb277 d94003f 95cb277 9d84578 aec5cde f118b28 aec5cde ab86061 aec5cde 9d84578 aec5cde ab86061 aec5cde 9d84578 aec5cde f118b28 aec5cde 9d84578 ab86061 aec5cde 9d84578 aec5cde f118b28 ab86061 f118b28 ab86061 f118b28 ab86061 f118b28 ab86061 f118b28 0570674 f118b28 aa2570e ebd5c74 aa2570e aec5cde aa2570e d6a7010 aa2570e d6a7010 5ff8b91 d6a7010 aa2570e d6a7010 aa2570e d6a7010 5ff8b91 d6a7010 aa2570e d6a7010 0570674 d6a7010 aa2570e aec5cde f118b28 aec5cde b475a69 |
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 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 |
import gradio as gr
from PIL import Image
import numpy as np
# Modified matrices with improved red/cyan separation
matrices = {
'true': [
[0.299, 0.587, 0.114, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 0.299, 0.587, 0.114]
],
'mono': [
[0.299, 0.587, 0.114, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 0.299, 0.587, 0.114, 0.299, 0.587, 0.114]
],
'color': [
[1, 0, 0, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 1, 0, 0, 0, 1]
],
'halfcolor': [
[0.299, 0.587, 0.114, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 1, 0, 0, 0, 1]
],
'optimized': [
[0, 0.450, 1.050, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 1, 0, 0, 0, 1]
],
# New matrices with improved red/cyan separation
'dubois': [
[0.456, 0.5, 0.176, -0.04, -0.038, -0.016, -0.015, -0.021, -0.005], # Left image
[-0.043, -0.088, -0.002, 0.378, 0.734, -0.018, -0.072, -0.113, 1.226] # Right image
],
'dubois_optimized': [
[0.4561, 0.500484, 0.176381, -0.0400822, -0.0378246, -0.0157589, -0.0152161, -0.0205971, -0.00546856],
[-0.0434706, -0.0879388, -0.00155529, 0.378476, 0.73364, -0.0184503, -0.0721527, -0.112961, 1.2264]
]
}
def make_anaglyph(left_img, right_img, color_method):
"""Generate an anaglyph from left and right images using the specified color method"""
if left_img is None or right_img is None:
return None
# Convert from numpy array (from Gradio) to PIL Image
left = Image.fromarray(left_img)
right = Image.fromarray(right_img)
# Check if both images have the same dimensions
if left.size != right.size:
# Resize right image to match left image dimensions
right = right.resize(left.size, Image.LANCZOS)
# Create a new image for the result (important change)
result = Image.new("RGB", left.size)
# Get the pixel maps
width, height = left.size
leftMap = left.load()
rightMap = right.load()
resultMap = result.load()
# Use the selected color matrix
m = matrices[color_method]
# Apply the anaglyph transformation
for y in range(0, height):
for x in range(0, width):
r1, g1, b1 = leftMap[x, y]
r2, g2, b2 = rightMap[x, y]
resultMap[x, y] = (
int(r1*m[0][0] + g1*m[0][1] + b1*m[0][2] + r2*m[1][0] + g2*m[1][1] + b2*m[1][2]),
int(r1*m[0][3] + g1*m[0][4] + b1*m[0][5] + r2*m[1][3] + g2*m[1][4] + b2*m[1][5]),
int(r1*m[0][6] + g1*m[0][7] + b1*m[0][8] + r2*m[1][6] + g2*m[1][7] + b2*m[1][8])
)
# Convert back to numpy array for Gradio
return np.array(result)
def make_stereopair(left_img, right_img, color_method):
"""Generate a stereo pair from left and right images"""
if left_img is None or right_img is None:
return None
# Convert from numpy array (from Gradio) to PIL Image
left = Image.fromarray(left_img)
right = Image.fromarray(right_img)
# Check if both images have the same dimensions
if left.size != right.size:
# Resize right image to match left image dimensions
right = right.resize(left.size, Image.LANCZOS)
width, height = left.size
leftMap = left.load()
rightMap = right.load()
# Create a new image twice as wide
pair = Image.new('RGB', (width * 2, height))
pairMap = pair.load()
# Copy the left and right images side by side
for y in range(0, height):
for x in range(0, width):
pairMap[x, y] = leftMap[x, y]
pairMap[x + width, y] = rightMap[x, y]
# Convert to monochrome if required
if color_method == 'mono':
pair = pair.convert('L')
# Convert back to numpy array for Gradio
return np.array(pair)
def process_images(left_img, right_img, method, color_method):
"""Generate a 3D visualization from left and right stereo images.
This function processes a pair of stereo images (left and right views) and
generates a 3D image using the specified visualization method:
- "anaglyph": Combines the two images using a red-cyan color encoding, suitable
for viewing with 3D glasses.
- "parallel": Places the images side by side for stereoscopic viewing with the
parallel-eye method.
- "crossed": Similar to parallel, but with the left and right images swapped,
suitable for cross-eyed viewing.
You can also specify the color processing style (e.g., "optimized", "mono", "true", etc.)
for finer control over color blending or grayscale conversion.
Args:
left_img (numpy.ndarray): The left-eye image as a NumPy array.
right_img (numpy.ndarray): The right-eye image as a NumPy array.
method (str): The 3D generation method, one of: "anaglyph", "parallel", or "crossed".
color_method (str): The color matrix to use for processing. Options include: "optimized", "true", "mono", "color", "halfcolor", "dubois", "dubois_optimized".
Returns:
numpy.ndarray: The resulting 3D image, ready to be displayed or saved.
"""
if method == "anaglyph":
return make_anaglyph(left_img, right_img, color_method)
elif method == "parallel":
return make_stereopair(left_img, right_img, color_method)
elif method == "crossed":
return make_stereopair(right_img, left_img, color_method)
return None
css="""
div#col-container{
margin: 0 auto;
max-width: 840px;
}
"""
# Create the Gradio interface
with gr.Blocks(css=css) as app:
with gr.Column(elem_id="col-container"):
gr.Markdown("# 3D Anaglyph Image Generator")
gr.Markdown("Upload left and right images to create 3D images using different methods.")
with gr.Row():
left_input = gr.Image(label="Left Image")
right_input = gr.Image(label="Right Image")
method = gr.Radio(
["anaglyph", "parallel", "crossed"],
label="Method",
value="anaglyph",
info="Select the 3D image creation method"
)
color_method = gr.Radio(
["optimized", "true", "mono", "color", "halfcolor", "dubois", "dubois_optimized"],
label="Color Method",
value="dubois",
info="Select the color processing method"
)
with gr.Accordion("Details about methods", open=False):
gr.Markdown("""
### Methods:
- **anaglyph**: Creates a red-cyan 3D image (requires 3D glasses)
- **parallel**: Creates side-by-side images for parallel viewing
- **crossed**: Creates side-by-side images for cross-eyed viewing
### Color Methods:
- **optimized**: Best for most images (default)
- **true**: True color anaglyph
- **mono**: Monochrome output
- **color**: Full color (may cause ghosting)
- **halfcolor**: Balance between color and depth
""")
generate_btn = gr.Button("Generate 3D Image", variant="primary")
output = gr.Image(label="Generated 3D Anaglyph Image")
generate_btn.click(
fn=process_images,
inputs=[left_input, right_input, method, color_method],
outputs=output
)
# Launch the app
if __name__ == "__main__":
app.launch(ssr_mode=False, mcp_server=True) |