arantius (owner)

Revisions

gist: 212688 Download_button fork
public
Public Clone URL: git://gist.github.com/212688.git
Embed All Files: show embed
farsidefix.py #
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
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
#!/usr/bin/env python
 
import Image
import ImageEnhance
import logging
import math
 
edge_buffer=25
black_threshold=96
search_indicator=None
 
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
 
class FarsideFixError(Exception): pass
class FarsideFixFindEdgeError(FarsideFixError): pass
 
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
 
def PixelValue(color):
return sum(color)/3
 
def FindEdge(pixels, start_x, start_y, inc_x, inc_y):
x=start_x
y=start_y
 
for i in xrange(999):
try:
if PixelValue(pixels[x, y]) < black_threshold:
return (x, y)
if search_indicator:
pixels[x, y]=search_indicator
except IndexError:
raise FarsideFixFindEdgeError
x+=inc_x
y+=inc_y
 
raise FarsideFixFindEdgeError
 
def FindCorner(pixels, start_x, start_y, inc_x, inc_y, search_x, search_y):
try:
corner=None
x=start_x
y=start_y
hit=None
last_hit=None
while True:
hit=FindEdge(pixels, x, y, inc_x, inc_y)
 
if last_hit:
moved=( (hit[0]-last_hit[0])*inc_x, (hit[1]-last_hit[1])*inc_y )
if moved[0]<-5 or moved[1]<-5:
# We moved "back" too much, probably hit an errant dot,
# ignore this hit.
hit=last_hit
elif moved[0]>10 or moved[1]>10:
# We jumped "forward", so we just passed the corner.
break
 
last_hit=hit
x+=search_x
y+=search_y
except FarsideFixFindEdgeError:
if not last_hit:
raise
 
return last_hit
 
def PointDistance(a, b):
return math.sqrt( (a[0]-b[0])**2 + (a[1]-b[1])**2 )
 
class Line(object):
def __init__(self, lower_point, upper_point):
self.lower_point=lower_point
self.upper_point=upper_point
self.angle=math.atan2(
(upper_point[1]-lower_point[1]),
(upper_point[0]-lower_point[0])
)
 
def x_at_y(self, y):
width=float(self.lower_point[0]-self.upper_point[0])
height=float(self.lower_point[1]-self.upper_point[1])
rise_rate=float(width)/height
return self.lower_point[0] + ( rise_rate * (y-self.lower_point[1]) )
 
def extend_by(self, distance):
return (
int(self.lower_point[0] - math.cos(self.angle)*distance),
int(self.lower_point[1] - math.sin(self.angle)*distance))
 
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
 
def FixImage(filename_in):
global search_indicator
 
try:
image=Image.open(filename_in)
pixels=image.load()
(width, height)=image.size
 
# Chop off the non-comic space on the right.
top_right=FindCorner(pixels, width/2, 0, 1, 1, 1, 0)
right=top_right[0]+edge_buffer*3
image=image.crop( (0, 0, right, height) )
 
pixels=image.load()
(width, height)=image.size
 
# Find the other edges of the comic.
left=width
for y in xrange(0, height, height/50):
try:
point=FindEdge(pixels, 0, y, 1, 0)
if point[0]<left: left=point[0]
except FarsideFixError:
pass
top=height
for x in xrange(left, width, width/50):
try:
point=FindEdge(pixels, x, 0, 0, 1)
if point[1]<top: top=point[1]
except FarsideFixError:
pass
bottom=0
for x in xrange(left, width, width/50):
try:
point=FindEdge(pixels, x, height-2, 0, -1)
if point[1]>bottom: bottom=point[1]
except FarsideFixError:
pass
 
# Add some buffer space to these edges.
left=max(0, left-edge_buffer)
top=max(0, top-edge_buffer)
bottom=min(height-2, bottom+edge_buffer)
 
# Crop off the chaff.
image=image.crop( (left, top, width, bottom) )
 
pixels=image.load()
(width, height)=image.size
 
# Paste this cropped image into a blank one (guaranteed border space).
matte=Image.new(
"RGB",
(width+edge_buffer*2, height+edge_buffer*2),
(255, 255, 255))
matte.paste(image, (edge_buffer, edge_buffer))
image=matte
 
pixels=image.load()
(width, height)=image.size
 
# Find the corners of the box.
top_left=FindCorner(pixels, width/3, 0, -1, 1, -1, 0)
top_right=FindCorner(pixels, width*2/3, 0, 1, 1, 1, 0)
bottom_left=FindCorner(pixels, 0, height/2, 1, 1, 0, 1)
bottom_right=FindCorner(pixels, width-1, height*2/3, -1, 1, 0, 1)
 
# Add a buffer from these found edges, within the image.
top_left=(top_left[0]-edge_buffer, top_left[1]-edge_buffer)
top_right=(top_right[0]+edge_buffer, top_right[1]-edge_buffer)
bottom_left=(bottom_left[0]-edge_buffer, bottom_left[1]+edge_buffer)
bottom_right=(bottom_right[0]+edge_buffer, bottom_right[1]+edge_buffer)
 
# Extend them down to include the caption.
left_line=Line(bottom_left, top_left)
right_line=Line(bottom_right, top_right)
 
# Find which side is lower, extend that side's line down to the bottom,
# then extend the other side by the same distance.
if bottom_right[1]>bottom_left[1]:
intersect=right_line.x_at_y(height-2)
bottom_right_extra=(intersect, height-2)
distance=PointDistance(bottom_right, bottom_right_extra)
bottom_left_extra=left_line.extend_by(distance)
else:
intersect=left_line.x_at_y(height-2)
bottom_left_extra=(intersect, height-2)
distance=PointDistance(bottom_left, bottom_left_extra)
bottom_right_extra=right_line.extend_by(distance)
 
# Transform these corner points into a straight rectangle.
new_size=(int(PointDistance(top_left, top_right)),
int(PointDistance(top_left, bottom_left_extra)))
matte=Image.new("RGB", new_size, (255, 255, 255))
image=image.convert("RGBA").transform(
new_size,
Image.QUAD,
top_left+bottom_left_extra+bottom_right_extra+top_right,
Image.BICUBIC)
matte.paste(image, image)
image=matte
 
pixels=image.load()
(width, height)=image.size
 
# Find the real bottom. Many samples, because it is likely sparse text.
bottom=0
for x in xrange(100, width, width/30):
try:
(unused, bottom_tmp)=FindEdge(pixels, x, height-2, 0, -1)
bottom=max(bottom, bottom_tmp)
except FarsideFixFindEdgeError:
pass
bottom=min(height-1, bottom+edge_buffer)
image=image.crop((0, 0, width-1, bottom))
except FarsideFixError, e:
return (False, e)
 
image.load()
return (True, image)
 
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
 
if __name__=="__main__":
from glob import glob
import os
import sys
 
if len(sys.argv)>1:
filenames=sys.argv[1:]
else:
filenames=glob('in/*.jpg')
filenames.sort()
 
for filename_in in filenames:
filename_out='out'+filename_in[2:]
 
if os.path.exists(filename_out):
continue
 
print "Processing %s ..." % filename_in,
 
result=FixImage(filename_in)
if result[0]:
result[1].save(filename_out)
print "OK!"
else:
print "Fail! ", result[1]