Skip to content

Instantly share code, notes, and snippets.

@VeryFatBoy
Forked from badjano/autostereogram.py
Created May 13, 2025 20:52
Show Gist options
  • Select an option

  • Save VeryFatBoy/a7a8152eb0efe3b7a6c70b24fb87ffea to your computer and use it in GitHub Desktop.

Select an option

Save VeryFatBoy/a7a8152eb0efe3b7a6c70b24fb87ffea to your computer and use it in GitHub Desktop.
import sys
import numpy as np
from PIL import Image
import argparse
import os
def create_autostereogram(pattern_path, depth_map_path, output_path, repeat_width=128):
"""
Generate an autostereogram from a pattern image and a depth map.
Args:
pattern_path (str): Path to the pattern image
depth_map_path (str): Path to the depth map image
output_path (str): Path to save the output autostereogram
repeat_width (int): Width of the repeating pattern in pixels
"""
# Load pattern and depth map
try:
pattern = Image.open(pattern_path).convert('RGB')
depth_map = Image.open(depth_map_path).convert('L') # Convert depth map to grayscale
except Exception as e:
print(f"Error loading images: {e}")
return False
# resize pattern to a fixed size
pattern = pattern.resize((repeat_width, repeat_width))
# Resize depth map to match the pattern's height while maintaining aspect ratio
pattern_width, pattern_height = pattern.size
depth_width, depth_height = depth_map.size
# Convert images to numpy arrays for faster processing
pattern_array = np.array(pattern)
depth_array = np.array(depth_map)
output_array = np.zeros((depth_height, depth_width, 3), dtype=np.uint8)
# Calculate maximum pixel shift based on depth factor (as a fraction of pattern width)
depth_factor = 0.2 # Adjust this value to control depth effect intensity
max_shift = int(pattern_width * depth_factor)
# get array from pattern
strip = np.zeros((pattern_height, pattern_width, 3), dtype=np.uint8)
for y in range(pattern_height):
for x in range(pattern_width):
# Get the color from the pattern
strip[y, x] = pattern_array[y % pattern_height, x % pattern_width]
output_height = depth_height
output_width = depth_width
# Generate autostereogram
for y in range(output_height):
# For each row of the output image
for x in range(output_width):
# Skip the first pattern width of pixels (reference strip)
if x < pattern_width:
output_array[y, x] = strip[y % repeat_width, x % repeat_width]
else:
# Calculate shift based on depth
if x < depth_array.shape[1]:
# Normalize depth value (0-255) to (0-max_shift)
shift = int((depth_array[y, x] / 255.0) * max_shift)
# Look up the color from the left, shifted by depth
sample_x = x - pattern_width + shift
# Ensure sample_x is within bounds
if sample_x < 0:
sample_x = 0
elif sample_x >= output_width:
sample_x = output_width - 1
output_array[y, x] = output_array[y, sample_x]
else:
# For areas beyond the depth map, just repeat the pattern
output_array[y, x] = strip[y, x % pattern_width]
# Convert back to PIL image and save
output = Image.fromarray(output_array)
output.save(output_path)
print(f"Autostereogram saved to {output_path}")
return True
def main():
if len(sys.argv) < 3:
create_autostereogram("pattern.png", "depth.png", "autostereogram.png", 256)
return
parser = argparse.ArgumentParser(description='Generate an autostereogram from a pattern and depth map.')
parser.add_argument('pattern', help='Path to the pattern image')
parser.add_argument('depth_map', help='Path to the depth map image')
parser.add_argument('--output', '-o', default='autostereogram.png', help='Output image path')
parser.add_argument('--depth_factor', '-d', type=float, default=0.2,
help='Depth effect intensity (0.0-1.0)')
parser.add_argument('--repeat_width', '-r', type=int, default=128,
help='Number of times to repeat the pattern horizontally')
args = parser.parse_args()
if not os.path.exists(args.pattern):
print(f"Error: Pattern file not found: {args.pattern}")
return
if not os.path.exists(args.depth_map):
print(f"Error: Depth map file not found: {args.depth_map}")
return
create_autostereogram(args.pattern, args.depth_map, args.output,
args.depth_factor, args.repeat_width)
if __name__ == "__main__":
main()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment