summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorache <ache@ache.one>2025-05-25 20:08:36 +0200
committerache <ache@ache.one>2025-05-25 20:08:36 +0200
commit5bdc32f2574c8d71f901cd731e51ebb2fb76804d (patch)
treeb82c8f21bc2c58a6b99c3ca51e46c51ddbff7b89
parentImplement bayer matrix dithering (diff)
Implement scolorq dithering
-rw-r--r--src/kernel.rs1287
-rw-r--r--src/lib.rs1617
-rw-r--r--src/main.rs39
3 files changed, 2933 insertions, 10 deletions
diff --git a/src/kernel.rs b/src/kernel.rs
index f1cb78d..73c950e 100644
--- a/src/kernel.rs
+++ b/src/kernel.rs
@@ -923,3 +923,1290 @@ pub const SOBEL_KERNEL: [WeightedNeighbor; 4] = [
weight: 0.25,
},
];
+/**
+* Ostromoukhov kernels
+*
+* https://perso.liris.cnrs.fr/victor.ostromoukhov/publications/pdf/SIGGRAPH01_varcoeffED.pdf
+*/
+pub const OSTROMOUKHOV_KERNELS: [[WeightedNeighborInteger; 3]; 256] = [
+ [
+ WeightedNeighborInteger { dx: 1, dy: 0, weight: 13, },
+ WeightedNeighborInteger { dx: -1, dy: 1, weight: 0, },
+ WeightedNeighborInteger { dx: 0, dy: 1, weight: 5, },
+ ],
+ [
+ WeightedNeighborInteger { dx: 1, dy: 0, weight: 13, },
+ WeightedNeighborInteger { dx: -1, dy: 1, weight: 0, },
+ WeightedNeighborInteger { dx: 0, dy: 1, weight: 5, },
+ ],
+ [
+ WeightedNeighborInteger { dx: 1, dy: 0, weight: 21, },
+ WeightedNeighborInteger { dx: -1, dy: 1, weight: 0, },
+ WeightedNeighborInteger { dx: 0, dy: 1, weight: 10, },
+ ],
+ [
+ WeightedNeighborInteger { dx: 1, dy: 0, weight: 7, },
+ WeightedNeighborInteger { dx: -1, dy: 1, weight: 0, },
+ WeightedNeighborInteger { dx: 0, dy: 1, weight: 4, },
+ ],
+ [
+ WeightedNeighborInteger { dx: 1, dy: 0, weight: 8, },
+ WeightedNeighborInteger { dx: -1, dy: 1, weight: 0, },
+ WeightedNeighborInteger { dx: 0, dy: 1, weight: 5, },
+ ],
+ [
+ WeightedNeighborInteger { dx: 1, dy: 0, weight: 47, },
+ WeightedNeighborInteger { dx: -1, dy: 1, weight: 3, },
+ WeightedNeighborInteger { dx: 0, dy: 1, weight: 28, },
+ ],
+ [
+ WeightedNeighborInteger { dx: 1, dy: 0, weight: 23, },
+ WeightedNeighborInteger { dx: -1, dy: 1, weight: 3, },
+ WeightedNeighborInteger { dx: 0, dy: 1, weight: 13, },
+ ],
+ [
+ WeightedNeighborInteger { dx: 1, dy: 0, weight: 15, },
+ WeightedNeighborInteger { dx: -1, dy: 1, weight: 3, },
+ WeightedNeighborInteger { dx: 0, dy: 1, weight: 8, },
+ ],
+ [
+ WeightedNeighborInteger { dx: 1, dy: 0, weight: 22, },
+ WeightedNeighborInteger { dx: -1, dy: 1, weight: 6, },
+ WeightedNeighborInteger { dx: 0, dy: 1, weight: 11, },
+ ],
+ [
+ WeightedNeighborInteger { dx: 1, dy: 0, weight: 43, },
+ WeightedNeighborInteger { dx: -1, dy: 1, weight: 15, },
+ WeightedNeighborInteger { dx: 0, dy: 1, weight: 20, },
+ ],
+ [
+ WeightedNeighborInteger { dx: 1, dy: 0, weight: 7, },
+ WeightedNeighborInteger { dx: -1, dy: 1, weight: 3, },
+ WeightedNeighborInteger { dx: 0, dy: 1, weight: 3, },
+ ],
+ [
+ WeightedNeighborInteger { dx: 1, dy: 0, weight: 501, },
+ WeightedNeighborInteger { dx: -1, dy: 1, weight: 224, },
+ WeightedNeighborInteger { dx: 0, dy: 1, weight: 211, },
+ ],
+ [
+ WeightedNeighborInteger { dx: 1, dy: 0, weight: 249, },
+ WeightedNeighborInteger { dx: -1, dy: 1, weight: 116, },
+ WeightedNeighborInteger { dx: 0, dy: 1, weight: 103, },
+ ],
+ [
+ WeightedNeighborInteger { dx: 1, dy: 0, weight: 165, },
+ WeightedNeighborInteger { dx: -1, dy: 1, weight: 80, },
+ WeightedNeighborInteger { dx: 0, dy: 1, weight: 67, },
+ ],
+ [
+ WeightedNeighborInteger { dx: 1, dy: 0, weight: 123, },
+ WeightedNeighborInteger { dx: -1, dy: 1, weight: 62, },
+ WeightedNeighborInteger { dx: 0, dy: 1, weight: 49, },
+ ],
+ [
+ WeightedNeighborInteger { dx: 1, dy: 0, weight: 489, },
+ WeightedNeighborInteger { dx: -1, dy: 1, weight: 256, },
+ WeightedNeighborInteger { dx: 0, dy: 1, weight: 191, },
+ ],
+ [
+ WeightedNeighborInteger { dx: 1, dy: 0, weight: 81, },
+ WeightedNeighborInteger { dx: -1, dy: 1, weight: 44, },
+ WeightedNeighborInteger { dx: 0, dy: 1, weight: 31, },
+ ],
+ [
+ WeightedNeighborInteger { dx: 1, dy: 0, weight: 483, },
+ WeightedNeighborInteger { dx: -1, dy: 1, weight: 272, },
+ WeightedNeighborInteger { dx: 0, dy: 1, weight: 181, },
+ ],
+ [
+ WeightedNeighborInteger { dx: 1, dy: 0, weight: 60, },
+ WeightedNeighborInteger { dx: -1, dy: 1, weight: 35, },
+ WeightedNeighborInteger { dx: 0, dy: 1, weight: 22, },
+ ],
+ [
+ WeightedNeighborInteger { dx: 1, dy: 0, weight: 53, },
+ WeightedNeighborInteger { dx: -1, dy: 1, weight: 32, },
+ WeightedNeighborInteger { dx: 0, dy: 1, weight: 19, },
+ ],
+ [
+ WeightedNeighborInteger { dx: 1, dy: 0, weight: 237, },
+ WeightedNeighborInteger { dx: -1, dy: 1, weight: 148, },
+ WeightedNeighborInteger { dx: 0, dy: 1, weight: 83, },
+ ],
+ [
+ WeightedNeighborInteger { dx: 1, dy: 0, weight: 471, },
+ WeightedNeighborInteger { dx: -1, dy: 1, weight: 304, },
+ WeightedNeighborInteger { dx: 0, dy: 1, weight: 161, },
+ ],
+ [
+ WeightedNeighborInteger { dx: 1, dy: 0, weight: 3, },
+ WeightedNeighborInteger { dx: -1, dy: 1, weight: 2, },
+ WeightedNeighborInteger { dx: 0, dy: 1, weight: 1, },
+ ],
+ [
+ WeightedNeighborInteger { dx: 1, dy: 0, weight: 459, },
+ WeightedNeighborInteger { dx: -1, dy: 1, weight: 304, },
+ WeightedNeighborInteger { dx: 0, dy: 1, weight: 161, },
+ ],
+ [
+ WeightedNeighborInteger { dx: 1, dy: 0, weight: 38, },
+ WeightedNeighborInteger { dx: -1, dy: 1, weight: 25, },
+ WeightedNeighborInteger { dx: 0, dy: 1, weight: 14, },
+ ],
+ [
+ WeightedNeighborInteger { dx: 1, dy: 0, weight: 453, },
+ WeightedNeighborInteger { dx: -1, dy: 1, weight: 296, },
+ WeightedNeighborInteger { dx: 0, dy: 1, weight: 175, },
+ ],
+ [
+ WeightedNeighborInteger { dx: 1, dy: 0, weight: 225, },
+ WeightedNeighborInteger { dx: -1, dy: 1, weight: 146, },
+ WeightedNeighborInteger { dx: 0, dy: 1, weight: 91, },
+ ],
+ [
+ WeightedNeighborInteger { dx: 1, dy: 0, weight: 149, },
+ WeightedNeighborInteger { dx: -1, dy: 1, weight: 96, },
+ WeightedNeighborInteger { dx: 0, dy: 1, weight: 63, },
+ ],
+ [
+ WeightedNeighborInteger { dx: 1, dy: 0, weight: 111, },
+ WeightedNeighborInteger { dx: -1, dy: 1, weight: 71, },
+ WeightedNeighborInteger { dx: 0, dy: 1, weight: 49, },
+ ],
+ [
+ WeightedNeighborInteger { dx: 1, dy: 0, weight: 63, },
+ WeightedNeighborInteger { dx: -1, dy: 1, weight: 40, },
+ WeightedNeighborInteger { dx: 0, dy: 1, weight: 29, },
+ ],
+ [
+ WeightedNeighborInteger { dx: 1, dy: 0, weight: 73, },
+ WeightedNeighborInteger { dx: -1, dy: 1, weight: 46, },
+ WeightedNeighborInteger { dx: 0, dy: 1, weight: 35, },
+ ],
+ [
+ WeightedNeighborInteger { dx: 1, dy: 0, weight: 435, },
+ WeightedNeighborInteger { dx: -1, dy: 1, weight: 272, },
+ WeightedNeighborInteger { dx: 0, dy: 1, weight: 217, },
+ ],
+ [
+ WeightedNeighborInteger { dx: 1, dy: 0, weight: 108, },
+ WeightedNeighborInteger { dx: -1, dy: 1, weight: 67, },
+ WeightedNeighborInteger { dx: 0, dy: 1, weight: 56, },
+ ],
+ [
+ WeightedNeighborInteger { dx: 1, dy: 0, weight: 13, },
+ WeightedNeighborInteger { dx: -1, dy: 1, weight: 8, },
+ WeightedNeighborInteger { dx: 0, dy: 1, weight: 7, },
+ ],
+ [
+ WeightedNeighborInteger { dx: 1, dy: 0, weight: 213, },
+ WeightedNeighborInteger { dx: -1, dy: 1, weight: 130, },
+ WeightedNeighborInteger { dx: 0, dy: 1, weight: 119, },
+ ],
+ [
+ WeightedNeighborInteger { dx: 1, dy: 0, weight: 423, },
+ WeightedNeighborInteger { dx: -1, dy: 1, weight: 256, },
+ WeightedNeighborInteger { dx: 0, dy: 1, weight: 245, },
+ ],
+ [
+ WeightedNeighborInteger { dx: 1, dy: 0, weight: 5, },
+ WeightedNeighborInteger { dx: -1, dy: 1, weight: 3, },
+ WeightedNeighborInteger { dx: 0, dy: 1, weight: 3, },
+ ],
+ [
+ WeightedNeighborInteger { dx: 1, dy: 0, weight: 281, },
+ WeightedNeighborInteger { dx: -1, dy: 1, weight: 173, },
+ WeightedNeighborInteger { dx: 0, dy: 1, weight: 162, },
+ ],
+ [
+ WeightedNeighborInteger { dx: 1, dy: 0, weight: 141, },
+ WeightedNeighborInteger { dx: -1, dy: 1, weight: 89, },
+ WeightedNeighborInteger { dx: 0, dy: 1, weight: 78, },
+ ],
+ [
+ WeightedNeighborInteger { dx: 1, dy: 0, weight: 283, },
+ WeightedNeighborInteger { dx: -1, dy: 1, weight: 183, },
+ WeightedNeighborInteger { dx: 0, dy: 1, weight: 150, },
+ ],
+ [
+ WeightedNeighborInteger { dx: 1, dy: 0, weight: 71, },
+ WeightedNeighborInteger { dx: -1, dy: 1, weight: 47, },
+ WeightedNeighborInteger { dx: 0, dy: 1, weight: 36, },
+ ],
+ [
+ WeightedNeighborInteger { dx: 1, dy: 0, weight: 285, },
+ WeightedNeighborInteger { dx: -1, dy: 1, weight: 193, },
+ WeightedNeighborInteger { dx: 0, dy: 1, weight: 138, },
+ ],
+ [
+ WeightedNeighborInteger { dx: 1, dy: 0, weight: 13, },
+ WeightedNeighborInteger { dx: -1, dy: 1, weight: 9, },
+ WeightedNeighborInteger { dx: 0, dy: 1, weight: 6, },
+ ],
+ [
+ WeightedNeighborInteger { dx: 1, dy: 0, weight: 41, },
+ WeightedNeighborInteger { dx: -1, dy: 1, weight: 29, },
+ WeightedNeighborInteger { dx: 0, dy: 1, weight: 18, },
+ ],
+ [
+ WeightedNeighborInteger { dx: 1, dy: 0, weight: 36, },
+ WeightedNeighborInteger { dx: -1, dy: 1, weight: 26, },
+ WeightedNeighborInteger { dx: 0, dy: 1, weight: 15, },
+ ],
+ [
+ WeightedNeighborInteger { dx: 1, dy: 0, weight: 289, },
+ WeightedNeighborInteger { dx: -1, dy: 1, weight: 213, },
+ WeightedNeighborInteger { dx: 0, dy: 1, weight: 114, },
+ ],
+ [
+ WeightedNeighborInteger { dx: 1, dy: 0, weight: 145, },
+ WeightedNeighborInteger { dx: -1, dy: 1, weight: 109, },
+ WeightedNeighborInteger { dx: 0, dy: 1, weight: 54, },
+ ],
+ [
+ WeightedNeighborInteger { dx: 1, dy: 0, weight: 291, },
+ WeightedNeighborInteger { dx: -1, dy: 1, weight: 223, },
+ WeightedNeighborInteger { dx: 0, dy: 1, weight: 102, },
+ ],
+ [
+ WeightedNeighborInteger { dx: 1, dy: 0, weight: 73, },
+ WeightedNeighborInteger { dx: -1, dy: 1, weight: 57, },
+ WeightedNeighborInteger { dx: 0, dy: 1, weight: 24, },
+ ],
+ [
+ WeightedNeighborInteger { dx: 1, dy: 0, weight: 293, },
+ WeightedNeighborInteger { dx: -1, dy: 1, weight: 233, },
+ WeightedNeighborInteger { dx: 0, dy: 1, weight: 90, },
+ ],
+ [
+ WeightedNeighborInteger { dx: 1, dy: 0, weight: 21, },
+ WeightedNeighborInteger { dx: -1, dy: 1, weight: 17, },
+ WeightedNeighborInteger { dx: 0, dy: 1, weight: 6, },
+ ],
+ [
+ WeightedNeighborInteger { dx: 1, dy: 0, weight: 295, },
+ WeightedNeighborInteger { dx: -1, dy: 1, weight: 243, },
+ WeightedNeighborInteger { dx: 0, dy: 1, weight: 78, },
+ ],
+ [
+ WeightedNeighborInteger { dx: 1, dy: 0, weight: 37, },
+ WeightedNeighborInteger { dx: -1, dy: 1, weight: 31, },
+ WeightedNeighborInteger { dx: 0, dy: 1, weight: 9, },
+ ],
+ [
+ WeightedNeighborInteger { dx: 1, dy: 0, weight: 27, },
+ WeightedNeighborInteger { dx: -1, dy: 1, weight: 23, },
+ WeightedNeighborInteger { dx: 0, dy: 1, weight: 6, },
+ ],
+ [
+ WeightedNeighborInteger { dx: 1, dy: 0, weight: 149, },
+ WeightedNeighborInteger { dx: -1, dy: 1, weight: 129, },
+ WeightedNeighborInteger { dx: 0, dy: 1, weight: 30, },
+ ],
+ [
+ WeightedNeighborInteger { dx: 1, dy: 0, weight: 299, },
+ WeightedNeighborInteger { dx: -1, dy: 1, weight: 263, },
+ WeightedNeighborInteger { dx: 0, dy: 1, weight: 54, },
+ ],
+ [
+ WeightedNeighborInteger { dx: 1, dy: 0, weight: 75, },
+ WeightedNeighborInteger { dx: -1, dy: 1, weight: 67, },
+ WeightedNeighborInteger { dx: 0, dy: 1, weight: 12, },
+ ],
+ [
+ WeightedNeighborInteger { dx: 1, dy: 0, weight: 43, },
+ WeightedNeighborInteger { dx: -1, dy: 1, weight: 39, },
+ WeightedNeighborInteger { dx: 0, dy: 1, weight: 6, },
+ ],
+ [
+ WeightedNeighborInteger { dx: 1, dy: 0, weight: 151, },
+ WeightedNeighborInteger { dx: -1, dy: 1, weight: 139, },
+ WeightedNeighborInteger { dx: 0, dy: 1, weight: 18, },
+ ],
+ [
+ WeightedNeighborInteger { dx: 1, dy: 0, weight: 303, },
+ WeightedNeighborInteger { dx: -1, dy: 1, weight: 283, },
+ WeightedNeighborInteger { dx: 0, dy: 1, weight: 30, },
+ ],
+ [
+ WeightedNeighborInteger { dx: 1, dy: 0, weight: 38, },
+ WeightedNeighborInteger { dx: -1, dy: 1, weight: 36, },
+ WeightedNeighborInteger { dx: 0, dy: 1, weight: 3, },
+ ],
+ [
+ WeightedNeighborInteger { dx: 1, dy: 0, weight: 305, },
+ WeightedNeighborInteger { dx: -1, dy: 1, weight: 293, },
+ WeightedNeighborInteger { dx: 0, dy: 1, weight: 18, },
+ ],
+ [
+ WeightedNeighborInteger { dx: 1, dy: 0, weight: 153, },
+ WeightedNeighborInteger { dx: -1, dy: 1, weight: 149, },
+ WeightedNeighborInteger { dx: 0, dy: 1, weight: 6, },
+ ],
+ [
+ WeightedNeighborInteger { dx: 1, dy: 0, weight: 307, },
+ WeightedNeighborInteger { dx: -1, dy: 1, weight: 303, },
+ WeightedNeighborInteger { dx: 0, dy: 1, weight: 6, },
+ ],
+ [
+ WeightedNeighborInteger { dx: 1, dy: 0, weight: 1, },
+ WeightedNeighborInteger { dx: -1, dy: 1, weight: 1, },
+ WeightedNeighborInteger { dx: 0, dy: 1, weight: 0, },
+ ],
+ [
+ WeightedNeighborInteger { dx: 1, dy: 0, weight: 101, },
+ WeightedNeighborInteger { dx: -1, dy: 1, weight: 105, },
+ WeightedNeighborInteger { dx: 0, dy: 1, weight: 2, },
+ ],
+ [
+ WeightedNeighborInteger { dx: 1, dy: 0, weight: 49, },
+ WeightedNeighborInteger { dx: -1, dy: 1, weight: 53, },
+ WeightedNeighborInteger { dx: 0, dy: 1, weight: 2, },
+ ],
+ [
+ WeightedNeighborInteger { dx: 1, dy: 0, weight: 95, },
+ WeightedNeighborInteger { dx: -1, dy: 1, weight: 107, },
+ WeightedNeighborInteger { dx: 0, dy: 1, weight: 6, },
+ ],
+ [
+ WeightedNeighborInteger { dx: 1, dy: 0, weight: 23, },
+ WeightedNeighborInteger { dx: -1, dy: 1, weight: 27, },
+ WeightedNeighborInteger { dx: 0, dy: 1, weight: 2, },
+ ],
+ [
+ WeightedNeighborInteger { dx: 1, dy: 0, weight: 89, },
+ WeightedNeighborInteger { dx: -1, dy: 1, weight: 109, },
+ WeightedNeighborInteger { dx: 0, dy: 1, weight: 10, },
+ ],
+ [
+ WeightedNeighborInteger { dx: 1, dy: 0, weight: 43, },
+ WeightedNeighborInteger { dx: -1, dy: 1, weight: 55, },
+ WeightedNeighborInteger { dx: 0, dy: 1, weight: 6, },
+ ],
+ [
+ WeightedNeighborInteger { dx: 1, dy: 0, weight: 83, },
+ WeightedNeighborInteger { dx: -1, dy: 1, weight: 111, },
+ WeightedNeighborInteger { dx: 0, dy: 1, weight: 14, },
+ ],
+ [
+ WeightedNeighborInteger { dx: 1, dy: 0, weight: 5, },
+ WeightedNeighborInteger { dx: -1, dy: 1, weight: 7, },
+ WeightedNeighborInteger { dx: 0, dy: 1, weight: 1, },
+ ],
+ [
+ WeightedNeighborInteger { dx: 1, dy: 0, weight: 172, },
+ WeightedNeighborInteger { dx: -1, dy: 1, weight: 181, },
+ WeightedNeighborInteger { dx: 0, dy: 1, weight: 37, },
+ ],
+ [
+ WeightedNeighborInteger { dx: 1, dy: 0, weight: 97, },
+ WeightedNeighborInteger { dx: -1, dy: 1, weight: 76, },
+ WeightedNeighborInteger { dx: 0, dy: 1, weight: 22, },
+ ],
+ [
+ WeightedNeighborInteger { dx: 1, dy: 0, weight: 72, },
+ WeightedNeighborInteger { dx: -1, dy: 1, weight: 41, },
+ WeightedNeighborInteger { dx: 0, dy: 1, weight: 17, },
+ ],
+ [
+ WeightedNeighborInteger { dx: 1, dy: 0, weight: 119, },
+ WeightedNeighborInteger { dx: -1, dy: 1, weight: 47, },
+ WeightedNeighborInteger { dx: 0, dy: 1, weight: 29, },
+ ],
+ [
+ WeightedNeighborInteger { dx: 1, dy: 0, weight: 4, },
+ WeightedNeighborInteger { dx: -1, dy: 1, weight: 1, },
+ WeightedNeighborInteger { dx: 0, dy: 1, weight: 1, },
+ ],
+ [
+ WeightedNeighborInteger { dx: 1, dy: 0, weight: 4, },
+ WeightedNeighborInteger { dx: -1, dy: 1, weight: 1, },
+ WeightedNeighborInteger { dx: 0, dy: 1, weight: 1, },
+ ],
+ [
+ WeightedNeighborInteger { dx: 1, dy: 0, weight: 4, },
+ WeightedNeighborInteger { dx: -1, dy: 1, weight: 1, },
+ WeightedNeighborInteger { dx: 0, dy: 1, weight: 1, },
+ ],
+ [
+ WeightedNeighborInteger { dx: 1, dy: 0, weight: 4, },
+ WeightedNeighborInteger { dx: -1, dy: 1, weight: 1, },
+ WeightedNeighborInteger { dx: 0, dy: 1, weight: 1, },
+ ],
+ [
+ WeightedNeighborInteger { dx: 1, dy: 0, weight: 4, },
+ WeightedNeighborInteger { dx: -1, dy: 1, weight: 1, },
+ WeightedNeighborInteger { dx: 0, dy: 1, weight: 1, },
+ ],
+ [
+ WeightedNeighborInteger { dx: 1, dy: 0, weight: 4, },
+ WeightedNeighborInteger { dx: -1, dy: 1, weight: 1, },
+ WeightedNeighborInteger { dx: 0, dy: 1, weight: 1, },
+ ],
+ [
+ WeightedNeighborInteger { dx: 1, dy: 0, weight: 4, },
+ WeightedNeighborInteger { dx: -1, dy: 1, weight: 1, },
+ WeightedNeighborInteger { dx: 0, dy: 1, weight: 1, },
+ ],
+ [
+ WeightedNeighborInteger { dx: 1, dy: 0, weight: 4, },
+ WeightedNeighborInteger { dx: -1, dy: 1, weight: 1, },
+ WeightedNeighborInteger { dx: 0, dy: 1, weight: 1, },
+ ],
+ [
+ WeightedNeighborInteger { dx: 1, dy: 0, weight: 4, },
+ WeightedNeighborInteger { dx: -1, dy: 1, weight: 1, },
+ WeightedNeighborInteger { dx: 0, dy: 1, weight: 1, },
+ ],
+ [
+ WeightedNeighborInteger { dx: 1, dy: 0, weight: 65, },
+ WeightedNeighborInteger { dx: -1, dy: 1, weight: 18, },
+ WeightedNeighborInteger { dx: 0, dy: 1, weight: 17, },
+ ],
+ [
+ WeightedNeighborInteger { dx: 1, dy: 0, weight: 95, },
+ WeightedNeighborInteger { dx: -1, dy: 1, weight: 29, },
+ WeightedNeighborInteger { dx: 0, dy: 1, weight: 26, },
+ ],
+ [
+ WeightedNeighborInteger { dx: 1, dy: 0, weight: 185, },
+ WeightedNeighborInteger { dx: -1, dy: 1, weight: 62, },
+ WeightedNeighborInteger { dx: 0, dy: 1, weight: 53, },
+ ],
+ [
+ WeightedNeighborInteger { dx: 1, dy: 0, weight: 30, },
+ WeightedNeighborInteger { dx: -1, dy: 1, weight: 11, },
+ WeightedNeighborInteger { dx: 0, dy: 1, weight: 9, },
+ ],
+ [
+ WeightedNeighborInteger { dx: 1, dy: 0, weight: 35, },
+ WeightedNeighborInteger { dx: -1, dy: 1, weight: 14, },
+ WeightedNeighborInteger { dx: 0, dy: 1, weight: 11, },
+ ],
+ [
+ WeightedNeighborInteger { dx: 1, dy: 0, weight: 85, },
+ WeightedNeighborInteger { dx: -1, dy: 1, weight: 37, },
+ WeightedNeighborInteger { dx: 0, dy: 1, weight: 28, },
+ ],
+ [
+ WeightedNeighborInteger { dx: 1, dy: 0, weight: 55, },
+ WeightedNeighborInteger { dx: -1, dy: 1, weight: 26, },
+ WeightedNeighborInteger { dx: 0, dy: 1, weight: 19, },
+ ],
+ [
+ WeightedNeighborInteger { dx: 1, dy: 0, weight: 80, },
+ WeightedNeighborInteger { dx: -1, dy: 1, weight: 41, },
+ WeightedNeighborInteger { dx: 0, dy: 1, weight: 29, },
+ ],
+ [
+ WeightedNeighborInteger { dx: 1, dy: 0, weight: 155, },
+ WeightedNeighborInteger { dx: -1, dy: 1, weight: 86, },
+ WeightedNeighborInteger { dx: 0, dy: 1, weight: 59, },
+ ],
+ [
+ WeightedNeighborInteger { dx: 1, dy: 0, weight: 5, },
+ WeightedNeighborInteger { dx: -1, dy: 1, weight: 3, },
+ WeightedNeighborInteger { dx: 0, dy: 1, weight: 2, },
+ ],
+ [
+ WeightedNeighborInteger { dx: 1, dy: 0, weight: 5, },
+ WeightedNeighborInteger { dx: -1, dy: 1, weight: 3, },
+ WeightedNeighborInteger { dx: 0, dy: 1, weight: 2, },
+ ],
+ [
+ WeightedNeighborInteger { dx: 1, dy: 0, weight: 5, },
+ WeightedNeighborInteger { dx: -1, dy: 1, weight: 3, },
+ WeightedNeighborInteger { dx: 0, dy: 1, weight: 2, },
+ ],
+ [
+ WeightedNeighborInteger { dx: 1, dy: 0, weight: 5, },
+ WeightedNeighborInteger { dx: -1, dy: 1, weight: 3, },
+ WeightedNeighborInteger { dx: 0, dy: 1, weight: 2, },
+ ],
+ [
+ WeightedNeighborInteger { dx: 1, dy: 0, weight: 5, },
+ WeightedNeighborInteger { dx: -1, dy: 1, weight: 3, },
+ WeightedNeighborInteger { dx: 0, dy: 1, weight: 2, },
+ ],
+ [
+ WeightedNeighborInteger { dx: 1, dy: 0, weight: 5, },
+ WeightedNeighborInteger { dx: -1, dy: 1, weight: 3, },
+ WeightedNeighborInteger { dx: 0, dy: 1, weight: 2, },
+ ],
+ [
+ WeightedNeighborInteger { dx: 1, dy: 0, weight: 5, },
+ WeightedNeighborInteger { dx: -1, dy: 1, weight: 3, },
+ WeightedNeighborInteger { dx: 0, dy: 1, weight: 2, },
+ ],
+ [
+ WeightedNeighborInteger { dx: 1, dy: 0, weight: 5, },
+ WeightedNeighborInteger { dx: -1, dy: 1, weight: 3, },
+ WeightedNeighborInteger { dx: 0, dy: 1, weight: 2, },
+ ],
+ [
+ WeightedNeighborInteger { dx: 1, dy: 0, weight: 5, },
+ WeightedNeighborInteger { dx: -1, dy: 1, weight: 3, },
+ WeightedNeighborInteger { dx: 0, dy: 1, weight: 2, },
+ ],
+ [
+ WeightedNeighborInteger { dx: 1, dy: 0, weight: 5, },
+ WeightedNeighborInteger { dx: -1, dy: 1, weight: 3, },
+ WeightedNeighborInteger { dx: 0, dy: 1, weight: 2, },
+ ],
+ [
+ WeightedNeighborInteger { dx: 1, dy: 0, weight: 5, },
+ WeightedNeighborInteger { dx: -1, dy: 1, weight: 3, },
+ WeightedNeighborInteger { dx: 0, dy: 1, weight: 2, },
+ ],
+ [
+ WeightedNeighborInteger { dx: 1, dy: 0, weight: 5, },
+ WeightedNeighborInteger { dx: -1, dy: 1, weight: 3, },
+ WeightedNeighborInteger { dx: 0, dy: 1, weight: 2, },
+ ],
+ [
+ WeightedNeighborInteger { dx: 1, dy: 0, weight: 5, },
+ WeightedNeighborInteger { dx: -1, dy: 1, weight: 3, },
+ WeightedNeighborInteger { dx: 0, dy: 1, weight: 2, },
+ ],
+ [
+ WeightedNeighborInteger { dx: 1, dy: 0, weight: 305, },
+ WeightedNeighborInteger { dx: -1, dy: 1, weight: 176, },
+ WeightedNeighborInteger { dx: 0, dy: 1, weight: 119, },
+ ],
+ [
+ WeightedNeighborInteger { dx: 1, dy: 0, weight: 155, },
+ WeightedNeighborInteger { dx: -1, dy: 1, weight: 86, },
+ WeightedNeighborInteger { dx: 0, dy: 1, weight: 59, },
+ ],
+ [
+ WeightedNeighborInteger { dx: 1, dy: 0, weight: 105, },
+ WeightedNeighborInteger { dx: -1, dy: 1, weight: 56, },
+ WeightedNeighborInteger { dx: 0, dy: 1, weight: 39, },
+ ],
+ [
+ WeightedNeighborInteger { dx: 1, dy: 0, weight: 80, },
+ WeightedNeighborInteger { dx: -1, dy: 1, weight: 41, },
+ WeightedNeighborInteger { dx: 0, dy: 1, weight: 29, },
+ ],
+ [
+ WeightedNeighborInteger { dx: 1, dy: 0, weight: 65, },
+ WeightedNeighborInteger { dx: -1, dy: 1, weight: 32, },
+ WeightedNeighborInteger { dx: 0, dy: 1, weight: 23, },
+ ],
+ [
+ WeightedNeighborInteger { dx: 1, dy: 0, weight: 55, },
+ WeightedNeighborInteger { dx: -1, dy: 1, weight: 26, },
+ WeightedNeighborInteger { dx: 0, dy: 1, weight: 19, },
+ ],
+ [
+ WeightedNeighborInteger { dx: 1, dy: 0, weight: 335, },
+ WeightedNeighborInteger { dx: -1, dy: 1, weight: 152, },
+ WeightedNeighborInteger { dx: 0, dy: 1, weight: 113, },
+ ],
+ [
+ WeightedNeighborInteger { dx: 1, dy: 0, weight: 85, },
+ WeightedNeighborInteger { dx: -1, dy: 1, weight: 37, },
+ WeightedNeighborInteger { dx: 0, dy: 1, weight: 28, },
+ ],
+ [
+ WeightedNeighborInteger { dx: 1, dy: 0, weight: 115, },
+ WeightedNeighborInteger { dx: -1, dy: 1, weight: 48, },
+ WeightedNeighborInteger { dx: 0, dy: 1, weight: 37, },
+ ],
+ [
+ WeightedNeighborInteger { dx: 1, dy: 0, weight: 35, },
+ WeightedNeighborInteger { dx: -1, dy: 1, weight: 14, },
+ WeightedNeighborInteger { dx: 0, dy: 1, weight: 11, },
+ ],
+ [
+ WeightedNeighborInteger { dx: 1, dy: 0, weight: 355, },
+ WeightedNeighborInteger { dx: -1, dy: 1, weight: 136, },
+ WeightedNeighborInteger { dx: 0, dy: 1, weight: 109, },
+ ],
+ [
+ WeightedNeighborInteger { dx: 1, dy: 0, weight: 30, },
+ WeightedNeighborInteger { dx: -1, dy: 1, weight: 11, },
+ WeightedNeighborInteger { dx: 0, dy: 1, weight: 9, },
+ ],
+ [
+ WeightedNeighborInteger { dx: 1, dy: 0, weight: 365, },
+ WeightedNeighborInteger { dx: -1, dy: 1, weight: 128, },
+ WeightedNeighborInteger { dx: 0, dy: 1, weight: 107, },
+ ],
+ [
+ WeightedNeighborInteger { dx: 1, dy: 0, weight: 185, },
+ WeightedNeighborInteger { dx: -1, dy: 1, weight: 62, },
+ WeightedNeighborInteger { dx: 0, dy: 1, weight: 53, },
+ ],
+ [
+ WeightedNeighborInteger { dx: 1, dy: 0, weight: 25, },
+ WeightedNeighborInteger { dx: -1, dy: 1, weight: 8, },
+ WeightedNeighborInteger { dx: 0, dy: 1, weight: 7, },
+ ],
+ [
+ WeightedNeighborInteger { dx: 1, dy: 0, weight: 95, },
+ WeightedNeighborInteger { dx: -1, dy: 1, weight: 29, },
+ WeightedNeighborInteger { dx: 0, dy: 1, weight: 26, },
+ ],
+ [
+ WeightedNeighborInteger { dx: 1, dy: 0, weight: 385, },
+ WeightedNeighborInteger { dx: -1, dy: 1, weight: 112, },
+ WeightedNeighborInteger { dx: 0, dy: 1, weight: 103, },
+ ],
+ [
+ WeightedNeighborInteger { dx: 1, dy: 0, weight: 65, },
+ WeightedNeighborInteger { dx: -1, dy: 1, weight: 18, },
+ WeightedNeighborInteger { dx: 0, dy: 1, weight: 17, },
+ ],
+ [
+ WeightedNeighborInteger { dx: 1, dy: 0, weight: 395, },
+ WeightedNeighborInteger { dx: -1, dy: 1, weight: 104, },
+ WeightedNeighborInteger { dx: 0, dy: 1, weight: 101, },
+ ],
+ [
+ WeightedNeighborInteger { dx: 1, dy: 0, weight: 4, },
+ WeightedNeighborInteger { dx: -1, dy: 1, weight: 1, },
+ WeightedNeighborInteger { dx: 0, dy: 1, weight: 1, },
+ ],
+ [
+ WeightedNeighborInteger { dx: 1, dy: 0, weight: 4, },
+ WeightedNeighborInteger { dx: -1, dy: 1, weight: 1, },
+ WeightedNeighborInteger { dx: 0, dy: 1, weight: 1, },
+ ],
+ [
+ WeightedNeighborInteger { dx: 1, dy: 0, weight: 395, },
+ WeightedNeighborInteger { dx: -1, dy: 1, weight: 104, },
+ WeightedNeighborInteger { dx: 0, dy: 1, weight: 101, },
+ ],
+ [
+ WeightedNeighborInteger { dx: 1, dy: 0, weight: 65, },
+ WeightedNeighborInteger { dx: -1, dy: 1, weight: 18, },
+ WeightedNeighborInteger { dx: 0, dy: 1, weight: 17, },
+ ],
+ [
+ WeightedNeighborInteger { dx: 1, dy: 0, weight: 385, },
+ WeightedNeighborInteger { dx: -1, dy: 1, weight: 112, },
+ WeightedNeighborInteger { dx: 0, dy: 1, weight: 103, },
+ ],
+ [
+ WeightedNeighborInteger { dx: 1, dy: 0, weight: 95, },
+ WeightedNeighborInteger { dx: -1, dy: 1, weight: 29, },
+ WeightedNeighborInteger { dx: 0, dy: 1, weight: 26, },
+ ],
+ [
+ WeightedNeighborInteger { dx: 1, dy: 0, weight: 25, },
+ WeightedNeighborInteger { dx: -1, dy: 1, weight: 8, },
+ WeightedNeighborInteger { dx: 0, dy: 1, weight: 7, },
+ ],
+ [
+ WeightedNeighborInteger { dx: 1, dy: 0, weight: 185, },
+ WeightedNeighborInteger { dx: -1, dy: 1, weight: 62, },
+ WeightedNeighborInteger { dx: 0, dy: 1, weight: 53, },
+ ],
+ [
+ WeightedNeighborInteger { dx: 1, dy: 0, weight: 365, },
+ WeightedNeighborInteger { dx: -1, dy: 1, weight: 128, },
+ WeightedNeighborInteger { dx: 0, dy: 1, weight: 107, },
+ ],
+ [
+ WeightedNeighborInteger { dx: 1, dy: 0, weight: 30, },
+ WeightedNeighborInteger { dx: -1, dy: 1, weight: 11, },
+ WeightedNeighborInteger { dx: 0, dy: 1, weight: 9, },
+ ],
+ [
+ WeightedNeighborInteger { dx: 1, dy: 0, weight: 355, },
+ WeightedNeighborInteger { dx: -1, dy: 1, weight: 136, },
+ WeightedNeighborInteger { dx: 0, dy: 1, weight: 109, },
+ ],
+ [
+ WeightedNeighborInteger { dx: 1, dy: 0, weight: 35, },
+ WeightedNeighborInteger { dx: -1, dy: 1, weight: 14, },
+ WeightedNeighborInteger { dx: 0, dy: 1, weight: 11, },
+ ],
+ [
+ WeightedNeighborInteger { dx: 1, dy: 0, weight: 115, },
+ WeightedNeighborInteger { dx: -1, dy: 1, weight: 48, },
+ WeightedNeighborInteger { dx: 0, dy: 1, weight: 37, },
+ ],
+ [
+ WeightedNeighborInteger { dx: 1, dy: 0, weight: 85, },
+ WeightedNeighborInteger { dx: -1, dy: 1, weight: 37, },
+ WeightedNeighborInteger { dx: 0, dy: 1, weight: 28, },
+ ],
+ [
+ WeightedNeighborInteger { dx: 1, dy: 0, weight: 335, },
+ WeightedNeighborInteger { dx: -1, dy: 1, weight: 152, },
+ WeightedNeighborInteger { dx: 0, dy: 1, weight: 113, },
+ ],
+ [
+ WeightedNeighborInteger { dx: 1, dy: 0, weight: 55, },
+ WeightedNeighborInteger { dx: -1, dy: 1, weight: 26, },
+ WeightedNeighborInteger { dx: 0, dy: 1, weight: 19, },
+ ],
+ [
+ WeightedNeighborInteger { dx: 1, dy: 0, weight: 65, },
+ WeightedNeighborInteger { dx: -1, dy: 1, weight: 32, },
+ WeightedNeighborInteger { dx: 0, dy: 1, weight: 23, },
+ ],
+ [
+ WeightedNeighborInteger { dx: 1, dy: 0, weight: 80, },
+ WeightedNeighborInteger { dx: -1, dy: 1, weight: 41, },
+ WeightedNeighborInteger { dx: 0, dy: 1, weight: 29, },
+ ],
+ [
+ WeightedNeighborInteger { dx: 1, dy: 0, weight: 105, },
+ WeightedNeighborInteger { dx: -1, dy: 1, weight: 56, },
+ WeightedNeighborInteger { dx: 0, dy: 1, weight: 39, },
+ ],
+ [
+ WeightedNeighborInteger { dx: 1, dy: 0, weight: 155, },
+ WeightedNeighborInteger { dx: -1, dy: 1, weight: 86, },
+ WeightedNeighborInteger { dx: 0, dy: 1, weight: 59, },
+ ],
+ [
+ WeightedNeighborInteger { dx: 1, dy: 0, weight: 305, },
+ WeightedNeighborInteger { dx: -1, dy: 1, weight: 176, },
+ WeightedNeighborInteger { dx: 0, dy: 1, weight: 119, },
+ ],
+ [
+ WeightedNeighborInteger { dx: 1, dy: 0, weight: 5, },
+ WeightedNeighborInteger { dx: -1, dy: 1, weight: 3, },
+ WeightedNeighborInteger { dx: 0, dy: 1, weight: 2, },
+ ],
+ [
+ WeightedNeighborInteger { dx: 1, dy: 0, weight: 5, },
+ WeightedNeighborInteger { dx: -1, dy: 1, weight: 3, },
+ WeightedNeighborInteger { dx: 0, dy: 1, weight: 2, },
+ ],
+ [
+ WeightedNeighborInteger { dx: 1, dy: 0, weight: 5, },
+ WeightedNeighborInteger { dx: -1, dy: 1, weight: 3, },
+ WeightedNeighborInteger { dx: 0, dy: 1, weight: 2, },
+ ],
+ [
+ WeightedNeighborInteger { dx: 1, dy: 0, weight: 5, },
+ WeightedNeighborInteger { dx: -1, dy: 1, weight: 3, },
+ WeightedNeighborInteger { dx: 0, dy: 1, weight: 2, },
+ ],
+ [
+ WeightedNeighborInteger { dx: 1, dy: 0, weight: 5, },
+ WeightedNeighborInteger { dx: -1, dy: 1, weight: 3, },
+ WeightedNeighborInteger { dx: 0, dy: 1, weight: 2, },
+ ],
+ [
+ WeightedNeighborInteger { dx: 1, dy: 0, weight: 5, },
+ WeightedNeighborInteger { dx: -1, dy: 1, weight: 3, },
+ WeightedNeighborInteger { dx: 0, dy: 1, weight: 2, },
+ ],
+ [
+ WeightedNeighborInteger { dx: 1, dy: 0, weight: 5, },
+ WeightedNeighborInteger { dx: -1, dy: 1, weight: 3, },
+ WeightedNeighborInteger { dx: 0, dy: 1, weight: 2, },
+ ],
+ [
+ WeightedNeighborInteger { dx: 1, dy: 0, weight: 5, },
+ WeightedNeighborInteger { dx: -1, dy: 1, weight: 3, },
+ WeightedNeighborInteger { dx: 0, dy: 1, weight: 2, },
+ ],
+ [
+ WeightedNeighborInteger { dx: 1, dy: 0, weight: 5, },
+ WeightedNeighborInteger { dx: -1, dy: 1, weight: 3, },
+ WeightedNeighborInteger { dx: 0, dy: 1, weight: 2, },
+ ],
+ [
+ WeightedNeighborInteger { dx: 1, dy: 0, weight: 5, },
+ WeightedNeighborInteger { dx: -1, dy: 1, weight: 3, },
+ WeightedNeighborInteger { dx: 0, dy: 1, weight: 2, },
+ ],
+ [
+ WeightedNeighborInteger { dx: 1, dy: 0, weight: 5, },
+ WeightedNeighborInteger { dx: -1, dy: 1, weight: 3, },
+ WeightedNeighborInteger { dx: 0, dy: 1, weight: 2, },
+ ],
+ [
+ WeightedNeighborInteger { dx: 1, dy: 0, weight: 5, },
+ WeightedNeighborInteger { dx: -1, dy: 1, weight: 3, },
+ WeightedNeighborInteger { dx: 0, dy: 1, weight: 2, },
+ ],
+ [
+ WeightedNeighborInteger { dx: 1, dy: 0, weight: 5, },
+ WeightedNeighborInteger { dx: -1, dy: 1, weight: 3, },
+ WeightedNeighborInteger { dx: 0, dy: 1, weight: 2, },
+ ],
+ [
+ WeightedNeighborInteger { dx: 1, dy: 0, weight: 155, },
+ WeightedNeighborInteger { dx: -1, dy: 1, weight: 86, },
+ WeightedNeighborInteger { dx: 0, dy: 1, weight: 59, },
+ ],
+ [
+ WeightedNeighborInteger { dx: 1, dy: 0, weight: 80, },
+ WeightedNeighborInteger { dx: -1, dy: 1, weight: 41, },
+ WeightedNeighborInteger { dx: 0, dy: 1, weight: 29, },
+ ],
+ [
+ WeightedNeighborInteger { dx: 1, dy: 0, weight: 55, },
+ WeightedNeighborInteger { dx: -1, dy: 1, weight: 26, },
+ WeightedNeighborInteger { dx: 0, dy: 1, weight: 19, },
+ ],
+ [
+ WeightedNeighborInteger { dx: 1, dy: 0, weight: 85, },
+ WeightedNeighborInteger { dx: -1, dy: 1, weight: 37, },
+ WeightedNeighborInteger { dx: 0, dy: 1, weight: 28, },
+ ],
+ [
+ WeightedNeighborInteger { dx: 1, dy: 0, weight: 35, },
+ WeightedNeighborInteger { dx: -1, dy: 1, weight: 14, },
+ WeightedNeighborInteger { dx: 0, dy: 1, weight: 11, },
+ ],
+ [
+ WeightedNeighborInteger { dx: 1, dy: 0, weight: 30, },
+ WeightedNeighborInteger { dx: -1, dy: 1, weight: 11, },
+ WeightedNeighborInteger { dx: 0, dy: 1, weight: 9, },
+ ],
+ [
+ WeightedNeighborInteger { dx: 1, dy: 0, weight: 185, },
+ WeightedNeighborInteger { dx: -1, dy: 1, weight: 62, },
+ WeightedNeighborInteger { dx: 0, dy: 1, weight: 53, },
+ ],
+ [
+ WeightedNeighborInteger { dx: 1, dy: 0, weight: 95, },
+ WeightedNeighborInteger { dx: -1, dy: 1, weight: 29, },
+ WeightedNeighborInteger { dx: 0, dy: 1, weight: 26, },
+ ],
+ [
+ WeightedNeighborInteger { dx: 1, dy: 0, weight: 65, },
+ WeightedNeighborInteger { dx: -1, dy: 1, weight: 18, },
+ WeightedNeighborInteger { dx: 0, dy: 1, weight: 17, },
+ ],
+ [
+ WeightedNeighborInteger { dx: 1, dy: 0, weight: 4, },
+ WeightedNeighborInteger { dx: -1, dy: 1, weight: 1, },
+ WeightedNeighborInteger { dx: 0, dy: 1, weight: 1, },
+ ],
+ [
+ WeightedNeighborInteger { dx: 1, dy: 0, weight: 4, },
+ WeightedNeighborInteger { dx: -1, dy: 1, weight: 1, },
+ WeightedNeighborInteger { dx: 0, dy: 1, weight: 1, },
+ ],
+ [
+ WeightedNeighborInteger { dx: 1, dy: 0, weight: 4, },
+ WeightedNeighborInteger { dx: -1, dy: 1, weight: 1, },
+ WeightedNeighborInteger { dx: 0, dy: 1, weight: 1, },
+ ],
+ [
+ WeightedNeighborInteger { dx: 1, dy: 0, weight: 4, },
+ WeightedNeighborInteger { dx: -1, dy: 1, weight: 1, },
+ WeightedNeighborInteger { dx: 0, dy: 1, weight: 1, },
+ ],
+ [
+ WeightedNeighborInteger { dx: 1, dy: 0, weight: 4, },
+ WeightedNeighborInteger { dx: -1, dy: 1, weight: 1, },
+ WeightedNeighborInteger { dx: 0, dy: 1, weight: 1, },
+ ],
+ [
+ WeightedNeighborInteger { dx: 1, dy: 0, weight: 4, },
+ WeightedNeighborInteger { dx: -1, dy: 1, weight: 1, },
+ WeightedNeighborInteger { dx: 0, dy: 1, weight: 1, },
+ ],
+ [
+ WeightedNeighborInteger { dx: 1, dy: 0, weight: 4, },
+ WeightedNeighborInteger { dx: -1, dy: 1, weight: 1, },
+ WeightedNeighborInteger { dx: 0, dy: 1, weight: 1, },
+ ],
+ [
+ WeightedNeighborInteger { dx: 1, dy: 0, weight: 4, },
+ WeightedNeighborInteger { dx: -1, dy: 1, weight: 1, },
+ WeightedNeighborInteger { dx: 0, dy: 1, weight: 1, },
+ ],
+ [
+ WeightedNeighborInteger { dx: 1, dy: 0, weight: 4, },
+ WeightedNeighborInteger { dx: -1, dy: 1, weight: 1, },
+ WeightedNeighborInteger { dx: 0, dy: 1, weight: 1, },
+ ],
+ [
+ WeightedNeighborInteger { dx: 1, dy: 0, weight: 119, },
+ WeightedNeighborInteger { dx: -1, dy: 1, weight: 47, },
+ WeightedNeighborInteger { dx: 0, dy: 1, weight: 29, },
+ ],
+ [
+ WeightedNeighborInteger { dx: 1, dy: 0, weight: 72, },
+ WeightedNeighborInteger { dx: -1, dy: 1, weight: 41, },
+ WeightedNeighborInteger { dx: 0, dy: 1, weight: 17, },
+ ],
+ [
+ WeightedNeighborInteger { dx: 1, dy: 0, weight: 97, },
+ WeightedNeighborInteger { dx: -1, dy: 1, weight: 76, },
+ WeightedNeighborInteger { dx: 0, dy: 1, weight: 22, },
+ ],
+ [
+ WeightedNeighborInteger { dx: 1, dy: 0, weight: 172, },
+ WeightedNeighborInteger { dx: -1, dy: 1, weight: 181, },
+ WeightedNeighborInteger { dx: 0, dy: 1, weight: 37, },
+ ],
+ [
+ WeightedNeighborInteger { dx: 1, dy: 0, weight: 5, },
+ WeightedNeighborInteger { dx: -1, dy: 1, weight: 7, },
+ WeightedNeighborInteger { dx: 0, dy: 1, weight: 1, },
+ ],
+ [
+ WeightedNeighborInteger { dx: 1, dy: 0, weight: 83, },
+ WeightedNeighborInteger { dx: -1, dy: 1, weight: 111, },
+ WeightedNeighborInteger { dx: 0, dy: 1, weight: 14, },
+ ],
+ [
+ WeightedNeighborInteger { dx: 1, dy: 0, weight: 43, },
+ WeightedNeighborInteger { dx: -1, dy: 1, weight: 55, },
+ WeightedNeighborInteger { dx: 0, dy: 1, weight: 6, },
+ ],
+ [
+ WeightedNeighborInteger { dx: 1, dy: 0, weight: 89, },
+ WeightedNeighborInteger { dx: -1, dy: 1, weight: 109, },
+ WeightedNeighborInteger { dx: 0, dy: 1, weight: 10, },
+ ],
+ [
+ WeightedNeighborInteger { dx: 1, dy: 0, weight: 23, },
+ WeightedNeighborInteger { dx: -1, dy: 1, weight: 27, },
+ WeightedNeighborInteger { dx: 0, dy: 1, weight: 2, },
+ ],
+ [
+ WeightedNeighborInteger { dx: 1, dy: 0, weight: 95, },
+ WeightedNeighborInteger { dx: -1, dy: 1, weight: 107, },
+ WeightedNeighborInteger { dx: 0, dy: 1, weight: 6, },
+ ],
+ [
+ WeightedNeighborInteger { dx: 1, dy: 0, weight: 49, },
+ WeightedNeighborInteger { dx: -1, dy: 1, weight: 53, },
+ WeightedNeighborInteger { dx: 0, dy: 1, weight: 2, },
+ ],
+ [
+ WeightedNeighborInteger { dx: 1, dy: 0, weight: 101, },
+ WeightedNeighborInteger { dx: -1, dy: 1, weight: 105, },
+ WeightedNeighborInteger { dx: 0, dy: 1, weight: 2, },
+ ],
+ [
+ WeightedNeighborInteger { dx: 1, dy: 0, weight: 1, },
+ WeightedNeighborInteger { dx: -1, dy: 1, weight: 1, },
+ WeightedNeighborInteger { dx: 0, dy: 1, weight: 0, },
+ ],
+ [
+ WeightedNeighborInteger { dx: 1, dy: 0, weight: 307, },
+ WeightedNeighborInteger { dx: -1, dy: 1, weight: 303, },
+ WeightedNeighborInteger { dx: 0, dy: 1, weight: 6, },
+ ],
+ [
+ WeightedNeighborInteger { dx: 1, dy: 0, weight: 153, },
+ WeightedNeighborInteger { dx: -1, dy: 1, weight: 149, },
+ WeightedNeighborInteger { dx: 0, dy: 1, weight: 6, },
+ ],
+ [
+ WeightedNeighborInteger { dx: 1, dy: 0, weight: 305, },
+ WeightedNeighborInteger { dx: -1, dy: 1, weight: 293, },
+ WeightedNeighborInteger { dx: 0, dy: 1, weight: 18, },
+ ],
+ [
+ WeightedNeighborInteger { dx: 1, dy: 0, weight: 38, },
+ WeightedNeighborInteger { dx: -1, dy: 1, weight: 36, },
+ WeightedNeighborInteger { dx: 0, dy: 1, weight: 3, },
+ ],
+ [
+ WeightedNeighborInteger { dx: 1, dy: 0, weight: 303, },
+ WeightedNeighborInteger { dx: -1, dy: 1, weight: 283, },
+ WeightedNeighborInteger { dx: 0, dy: 1, weight: 30, },
+ ],
+ [
+ WeightedNeighborInteger { dx: 1, dy: 0, weight: 151, },
+ WeightedNeighborInteger { dx: -1, dy: 1, weight: 139, },
+ WeightedNeighborInteger { dx: 0, dy: 1, weight: 18, },
+ ],
+ [
+ WeightedNeighborInteger { dx: 1, dy: 0, weight: 43, },
+ WeightedNeighborInteger { dx: -1, dy: 1, weight: 39, },
+ WeightedNeighborInteger { dx: 0, dy: 1, weight: 6, },
+ ],
+ [
+ WeightedNeighborInteger { dx: 1, dy: 0, weight: 75, },
+ WeightedNeighborInteger { dx: -1, dy: 1, weight: 67, },
+ WeightedNeighborInteger { dx: 0, dy: 1, weight: 12, },
+ ],
+ [
+ WeightedNeighborInteger { dx: 1, dy: 0, weight: 299, },
+ WeightedNeighborInteger { dx: -1, dy: 1, weight: 263, },
+ WeightedNeighborInteger { dx: 0, dy: 1, weight: 54, },
+ ],
+ [
+ WeightedNeighborInteger { dx: 1, dy: 0, weight: 149, },
+ WeightedNeighborInteger { dx: -1, dy: 1, weight: 129, },
+ WeightedNeighborInteger { dx: 0, dy: 1, weight: 30, },
+ ],
+ [
+ WeightedNeighborInteger { dx: 1, dy: 0, weight: 27, },
+ WeightedNeighborInteger { dx: -1, dy: 1, weight: 23, },
+ WeightedNeighborInteger { dx: 0, dy: 1, weight: 6, },
+ ],
+ [
+ WeightedNeighborInteger { dx: 1, dy: 0, weight: 37, },
+ WeightedNeighborInteger { dx: -1, dy: 1, weight: 31, },
+ WeightedNeighborInteger { dx: 0, dy: 1, weight: 9, },
+ ],
+ [
+ WeightedNeighborInteger { dx: 1, dy: 0, weight: 295, },
+ WeightedNeighborInteger { dx: -1, dy: 1, weight: 243, },
+ WeightedNeighborInteger { dx: 0, dy: 1, weight: 78, },
+ ],
+ [
+ WeightedNeighborInteger { dx: 1, dy: 0, weight: 21, },
+ WeightedNeighborInteger { dx: -1, dy: 1, weight: 17, },
+ WeightedNeighborInteger { dx: 0, dy: 1, weight: 6, },
+ ],
+ [
+ WeightedNeighborInteger { dx: 1, dy: 0, weight: 293, },
+ WeightedNeighborInteger { dx: -1, dy: 1, weight: 233, },
+ WeightedNeighborInteger { dx: 0, dy: 1, weight: 90, },
+ ],
+ [
+ WeightedNeighborInteger { dx: 1, dy: 0, weight: 73, },
+ WeightedNeighborInteger { dx: -1, dy: 1, weight: 57, },
+ WeightedNeighborInteger { dx: 0, dy: 1, weight: 24, },
+ ],
+ [
+ WeightedNeighborInteger { dx: 1, dy: 0, weight: 291, },
+ WeightedNeighborInteger { dx: -1, dy: 1, weight: 223, },
+ WeightedNeighborInteger { dx: 0, dy: 1, weight: 102, },
+ ],
+ [
+ WeightedNeighborInteger { dx: 1, dy: 0, weight: 145, },
+ WeightedNeighborInteger { dx: -1, dy: 1, weight: 109, },
+ WeightedNeighborInteger { dx: 0, dy: 1, weight: 54, },
+ ],
+ [
+ WeightedNeighborInteger { dx: 1, dy: 0, weight: 289, },
+ WeightedNeighborInteger { dx: -1, dy: 1, weight: 213, },
+ WeightedNeighborInteger { dx: 0, dy: 1, weight: 114, },
+ ],
+ [
+ WeightedNeighborInteger { dx: 1, dy: 0, weight: 36, },
+ WeightedNeighborInteger { dx: -1, dy: 1, weight: 26, },
+ WeightedNeighborInteger { dx: 0, dy: 1, weight: 15, },
+ ],
+ [
+ WeightedNeighborInteger { dx: 1, dy: 0, weight: 41, },
+ WeightedNeighborInteger { dx: -1, dy: 1, weight: 29, },
+ WeightedNeighborInteger { dx: 0, dy: 1, weight: 18, },
+ ],
+ [
+ WeightedNeighborInteger { dx: 1, dy: 0, weight: 13, },
+ WeightedNeighborInteger { dx: -1, dy: 1, weight: 9, },
+ WeightedNeighborInteger { dx: 0, dy: 1, weight: 6, },
+ ],
+ [
+ WeightedNeighborInteger { dx: 1, dy: 0, weight: 285, },
+ WeightedNeighborInteger { dx: -1, dy: 1, weight: 193, },
+ WeightedNeighborInteger { dx: 0, dy: 1, weight: 138, },
+ ],
+ [
+ WeightedNeighborInteger { dx: 1, dy: 0, weight: 71, },
+ WeightedNeighborInteger { dx: -1, dy: 1, weight: 47, },
+ WeightedNeighborInteger { dx: 0, dy: 1, weight: 36, },
+ ],
+ [
+ WeightedNeighborInteger { dx: 1, dy: 0, weight: 283, },
+ WeightedNeighborInteger { dx: -1, dy: 1, weight: 183, },
+ WeightedNeighborInteger { dx: 0, dy: 1, weight: 150, },
+ ],
+ [
+ WeightedNeighborInteger { dx: 1, dy: 0, weight: 141, },
+ WeightedNeighborInteger { dx: -1, dy: 1, weight: 89, },
+ WeightedNeighborInteger { dx: 0, dy: 1, weight: 78, },
+ ],
+ [
+ WeightedNeighborInteger { dx: 1, dy: 0, weight: 281, },
+ WeightedNeighborInteger { dx: -1, dy: 1, weight: 173, },
+ WeightedNeighborInteger { dx: 0, dy: 1, weight: 162, },
+ ],
+ [
+ WeightedNeighborInteger { dx: 1, dy: 0, weight: 5, },
+ WeightedNeighborInteger { dx: -1, dy: 1, weight: 3, },
+ WeightedNeighborInteger { dx: 0, dy: 1, weight: 3, },
+ ],
+ [
+ WeightedNeighborInteger { dx: 1, dy: 0, weight: 423, },
+ WeightedNeighborInteger { dx: -1, dy: 1, weight: 256, },
+ WeightedNeighborInteger { dx: 0, dy: 1, weight: 245, },
+ ],
+ [
+ WeightedNeighborInteger { dx: 1, dy: 0, weight: 213, },
+ WeightedNeighborInteger { dx: -1, dy: 1, weight: 130, },
+ WeightedNeighborInteger { dx: 0, dy: 1, weight: 119, },
+ ],
+ [
+ WeightedNeighborInteger { dx: 1, dy: 0, weight: 13, },
+ WeightedNeighborInteger { dx: -1, dy: 1, weight: 8, },
+ WeightedNeighborInteger { dx: 0, dy: 1, weight: 7, },
+ ],
+ [
+ WeightedNeighborInteger { dx: 1, dy: 0, weight: 108, },
+ WeightedNeighborInteger { dx: -1, dy: 1, weight: 67, },
+ WeightedNeighborInteger { dx: 0, dy: 1, weight: 56, },
+ ],
+ [
+ WeightedNeighborInteger { dx: 1, dy: 0, weight: 435, },
+ WeightedNeighborInteger { dx: -1, dy: 1, weight: 272, },
+ WeightedNeighborInteger { dx: 0, dy: 1, weight: 217, },
+ ],
+ [
+ WeightedNeighborInteger { dx: 1, dy: 0, weight: 73, },
+ WeightedNeighborInteger { dx: -1, dy: 1, weight: 46, },
+ WeightedNeighborInteger { dx: 0, dy: 1, weight: 35, },
+ ],
+ [
+ WeightedNeighborInteger { dx: 1, dy: 0, weight: 63, },
+ WeightedNeighborInteger { dx: -1, dy: 1, weight: 40, },
+ WeightedNeighborInteger { dx: 0, dy: 1, weight: 29, },
+ ],
+ [
+ WeightedNeighborInteger { dx: 1, dy: 0, weight: 111, },
+ WeightedNeighborInteger { dx: -1, dy: 1, weight: 71, },
+ WeightedNeighborInteger { dx: 0, dy: 1, weight: 49, },
+ ],
+ [
+ WeightedNeighborInteger { dx: 1, dy: 0, weight: 149, },
+ WeightedNeighborInteger { dx: -1, dy: 1, weight: 96, },
+ WeightedNeighborInteger { dx: 0, dy: 1, weight: 63, },
+ ],
+ [
+ WeightedNeighborInteger { dx: 1, dy: 0, weight: 225, },
+ WeightedNeighborInteger { dx: -1, dy: 1, weight: 146, },
+ WeightedNeighborInteger { dx: 0, dy: 1, weight: 91, },
+ ],
+ [
+ WeightedNeighborInteger { dx: 1, dy: 0, weight: 453, },
+ WeightedNeighborInteger { dx: -1, dy: 1, weight: 296, },
+ WeightedNeighborInteger { dx: 0, dy: 1, weight: 175, },
+ ],
+ [
+ WeightedNeighborInteger { dx: 1, dy: 0, weight: 38, },
+ WeightedNeighborInteger { dx: -1, dy: 1, weight: 25, },
+ WeightedNeighborInteger { dx: 0, dy: 1, weight: 14, },
+ ],
+ [
+ WeightedNeighborInteger { dx: 1, dy: 0, weight: 459, },
+ WeightedNeighborInteger { dx: -1, dy: 1, weight: 304, },
+ WeightedNeighborInteger { dx: 0, dy: 1, weight: 161, },
+ ],
+ [
+ WeightedNeighborInteger { dx: 1, dy: 0, weight: 3, },
+ WeightedNeighborInteger { dx: -1, dy: 1, weight: 2, },
+ WeightedNeighborInteger { dx: 0, dy: 1, weight: 1, },
+ ],
+ [
+ WeightedNeighborInteger { dx: 1, dy: 0, weight: 471, },
+ WeightedNeighborInteger { dx: -1, dy: 1, weight: 304, },
+ WeightedNeighborInteger { dx: 0, dy: 1, weight: 161, },
+ ],
+ [
+ WeightedNeighborInteger { dx: 1, dy: 0, weight: 237, },
+ WeightedNeighborInteger { dx: -1, dy: 1, weight: 148, },
+ WeightedNeighborInteger { dx: 0, dy: 1, weight: 83, },
+ ],
+ [
+ WeightedNeighborInteger { dx: 1, dy: 0, weight: 53, },
+ WeightedNeighborInteger { dx: -1, dy: 1, weight: 32, },
+ WeightedNeighborInteger { dx: 0, dy: 1, weight: 19, },
+ ],
+ [
+ WeightedNeighborInteger { dx: 1, dy: 0, weight: 60, },
+ WeightedNeighborInteger { dx: -1, dy: 1, weight: 35, },
+ WeightedNeighborInteger { dx: 0, dy: 1, weight: 22, },
+ ],
+ [
+ WeightedNeighborInteger { dx: 1, dy: 0, weight: 483, },
+ WeightedNeighborInteger { dx: -1, dy: 1, weight: 272, },
+ WeightedNeighborInteger { dx: 0, dy: 1, weight: 181, },
+ ],
+ [
+ WeightedNeighborInteger { dx: 1, dy: 0, weight: 81, },
+ WeightedNeighborInteger { dx: -1, dy: 1, weight: 44, },
+ WeightedNeighborInteger { dx: 0, dy: 1, weight: 31, },
+ ],
+ [
+ WeightedNeighborInteger { dx: 1, dy: 0, weight: 489, },
+ WeightedNeighborInteger { dx: -1, dy: 1, weight: 256, },
+ WeightedNeighborInteger { dx: 0, dy: 1, weight: 191, },
+ ],
+ [
+ WeightedNeighborInteger { dx: 1, dy: 0, weight: 123, },
+ WeightedNeighborInteger { dx: -1, dy: 1, weight: 62, },
+ WeightedNeighborInteger { dx: 0, dy: 1, weight: 49, },
+ ],
+ [
+ WeightedNeighborInteger { dx: 1, dy: 0, weight: 165, },
+ WeightedNeighborInteger { dx: -1, dy: 1, weight: 80, },
+ WeightedNeighborInteger { dx: 0, dy: 1, weight: 67, },
+ ],
+ [
+ WeightedNeighborInteger { dx: 1, dy: 0, weight: 249, },
+ WeightedNeighborInteger { dx: -1, dy: 1, weight: 116, },
+ WeightedNeighborInteger { dx: 0, dy: 1, weight: 103, },
+ ],
+ [
+ WeightedNeighborInteger { dx: 1, dy: 0, weight: 501, },
+ WeightedNeighborInteger { dx: -1, dy: 1, weight: 224, },
+ WeightedNeighborInteger { dx: 0, dy: 1, weight: 211, },
+ ],
+ [
+ WeightedNeighborInteger { dx: 1, dy: 0, weight: 7, },
+ WeightedNeighborInteger { dx: -1, dy: 1, weight: 3, },
+ WeightedNeighborInteger { dx: 0, dy: 1, weight: 3, },
+ ],
+ [
+ WeightedNeighborInteger { dx: 1, dy: 0, weight: 43, },
+ WeightedNeighborInteger { dx: -1, dy: 1, weight: 15, },
+ WeightedNeighborInteger { dx: 0, dy: 1, weight: 20, },
+ ],
+ [
+ WeightedNeighborInteger { dx: 1, dy: 0, weight: 22, },
+ WeightedNeighborInteger { dx: -1, dy: 1, weight: 6, },
+ WeightedNeighborInteger { dx: 0, dy: 1, weight: 11, },
+ ],
+ [
+ WeightedNeighborInteger { dx: 1, dy: 0, weight: 15, },
+ WeightedNeighborInteger { dx: -1, dy: 1, weight: 3, },
+ WeightedNeighborInteger { dx: 0, dy: 1, weight: 8, },
+ ],
+ [
+ WeightedNeighborInteger { dx: 1, dy: 0, weight: 23, },
+ WeightedNeighborInteger { dx: -1, dy: 1, weight: 3, },
+ WeightedNeighborInteger { dx: 0, dy: 1, weight: 13, },
+ ],
+ [
+ WeightedNeighborInteger { dx: 1, dy: 0, weight: 47, },
+ WeightedNeighborInteger { dx: -1, dy: 1, weight: 3, },
+ WeightedNeighborInteger { dx: 0, dy: 1, weight: 28, },
+ ],
+ [
+ WeightedNeighborInteger { dx: 1, dy: 0, weight: 8, },
+ WeightedNeighborInteger { dx: -1, dy: 1, weight: 0, },
+ WeightedNeighborInteger { dx: 0, dy: 1, weight: 5, },
+ ],
+ [
+ WeightedNeighborInteger { dx: 1, dy: 0, weight: 7, },
+ WeightedNeighborInteger { dx: -1, dy: 1, weight: 0, },
+ WeightedNeighborInteger { dx: 0, dy: 1, weight: 4, },
+ ],
+ [
+ WeightedNeighborInteger { dx: 1, dy: 0, weight: 21, },
+ WeightedNeighborInteger { dx: -1, dy: 1, weight: 0, },
+ WeightedNeighborInteger { dx: 0, dy: 1, weight: 10, },
+ ],
+ [
+ WeightedNeighborInteger { dx: 1, dy: 0, weight: 13, },
+ WeightedNeighborInteger { dx: -1, dy: 1, weight: 0, },
+ WeightedNeighborInteger { dx: 0, dy: 1, weight: 5, },
+ ],
+ [
+ WeightedNeighborInteger { dx: 1, dy: 0, weight: 13, },
+ WeightedNeighborInteger { dx: -1, dy: 1, weight: 0, },
+ WeightedNeighborInteger { dx: 0, dy: 1, weight: 5, },
+ ],
+];
diff --git a/src/lib.rs b/src/lib.rs
index a8b413c..133432f 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -4,6 +4,10 @@ use image::{ImageBuffer, Rgb, RgbImage};
use palette::{LinSrgb, Srgb, color_difference::EuclideanDistance};
use rand::rngs::SmallRng;
use rand::{RngCore, SeedableRng};
+use std::cmp;
+use std::collections::VecDeque;
+use std::num::Wrapping;
+use std::process;
const BLACK_SRGB: Srgb<f32> = Srgb::new(0., 0., 0.);
const WHITE_SRGB: Srgb<f32> = Srgb::new(1., 1., 1.);
@@ -11,6 +15,25 @@ const WHITE_SRGB: Srgb<f32> = Srgb::new(1., 1., 1.);
const BLACK_LINEAR_SRGB: LinSrgb<f32> = LinSrgb::new(0., 0., 0.);
const WHITE_LINEAR_SRGB: LinSrgb<f32> = LinSrgb::new(1., 1., 1.);
+const MULTIPLIER: u32 = 1303515245;
+const INCREMENT: u32 = 12345;
+const MODULUS: u32 = 1 << 31;
+
+fn lcg_next(state: &mut u32) -> u32 {
+ let tmp_state = Wrapping(*state);
+ *state = ((Wrapping(MULTIPLIER) * tmp_state + Wrapping(INCREMENT)) % Wrapping(MODULUS)).0;
+ *state
+}
+
+fn rand_(state: &mut u32) -> u32 {
+ lcg_next(state)
+}
+
+fn rand_double(state: &mut u32) -> f64 {
+ // TODO: Should to it with 64bits integers
+ (lcg_next(state) as f64) / (MODULUS as f64)
+}
+
#[allow(dead_code)]
fn dither_chose_color_linear_sqrt(diffused_error: f32, pixel: u8) -> (u8, f32) {
let grey_pixel = Srgb::new(pixel, pixel, pixel).into_linear();
@@ -73,6 +96,49 @@ fn dither_integer_chose_color(diffused_error: i32, pixel: i32) -> (u8, i32) {
(255, distance_to_white)
}
}
+fn dither_float_chose_3b(
+ diffused_error_r: f32,
+ diffused_error_g: f32,
+ diffused_error_b: f32,
+ pixel: Rgb<u8>,
+) -> (Rgb<u8>, [f32; 3]) {
+ let Rgb([r, g, b]) = pixel;
+ let (red, green, blue): (i32, i32, i32) = (r as i32, g as i32, b as i32);
+ let dist_to_black_r = -red as f32 + diffused_error_r;
+ let dist_to_white_r = 255. - red as f32 + diffused_error_r;
+
+ let dist_to_black_g = -green as f32 + diffused_error_g;
+ let dist_to_white_g = 255. - green as f32 + diffused_error_g;
+
+ let dist_to_black_b = -blue as f32 + diffused_error_b;
+ let dist_to_white_b = 255. - blue as f32 + diffused_error_b;
+
+ let mut ret_diffused_error: [f32; 3] = [0., 0., 0.];
+ let mut ret_pix = Rgb([255, 0, 0]);
+ ret_pix.0[0] = if dist_to_black_r.abs() < dist_to_white_r.abs() {
+ ret_diffused_error[0] = dist_to_black_r;
+ 0
+ } else {
+ ret_diffused_error[0] = dist_to_white_r;
+ 255
+ };
+ ret_pix.0[1] = if dist_to_black_g.abs() < dist_to_white_g.abs() {
+ ret_diffused_error[1] = dist_to_black_g;
+ 0
+ } else {
+ ret_diffused_error[1] = dist_to_white_g;
+ 255
+ };
+ ret_pix.0[2] = if dist_to_black_b.abs() < dist_to_white_b.abs() {
+ ret_diffused_error[2] = dist_to_black_b;
+ 0
+ } else {
+ ret_diffused_error[2] = dist_to_white_b;
+ 255
+ };
+
+ (ret_pix, ret_diffused_error)
+}
fn dither_integer_chose_8colors(
diffused_error_r: i32,
diffused_error_g: i32,
@@ -446,6 +512,168 @@ pub fn dither(image: &mut RgbImage, kernel: kernel::Kernel) {
*pixel_ = image::Rgb([pixel, pixel, pixel]);
}
}
+pub fn dither_ostromoukhov_1b_alt(image: &mut RgbImage) {
+ let (width, height) = image.dimensions();
+ let (width, height): (usize, usize) = (width as usize, height as usize);
+ let error_buffer_size = width + 1;
+ assert!(error_buffer_size > 0);
+ let mut error_diff: Vec<Vec<f32>> = vec![vec![0.; height]; width];
+
+ for y in 0..(height as u32) {
+ let serpentine_coef: i32 = if y % 2 == 0 { 1 } else { -1 };
+ for x in 0..(width as u32) {
+ let x = if y % 2 == 0 { x } else { width as u32 - 1 - x };
+
+ let Rgb([r, g, b]) = image.get_pixel(x, y);
+ let old_pixel = (*r as f32 + *g as f32 + *b as f32) as f32 / 3.;
+ // let (pixel, err) = dither_float_chose_color(error[err_pos as usize], pixel);
+ let (pixel, _) =
+ dither_atkinson_chose_color(0., error_diff[x as usize][y as usize] + old_pixel);
+ let pixel_u8 = old_pixel.clamp(0., 255.) as usize;
+ let sum = kernel::OSTROMOUKHOV_KERNELS[pixel_u8][0].weight
+ + kernel::OSTROMOUKHOV_KERNELS[pixel_u8][1].weight
+ + kernel::OSTROMOUKHOV_KERNELS[pixel_u8][2].weight;
+
+ let err = (old_pixel + error_diff[x as usize][y as usize]) - pixel as f32;
+
+ error_diff[x as usize][y as usize] = 0.;
+ for e in &kernel::OSTROMOUKHOV_KERNELS[pixel_u8] {
+ let (mut dx, dy) = (x as i32 + e.dx * serpentine_coef, y as i32 + e.dy);
+ while dx < 0 {
+ dx += width as i32;
+ }
+ let (dx, dy) = (dx as usize, dy as usize);
+
+ error_diff[dx][dy] = error_diff[dx][dy] + err * e.weight as f32 / sum as f32;
+ }
+
+ image.put_pixel(x, y, image::Rgb([pixel, pixel, pixel]));
+ }
+ }
+}
+pub fn dither_ostromoukhov_3b(image: &mut RgbImage) {
+ let (width, height) = image.dimensions();
+ let (width, height): (usize, usize) = (width as usize, height as usize);
+ let error_buffer_size = width + 1;
+ assert!(error_buffer_size > 0);
+ let mut error: [Vec<f32>; 3] = [
+ vec![0.; error_buffer_size],
+ vec![0.; error_buffer_size],
+ vec![0.; error_buffer_size],
+ ];
+
+ for y in 0..(height as u32) {
+ let serpentine_coef: i32 = if y % 2 == 0 { 1 } else { -1 };
+ for x in 0..(width as u32) {
+ let x = if y % 2 == 0 { x } else { width as u32 - 1 - x };
+
+ let old_pixel = image.get_pixel(x, y);
+ let mut new_pixel = Rgb([0, 0, 0]);
+
+ for color_index in 0..3 {
+ let pixel_u8 = old_pixel.0[color_index];
+ let err_pos: u32 = (y * width as u32 + x) % (error_buffer_size as u32);
+
+ // let (pixel, err) = dither_float_chose_color(error[err_pos as usize], pixel);
+ let (pixel, err) = dither_atkinson_chose_color(
+ error[color_index][err_pos as usize],
+ pixel_u8 as f32,
+ );
+ let sum = kernel::OSTROMOUKHOV_KERNELS[pixel_u8 as usize][0].weight
+ + kernel::OSTROMOUKHOV_KERNELS[pixel_u8 as usize][1].weight
+ + kernel::OSTROMOUKHOV_KERNELS[pixel_u8 as usize][2].weight;
+
+ error[color_index][err_pos as usize] = 0.;
+ for e in &kernel::OSTROMOUKHOV_KERNELS[pixel_u8 as usize] {
+ error[color_index][(err_pos as i32
+ + e.dx * serpentine_coef
+ + width as i32 * e.dy)
+ .rem_euclid(error_buffer_size as i32)
+ as usize] += err / sum as f32 * e.weight as f32;
+ }
+ new_pixel.0[color_index] = pixel;
+ }
+
+ image.put_pixel(x, y, new_pixel);
+ }
+ }
+}
+pub fn dither_ostromoukhov_1b_alt2(image: &mut RgbImage) {
+ let (width, height) = image.dimensions();
+ let (width, height): (usize, usize) = (width as usize, height as usize);
+ let error_buffer_size = width + 1;
+ assert!(error_buffer_size > 0);
+ let mut error_diff: Vec<Vec<f32>> = vec![vec![0.; height]; width];
+
+ for y in 0..(height as u32) {
+ let serpentine_coef: i32 = if y % 2 == 0 { 1 } else { -1 };
+ for x in 0..(width as u32) {
+ let x = if y % 2 == 0 { x } else { width as u32 - 1 - x };
+
+ let Rgb([r, g, b]) = image.get_pixel(x, y);
+ let old_pixel = (*r as f32 + *g as f32 + *b as f32) as f32 / 3.;
+ // let (pixel, err) = dither_float_chose_color(error[err_pos as usize], pixel);
+ //
+ let (pixel, err) =
+ dither_atkinson_chose_color(error_diff[x as usize][y as usize], old_pixel);
+ let pixel_u8 = old_pixel.clamp(0., 255.) as usize;
+ let sum = kernel::OSTROMOUKHOV_KERNELS[pixel_u8][0].weight
+ + kernel::OSTROMOUKHOV_KERNELS[pixel_u8][1].weight
+ + kernel::OSTROMOUKHOV_KERNELS[pixel_u8][2].weight;
+
+ error_diff[x as usize][y as usize] = 0.;
+ for e in &kernel::OSTROMOUKHOV_KERNELS[pixel_u8] {
+ let mut dx = x as i32 + e.dx * serpentine_coef;
+ let dy = y as i32 + e.dy;
+ while dx < 0 {
+ dx += width as i32;
+ }
+ let (dx, dy) = (dx as usize, dy as usize);
+
+ if dx >= width || dy >= height {
+ continue;
+ }
+ error_diff[dx as usize][dy as usize] += err / sum as f32 * e.weight as f32;
+ }
+
+ image.put_pixel(x, y, image::Rgb([pixel, pixel, pixel]));
+ }
+ }
+}
+pub fn dither_ostromoukhov_1b(image: &mut RgbImage) {
+ let (width, height) = image.dimensions();
+ let (width, height): (usize, usize) = (width as usize, height as usize);
+ let error_buffer_size = width + 1;
+ assert!(error_buffer_size > 0);
+ let mut error: Vec<f32> = vec![0.; error_buffer_size];
+
+ for y in 0..(height as u32) {
+ let serpentine_coef: i32 = if y % 2 == 0 { 1 } else { -1 };
+ for x in 0..(width as u32) {
+ let x = if y % 2 == 0 { x } else { width as u32 - 1 - x };
+
+ let Rgb([r, g, b]) = image.get_pixel(x, y);
+ let old_pixel = (*r as f32 + *g as f32 + *b as f32) as f32 / 3.;
+ let err_pos: u32 = (y * width as u32 + x) % (error_buffer_size as u32);
+
+ // let (pixel, err) = dither_float_chose_color(error[err_pos as usize], pixel);
+ let (pixel, err) = dither_atkinson_chose_color(error[err_pos as usize], old_pixel);
+ let pixel_u8 = old_pixel.clamp(0., 255.) as usize;
+ let sum = kernel::OSTROMOUKHOV_KERNELS[pixel_u8][0].weight
+ + kernel::OSTROMOUKHOV_KERNELS[pixel_u8][1].weight
+ + kernel::OSTROMOUKHOV_KERNELS[pixel_u8][2].weight;
+
+ error[err_pos as usize] = 0.;
+ for e in &kernel::OSTROMOUKHOV_KERNELS[pixel_u8] {
+ error[(err_pos as i32 + e.dx * serpentine_coef + width as i32 * e.dy)
+ .rem_euclid(error_buffer_size as i32) as usize] +=
+ err / sum as f32 * e.weight as f32;
+ }
+
+ image.put_pixel(x, y, image::Rgb([pixel, pixel, pixel]));
+ }
+ }
+}
pub fn dither_serpentine_1b(image: &mut RgbImage, kernel: kernel::Kernel) {
let (width, height) = image.dimensions();
let (width, height): (usize, usize) = (width as usize, height as usize);
@@ -887,3 +1115,1392 @@ pub fn dither_bayer(n: u32, image: &mut RgbImage) {
}
}
}
+
+///////////////////////////////////////////////////////////////////////////////////
+///////////////////////////////////////////////////////////////////////////////////
+///////////////////////////////////////////////////////////////////////////////////
+///////////////////////////////////////////////////////////////////////////////////
+
+// NOTE: Done and tested
+fn multiply_row_scalar(matrix: &mut Vec<Vec<f64>>, row: usize, scalar: f64) {
+ for value in &mut matrix[row] {
+ *value *= scalar;
+ }
+}
+// NOTE: Done and tested
+fn add_row_multiple(
+ matrix: &mut Vec<Vec<f64>>,
+ row_to_add: usize,
+ row_to_add_to: usize,
+ scalar: f64,
+) {
+ for index in 0..matrix[row_to_add].len() {
+ matrix[row_to_add_to][index] += matrix[row_to_add][index] * scalar;
+ }
+}
+
+// NOTE: Done
+// NOTE: Test done
+// TODO: Improve maybe
+fn invert_matrix(matrix: &mut Vec<Vec<f64>>) -> Vec<Vec<f64>> {
+ let (width, height) = (matrix[0].len(), matrix.len());
+ let mut result = vec![vec![0.; width]; height];
+
+ // Set result to identity matrix
+ for i in 0..height {
+ result[i][i] = 1.;
+ }
+
+ for i in 0..height {
+ let pivot = matrix[i][i];
+ multiply_row_scalar(&mut result, i, 1. / pivot);
+ multiply_row_scalar(matrix, i, 1. / pivot);
+
+ for j in (i + 1)..width {
+ let pivot = matrix[j][i];
+ add_row_multiple(&mut result, i, j, -pivot);
+ add_row_multiple(matrix, i, j, -pivot);
+ }
+ }
+
+ // Back substitue, mirroring in result (???!)
+ for i in (0..height).rev() {
+ for j in (0..i).rev() {
+ let pivot = matrix[j][i];
+ add_row_multiple(&mut result, i, j, -pivot);
+ add_row_multiple(matrix, i, j, -pivot);
+ }
+ }
+
+ result
+}
+
+pub fn scolorq_max_coarse_level(mut width: u32, mut height: u32) -> i32 {
+ // NOTE: Done, tested and working.
+
+ // We want the coarsest layer to have at most 4 000 pixels.
+ // coarsest mean "grossier", "rude" in french.
+
+ let max_pixels = 4_000;
+ let mut result = 0 as i32;
+ while width * height > max_pixels {
+ width >>= 1;
+ height >>= 1;
+ result += 1;
+ }
+
+ result
+}
+
+pub fn direct_product(a: Vec<Vec<[f64; 3]>>, b: Vec<Vec<[f64; 3]>>) -> Vec<Vec<[f64; 3]>> {
+ if a.len() != b.len() {
+ panic!("a and b must have the same length");
+ }
+ if a.len() == 0 || b.len() == 0 {
+ return vec![];
+ }
+ let mut result: Vec<Vec<[f64; 3]>> = Vec::with_capacity(a.len());
+ for i in 0..a.len() {
+ let mut row = Vec::with_capacity(a[0].len());
+ for j in 0..a[0].len() {
+ let val: [f64; 3] = [
+ a[i][j][0] * b[i][j][0],
+ a[i][j][1] * b[i][j][1],
+ a[i][j][2] * b[i][j][2],
+ ];
+ row.push(val);
+ }
+ result.push(row)
+ }
+
+ result
+}
+
+pub fn b_value(b: &Vec<Vec<[f64; 3]>>, i_x: i32, i_y: i32, j_x: i32, j_y: i32) -> [f64; 3] {
+ let b_width = b.len();
+ let b_height = b[0].len();
+ // δΈ­εΏƒη‚Ή ?!! Merci le LLM
+ let radius_width = (b_width - 1) / 2;
+ let radius_height = (b_height - 1) / 2;
+
+ let k_x = j_x + radius_width as i32 - i_x;
+ let k_y = j_y + radius_height as i32 - i_y;
+
+ // θΎΉη•Œε€„η† (Oh mon dieu! Le LLM s'emballe)
+ if k_x < 0 || k_y < 0 || k_x >= b_width as i32 || k_y >= b_height as i32 {
+ [0.0, 0.0, 0.0]
+ } else {
+ b[k_x as usize][k_y as usize]
+ }
+}
+
+pub fn compute_a_image(
+ image: &Vec<Vec<[f64; 3]>>,
+ a: &mut Vec<Vec<[f64; 3]>>,
+ b: &Vec<Vec<[f64; 3]>>,
+) {
+ // NOTE: Done and verified
+ let b_width = b.len();
+ let b_height = b[0].len();
+ let a_width = a.len();
+ let a_height = a[0].len();
+ let radius_width = (b_width as i32 - 1) / 2;
+ let radius_height = (b_height as i32 - 1) / 2;
+
+ let (_test_x, _test_y) = (0, 10);
+
+ for i_y in 0..(a_height as i32) {
+ for i_x in 0..(a_width as i32) {
+ for j_y_tmp in (i_y - radius_height)..(i_y + radius_height + 1) {
+ let j_y = j_y_tmp;
+ // Should be:
+ // let j_y = j_y.max(0).min(a_height - 1);
+ if j_y < 0 {
+ continue;
+ }
+ if j_y >= a_height as i32 {
+ break;
+ }
+ for j_x_tmp in (i_x - radius_width)..(i_x + radius_width + 1) {
+ let j_x = j_x_tmp;
+ // Should be:
+ // let j_x = j_x.max(0).min(a_height - 1);
+ if j_x < 0 {
+ continue;
+ }
+ if j_x >= a_width as i32 {
+ break;
+ }
+
+ let b_value_pixel = b_value(b, i_x, i_y, j_x, j_y);
+ let image_pixel = image[j_x as usize][j_y as usize];
+
+ for i in 0..3 {
+ a[i_x as usize][i_y as usize][i] += b_value_pixel[i] * image_pixel[i];
+ }
+
+ /*
+ if i_x == test_x && i_y == test_y {
+ println!("🦊: j_x, j_y; {} {}", j_x, j_y);
+ println!(
+ "🦊: b_value:{:?}, image_pixel:{:?}\na_value:{:?}, dprod:[{}, {}, {}]",
+ b_value_pixel,
+ image_pixel,
+ a[i_x as usize][i_y as usize],
+ b_value_pixel[0] * image_pixel[0],
+ b_value_pixel[1] * image_pixel[1],
+ b_value_pixel[2] * image_pixel[2],
+ );
+ }
+ */
+ }
+ }
+
+ for i in 0..3 {
+ a[i_x as usize][i_y as usize][i] *= -2.0;
+ }
+
+ /*
+ if i_x == test_x && i_y == test_y {
+ println!(
+ "a[{}][{}] = {:?}\n",
+ test_x, test_y, a[i_x as usize][i_y as usize]
+ );
+ }
+ */
+ }
+ }
+}
+
+// NOTE: Done and tested
+pub fn compute_b_array(filter_weights: &Vec<Vec<[f64; 3]>>, b: &mut Vec<Vec<[f64; 3]>>) {
+ // NOTE: Original comment
+ // Assume that the pixel i is always located at the center of b,
+ // and vary pixel j's location through each location in b.
+
+ let radius_width = (filter_weights.len() - 1) / 2;
+ let radius_height = (filter_weights[0].len() - 1) / 2;
+
+ let offset_x = (b.len() - 1) / 2 - radius_width;
+ let offset_y = (b[0].len() - 1) / 2 - radius_height;
+
+ for j_y in 0..b[0].len() {
+ for j_x in 0..b.len() {
+ for k_y in 0..filter_weights[0].len() {
+ for k_x in 0..filter_weights.len() {
+ if k_x as i32 + offset_x as i32 >= j_x as i32 - radius_width as i32
+ && k_x as i32 + offset_x as i32 <= j_x as i32 + radius_width as i32
+ && k_y as i32 + offset_y as i32 >= j_y as i32 - radius_height as i32
+ && k_y as i32 + offset_y as i32 <= j_y as i32 + radius_height as i32
+ {
+ for i in 0..3 {
+ let a = filter_weights[k_x][k_y][i];
+ let a_2 = filter_weights[k_x + offset_x + radius_width - j_x]
+ [k_y + offset_y + radius_height - j_y][i];
+ b[j_x][j_y][i] += a * a_2;
+ }
+ }
+ }
+ }
+ }
+ }
+}
+
+pub fn compute_a_array(
+ image: &Vec<Vec<[f64; 3]>>,
+ a: &mut Vec<Vec<[f64; 3]>>,
+ b: &Vec<Vec<[f64; 3]>>,
+) {
+ // NOTE: Check compute_a_image
+ panic!("Do not use");
+ let radius_width = (b.len() as i32 - 1) / 2;
+ let radius_height = (b[0].len() as i32 - 1) / 2;
+
+ for i_y in 0..(a.len() as i32) {
+ for i_x in 0..(a[0].len() as i32) {
+ for mut j_y in (i_y - radius_height)..(i_y + radius_height) {
+ if j_y < 0 {
+ j_y = 0; // NOTE: Maybe continue instead
+ }
+ if j_y >= a[0].len() as i32 {
+ break; // NOTE: BREAK ?!?! Ok maybe legit
+ }
+ for mut j_x in (i_x - radius_width)..(i_x + radius_width) {
+ if j_x < 0 {
+ j_x = 0; // NOTE: Maybe continue instead
+ }
+ if j_x >= a.len() as i32 {
+ break; // NOTE: BREAK ?!?! Ok maybe legit
+ }
+ let tmp_ret = b_value(b, i_x, i_y, j_x, j_y);
+ let image_pixel = image[j_x as usize][j_y as usize];
+
+ if i_x == 10 && i_y == 10 {
+ /*
+ println!(
+ "🐸 DEBUG: b_value:{:?}, image_pixel:{:?}",
+ tmp_ret, image_pixel
+ );
+ */
+ }
+
+ // directe direct_product
+ for i in 0..3 {
+ a[i_x as usize][i_y as usize][i] += tmp_ret[i] * image_pixel[i];
+ }
+ }
+ }
+ for i in 0..3 {
+ a[i_x as usize][i_y as usize][i] *= -2.0;
+ }
+ }
+ }
+}
+
+pub fn sum_coarsen(fine: &Vec<Vec<[f64; 3]>>, coarse: &mut Vec<Vec<[f64; 3]>>) {
+ // NOTE: Done
+ // TODO: To test
+
+ for y in 0..coarse[0].len() {
+ for x in 0..coarse.len() {
+ let mut _divisor = 1.0;
+ let mut val = fine[x * 2][y * 2];
+ if x * 2 + 1 < fine.len() {
+ _divisor += 1.0;
+ for i in 0..3 {
+ val[i] += fine[x * 2 + 1][y * 2][i];
+ }
+ }
+ if y * 2 + 1 < fine[0].len() {
+ _divisor += 1.0;
+ for i in 0..3 {
+ val[i] += fine[x * 2][y * 2 + 1][i];
+ }
+ }
+ if x * 2 + 1 < fine.len() && y * 2 + 1 < fine[0].len() {
+ _divisor += 1.0;
+ for i in 0..3 {
+ val[i] += fine[x * 2 + 1][y * 2 + 1][i];
+ }
+ }
+
+ for i in 0..3 {
+ coarse[x][y][i] += /*(1/divisor)**/val[i];
+ }
+ }
+ }
+}
+
+pub fn compute_initial_s(
+ s: &mut Vec<Vec<[f64; 3]>>,
+ coarse_variables: &Vec<Vec<Vec<f64>>>,
+ b: &Vec<Vec<[f64; 3]>>,
+) {
+ // NOTE: Done and tested
+ let palette_size = s.len();
+ let b_width = b.len();
+ let b_height = b[0].len();
+ let coarse_width = coarse_variables.len();
+ let coarse_height = coarse_variables[0].len();
+
+ let center_x = (b.len() - 1) >> 1;
+ let center_y = (b[0].len() - 1) >> 1;
+
+ let center_b = b_value(b, 0, 0, 0, 0);
+
+ for v in 0..palette_size {
+ for alpha in v..palette_size {
+ s[v][alpha] = [0.; 3];
+ }
+ }
+
+ for i_y in 0..coarse_height {
+ for i_x in 0..coarse_width {
+ let max_j_y = cmp::min(
+ coarse_height as i32,
+ i_y as i32 - center_y as i32 + b_height as i32,
+ ) as usize;
+ let max_j_x = cmp::min(
+ coarse_width as i32,
+ i_x as i32 - center_x as i32 + b_width as i32,
+ ) as usize;
+ let min_j_y = cmp::max(0, i_y as i32 - center_y as i32) as usize;
+ let min_j_x = cmp::max(0, i_x as i32 - center_x as i32) as usize;
+ for j_y in min_j_y..max_j_y {
+ for j_x in min_j_x..max_j_x {
+ if i_x == j_x && i_y == j_y {
+ continue;
+ }
+ let b_ij = b_value(b, i_x as i32, i_y as i32, j_x as i32, j_y as i32);
+ for v in 0..palette_size {
+ for alpha in v..palette_size {
+ let mult =
+ coarse_variables[i_x][i_y][v] * coarse_variables[j_x][j_y][alpha];
+ s[v][alpha][0] += mult * b_ij[0];
+ s[v][alpha][1] += mult * b_ij[1];
+ s[v][alpha][2] += mult * b_ij[2];
+ }
+ }
+ }
+ }
+ for v in 0..palette_size {
+ s[v][v][0] += coarse_variables[i_x][i_y][v] * center_b[0];
+ s[v][v][1] += coarse_variables[i_x][i_y][v] * center_b[1];
+ s[v][v][2] += coarse_variables[i_x][i_y][v] * center_b[2];
+ }
+ }
+ }
+}
+
+pub fn compute_initial_j_palette_sum(
+ j_palette_sum: &mut Vec<Vec<[f64; 3]>>,
+ coarse_variables: &Vec<Vec<Vec<f64>>>,
+ palette: &Vec<(f64, f64, f64)>,
+) {
+ // NOTE: Done
+ // TEST: Work on the first try. Must check coarse_variables.
+ //
+ println!("🀞🀞🀞🀞🀞🀞🀞🀞🀞🀞🀞🀞🀞compute_initial_j_palette_sum !!!!!!!");
+ let mut sum_init_j: f64 = 0.;
+ for j_y in 0..coarse_variables[0].len() {
+ for j_x in 0..coarse_variables.len() {
+ let mut palette_sum = [0.; 3];
+ for alpha in 0..palette.len() {
+ palette_sum[0] += coarse_variables[j_x][j_y][alpha] * palette[alpha].0;
+ palette_sum[1] += coarse_variables[j_x][j_y][alpha] * palette[alpha].1;
+ palette_sum[2] += coarse_variables[j_x][j_y][alpha] * palette[alpha].2;
+ }
+ j_palette_sum[j_x][j_y] = palette_sum;
+ sum_init_j += palette_sum[0];
+ sum_init_j += palette_sum[1];
+ sum_init_j += palette_sum[2];
+ }
+ }
+
+ // println!("@@@@@@@@@@@@@@@@@@@ Sum initial J: {:.6}", sum_init_j);
+}
+
+pub fn extract_vector_layer_2d(s: &Vec<Vec<[f64; 3]>>, k: usize) -> Vec<Vec<f64>> {
+ let mut result = vec![vec![0.; s[0].len()]; s.len()];
+ for i in 0..s.len() {
+ for j in 0..s[0].len() {
+ result[i][j] = s[i][j][k]
+ }
+ }
+
+ result
+}
+pub fn extract_vector_layer_1d(s: &Vec<[f64; 3]>, k: usize) -> Vec<f64> {
+ let mut result = Vec::with_capacity(s.len());
+ for i in 0..s.len() {
+ result.push(s[i][k])
+ }
+
+ result
+}
+
+pub fn refine_palette(
+ s: &Vec<Vec<[f64; 3]>>,
+ coarse_variables: &Vec<Vec<Vec<f64>>>,
+ a: &Vec<Vec<[f64; 3]>>,
+ palette: &mut Vec<(f64, f64, f64)>,
+) {
+ // TODO: done
+ // To test
+ // BUG: To test
+ // Must have an error
+ // The error seems to be from coarse variable
+
+ println!("##################### Refine palette");
+ print_palette(palette);
+
+ let mut sum_coarse_variables = 0.;
+ // Ici, vΓ©rifier les valeurs de coarse_variables
+ let mut r = vec![[0.; 3]; palette.len()];
+ for v in 0..palette.len() {
+ for i_y in 0..coarse_variables[0].len() {
+ for i_x in 0..coarse_variables.len() {
+ for i in 0..3 {
+ r[v][i] += coarse_variables[i_x][i_y][v] * a[i_x][i_y][i];
+ }
+ sum_coarse_variables += coarse_variables[i_x][i_y][v];
+ }
+ }
+ }
+
+ /*
+ for v in 0..palette.len() {
+ println!("v: {}", v);
+ for i_y in 0..5 {
+ for i_x in 0..5 {
+ print!("[{:.5}]", coarse_variables[i_x][i_y][v])
+ }
+ println!()
+ }
+ println!()
+ }
+ */
+
+ println!(
+ "Coarse variables: {:?} ({:.5})",
+ sum_coarse_variables, coarse_variables[1][1][1]
+ );
+
+ let mut palette_tmp = vec![[0.; 3]; palette.len()];
+ for v in 0..palette.len() {
+ palette_tmp[v][0] = palette[v].0;
+ palette_tmp[v][1] = palette[v].1;
+ palette_tmp[v][2] = palette[v].2;
+ }
+
+ for k in 0..3 {
+ // NOTE: VΓ©rifier ces deux fonctions
+ let mut s_k = extract_vector_layer_2d(s, k);
+ let r_k = extract_vector_layer_1d(&r, k);
+
+ for i in 0..s_k.len() {
+ for j in 0..s_k[0].len() {
+ s_k[i][j] *= 2.;
+ }
+ }
+
+ let palette_channel_mat = invert_matrix(&mut s_k);
+ let mut palette_channel = vec![0.; s_k.len()];
+ for i in 0..s_k.len() {
+ for j in 0..s_k[0].len() {
+ palette_channel[i] += r_k[j] * palette_channel_mat[i][j] * -1.;
+ }
+ }
+
+ for v in 0..palette.len() {
+ let mut val = palette_channel[v];
+ if val < 0. {
+ val = 0.
+ } else if val > 1. {
+ val = 1.
+ }
+ palette_tmp[v][k] = val;
+ }
+ }
+ for v in 0..palette.len() {
+ palette[v].0 = palette_tmp[v][0];
+ palette[v].1 = palette_tmp[v][1];
+ palette[v].2 = palette_tmp[v][2];
+ }
+
+ print_palette(palette);
+ println!("##################### End refine palette");
+}
+
+pub fn random_permutation_1d(count: usize, queue: &mut VecDeque<i32>, rng: &mut u32) {
+ // NOTE: Done and tested !
+ for i in 0..count {
+ queue.push_back(i as i32);
+ }
+ // shuffle
+ queue.make_contiguous();
+
+ for i in (1..count).rev() {
+ let rand_number = rand_(rng) % (i as u32 + 1);
+ queue.swap(i, rand_number as usize);
+ }
+}
+
+pub fn random_permutation_2d(
+ width: usize,
+ height: usize,
+ queue: &mut VecDeque<(i32, i32)>,
+ rng: &mut u32,
+) {
+ // NOTE: Done and tested !
+ // WARN: Should be improved.
+ let mut perm1d: VecDeque<i32> = VecDeque::with_capacity(width * height);
+ random_permutation_1d(width * height, &mut perm1d, rng);
+ while !perm1d.is_empty() {
+ let rand = perm1d.pop_back().unwrap();
+ queue.push_back((rand % width as i32, rand / width as i32));
+ }
+}
+
+pub fn best_match_color(
+ coarse_variables: &Vec<Vec<Vec<f64>>>,
+ i_x: usize,
+ i_y: usize,
+ palette: &Vec<(f64, f64, f64)>,
+) -> usize {
+ let mut max_v = 0;
+ let mut max_weight = coarse_variables[i_x][i_y][0];
+ for v in 1..palette.len() {
+ let weight = coarse_variables[i_x][i_y][v];
+ if weight > max_weight {
+ max_v = v;
+ max_weight = weight;
+ }
+ }
+
+ return max_v;
+}
+
+pub fn update_s(
+ s: &mut Vec<Vec<[f64; 3]>>,
+ coarse_variables: &Vec<Vec<Vec<f64>>>,
+ b: &Vec<Vec<[f64; 3]>>,
+ j_x: i32,
+ j_y: i32,
+ alpha: i32,
+ delta: f64,
+) {
+ // TEST: Done
+ // WARN: Must be tested
+ // BUG: It doesn't work as expected, there is a bug.
+ let palette_size = s.len() as usize;
+ let coarse_width = coarse_variables.len();
+ let coarse_height = coarse_variables[0].len();
+ let center_x = (b.len() as i32 - 1) / 2;
+ let center_y = (b[0].len() as i32 - 1) / 2;
+
+ let max_i_x = cmp::min(coarse_width as i32, j_x + center_x + 1) as usize;
+ let max_i_y = cmp::min(coarse_height as i32, j_y + center_y + 1) as usize;
+ let min_i_x = cmp::max(0, j_x as i32 - center_y as i32) as usize;
+ let min_i_y = cmp::max(0, j_y as i32 - center_y as i32) as usize;
+
+ for i_y in min_i_y..max_i_y {
+ for i_x in min_i_x..max_i_x {
+ let mut delta_b_ij = b_value(b, i_x as i32, i_y as i32, j_x, j_y);
+ delta_b_ij[0] *= delta as f64;
+ delta_b_ij[1] *= delta as f64;
+ delta_b_ij[2] *= delta as f64;
+
+ if i_x == j_x as usize && i_y == j_y as usize {
+ continue;
+ }
+ for v in 0..=alpha {
+ let mult = coarse_variables[i_x][i_y][v as usize];
+ s[v as usize][alpha as usize][0] += mult * delta_b_ij[0];
+ s[v as usize][alpha as usize][1] += mult * delta_b_ij[1];
+ s[v as usize][alpha as usize][2] += mult * delta_b_ij[2];
+ }
+ for v in (alpha as usize)..palette_size {
+ let mult = coarse_variables[i_x][i_y][v as usize];
+
+ s[alpha as usize][v as usize][0] += mult * delta_b_ij[0];
+ s[alpha as usize][v as usize][1] += mult * delta_b_ij[1];
+ s[alpha as usize][v as usize][2] += mult * delta_b_ij[2];
+ }
+ }
+ }
+
+ // NOTE: I'm pretty sure I forgot to code this.
+ // Here it is if I need them.
+ let zero_b = b_value(b, 0, 0, 0, 0);
+
+ s[alpha as usize][alpha as usize][0] += delta * zero_b[0];
+ s[alpha as usize][alpha as usize][1] += delta * zero_b[1];
+ s[alpha as usize][alpha as usize][2] += delta * zero_b[2];
+
+ let mut _sum_update_s: f64 = 0.;
+ for i in 0..palette_size {
+ for j in 0..palette_size {
+ for v in 0..3 {
+ _sum_update_s += s[i][j][v];
+ }
+ }
+ }
+ if alpha == 1 {
+ // println!("####################### sum_update_s: {}", _sum_update_s);
+ }
+
+ // BUG: Should print something. It doesn't
+ // if (_sum_update_s - 2531554.643253).abs() < 0.0001 {
+ // println!("####################### sum_update_s: {}", _sum_update_s);
+ // }
+}
+
+pub fn norm_squared(v: &Vec<f64>) -> f64 {
+ let mut sum = 0.;
+ for i in 0..v.len() {
+ sum += v[i] * v[i];
+ }
+
+ return sum;
+}
+
+pub fn zoom_double(small: &Vec<Vec<Vec<f64>>>, big: &mut Vec<Vec<Vec<f64>>>) {
+ println!(
+ "====== Zooming from {}x{} to {}x{}",
+ small.len(),
+ small[0].len(),
+ big.len(),
+ big[0].len()
+ );
+ let mut sum_small = 0.;
+ let mut sum_big = 0.;
+
+ for y in 0..small.len() {
+ for x in 0..small[0].len() {
+ sum_small += small[y][x][0];
+ }
+ }
+ for y in 0..big.len() {
+ for x in 0..big[0].len() {
+ sum_big += big[y][x][0];
+ }
+ }
+ println!("Sum of small: {}", sum_small);
+ println!("Sum of big: {}", sum_big);
+
+ // Simple scaling of the weights array based on mixing the four
+ // pixels falling under each fine pixel, weighted by area.
+ // To mix the pixels a little, we assume each fine pixel
+ // is 1.2 fine pixels wide and high.
+ let (width_small, height_small) = (small.len(), small[0].len());
+ let (width_big, height_big, deep_big) = (big.len(), big[0].len(), big[0][0].len());
+ let (width_big_div, height_big_div) = ((width_big >> 1) * 2, (height_big >> 1) * 2);
+
+ for y in 0..height_big_div {
+ for x in 0..width_big_div {
+ let left = (0. as f64).max((x as f64 - 0.1) / 2.0);
+ let right = (width_small as f64 - 0.001).min((x as f64 + 1.1) / 2.0);
+
+ let top = (0. as f64).max((y as f64 - 0.1) / 2.0);
+ let bottom = (height_small as f64 - 0.001).min((y as f64 + 1.1) / 2.0);
+
+ let x_left = left.floor() as usize;
+ let x_right = right.floor() as usize;
+ let y_top = top.floor() as usize;
+ let y_bottom = bottom.floor() as usize;
+
+ let area = (right - left) * (bottom - top);
+ let top_left_weight = ((left.ceil() - left) * (top.ceil() - top)) / area;
+ let top_right_weight = ((right - right.floor()) * (top.ceil() - top)) / area;
+ let bottom_left_weight = ((left.ceil() - left) * (bottom - bottom.floor())) / area;
+ let bottom_right_weight = ((right - right.floor()) * (bottom - bottom.floor())) / area;
+
+ let top_weight = ((right - left) * (top.ceil() - top)) / area;
+ let bottom_weight = ((right - left) * (bottom - bottom.floor())) / area;
+ let left_weight = ((bottom - top) * (left.ceil() - left)) / area;
+ let right_weight = ((bottom - top) * (right - right.floor())) / area;
+
+ for z in 0..deep_big {
+ if x_left == x_right && y_top == y_bottom {
+ big[x][y][z] = small[x_left][y_top][z]
+ } else if x_left == x_right {
+ big[x][y][z] = small[x_left][y_top][z] * top_weight
+ + small[x_left][y_bottom][z] * bottom_weight;
+ } else if y_top == y_bottom {
+ big[x][y][z] = small[x_left][y_top][z] * left_weight
+ + small[x_right][y_top][z] * right_weight;
+ } else {
+ big[x][y][z] = small[x_left][y_top][z] * top_left_weight
+ + small[x_left][y_bottom][z] * bottom_left_weight
+ + small[x_right][y_top][z] * top_right_weight
+ + small[x_right][y_bottom][z] * bottom_right_weight;
+ }
+ }
+ }
+ }
+
+ let mut sum_small = 0.;
+ let mut sum_big = 0.;
+
+ for y in 0..small.len() {
+ for x in 0..small[0].len() {
+ sum_small += small[y][x][0];
+ }
+ }
+ for y in 0..big.len() {
+ for x in 0..big[0].len() {
+ sum_big += big[y][x][0];
+ }
+ }
+ println!("Sum of small: {}", sum_small);
+ println!("Sum of big: {}", sum_big);
+
+ println!("==== Done zooming");
+}
+
+pub fn print_palette(palette: &Vec<(f64, f64, f64)>) {
+ print!("Palette: ");
+ for v in 0..palette.len() {
+ print!(
+ "[{:.4},{:.4},{:.4}] ",
+ palette[v].0, palette[v].1, palette[v].2
+ )
+ }
+ println!()
+}
+pub fn dither_scolorq(image_in: &mut RgbImage, _palette_size: u8) {
+ // let matrix = vec![vec![6., 1., 1.], vec![4., -2., 5.], vec![2., 8., 7.]];
+ // let res = invert_matrix(&mut matrix);
+ let (width, height) = image_in.dimensions();
+
+ let palette_size = 6;
+
+ let ditherring_level =
+ 0.09 * ((width * height) as f64).ln() - 0.04 * (palette_size as f64).ln() + 0.001;
+
+ println!("Dimensions: {}x{}", width, height);
+ println!("Palette size: {}", palette_size);
+ println!("Dithering level: {}", ditherring_level);
+
+ let mut rng: u32 = 42;
+
+ let mut image = vec![vec![[0.; 3]; width as usize]; height as usize];
+ let _filter_weights_1 = vec![vec![[0.; 3]; 1]; 1];
+ let mut filter_weights_3 = vec![vec![[1.; 3]; 3]; 3];
+ let mut filter_weights_5 = vec![vec![[0.; 3]; 5]; 5];
+ let mut quantized_image = vec![vec![0; width as usize]; height as usize];
+
+ let mut palette: Vec<(f64, f64, f64)> = Vec::with_capacity(palette_size);
+
+ for _ in 0..palette_size {
+ let color: (f64, f64, f64) = (
+ rand_double(&mut rng),
+ rand_double(&mut rng),
+ rand_double(&mut rng),
+ );
+ palette.push(color);
+ }
+
+ for x in 0..width {
+ for y in 0..height {
+ for c in 0..3 {
+ image[x as usize][y as usize][c] = image_in.get_pixel(x, y).0[c] as f64 / 255.;
+ }
+ }
+ }
+ let mut _sum = 0.;
+ for i in 0..3 {
+ for j in 0..3 {
+ for k in 0..3 {
+ let tmp_val = (i as i32 - 1) * (i as i32 - 1) + (j as i32 - 1) * (j as i32 - 1);
+ let tmp_val = -f64::sqrt(tmp_val as f64) / (ditherring_level * ditherring_level);
+ let tmp_val = tmp_val.exp();
+ filter_weights_3[i][j][k] = tmp_val;
+ _sum += tmp_val;
+ }
+ }
+ }
+
+ // println!("Sum: {}", _sum);
+
+ _sum /= 3.;
+ for i in 0..3 {
+ for j in 0..3 {
+ for k in 0..3 {
+ filter_weights_3[i][j][k] /= _sum;
+ }
+ }
+ }
+
+ _sum = 0.;
+ for i in 0..5 {
+ for j in 0..5 {
+ for k in 0..3 {
+ let tmp_val = (i as i32 - 2) * (i as i32 - 2) + (j as i32 - 2) * (j as i32 - 2);
+ let tmp_val = -f64::sqrt(tmp_val as f64) / (ditherring_level * ditherring_level);
+ let tmp_val = tmp_val.exp();
+ filter_weights_5[i][j][k] = tmp_val;
+ _sum += tmp_val;
+ }
+ }
+ }
+
+ // println!("Sum5: {}", sum);
+
+ _sum /= 3.;
+ for i in 0..5 {
+ for j in 0..5 {
+ for k in 0..3 {
+ filter_weights_5[i][j][k] /= _sum;
+ }
+ }
+ }
+
+ let initial_temperature = 1.0;
+ let final_temperature = 0.001;
+ let temps_per_level = 3;
+ let repeats_per_temp = 1;
+
+ let max_coarse_level: i32 = scolorq_max_coarse_level(width, height);
+ let mut coarse_variables =
+ vec![
+ vec![vec![0.; palette_size]; (width >> max_coarse_level) as usize];
+ (height >> max_coarse_level) as usize
+ ];
+
+ // NOTE: The initialisation is tested
+ let mut pcoarse_variables =
+ vec![
+ vec![vec![0.; palette_size]; (width >> max_coarse_level) as usize];
+ (height >> max_coarse_level) as usize
+ ];
+ for i in 0..(pcoarse_variables.len() as usize) {
+ for j in 0..(pcoarse_variables[0].len() as usize) {
+ for c in 0..palette_size {
+ pcoarse_variables[i][j][c] = rand_double(&mut rng);
+ coarse_variables[i][j][c] = pcoarse_variables[i][j][c];
+ }
+ }
+ }
+ let mut temperature = 1.0;
+
+ // filter_size = 3
+ let extended_neighborhood_width = filter_weights_3.len() * 2 - 1;
+ let extended_neighborhood_height = filter_weights_3[0].len() * 2 - 1;
+ let mut b0 = vec![
+ vec![[0.; 3]; extended_neighborhood_width as usize];
+ extended_neighborhood_height as usize
+ ];
+
+ /*
+ for i in 0..3 {
+ println!("\nfilter_weights_3[{}]", i);
+ for i in 0..filter_weights_3.len() {
+ for j in 0..filter_weights_3[0].len() {
+ print!("[{}]", filter_weights_3[i][j][i]);
+ }
+ println!()
+ }
+ }
+ */
+
+ compute_b_array(&filter_weights_3, &mut b0);
+ let mut _sum_b0: f64 = 0.;
+ for _k in 0..3 {
+ for i in 0..b0.len() {
+ for j in 0..b0[0].len() {
+ // print!("[{}]", b0[i][j][k]);
+ _sum_b0 += b0[i][j][0] + b0[i][j][1] + b0[i][j][2];
+ }
+ }
+ }
+ let mut a0 = vec![vec![[0.; 3]; width as usize]; height as usize];
+
+ compute_a_image(&image, &mut a0, &b0);
+
+ // Compute a_I^l, b_{IJ}^l according to (18)
+ let mut a_vec: Vec<Vec<Vec<[f64; 3]>>> = Vec::new();
+ let mut b_vec: Vec<Vec<Vec<[f64; 3]>>> = Vec::new();
+ let mut last_bvec_width = b0.len();
+ let mut last_bvec_height = b0[0].len();
+ a_vec.push(a0);
+ b_vec.push(b0);
+
+ for coarse_level in 1..(max_coarse_level + 1) {
+ let b_last = b_vec.last().unwrap();
+ let a_last = a_vec.last().unwrap();
+
+ let radius_width = (filter_weights_3.len() - 1) / 2;
+ let radius_height = (filter_weights_3[0].len() - 1) / 2;
+ let bi_width = cmp::max(3, last_bvec_width - 2);
+ let bi_height = cmp::max(3, last_bvec_height - 2);
+ last_bvec_width = bi_width;
+ last_bvec_height = bi_height;
+
+ let mut bi: Vec<Vec<[f64; 3]>> = vec![vec![[0.; 3]; bi_width as usize]; bi_height as usize];
+
+ for j_j_y in 0..bi_height {
+ for j_j_x in 0..bi_width {
+ for i_y in (radius_height * 2)..(radius_height * 2 + 2) {
+ for i_x in (radius_width * 2)..(radius_width * 2 + 2) {
+ for j_y in (j_j_y * 2)..(j_j_y * 2 + 2) {
+ for j_x in (j_j_x * 2)..(j_j_x * 2 + 2) {
+ let b_v =
+ b_value(b_last, i_x as i32, i_y as i32, j_x as i32, j_y as i32);
+ for i in 0..3 {
+ bi[j_j_x][j_j_y][i] += b_v[i];
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ b_vec.push(bi);
+
+ let ai_width = image.len() >> coarse_level;
+ let ai_height = image[0].len() >> coarse_level;
+ let mut ai: Vec<Vec<[f64; 3]>> = vec![vec![[0.; 3]; ai_width as usize]; ai_height as usize];
+ let mut sum_ai: f64 = 0.;
+ sum_coarsen(a_last, &mut ai);
+
+ for i in 0..ai.len() {
+ for j in 0..ai[0].len() {
+ sum_ai += ai[i][j][0] + ai[i][j][1] + ai[i][j][2];
+ }
+ }
+ a_vec.push(ai);
+ }
+
+ // Multiscale annealing
+ let mut coarse_level: i32 = max_coarse_level;
+ let iters_per_level = temps_per_level;
+
+ let temperature_multiplier: f64 = f64::powf(
+ final_temperature / initial_temperature,
+ 1.0 / ((cmp::max(3, max_coarse_level * iters_per_level)) as f64),
+ );
+
+ // println!("Temperature multiplier: {}", temperature_multiplier);
+
+ let mut iters_at_current_level = 0;
+ let mut skip_palette_maintenance = false;
+
+ let mut s = vec![vec![[0.; 3]; palette_size]; palette_size];
+ compute_initial_s(&mut s, &coarse_variables, &b_vec[coarse_level as usize]);
+
+ // BUG: Isn't the same as in C++
+ // for v in 0..3 {
+ // for i in 0..5 {
+ // for j in 0..5 {
+ // print!("[{}]", s[i][j][v]);
+ // }
+ // println!();
+ // }
+ // println!();
+ // }
+
+ let mut j_palette_sum = vec![vec![[0.; 3]; coarse_variables.len()]; coarse_variables[0].len()];
+ compute_initial_j_palette_sum(&mut j_palette_sum, &coarse_variables, &palette);
+
+ while coarse_level >= 0 || temperature > final_temperature {
+ // Need to reseat this reference in case we changed p_coarse_variables
+ coarse_variables = vec![
+ vec![vec![0.; palette_size]; pcoarse_variables.len() as usize];
+ pcoarse_variables[0].len() as usize
+ ];
+
+ println!("1x 🍌🍌🍌🍌🍌🍌🍌🍌🍌🍌🍌🍌🍌🍌");
+ for i in 0..pcoarse_variables.len() {
+ for j in 0..pcoarse_variables[0].len() {
+ for v in 0..palette_size {
+ coarse_variables[i][j][v] = pcoarse_variables[i][j][v];
+ }
+ }
+ }
+
+ let mut a = &mut a_vec[coarse_level as usize];
+ let b = &b_vec[coarse_level as usize];
+ let mut middle_b = b_value(b, 0, 0, 0, 0);
+
+ // println!(
+ // "coarse_level: {} / Temperature: {}",
+ // coarse_level, temperature
+ // );
+
+ let center_x = (b.len() - 1) >> 1;
+ let center_y = (b[0].len() - 1) >> 1;
+ let mut step_counter = 0;
+
+ for _repeat in 0..repeats_per_temp {
+ let mut pixels_changed = 0;
+ let mut _pixel_visited = 0;
+ let mut visit_queue: VecDeque<(i32, i32)> = VecDeque::new();
+ let coarse_variables_width = coarse_variables.len();
+ let coarse_variables_height = coarse_variables[0].len();
+
+ println!("Rng: {}", rng);
+ random_permutation_2d(
+ coarse_variables_width,
+ coarse_variables_height,
+ &mut visit_queue,
+ &mut rng,
+ );
+ for v in 0..palette.len() {
+ println!("v: {}", v);
+ for i_y in 0..5 {
+ for i_x in 0..5 {
+ print!("[{:.5}]", coarse_variables[i_x][i_y][v])
+ }
+ println!()
+ }
+ println!()
+ }
+
+ // println!("Visit queue size: {}", visit_queue.len());
+ // if _repeat == 0 && temperature == initial_temperature {
+ // println!("Visit queue: {:?}", visit_queue);
+ // }
+
+ while !visit_queue.is_empty() {
+ // println!("j_palette_sum[1][9]: {:.7}", j_palette_sum[1][9][0]);
+ if visit_queue.len() > coarse_variables_width * coarse_variables_height * 11 / 10 {
+ visit_queue.clear();
+ random_permutation_2d(
+ coarse_variables_width,
+ coarse_variables_height,
+ &mut visit_queue,
+ &mut rng,
+ );
+ }
+
+ let (i_x, i_y) = visit_queue.pop_front().unwrap();
+
+ // Compute (25)
+ let mut p_i = [0.; 3];
+ for y in 0..b[0].len() {
+ for x in 0..b.len() {
+ let j_x = x as i32 - center_x as i32 + i_x;
+ let j_y = y as i32 - center_y as i32 + i_y;
+ if i_x == j_x && i_y == j_y {
+ continue;
+ }
+ if j_x < 0
+ || j_x >= coarse_variables_width as i32
+ || j_y < 0
+ || j_y >= coarse_variables_height as i32
+ {
+ continue;
+ }
+
+ let b_ij = b_value(b, i_x, i_y, j_x, j_y);
+ let j_pal = j_palette_sum[j_x as usize][j_y as usize];
+ // if pixels_changed >= 15 {
+ // println!(
+ // "p_i[0] = {:.5} ({:.5} + {:.5}), j_x, j_y: {}, {}",
+ // p_i[0], b_ij[0], j_pal[0], j_x, j_y
+ // );
+ // }
+
+ p_i[0] += b_ij[0] * j_pal[0];
+ p_i[1] += b_ij[1] * j_pal[1];
+ p_i[2] += b_ij[2] * j_pal[2];
+ }
+ }
+ // if pixels_changed >= 16 {
+ // println!(
+ // "p_i[0]: {:.7} / a[{}][{}]: {:.7}",
+ // p_i[0], i_x, i_y, a[i_x as usize][i_y as usize][0]
+ // );
+ // }
+
+ p_i[0] = p_i[0] * 2.0 + a[i_x as usize][i_y as usize][0];
+ p_i[1] = p_i[1] * 2.0 + a[i_x as usize][i_y as usize][1];
+ p_i[2] = p_i[2] * 2.0 + a[i_x as usize][i_y as usize][2];
+
+ let mut meanfield_logs: Vec<f64> = Vec::new();
+ let mut meanfields: Vec<f64> = Vec::new();
+ let mut max_meanfield_log = f64::NEG_INFINITY;
+ let mut meanfield_sum = 0.;
+
+ for v in 0..palette_size {
+ // Update m_{pi(i)v}^I according to (23)
+ // We can subtract an arbitrary factor to prevent overflow,
+ // since only the weight relative to the sum matters, so we
+ // will choose a value that makes the maximum e^100.
+ let palette_v = [palette[v].0, palette[v].1, palette[v].2];
+ if pixels_changed >= 16 {
+ // println!(
+ // "Palette: {:.7}, {:.7}, {:.7}",
+ // palette_v[0], palette_v[1], palette_v[2]
+ // );
+ // println!("P_i: ({:.7}, {:.7}, {:.7})", p_i[0], p_i[1], p_i[2]);
+ }
+
+ let mut middle_b_tmp = vec![0.; middle_b.len()];
+ for i in 0..middle_b.len() {
+ middle_b_tmp[i] = middle_b[i] * palette_v[i];
+ }
+ let mut middle_b_p_i_sum = 0.;
+ for i in 0..middle_b_tmp.len() {
+ middle_b_p_i_sum += (middle_b_tmp[i] + p_i[i]) * palette_v[i];
+ }
+ let meanfield_logs_last = -(middle_b_p_i_sum / temperature);
+ meanfield_logs.push(meanfield_logs_last);
+ if pixels_changed >= 16 {
+ // println!(
+ // "temperature: {:.7} / meanfield_logs[0]: {:.7}",
+ // temperature, meanfield_logs_last
+ // );
+ }
+ if meanfield_logs_last > max_meanfield_log {
+ max_meanfield_log = meanfield_logs_last;
+ }
+ }
+
+ for v in 0..palette.len() {
+ let tmp = f64::exp(meanfield_logs[v] - max_meanfield_log + 100.);
+ meanfields.push(tmp);
+ meanfield_sum += tmp;
+ }
+ // println!(
+ // "Meanfield_sum: {:.7} / max_meanfield_log: {:.7}",
+ // meanfield_sum, max_meanfield_log
+ // );
+ if meanfield_sum == 0. {
+ println!("Fatal errorr: Meanfield sum underflowed. Please contact developper.");
+ process::exit(1);
+ }
+ let old_max_v =
+ best_match_color(&coarse_variables, i_x as usize, i_y as usize, &palette);
+ {
+ let mut j_pal = &mut j_palette_sum[i_x as usize][i_y as usize];
+ // println!("j_pal: ({:.5}, {:.5}, {:.5})", j_pal[0], j_pal[1], j_pal[2]);
+
+ for v in 0..palette.len() {
+ let mut new_val = meanfields[v] / meanfield_sum;
+ // Prevent the matrix S from becoming singular
+ if new_val <= 0. {
+ new_val = 1e-10;
+ } else if new_val >= 1. {
+ new_val = 1. - 1e-10;
+ }
+
+ if i_x > 2 && i_x <= 5 && i_y == 3 {
+ println!("New val: {:.5}", new_val);
+ }
+
+ let delta_m_iv = new_val - coarse_variables[i_x as usize][i_y as usize][v];
+ coarse_variables[i_x as usize][i_y as usize][v] = new_val;
+ pcoarse_variables[i_x as usize][i_y as usize][v] = new_val;
+
+ j_pal[0] += delta_m_iv * palette[v].0;
+ j_pal[1] += delta_m_iv * palette[v].1;
+ j_pal[2] += delta_m_iv * palette[v].2;
+ // println!("delta_m_iv: {:.7}", delta_m_iv,);
+ if delta_m_iv.abs() > 0.001 && !skip_palette_maintenance {
+ update_s(&mut s, &coarse_variables, b, i_x, i_y, v as i32, delta_m_iv);
+ }
+ }
+ }
+ // println!(
+ // "j_palette_sum: ({:.5}, {:.5}, {:.5})",
+ // j_palette_sum[i_x as usize][i_y as usize][0],
+ // j_palette_sum[i_x as usize][i_y as usize][1],
+ // j_palette_sum[i_x as usize][i_y as usize][2]
+ // );
+
+ let max_v =
+ best_match_color(&coarse_variables, i_x as usize, i_y as usize, &palette);
+ // println!("Best match color: {}", max_v);
+ // Only consider it a change if the colors are different enough
+ let norm = (palette[max_v].0 - palette[old_max_v].0)
+ * (palette[max_v].0 - palette[old_max_v].0)
+ + (palette[max_v].1 - palette[old_max_v].1)
+ * (palette[max_v].1 - palette[old_max_v].1)
+ + (palette[max_v].2 - palette[old_max_v].2)
+ * (palette[max_v].2 - palette[old_max_v].2);
+ // println!(
+ // "Pixel change norm: {:.7} ({} vs {}) / {}",
+ // norm, max_v, old_max_v, pixels_changed
+ // );
+ if norm >= 1.0 / (255.0 * 255.0) {
+ pixels_changed += 1;
+
+ // We don't add the outer layer of pixels , because
+ // there isn't much weight there, and if it does need
+ // to be visited, it'll probably be added when we visit
+ // neighboring pixels.
+ // The commented out loops are faster but cause a little bit of
+ // distortion
+ // for (int y=center_y-1; y<center_y+1; y++) {
+ // for (int x=center_x-1; x<center_x+1; x++) {
+ let min_y = cmp::min(1, center_y - 1);
+ let max_y = cmp::max(b[0].len() as i32 - 1, center_y as i32 + 1) as usize;
+
+ let min_x = cmp::min(1, center_x - 1);
+ let max_x = cmp::max(b.len() as i32 - 1, center_x as i32 + 1) as usize;
+ for y in min_y..max_y {
+ for x in min_x..max_x {
+ let j_x = x as i32 - center_x as i32 + i_x as i32;
+ let j_y = y as i32 - center_y as i32 + i_y as i32;
+ if j_x < 0
+ || j_y < 0
+ || j_x >= coarse_variables.len() as i32
+ || j_y >= coarse_variables[0].len() as i32
+ {
+ continue;
+ }
+ visit_queue.push_back((j_x, j_y))
+ }
+ }
+ }
+ _pixel_visited += 1;
+
+ // Show progress with dots - in a graphical interface,
+ // we'd show progressive refinements of the image instead,
+ // and maybe a palette preview.
+ step_counter += 1;
+ if step_counter % 10_000 == 0 {
+ print!(".");
+ }
+ }
+ println!("Queue visit end!");
+ println!("Pixels changed: {} / {}", pixels_changed, _pixel_visited);
+ if skip_palette_maintenance {
+ println!("🦊🦊🦊🦊🦊🦊🦊🦊🦊🦊🦊🦊");
+ compute_initial_s(&mut s, &pcoarse_variables, &b_vec[coarse_level as usize]);
+ }
+ // We only computed the half of S above the diagonal - reflect it
+ for v in 0..s.len() {
+ for alpha in 0..v {
+ s[v][alpha] = s[alpha][v];
+ }
+ }
+
+ refine_palette(&s, &coarse_variables, &a, &mut palette);
+ compute_initial_j_palette_sum(&mut j_palette_sum, &coarse_variables, &palette);
+ }
+
+ iters_at_current_level += 1;
+ skip_palette_maintenance = false;
+ // println!(
+ // "Coarse level: {}, {} iters (per level: {})",
+ // coarse_level, iters_at_current_level, iters_per_level
+ // );
+ // println!("Temperature: {:.3} / {:.3}", temperature, final_temperature);
+ if (temperature <= final_temperature || coarse_level > 0)
+ && iters_at_current_level >= iters_per_level
+ {
+ coarse_level -= 1;
+ if coarse_level < 0 {
+ break;
+ }
+ let mut p_new_coarse_variables =
+ vec![
+ vec![vec![0.; palette_size]; (width >> coarse_level) as usize];
+ (height >> coarse_level) as usize
+ ];
+ for x in 0..((width >> coarse_level) as usize) {
+ for y in 0..((height >> coarse_level) as usize) {
+ for v in 0..palette_size {
+ p_new_coarse_variables[x][y][v] = 0.;
+ }
+ }
+ }
+ zoom_double(&coarse_variables, &mut p_new_coarse_variables);
+
+ println!("2x 🍌🍌🍌🍌🍌🍌🍌🍌🍌🍌🍌🍌🍌🍌");
+ pcoarse_variables = p_new_coarse_variables;
+ iters_at_current_level = 0;
+ j_palette_sum =
+ vec![vec![[0.; 3]; pcoarse_variables.len()]; pcoarse_variables[0].len()];
+ compute_initial_j_palette_sum(&mut j_palette_sum, &pcoarse_variables, &palette);
+
+ println!(
+ "Image new size: {}x{}",
+ pcoarse_variables.len(),
+ pcoarse_variables[0].len()
+ );
+ skip_palette_maintenance = true;
+ }
+ if temperature > final_temperature {
+ temperature *= temperature_multiplier;
+ }
+ }
+
+ // This is normally not used, but is handy sometimes for debugging
+ while coarse_level > 0 {
+ coarse_level -= 1;
+ let mut p_new_coarse_variables =
+ vec![
+ vec![vec![0.; palette_size]; (width >> coarse_level) as usize];
+ (height >> coarse_level) as usize
+ ];
+ zoom_double(&pcoarse_variables, &mut p_new_coarse_variables);
+ pcoarse_variables = p_new_coarse_variables;
+ println!(
+ "Image new_ size: {}x{}",
+ pcoarse_variables.len(),
+ pcoarse_variables[0].len()
+ );
+ }
+ {
+ // Need to reseat this reference in case wee change p_coarse_variables
+ let mut coarse_variables =
+ vec![
+ vec![vec![0.; palette_size]; pcoarse_variables.len() as usize];
+ pcoarse_variables[0].len() as usize
+ ];
+ for x in 0..pcoarse_variables.len() {
+ for y in 0..pcoarse_variables[0].len() {
+ for v in 0..palette_size {
+ coarse_variables[x][y][v] = pcoarse_variables[x][y][v];
+ }
+ }
+ }
+ for i_x in 0..width {
+ for i_y in 0..height {
+ quantized_image[i_x as usize][i_y as usize] =
+ best_match_color(&coarse_variables, i_x as usize, i_y as usize, &palette);
+ }
+ }
+
+ print!("Palette: ");
+ for v in 0..palette_size {
+ if palette[v].0 > 1.0 {
+ palette[v].0 = 1.0;
+ } else if palette[v].0 < 0.0 {
+ palette[v].0 = 0.0;
+ }
+
+ if palette[v].1 > 1.0 {
+ palette[v].1 = 1.0;
+ } else if palette[v].1 < 0.0 {
+ palette[v].1 = 0.0;
+ }
+
+ if palette[v].2 > 1.0 {
+ palette[v].2 = 1.0;
+ } else if palette[v].2 < 0.0 {
+ palette[v].2 = 0.0;
+ }
+ print!(
+ "[]{:.2},{:.2},{:.2}] ",
+ palette[v].0, palette[v].1, palette[v].2
+ )
+ }
+ }
+
+ for y in 0..(height as u32) {
+ for x in 0..(width as u32) {
+ image_in[(x, y)][0] =
+ (255. * palette[quantized_image[x as usize][y as usize]].0).ceil() as u8;
+ image_in[(x, y)][1] =
+ (255. * palette[quantized_image[x as usize][y as usize]].1).ceil() as u8;
+ image_in[(x, y)][2] =
+ (255. * palette[quantized_image[x as usize][y as usize]].2).ceil() as u8;
+ }
+ }
+}
diff --git a/src/main.rs b/src/main.rs
index e1ee198..8555232 100644
--- a/src/main.rs
+++ b/src/main.rs
@@ -2,15 +2,18 @@
use image::{ImageReader, Rgb};
use std::path::Path;
-const LIST_OF_SAMPLES: [&str; 7] = [
+const LIST_OF_SAMPLES: [&str; 2] = [
"samples/david.png",
"samples/david2.jpg",
- "samples/us.png",
- "samples/jane.jpg",
- "samples/jane2.webp",
- "samples/karel_kΓ€os.jpg",
- "samples/diderot_111.png",
+ /*
+ "samples/us.png",
+ "samples/jane.jpg",
+ "samples/jane2.webp",
+ "samples/karel_kΓ€os.jpg",
+ "samples/diderot_111.png",
+ */
];
+#[allow(dead_code)]
const PALETTE_3B: [Rgb<u8>; 8] = [
Rgb([0, 0, 255]),
Rgb([0, 255, 255]),
@@ -34,9 +37,26 @@ fn main() -> Result<(), image::ImageError> {
// ("kernel_atkinson_linear", |img| {
// dither::dither_linear(img, dither::kernel::ATKINSON_KERNEL.to_vec())
// }),
- ("kernel_atkinson_palette_3b", |img| {
- dither::dither_palette(img, &PALETTE_3B, dither::kernel::ATKINSON_KERNEL.to_vec())
+ /*
+ ("kernel_atkinson_serpentine_1b", |img| {
+ dither::dither_serpentine_1b(img, dither::kernel::ATKINSON_KERNEL.to_vec())
+ }),
+ ("kernel_atkinson_serpentine_3b", |img| {
+ dither::dither_serpentine_3b(img, dither::kernel::ATKINSON_KERNEL.to_vec())
+ }),
+ ("kernel_ostromoukhov_1b", |img| {
+ dither::dither_ostromoukhov_1b(img)
}),
+ ("kernel_ostromoukhov_3b", |img| {
+ dither::dither_ostromoukhov_3b(img)
+ }),
+ ("kernel_ostromoukhov_1b_alt", |img| {
+ dither::dither_ostromoukhov_1b_alt2(img)
+ }),
+ ("bayer_3b", |img| dither::dither_bayer(256, img)),
+ */
+ ("scolorq", |_img| dither::dither_scolorq(_img, 16)),
+ /*
("kernel_jarvis_judice_ninke_linear_3b", |img| {
dither::dither_palette_linear(
img,
@@ -44,7 +64,6 @@ fn main() -> Result<(), image::ImageError> {
dither::kernel::JARVIS_JUDICE_NINKE_KERNEL.to_vec(),
)
}),
- /*
("kernel_kong_kui_3b", |img| {
dither::dither_shift_8colors(
img,
@@ -69,7 +88,7 @@ fn main() -> Result<(), image::ImageError> {
}),*/
];
- for sample in LIST_OF_SAMPLES {
+ for sample in ["samples/us.png"] {
for (suffix, algo) in &algos {
println!("{} on {}", suffix, sample);
let path = Path::new(sample);