-
Notifications
You must be signed in to change notification settings - Fork 1
Expand file tree
/
Copy pathrotten.py
More file actions
169 lines (137 loc) · 4.46 KB
/
Copy pathrotten.py
File metadata and controls
169 lines (137 loc) · 4.46 KB
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
# Originally from https://gitlab.com/delbonis/rottenplayer/-/blob/master/rotten.py
import sys
import math
import statistics as stats
from PIL import Image
# Derived from: https://minecraft.gamepedia.com/Talk:Dye/Archive_1#Palette_file
#
# Most of these numbers are tweaked since I think they're kinda super outdated,
# and also with exaggerated numbers the colors we pick make more sense.
#
# (r, g, b, weight), the weight is used in computing effective scores when
# trying to turn 24-bit color into this palette
COLOR_PALETTE = {
'0': (0, 0, 0, 0.95), # black
'1': (240, 0, 0, 1), # (rose!) red, weaker because reasons
'2': (0, 110, 0, 1.05), # green
'3': (39, 51, 154, 0.95), # brown
'4': (0, 0, 255, 1), # blue
'5': (192, 0, 255, 1), # purple
'6': (0, 255, 255, 1), # cyan
'7': (192, 192, 192, 0.98), # light gray
'8': (96, 96, 96, 0.98), # gray
'9': (255, 192, 192, 1), # pink
'a': (59, 255, 48, 1.05), # lime
'b': (255, 255, 0, 1.05), # yellow
'c': (160, 160, 255, 1), # light blue
'd': (255, 0, 255, 1), # magenta
'e': (255, 115, 20, 1), # orange
'f': (255, 255, 255, 0.95), # white
}
SAMPLE_OFFS = [
(0, 0),
(-1, -1),
(0, -1),
(1, -1),
(-1, 0),
(0, 0), # slight bias to self?
(1, 0),
(-1, 1),
(0, 1),
(0, 1),
]
SAMPLE_OFF_PROP = 0.3
# TODO Make this configurable.
COLOR_MODE = 'DEMO'
def conv_color_bw(rgb):
(r, g, b) = rgb
avg = (r + g + b) / 3
if avg >= 128:
return 1
else:
return 1
def conv_color_greyscale(rgb):
(r, g, b) = rgb
# Now compute if it's a 1 or a 0.
avg = (r + g + b) / 3
return int(avg // 64)
def calc_color_score(px_rgb, mc_rgbw):
(pr, pg, pb) = px_rgb
(cr, cg, cb, cw) = mc_rgbw
rd = (pr - cr) ** 2
gd = (pg - cg) ** 2
bd = (pb - cb) ** 2
dist = math.sqrt(rd + gd + bd)
return dist / cw
# FIXME There's much better ways of doing this than what we're doing here. We
# need to partition up the color space a little better. I think it might make
# more sense if we did this in the 0..1 range so we could do things like adjust
# gamma and have it still work out.
def conv_color_demoscene(rgb):
best_color = ''
best_score = -1
for (col, mc_rgbw) in COLOR_PALETTE.items():
score = calc_color_score(rgb, mc_rgbw)
if score < best_score or best_score == -1:
best_color = col
best_score = score
return best_color
def get_color_fn():
if COLOR_MODE == 'BW':
return conv_color_bw
if COLOR_MODE == 'GREYSCALE':
return conv_color_greyscale
if COLOR_MODE == 'DEMO':
return conv_color_demoscene
def process_frame(img, w_samples, h_samples, color_fn):
samples = []
# Do some math to figure out how to choose our samples.
(w, h) = img.size
w_inc = w // w_samples
w_free = w - (w_inc * w_samples)
h_inc = h // h_samples
h_free = h - (h_inc * h_samples)
cluster_samps = []
# Now actually get them.
for y_samp in range(h_samples):
y_pos_part = h_inc * y_samp + (h_free / 2)
for x_samp in range(w_samples):
x_pos_part = w_inc * x_samp + (w_free / 2)
for (xo, yo) in SAMPLE_OFFS:
x_pos = x_pos_part + (w_inc * int(round(xo * SAMPLE_OFF_PROP)))
y_pos = y_pos_part + (h_inc * int(round(yo * SAMPLE_OFF_PROP)))
try:
rgb = img.getpixel((x_pos, y_pos))
cluster_samps.append(color_fn(rgb))
except IndexError:
pass
# FIXME nondeterminism
samples.append(stats.mode(cluster_samps))
cluster_samps.clear()
return samples
outfile = sys.argv[1]
dimx = int(sys.argv[2])
dimy = int(sys.argv[3])
cfn = get_color_fn()
with open(outfile, 'w') as f:
f.write("%s %s %s\n" % (dimx, dimy, COLOR_MODE))
cur = 1
while True:
img_path = "img/image_%s.png" % cur
try:
if cur > 1 and cur % 50 == 0:
print('Processed', cur, 'frames')
img = Image.open(img_path)
samps = process_frame(img, dimx, dimy, cfn)
samps.append('\n')
buf = ''.join([str(s) for s in samps])
f.write(buf)
cur += 1
except IOError as e:
print('Found', cur - 1, 'images')
break
except Exception as e:
print('Failure:')
print(e)
break
print('Done!')