1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
|
#!/usr/bin/python
import sys
import gtk
import Image, ImageDraw, ImageEnhance, ImageChops, ImageFilter, ImageOps
import pytesser
from misc import *
tesseract_bin = '/usr/local/bin/tesseract'
#for k, v in globals().items():
# print k, "=", v
class graphic():
'''Since we cannot subclass from PIL's image class, we're making a wrapper.'''
FLIP_LEFT_RIGHT = Image.FLIP_LEFT_RIGHT
FLIP_TOP_BOTTOM = Image.FLIP_TOP_BOTTOM
ROTATE_90 = Image.ROTATE_90
ROTATE_180 = Image.ROTATE_180
ROTATE_270 = Image.ROTATE_270
def __init__(self, tiff=''):
if isinstance(tiff, str):
self.im = Image.open(tiff)
elif isinstance(tiff, Image.Image):
self.im = tiff
elif isinstance(tiff, graphic):
self.im = tiff.im
elif isinstance(tiff, unicode):
self.im = Image.open(tiff)
else:
assert False, "Unhandled type in graphic init: %s" % tiff.__class__.__name__
self.w, self.h = self.im.size
self.size = self.im.size
self.mode = self.im.mode
self.data = False
def tesseract(self):
'run tesseract on the image and return the resulting text'
try:
text = pytesser.image_to_string(self.im)
except pytesser.errors.Tesser_General_Exception, value:
print "Couldn't OCR image with tesseract!"
text = ''
return text
def pixbuf(self):
'''Return pixbuf version of this image.
From http://faq.pygtk.org/index.py?req=show&file=faq08.014.htp'''
import StringIO
fd = StringIO.StringIO()
self.im.save(fd, "ppm")
contents = fd.getvalue()
fd.close()
loader = gtk.gdk.PixbufLoader("pnm")
loader.write(contents, len(contents))
pixbuf = loader.get_pixbuf()
loader.close()
return pixbuf
def enhance(self, brightness, contrast):
'''contrast and brightness are the target percentage values of each,
so contrast equals 400 is will enhance the contrast by +300%'''
self.im = self.im.convert("L") #grayscale
self.im = ImageOps.autocontrast(self.im, cutoff=0)
if contrast != 100:
self.im = ImageEnhance.Contrast(self.im).enhance(float(contrast)/100)
if brightness != 100:
self.im = ImageEnhance.Brightness(self.im).enhance(float(brightness)/100)
def whitespace(self, p1, p2, **kwargs):
'''Returns the percentage of the line p1,p2 that is whitespace.
p1 and p2 are arrays of 2 ints each.
skip is an optional kwarg. Set it to n to scan every nth line.'''
if p1[0] > p2[0]:
p_tmp = p1
p1 = p2
p2 = p_tmp
## Calc slope and y offset of line
s = slope(p1,p2)
b = p1[1] - s * p1[0]
## Count pixels on that line
white = black = noise = float(0)
x = p1[0]
if 'skip' in kwargs:
skip = kwargs['skip']
else:
skip = 1
while x < p2[0]:
## Calc y
y = int(s * x + b)
if y < 0: y = 0
if y > self.h-1: y = self.h-1
## Tally pixel (x,y)
color = self.im.getpixel((x,y))
if color <= 256/3:
black = black + 1
elif color >= 256*2/3:
white = white + 1
else:
noise = noise + 1
x = x + skip
if black == 0: black = 1 # divide by zero
return float(white)/black / (self.w / skip) * 100
def whitest_line(self, r1, r2):
'returns whitest line between y=r1 and y=r2'
max_white = 0
w,h = self.im.size
h1 = r1
h2 = r2
for y1 in range(r1, r2):
for y2 in range(r1, r2):
ratio = self.whitespace((0,y1),(w,y2))
if ratio > max_white:
max_white = ratio
h1 = y1
h2 = y2
return h1, h2
def blackest_line(self, r1=0, r2=-1):
'returns blackest line of image between y=r1 and y=r2'
min_whiteness=99999999
w,h = self.im.size
if r2 == -1:
r2 = h
for y1 in range(h):
for y2 in range(h):
r = self.whitespace((0,y1),(w,y2))
if r < min_whiteness:
min_whiteness = r
h1 = y1
h2 = y2
return h1, h2
def trim(self, border):
'Frederik Lundh: http://mail.python.org/pipermail/image-sig/2008-July/005092.html'
bg = Image.new(self.im.mode, self.size, border)
diff = ImageChops.difference(self.im, bg)
bbox = diff.getbbox()
if bbox:
return graphic(self.im.crop(bbox))
else:
# found no content
raise ValueError("cannot trim; image was empty")
def getdata(self, *arg, **kwarg):
self.data = self.im.getdata(*arg, **kwarg)
return self.data
def getpixel(self, *arg, **kwarg):
return self.im.getpixel(*arg, **kwarg)
def crop(self,*arg, **kwarg):
g = graphic(self.im.crop(*arg, **kwarg))
g.getdata()
return g
def show(self,*arg, **kwarg):
self.im.show(*arg, **kwarg)
def save(self, *arg, **kwarg):
self.im.save(*arg, **kwarg)
def thumbnail(self, *arg, **kwarg):
self.im.thumbnail(*arg, **kwarg)
self.w, self.h = self.im.size
def rotate(self,degrees, *args, **kwargs):
'rotate image'
r = self.im.rotate(degrees, *args, **kwargs)
return graphic(r)
## This old code put the rotated image on a light background.
## Ian says it hurst recognition. We should sample the greyish
## background and reconstruct that, perhaps.
n = Image.new(self.mode, self.size, 255)
n = n.rotate(degrees, expand=1)
n = ImageChops.lighter(ImageChops.invert(n), r)
return graphic(n)
def transpose(self, *args, **kwargs):
return graphic(self.im.transpose(*args, **kwargs))
def copy(self):
return graphic(self.im.crop((0,0,self.w,self.h)))
|