diff options
| author | ache <ache@ache.one> | 2025-05-25 20:08:36 +0200 |
|---|---|---|
| committer | ache <ache@ache.one> | 2025-05-25 20:08:36 +0200 |
| commit | 5bdc32f2574c8d71f901cd731e51ebb2fb76804d (patch) | |
| tree | b82c8f21bc2c58a6b99c3ca51e46c51ddbff7b89 | |
| parent | Implement bayer matrix dithering (diff) | |
Implement scolorq dithering
| -rw-r--r-- | src/kernel.rs | 1287 | ||||
| -rw-r--r-- | src/lib.rs | 1617 | ||||
| -rw-r--r-- | src/main.rs | 39 |
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, }, + ], +]; @@ -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); |