fffiloni's picture
Create anaglyph.py
3e0dba3 verified
# Copyright (c) 2013 by Miguel Grinberg
#
# Permission is hereby granted, free of charge, to any person obtaining a copy
# of this software and associated documentation files (the "Software"), to deal
# in the Software without restriction, including without limitation the rights
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
# copies of the Software, and to permit persons to whom the Software is furnished
# to do so, subject to the following conditions:
#
# The above copyright notice and this permission notice shall be included in all
# copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
# FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
# COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
# AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
import optparse
from PIL import Image, ImageSequence
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.7, 0.3, 0, 0, 0, 0, 0, 0 ], [ 0, 0, 0, 0, 1, 0, 0, 0, 1 ] ],
}
def make_anaglyph(left, right, color, path):
width, height = left.size
leftMap = left.load()
rightMap = right.load()
m = matrices[color]
for y in range(0, height):
for x in range(0, width):
r1, g1, b1 = leftMap[x, y]
r2, g2, b2 = rightMap[x, y]
leftMap[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])
)
left.save(path)
def make_stereopair(left, right, color, path):
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 == 'mono':
pair = pair.convert('L')
pair.save(path)
def make_wiggle3d(left, right, color, path):
if color == 'mono':
left = left.convert('L')
right = right.convert('L')
#writeGif(path, [left, right], 0.1, True, False, 0, False, 2)
left.save(path, save_all=True, append_images=[right], duration=0.1, loop=0,
dispose=2)
def parse_arguments():
parser = optparse.OptionParser(usage = 'usage: %prog [options] left_image right_image stereo_image')
group = optparse.OptionGroup(parser, "Stereo image options")
group.add_option('-a', '--anaglyph',
action = 'store_const', const = 'anaglyph', dest = 'type', default = 'anaglyph',
help = 'generate a stereo anaglyph (default)')
group.add_option('-p', '--parallel',
action = 'store_const', const = 'parallel', dest = 'type',
help = 'generate a parallel viewing stereo pair')
group.add_option('-x', '--crossed',
action = 'store_const', const = 'crossed', dest = 'type',
help = 'generate a crossed viewing stereo pair')
group.add_option('-w', '--wiggle',
action = 'store_const', const = 'wiggle', dest = 'type',
help = 'generate a "Wiggle 3D" animated GIF file')
parser.add_option_group(group)
group = optparse.OptionGroup(parser, "Color options")
group.add_option('-t', '--true',
action = 'store_const', const = 'true', dest = 'color',
help = 'generate a true color picture')
group.add_option('-m', '--mono',
action = 'store_const', const = 'mono', dest = 'color',
help = 'generate a monochrome picture')
group.add_option('-c', '--color',
action = 'store_const', const = 'color', dest = 'color',
help = 'generate a color picture')
group.add_option('-f', '--halfcolor',
action = 'store_const', const = 'halfcolor', dest = 'color',
help = 'generate a half color picture')
group.add_option('-o', '--optimized',
action = 'store_const', const = 'optimized', dest = 'color', default = 'optimized',
help = 'generate an optimized color picture (default)')
parser.add_option_group(group)
group = optparse.OptionGroup(parser, "Other options")
group.add_option('-r', '--resize',
action = 'store', type = 'int', dest = 'size', default = 0,
help = 'resize image to the given width (height is automatically calculated to preserve aspect ratio)')
parser.add_option_group(group)
options, args = parser.parse_args()
if len(args) != 3:
parser.error('wrong number of arguments')
leftImage = Image.open(args[0])
pixelMap = leftImage.load()
rightImage = Image.open(args[1])
if leftImage.size != rightImage.size:
parser.error('left and right images must have the same size')
if options.size > 0:
width, height = leftImage.size
leftImage = leftImage.resize((options.size, options.size * height / width), Image.ANTIALIAS)
rightImage = rightImage.resize((options.size, options.size * height / width), Image.ANTIALIAS)
return options, leftImage, rightImage, args[2]
def main():
options, leftImage, rightImage, stereoPath = parse_arguments()
if options.type == 'anaglyph':
make_anaglyph(leftImage, rightImage, options.color, stereoPath)
elif options.type == 'parallel':
make_stereopair(leftImage, rightImage, options.color, stereoPath)
elif options.type == 'crossed':
make_stereopair(rightImage, leftImage, options.color, stereoPath)
elif options.type == 'wiggle':
make_wiggle3d(leftImage, rightImage, options.color, stereoPath)
if __name__ == '__main__':
main()