wip
This commit is contained in:
parent
f5c8d219e8
commit
1d3712be5c
1 changed files with 14 additions and 29 deletions
|
@ -134,13 +134,23 @@ class RGB {
|
||||||
this.b * this.b;
|
this.b * this.b;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
sum() {
|
||||||
|
return this.r + this.g + this.b;
|
||||||
|
}
|
||||||
|
|
||||||
|
lumaScale() {
|
||||||
|
return new RGB(
|
||||||
|
this.r * 0.299,
|
||||||
|
this.g * 0.586,
|
||||||
|
this.b * 0.114
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
luma() {
|
luma() {
|
||||||
return this.r * 0.299 + this.g * 0.587 + this.b * 0.114;
|
return this.lumaScale().sum();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const maxDist = (new RGB(255, 255, 255)).magnitude();
|
|
||||||
|
|
||||||
// snarfed from https://lospec.com/palette-list/atari-8-bit-family-gtia
|
// snarfed from https://lospec.com/palette-list/atari-8-bit-family-gtia
|
||||||
// which was calculated with Retrospecs App's Atari 800 emulator
|
// which was calculated with Retrospecs App's Atari 800 emulator
|
||||||
let atariRGB = [
|
let atariRGB = [
|
||||||
|
@ -414,19 +424,6 @@ let atariRGB = [
|
||||||
* @returns {{output: number[], palette: number[], error: RGB[]}}
|
* @returns {{output: number[], palette: number[], error: RGB[]}}
|
||||||
*/
|
*/
|
||||||
function decimate(input, palette, n) {
|
function decimate(input, palette, n) {
|
||||||
// to brute-force, the possible palettes are:
|
|
||||||
// 255 * 254 * 253 = 16,386,810
|
|
||||||
//
|
|
||||||
// we could brute force it but that's a lot :D
|
|
||||||
// but can do some bisection :D
|
|
||||||
//
|
|
||||||
// need a fitness metric.
|
|
||||||
// each pixel in the dithered line gives a distance
|
|
||||||
// sum/average them? median? maximum?
|
|
||||||
// summing evens out the ups/downs from dithering
|
|
||||||
// but doesn't distinguish between two close and two distant options
|
|
||||||
// consider median, 90th-percentile, and max of abs(distance)
|
|
||||||
// consider doing the distance for each channel?
|
|
||||||
|
|
||||||
let width = input.length;
|
let width = input.length;
|
||||||
|
|
||||||
|
@ -440,7 +437,6 @@ function decimate(input, palette, n) {
|
||||||
|
|
||||||
// Apply dithering with given palette and collect color usage stats
|
// Apply dithering with given palette and collect color usage stats
|
||||||
let dither = (palette) => {
|
let dither = (palette) => {
|
||||||
let fitness = zeroes(width);
|
|
||||||
let error = {
|
let error = {
|
||||||
cur: [],
|
cur: [],
|
||||||
next: [],
|
next: [],
|
||||||
|
@ -467,7 +463,7 @@ function decimate(input, palette, n) {
|
||||||
|
|
||||||
for (let i = 0; i < palette.length; i++) {
|
for (let i = 0; i < palette.length; i++) {
|
||||||
let diff = rgb.difference(atariRGB[palette[i]]);
|
let diff = rgb.difference(atariRGB[palette[i]]);
|
||||||
let dist = diff.magnitude2();
|
let dist = diff.magnitude();
|
||||||
if (dist < shortest) {
|
if (dist < shortest) {
|
||||||
nextError = diff;
|
nextError = diff;
|
||||||
shortest = dist;
|
shortest = dist;
|
||||||
|
@ -484,21 +480,10 @@ function decimate(input, palette, n) {
|
||||||
error.next[x - 1]?.inc(share(3));
|
error.next[x - 1]?.inc(share(3));
|
||||||
error.next[x ]?.inc(share(5));
|
error.next[x ]?.inc(share(5));
|
||||||
error.next[x + 1]?.inc(share(1));
|
error.next[x + 1]?.inc(share(1));
|
||||||
|
|
||||||
let mag = nextError.magnitude();
|
|
||||||
fitness[x] = maxDist / mag;
|
|
||||||
// 442 is the 3d distance across the rgb cube
|
|
||||||
//fitness[x] = 442 - (nextError.magnitude());
|
|
||||||
//fitness[x] = 442 / (442 - nextError.magnitude());
|
|
||||||
fitness[x] = 255 / (256 - Math.max(0, nextError.r, nextError.g, nextError.b));
|
|
||||||
|
|
||||||
let mag2 = nextError.magnitude2();
|
|
||||||
distance2 += mag2;
|
|
||||||
}
|
}
|
||||||
return {
|
return {
|
||||||
output,
|
output,
|
||||||
palette,
|
palette,
|
||||||
fitness,
|
|
||||||
distance2,
|
distance2,
|
||||||
popularity,
|
popularity,
|
||||||
error: error.next
|
error: error.next
|
||||||
|
|
Loading…
Reference in a new issue