From 04e59ad2c819ee7213b0ae2efb2d14ddca827cd0 Mon Sep 17 00:00:00 2001 From: boatbomber Date: Fri, 12 Nov 2021 02:02:30 -0500 Subject: [PATCH] Dynamic lossy combined with CIE76 deltaE --- src/GuiPool.lua | 2 +- src/Util.lua | 88 ++++++++++++++++++++++++++++++++++++++++++++----- src/init.lua | 11 +++---- 3 files changed, 86 insertions(+), 15 deletions(-) diff --git a/src/GuiPool.lua b/src/GuiPool.lua index 4408295..237eb17 100644 --- a/src/GuiPool.lua +++ b/src/GuiPool.lua @@ -1,6 +1,6 @@ local module = {} -local OFF_SCREEN = UDim2.fromOffset(0,3000) +local OFF_SCREEN = UDim2.fromOffset(0, 3000) function module.new(original: GuiObject, initSize: number?) local Pool = { diff --git a/src/Util.lua b/src/Util.lua index 8c036e5..f787430 100644 --- a/src/Util.lua +++ b/src/Util.lua @@ -1,14 +1,86 @@ local Util = {} +-- D65/2° +local Xr = 95.047 +local Yr = 100.0 +local Zr = 108.883 +local labCache = {} +function Util.RGBtoLAB(c) + if labCache[c] then + return table.unpack(labCache[c]) + end + + local X, Y, Z + do -- Convert RGB to XYZ + local r, g, b = c.R, c.G, c.B + + if r > 0.04045 then + r = ((r + 0.055) / 1.055) ^ 2.4 + else + r /= 12.92 + end + + if g > 0.04045 then + g = ((g + 0.055) / 1.055) ^ 2.4 + else + g /= 12.92 + end + + if b > 0.04045 then + b = ((b + 0.055) / 1.055) ^ 2.4 + else + b /= 12.92 + end + + r *= 100 + g *= 100 + b *= 100 + + X = 0.4124 * r + 0.3576 * g + 0.1805 * b + Y = 0.2126 * r + 0.7152 * g + 0.0722 * b + Z = 0.0193 * r + 0.1192 * g + 0.9505 * b + end + + local l, a, b + do -- Convert XYZ to LAB + local xr, yr, zr = X / Xr, Y / Yr, Z / Zr + + if xr > 0.008856 then + xr = xr ^ (1 / 3) + else + xr = ((7.787 * xr) + 16 / 116.0) + end + + if yr > 0.008856 then + yr = yr ^ (1 / 3) + else + yr = ((7.787 * yr) + 16 / 116.0) + end + + if zr > 0.008856 then + zr = zr ^ (1 / 3) + else + zr = ((7.787 * zr) + 16 / 116.0) + end + + l, a, b = (116 * yr) - 16, 500 * (xr - yr), 200 * (yr - zr) + end + + labCache[c] = { l, a, b } + + return l, a, b +end + function Util.DeltaRGB(a: Color3, b: Color3) - local r1, g1, b1 = a.R,a.G,a.B - local r2, g2, b2 = b.R,b.G,b.B - local drp2 = (r1 - r2)^2 - local dgp2 = (g1 - g2)^2 - local dbp2 = (b1 - b2)^2 - local t = (r1 + r2) / 2 - - return math.sqrt(2 * drp2 + 4 * dgp2 + 3 * dbp2 + t * (drp2 - dbp2) / 256) / 3 + local l1, a1, b1 = Util.RGBtoLAB(a) + local l2, a2, b2 = Util.RGBtoLAB(b) + + local delta = math.sqrt((l2 - l1) ^ 2 + (a2 - a1) ^ 2 + (b2 - b1) ^ 2) + if delta < 30 then + return 0.03 + else + return delta / 200 + end end return Util diff --git a/src/init.lua b/src/init.lua index a2c184e..ac4735e 100644 --- a/src/init.lua +++ b/src/init.lua @@ -3,8 +3,6 @@ local module = {} local GuiPool = require(script.GuiPool) local Util = require(script.Util) -local LOSSY = 0.03 -- Use fewer Frames at cost of image accuracy (Some values get funky, tweak carefully) - local EMPTY_TABLE = {} function module.new(ResX: number, ResY: number) @@ -15,6 +13,8 @@ function module.new(ResX: number, ResY: number) } local invX, invY = 1 / ResX, 1 / ResY + local diff = 0.015 + local lossy = math.clamp(diff + ResY / 250, 0.02, 1) -- Generate initial grid of color data local Grid = table.create(ResX) @@ -73,7 +73,7 @@ function module.new(ResX: number, ResY: number) Frame.Parent = Container if Canvas._ColumnFrames[x] == nil then - Canvas._ColumnFrames[x] = {Frame} + Canvas._ColumnFrames[x] = { Frame } else table.insert(Canvas._ColumnFrames[x], Frame) end @@ -114,7 +114,6 @@ function module.new(ResX: number, ResY: number) self._ActiveFrames = 0 table.clear(self._ColumnFrames) end - end function Canvas:Render() @@ -132,10 +131,10 @@ function module.new(ResX: number, ResY: number) for y, Color in ipairs(Column) do pixelCount += 1 local delta = Util.DeltaRGB(lastColor, Color) - if delta > 0.015 then + if delta > diff then local offset = y - pixelStart - 1 - if delta > 0.015+LOSSY then + if delta > lossy then table.insert(Compressed, { p = offset - 0.02, c = lastColor }) end table.insert(Compressed, { p = offset, c = Color })