fffiloni commited on
Commit
3e0dba3
·
verified ·
1 Parent(s): 6ba6b5d

Create anaglyph.py

Browse files
Files changed (1) hide show
  1. anaglyph.py +140 -0
anaglyph.py ADDED
@@ -0,0 +1,140 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Copyright (c) 2013 by Miguel Grinberg
2
+ #
3
+ # Permission is hereby granted, free of charge, to any person obtaining a copy
4
+ # of this software and associated documentation files (the "Software"), to deal
5
+ # in the Software without restriction, including without limitation the rights
6
+ # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
7
+ # copies of the Software, and to permit persons to whom the Software is furnished
8
+ # to do so, subject to the following conditions:
9
+ #
10
+ # The above copyright notice and this permission notice shall be included in all
11
+ # copies or substantial portions of the Software.
12
+ #
13
+ # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14
+ # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
15
+ # FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
16
+ # COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
17
+ # AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
18
+ # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
19
+
20
+ import optparse
21
+ from PIL import Image, ImageSequence
22
+
23
+ matrices = {
24
+ '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 ] ],
25
+ '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 ] ],
26
+ 'color': [ [ 1, 0, 0, 0, 0, 0, 0, 0, 0 ], [ 0, 0, 0, 0, 1, 0, 0, 0, 1 ] ],
27
+ 'halfcolor': [ [ 0.299, 0.587, 0.114, 0, 0, 0, 0, 0, 0 ], [ 0, 0, 0, 0, 1, 0, 0, 0, 1 ] ],
28
+ 'optimized': [ [ 0, 0.7, 0.3, 0, 0, 0, 0, 0, 0 ], [ 0, 0, 0, 0, 1, 0, 0, 0, 1 ] ],
29
+ }
30
+
31
+ def make_anaglyph(left, right, color, path):
32
+ width, height = left.size
33
+ leftMap = left.load()
34
+ rightMap = right.load()
35
+ m = matrices[color]
36
+
37
+ for y in range(0, height):
38
+ for x in range(0, width):
39
+ r1, g1, b1 = leftMap[x, y]
40
+ r2, g2, b2 = rightMap[x, y]
41
+ leftMap[x, y] = (
42
+ 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]),
43
+ 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]),
44
+ 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])
45
+ )
46
+ left.save(path)
47
+
48
+ def make_stereopair(left, right, color, path):
49
+ width, height = left.size
50
+ leftMap = left.load()
51
+ rightMap = right.load()
52
+ pair = Image.new('RGB', (width * 2, height))
53
+ pairMap = pair.load()
54
+ for y in range(0, height):
55
+ for x in range(0, width):
56
+ pairMap[x, y] = leftMap[x, y]
57
+ pairMap[x + width, y] = rightMap[x, y]
58
+ if color == 'mono':
59
+ pair = pair.convert('L')
60
+ pair.save(path)
61
+
62
+ def make_wiggle3d(left, right, color, path):
63
+ if color == 'mono':
64
+ left = left.convert('L')
65
+ right = right.convert('L')
66
+ #writeGif(path, [left, right], 0.1, True, False, 0, False, 2)
67
+ left.save(path, save_all=True, append_images=[right], duration=0.1, loop=0,
68
+ dispose=2)
69
+
70
+ def parse_arguments():
71
+ parser = optparse.OptionParser(usage = 'usage: %prog [options] left_image right_image stereo_image')
72
+
73
+ group = optparse.OptionGroup(parser, "Stereo image options")
74
+ group.add_option('-a', '--anaglyph',
75
+ action = 'store_const', const = 'anaglyph', dest = 'type', default = 'anaglyph',
76
+ help = 'generate a stereo anaglyph (default)')
77
+ group.add_option('-p', '--parallel',
78
+ action = 'store_const', const = 'parallel', dest = 'type',
79
+ help = 'generate a parallel viewing stereo pair')
80
+ group.add_option('-x', '--crossed',
81
+ action = 'store_const', const = 'crossed', dest = 'type',
82
+ help = 'generate a crossed viewing stereo pair')
83
+ group.add_option('-w', '--wiggle',
84
+ action = 'store_const', const = 'wiggle', dest = 'type',
85
+ help = 'generate a "Wiggle 3D" animated GIF file')
86
+ parser.add_option_group(group)
87
+
88
+ group = optparse.OptionGroup(parser, "Color options")
89
+ group.add_option('-t', '--true',
90
+ action = 'store_const', const = 'true', dest = 'color',
91
+ help = 'generate a true color picture')
92
+ group.add_option('-m', '--mono',
93
+ action = 'store_const', const = 'mono', dest = 'color',
94
+ help = 'generate a monochrome picture')
95
+ group.add_option('-c', '--color',
96
+ action = 'store_const', const = 'color', dest = 'color',
97
+ help = 'generate a color picture')
98
+ group.add_option('-f', '--halfcolor',
99
+ action = 'store_const', const = 'halfcolor', dest = 'color',
100
+ help = 'generate a half color picture')
101
+ group.add_option('-o', '--optimized',
102
+ action = 'store_const', const = 'optimized', dest = 'color', default = 'optimized',
103
+ help = 'generate an optimized color picture (default)')
104
+ parser.add_option_group(group)
105
+
106
+ group = optparse.OptionGroup(parser, "Other options")
107
+ group.add_option('-r', '--resize',
108
+ action = 'store', type = 'int', dest = 'size', default = 0,
109
+ help = 'resize image to the given width (height is automatically calculated to preserve aspect ratio)')
110
+ parser.add_option_group(group)
111
+
112
+ options, args = parser.parse_args()
113
+ if len(args) != 3:
114
+ parser.error('wrong number of arguments')
115
+
116
+ leftImage = Image.open(args[0])
117
+ pixelMap = leftImage.load()
118
+ rightImage = Image.open(args[1])
119
+ if leftImage.size != rightImage.size:
120
+ parser.error('left and right images must have the same size')
121
+ if options.size > 0:
122
+ width, height = leftImage.size
123
+ leftImage = leftImage.resize((options.size, options.size * height / width), Image.ANTIALIAS)
124
+ rightImage = rightImage.resize((options.size, options.size * height / width), Image.ANTIALIAS)
125
+ return options, leftImage, rightImage, args[2]
126
+
127
+ def main():
128
+ options, leftImage, rightImage, stereoPath = parse_arguments()
129
+
130
+ if options.type == 'anaglyph':
131
+ make_anaglyph(leftImage, rightImage, options.color, stereoPath)
132
+ elif options.type == 'parallel':
133
+ make_stereopair(leftImage, rightImage, options.color, stereoPath)
134
+ elif options.type == 'crossed':
135
+ make_stereopair(rightImage, leftImage, options.color, stereoPath)
136
+ elif options.type == 'wiggle':
137
+ make_wiggle3d(leftImage, rightImage, options.color, stereoPath)
138
+
139
+ if __name__ == '__main__':
140
+ main()