|
import gradio as gr |
|
from PIL import Image |
|
import numpy as np |
|
|
|
|
|
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] |
|
], |
|
|
|
'dubois': [ |
|
[0.456, 0.5, 0.176, -0.04, -0.038, -0.016, -0.015, -0.021, -0.005], |
|
[-0.043, -0.088, -0.002, 0.378, 0.734, -0.018, -0.072, -0.113, 1.226] |
|
], |
|
'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 |
|
|
|
|
|
left = Image.fromarray(left_img) |
|
right = Image.fromarray(right_img) |
|
|
|
|
|
if left.size != right.size: |
|
|
|
right = right.resize(left.size, Image.LANCZOS) |
|
|
|
|
|
result = Image.new("RGB", left.size) |
|
|
|
|
|
width, height = left.size |
|
leftMap = left.load() |
|
rightMap = right.load() |
|
resultMap = result.load() |
|
|
|
|
|
m = matrices[color_method] |
|
|
|
|
|
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]) |
|
) |
|
|
|
|
|
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 |
|
|
|
|
|
left = Image.fromarray(left_img) |
|
right = Image.fromarray(right_img) |
|
|
|
|
|
if left.size != right.size: |
|
|
|
right = right.resize(left.size, Image.LANCZOS) |
|
|
|
width, height = left.size |
|
leftMap = left.load() |
|
rightMap = right.load() |
|
|
|
|
|
pair = Image.new('RGB', (width * 2, height)) |
|
pairMap = pair.load() |
|
|
|
|
|
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] |
|
|
|
|
|
if color_method == 'mono': |
|
pair = pair.convert('L') |
|
|
|
|
|
return np.array(pair) |
|
|
|
def process_images(left_img, right_img, method, color_method): |
|
"""Process images based on the selected method""" |
|
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: 1340px; |
|
} |
|
""" |
|
|
|
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(): |
|
with gr.Column(): |
|
|
|
with gr.Row(): |
|
with gr.Column(): |
|
left_input = gr.Image(label="Left Image") |
|
with gr.Column(): |
|
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="optimized", |
|
info="Select the color processing method" |
|
) |
|
|
|
generate_btn = gr.Button("Generate 3D Image", variant="primary") |
|
|
|
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 |
|
""") |
|
|
|
output = gr.Image(label="Generated 3D Anaglyph Image") |
|
|
|
generate_btn.click( |
|
fn=process_images, |
|
inputs=[left_input, right_input, method, color_method], |
|
outputs=output |
|
) |
|
|
|
|
|
if __name__ == "__main__": |
|
app.launch() |