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
|
local function color_dist(c1,c2)
local total = 0
for i=1,3 do total = total + (c1[i]-c2[i])^2 end
return total
end
local function closest_palette_color(R,c)
local closest = nil
local closest_dist = 99999999
for i=0,15 do
local pc = {R.getPaletteColor(2^i)}
local dist = color_dist(pc,c)
if dist < closest_dist then
closest = 2^i
closest_dist = dist
end
end
return closest
end
local function average_color(pxlist)
local count = #pxlist
if count == 0 then return {0,0,0} end
local tr,tg,tb = 0,0,0
for _,px in ipairs(pxlist) do
tr = tr + px[1]
tg = tg + px[2]
tb = tb + px[3]
end
return {tr/count,tg/count,tb/count}
end
local function sortby_r(pxlist) table.sort(pxlist,function(a,b) return a[1]<b[1] end) end
local function sortby_g(pxlist) table.sort(pxlist,function(a,b) return a[2]<b[2] end) end
local function sortby_b(pxlist) table.sort(pxlist,function(a,b) return a[3]<b[3] end) end
local function median_cut(pxlist,remaining)
remaining = remaining or 4
if remaining <= 0 then
return {average_color(pxlist)}
end
local maxr,maxg,maxb = -1,-1,-1
local minr,ming,minb = 999,999,999
local max,min = math.max,math.min
for _,px in ipairs(pxlist) do
maxr = max(maxr,px[1])
maxg = max(maxg,px[2])
maxb = max(maxb,px[3])
minr = min(minr,px[1])
ming = min(ming,px[2])
minb = min(minb,px[3])
end
local ranger,rangeg,rangeb = maxr-minr,maxg-ming,maxb-minb
if ranger > rangeg then
if ranger > rangeb then
-- red
sortby_r(pxlist)
else
-- blue
sortby_b(pxlist)
end
else
if rangeg > rangeb then
-- green
sortby_g(pxlist)
else
-- blue
sortby_b(pxlist)
end
end
local count = #pxlist
local hcount = math.floor(count/2)
local lhalf,uhalf = {},{}
for i=1,hcount do
lhalf[i] = pxlist[i]
end
for i=hcount+1,count do
uhalf[i-hcount] = pxlist[i]
end
local lcols = median_cut(lhalf,remaining-1)
local ucols = median_cut(uhalf,remaining-1)
for i=1,#ucols do table.insert(lcols,ucols[i]) end
return lcols
end
local function reset_palette(R)
for i=0,15 do
local cx = 2^i
R.setPaletteColor(cx,term.nativePaletteColor(cx))
end
end
local function improve_palette(R,img,w,h,imgx,imgy)
local pxlist = {}
local idx=1
for px=imgx,imgx+w-1 do
for py=imgy,imgy+h-1 do
pxlist[idx] = img[py][px]
idx = idx + 1
end
end
local palette = median_cut(pxlist)
assert(#palette==16,#palette.." doesn't equal 16")
for i=0,15 do
local pc = palette[i+1]
--print(table.unpack(pc))
R.setPaletteColor(2^i,table.unpack(pc))
end
end
return {
color_dist=color_dist,
closest_palette_color=closest_palette_color,
average_color=average_color,
median_cut=median_cut,
reset_palette=reset_palette,
improve_palette=improve_palette,
}
|