annotate data_generation/transformations/pycaptcha/Captcha/Visual/Distortions.py @ 618:14ba0120baff

review response changes
author Yoshua Bengio <bengioy@iro.umontreal.ca>
date Sun, 09 Jan 2011 14:13:23 -0500
parents 1f5937e9e530
children
rev   line source
87
4775b4195b4b code pour la generation de captchas
goldfinger
parents:
diff changeset
1 """ Captcha.Visual.Distortions
4775b4195b4b code pour la generation de captchas
goldfinger
parents:
diff changeset
2
4775b4195b4b code pour la generation de captchas
goldfinger
parents:
diff changeset
3 Distortion layers for visual CAPTCHAs
4775b4195b4b code pour la generation de captchas
goldfinger
parents:
diff changeset
4 """
4775b4195b4b code pour la generation de captchas
goldfinger
parents:
diff changeset
5 #
4775b4195b4b code pour la generation de captchas
goldfinger
parents:
diff changeset
6 # PyCAPTCHA Package
4775b4195b4b code pour la generation de captchas
goldfinger
parents:
diff changeset
7 # Copyright (C) 2004 Micah Dowty <micah@navi.cx>
4775b4195b4b code pour la generation de captchas
goldfinger
parents:
diff changeset
8 #
4775b4195b4b code pour la generation de captchas
goldfinger
parents:
diff changeset
9
4775b4195b4b code pour la generation de captchas
goldfinger
parents:
diff changeset
10 from Captcha.Visual import Layer
4775b4195b4b code pour la generation de captchas
goldfinger
parents:
diff changeset
11 import ImageDraw, Image
4775b4195b4b code pour la generation de captchas
goldfinger
parents:
diff changeset
12 import random, math
4775b4195b4b code pour la generation de captchas
goldfinger
parents:
diff changeset
13
4775b4195b4b code pour la generation de captchas
goldfinger
parents:
diff changeset
14
4775b4195b4b code pour la generation de captchas
goldfinger
parents:
diff changeset
15 class WigglyBlocks(Layer):
4775b4195b4b code pour la generation de captchas
goldfinger
parents:
diff changeset
16 """Randomly select and shift blocks of the image"""
4775b4195b4b code pour la generation de captchas
goldfinger
parents:
diff changeset
17 def __init__(self, blockSize=3, sigma=0.01, iterations=300):
4775b4195b4b code pour la generation de captchas
goldfinger
parents:
diff changeset
18 self.blockSize = blockSize
4775b4195b4b code pour la generation de captchas
goldfinger
parents:
diff changeset
19 self.sigma = sigma
4775b4195b4b code pour la generation de captchas
goldfinger
parents:
diff changeset
20 self.iterations = iterations
4775b4195b4b code pour la generation de captchas
goldfinger
parents:
diff changeset
21 self.seed = random.random()
4775b4195b4b code pour la generation de captchas
goldfinger
parents:
diff changeset
22
4775b4195b4b code pour la generation de captchas
goldfinger
parents:
diff changeset
23 def render(self, image):
4775b4195b4b code pour la generation de captchas
goldfinger
parents:
diff changeset
24 r = random.Random(self.seed)
4775b4195b4b code pour la generation de captchas
goldfinger
parents:
diff changeset
25 for i in xrange(self.iterations):
4775b4195b4b code pour la generation de captchas
goldfinger
parents:
diff changeset
26 # Select a block
4775b4195b4b code pour la generation de captchas
goldfinger
parents:
diff changeset
27 bx = int(r.uniform(0, image.size[0]-self.blockSize))
4775b4195b4b code pour la generation de captchas
goldfinger
parents:
diff changeset
28 by = int(r.uniform(0, image.size[1]-self.blockSize))
4775b4195b4b code pour la generation de captchas
goldfinger
parents:
diff changeset
29 block = image.crop((bx, by, bx+self.blockSize-1, by+self.blockSize-1))
4775b4195b4b code pour la generation de captchas
goldfinger
parents:
diff changeset
30
4775b4195b4b code pour la generation de captchas
goldfinger
parents:
diff changeset
31 # Figure out how much to move it.
4775b4195b4b code pour la generation de captchas
goldfinger
parents:
diff changeset
32 # The call to floor() is important so we always round toward
4775b4195b4b code pour la generation de captchas
goldfinger
parents:
diff changeset
33 # 0 rather than to -inf. Just int() would bias the block motion.
4775b4195b4b code pour la generation de captchas
goldfinger
parents:
diff changeset
34 mx = int(math.floor(r.normalvariate(0, self.sigma)))
4775b4195b4b code pour la generation de captchas
goldfinger
parents:
diff changeset
35 my = int(math.floor(r.normalvariate(0, self.sigma)))
4775b4195b4b code pour la generation de captchas
goldfinger
parents:
diff changeset
36
4775b4195b4b code pour la generation de captchas
goldfinger
parents:
diff changeset
37 # Now actually move the block
4775b4195b4b code pour la generation de captchas
goldfinger
parents:
diff changeset
38 image.paste(block, (bx+mx, by+my))
4775b4195b4b code pour la generation de captchas
goldfinger
parents:
diff changeset
39
4775b4195b4b code pour la generation de captchas
goldfinger
parents:
diff changeset
40
4775b4195b4b code pour la generation de captchas
goldfinger
parents:
diff changeset
41 class WarpBase(Layer):
4775b4195b4b code pour la generation de captchas
goldfinger
parents:
diff changeset
42 """Abstract base class for image warping. Subclasses define a
4775b4195b4b code pour la generation de captchas
goldfinger
parents:
diff changeset
43 function that maps points in the output image to points in the input image.
4775b4195b4b code pour la generation de captchas
goldfinger
parents:
diff changeset
44 This warping engine runs a grid of points through this transform and uses
4775b4195b4b code pour la generation de captchas
goldfinger
parents:
diff changeset
45 PIL's mesh transform to warp the image.
4775b4195b4b code pour la generation de captchas
goldfinger
parents:
diff changeset
46 """
4775b4195b4b code pour la generation de captchas
goldfinger
parents:
diff changeset
47 filtering = Image.BILINEAR
4775b4195b4b code pour la generation de captchas
goldfinger
parents:
diff changeset
48 resolution = 10
4775b4195b4b code pour la generation de captchas
goldfinger
parents:
diff changeset
49
4775b4195b4b code pour la generation de captchas
goldfinger
parents:
diff changeset
50 def getTransform(self, image):
4775b4195b4b code pour la generation de captchas
goldfinger
parents:
diff changeset
51 """Return a transformation function, subclasses should override this"""
4775b4195b4b code pour la generation de captchas
goldfinger
parents:
diff changeset
52 return lambda x, y: (x, y)
4775b4195b4b code pour la generation de captchas
goldfinger
parents:
diff changeset
53
4775b4195b4b code pour la generation de captchas
goldfinger
parents:
diff changeset
54 def render(self, image):
4775b4195b4b code pour la generation de captchas
goldfinger
parents:
diff changeset
55 r = self.resolution
4775b4195b4b code pour la generation de captchas
goldfinger
parents:
diff changeset
56 xPoints = image.size[0] / r + 2
4775b4195b4b code pour la generation de captchas
goldfinger
parents:
diff changeset
57 yPoints = image.size[1] / r + 2
4775b4195b4b code pour la generation de captchas
goldfinger
parents:
diff changeset
58 f = self.getTransform(image)
4775b4195b4b code pour la generation de captchas
goldfinger
parents:
diff changeset
59
4775b4195b4b code pour la generation de captchas
goldfinger
parents:
diff changeset
60 # Create a list of arrays with transformed points
4775b4195b4b code pour la generation de captchas
goldfinger
parents:
diff changeset
61 xRows = []
4775b4195b4b code pour la generation de captchas
goldfinger
parents:
diff changeset
62 yRows = []
4775b4195b4b code pour la generation de captchas
goldfinger
parents:
diff changeset
63 for j in xrange(yPoints):
4775b4195b4b code pour la generation de captchas
goldfinger
parents:
diff changeset
64 xRow = []
4775b4195b4b code pour la generation de captchas
goldfinger
parents:
diff changeset
65 yRow = []
4775b4195b4b code pour la generation de captchas
goldfinger
parents:
diff changeset
66 for i in xrange(xPoints):
4775b4195b4b code pour la generation de captchas
goldfinger
parents:
diff changeset
67 x, y = f(i*r, j*r)
4775b4195b4b code pour la generation de captchas
goldfinger
parents:
diff changeset
68
4775b4195b4b code pour la generation de captchas
goldfinger
parents:
diff changeset
69 # Clamp the edges so we don't get black undefined areas
4775b4195b4b code pour la generation de captchas
goldfinger
parents:
diff changeset
70 x = max(0, min(image.size[0]-1, x))
4775b4195b4b code pour la generation de captchas
goldfinger
parents:
diff changeset
71 y = max(0, min(image.size[1]-1, y))
4775b4195b4b code pour la generation de captchas
goldfinger
parents:
diff changeset
72
4775b4195b4b code pour la generation de captchas
goldfinger
parents:
diff changeset
73 xRow.append(x)
4775b4195b4b code pour la generation de captchas
goldfinger
parents:
diff changeset
74 yRow.append(y)
4775b4195b4b code pour la generation de captchas
goldfinger
parents:
diff changeset
75 xRows.append(xRow)
4775b4195b4b code pour la generation de captchas
goldfinger
parents:
diff changeset
76 yRows.append(yRow)
4775b4195b4b code pour la generation de captchas
goldfinger
parents:
diff changeset
77
4775b4195b4b code pour la generation de captchas
goldfinger
parents:
diff changeset
78 # Create the mesh list, with a transformation for
4775b4195b4b code pour la generation de captchas
goldfinger
parents:
diff changeset
79 # each square between points on the grid
4775b4195b4b code pour la generation de captchas
goldfinger
parents:
diff changeset
80 mesh = []
4775b4195b4b code pour la generation de captchas
goldfinger
parents:
diff changeset
81 for j in xrange(yPoints-1):
4775b4195b4b code pour la generation de captchas
goldfinger
parents:
diff changeset
82 for i in xrange(xPoints-1):
4775b4195b4b code pour la generation de captchas
goldfinger
parents:
diff changeset
83 mesh.append((
4775b4195b4b code pour la generation de captchas
goldfinger
parents:
diff changeset
84 # Destination rectangle
4775b4195b4b code pour la generation de captchas
goldfinger
parents:
diff changeset
85 (i*r, j*r,
4775b4195b4b code pour la generation de captchas
goldfinger
parents:
diff changeset
86 (i+1)*r, (j+1)*r),
4775b4195b4b code pour la generation de captchas
goldfinger
parents:
diff changeset
87 # Source quadrilateral
4775b4195b4b code pour la generation de captchas
goldfinger
parents:
diff changeset
88 (xRows[j ][i ], yRows[j ][i ],
4775b4195b4b code pour la generation de captchas
goldfinger
parents:
diff changeset
89 xRows[j+1][i ], yRows[j+1][i ],
4775b4195b4b code pour la generation de captchas
goldfinger
parents:
diff changeset
90 xRows[j+1][i+1], yRows[j+1][i+1],
4775b4195b4b code pour la generation de captchas
goldfinger
parents:
diff changeset
91 xRows[j ][i+1], yRows[j ][i+1]),
4775b4195b4b code pour la generation de captchas
goldfinger
parents:
diff changeset
92 ))
4775b4195b4b code pour la generation de captchas
goldfinger
parents:
diff changeset
93
4775b4195b4b code pour la generation de captchas
goldfinger
parents:
diff changeset
94 return image.transform(image.size, Image.MESH, mesh, self.filtering)
4775b4195b4b code pour la generation de captchas
goldfinger
parents:
diff changeset
95
4775b4195b4b code pour la generation de captchas
goldfinger
parents:
diff changeset
96
4775b4195b4b code pour la generation de captchas
goldfinger
parents:
diff changeset
97 class SineWarp(WarpBase):
4775b4195b4b code pour la generation de captchas
goldfinger
parents:
diff changeset
98 """Warp the image using a random composition of sine waves"""
4775b4195b4b code pour la generation de captchas
goldfinger
parents:
diff changeset
99
4775b4195b4b code pour la generation de captchas
goldfinger
parents:
diff changeset
100 def __init__(self,
4775b4195b4b code pour la generation de captchas
goldfinger
parents:
diff changeset
101 amplitudeRange = (3, 6.5),
4775b4195b4b code pour la generation de captchas
goldfinger
parents:
diff changeset
102 periodRange = (0.04, 0.1),
4775b4195b4b code pour la generation de captchas
goldfinger
parents:
diff changeset
103 ):
4775b4195b4b code pour la generation de captchas
goldfinger
parents:
diff changeset
104 self.amplitude = random.uniform(*amplitudeRange)
4775b4195b4b code pour la generation de captchas
goldfinger
parents:
diff changeset
105 self.period = random.uniform(*periodRange)
4775b4195b4b code pour la generation de captchas
goldfinger
parents:
diff changeset
106 self.offset = (random.uniform(0, math.pi * 2 / self.period),
4775b4195b4b code pour la generation de captchas
goldfinger
parents:
diff changeset
107 random.uniform(0, math.pi * 2 / self.period))
4775b4195b4b code pour la generation de captchas
goldfinger
parents:
diff changeset
108
4775b4195b4b code pour la generation de captchas
goldfinger
parents:
diff changeset
109 def getTransform(self, image):
4775b4195b4b code pour la generation de captchas
goldfinger
parents:
diff changeset
110 return (lambda x, y,
4775b4195b4b code pour la generation de captchas
goldfinger
parents:
diff changeset
111 a = self.amplitude,
4775b4195b4b code pour la generation de captchas
goldfinger
parents:
diff changeset
112 p = self.period,
4775b4195b4b code pour la generation de captchas
goldfinger
parents:
diff changeset
113 o = self.offset:
4775b4195b4b code pour la generation de captchas
goldfinger
parents:
diff changeset
114 (math.sin( (y+o[0])*p )*a + x,
4775b4195b4b code pour la generation de captchas
goldfinger
parents:
diff changeset
115 math.sin( (x+o[1])*p )*a + y))
4775b4195b4b code pour la generation de captchas
goldfinger
parents:
diff changeset
116
4775b4195b4b code pour la generation de captchas
goldfinger
parents:
diff changeset
117 ### The End ###