feat: use better calculations for distance and average color
This commit is contained in:
1
.gitattributes
vendored
Normal file
1
.gitattributes
vendored
Normal file
@@ -0,0 +1 @@
|
|||||||
|
Cargo.lock -diff
|
5
.gitignore
vendored
5
.gitignore
vendored
@@ -7,5 +7,8 @@
|
|||||||
*.heic
|
*.heic
|
||||||
*.mp4
|
*.mp4
|
||||||
*.webm
|
*.webm
|
||||||
|
*.webp
|
||||||
/.mypy_cache/
|
/.mypy_cache/
|
||||||
tiles/
|
/tiles/
|
||||||
|
/input/
|
||||||
|
/output/
|
||||||
|
323
Cargo.lock
generated
323
Cargo.lock
generated
@@ -23,12 +23,6 @@ dependencies = [
|
|||||||
"winapi",
|
"winapi",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "anyhow"
|
|
||||||
version = "1.0.58"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "bb07d2053ccdbe10e2af2995a2f116c1330396493dc1269f6a91d0ae82e19704"
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "atty"
|
name = "atty"
|
||||||
version = "0.2.14"
|
version = "0.2.14"
|
||||||
@@ -46,12 +40,24 @@ version = "1.1.0"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa"
|
checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "bit_field"
|
||||||
|
version = "0.10.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "dcb6dd1c2376d2e096796e234a70e17e94cc2d5d54ff8ce42b28cef1d0d359a4"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "bitflags"
|
name = "bitflags"
|
||||||
version = "1.3.2"
|
version = "1.3.2"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a"
|
checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "bumpalo"
|
||||||
|
version = "3.10.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "37ccbd214614c6783386c1af30caf03192f17891059cecc394b4fb119e363de3"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "bytemuck"
|
name = "bytemuck"
|
||||||
version = "1.10.0"
|
version = "1.10.0"
|
||||||
@@ -100,7 +106,6 @@ dependencies = [
|
|||||||
"encode_unicode",
|
"encode_unicode",
|
||||||
"libc",
|
"libc",
|
||||||
"once_cell",
|
"once_cell",
|
||||||
"regex",
|
|
||||||
"terminal_size",
|
"terminal_size",
|
||||||
"unicode-width",
|
"unicode-width",
|
||||||
"winapi",
|
"winapi",
|
||||||
@@ -162,12 +167,11 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "deflate"
|
name = "deflate"
|
||||||
version = "0.8.6"
|
version = "1.0.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "73770f8e1fe7d64df17ca66ad28994a0a623ea497fa69486e14984e715c5d174"
|
checksum = "c86f7e25f518f4b81808a2cf1c50996a61f5c2eb394b2393bd87f2a4780a432f"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"adler32",
|
"adler32",
|
||||||
"byteorder",
|
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@@ -182,6 +186,80 @@ version = "0.3.6"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "a357d28ed41a50f9c765dbfe56cbc04a64e53e5fc58ba79fbc34c10ef3df831f"
|
checksum = "a357d28ed41a50f9c765dbfe56cbc04a64e53e5fc58ba79fbc34c10ef3df831f"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "exr"
|
||||||
|
version = "1.4.2"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "14cc0e06fb5f67e5d6beadf3a382fec9baca1aa751c6d5368fdeee7e5932c215"
|
||||||
|
dependencies = [
|
||||||
|
"bit_field",
|
||||||
|
"deflate",
|
||||||
|
"flume",
|
||||||
|
"half",
|
||||||
|
"inflate",
|
||||||
|
"lebe",
|
||||||
|
"smallvec",
|
||||||
|
"threadpool",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "eyre"
|
||||||
|
version = "0.6.8"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "4c2b6b5a29c02cdc822728b7d7b8ae1bab3e3b05d44522770ddd49722eeac7eb"
|
||||||
|
dependencies = [
|
||||||
|
"indenter",
|
||||||
|
"once_cell",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "flate2"
|
||||||
|
version = "1.0.24"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "f82b0f4c27ad9f8bfd1f3208d882da2b09c301bc1c828fd3a00d0216d2fbbff6"
|
||||||
|
dependencies = [
|
||||||
|
"crc32fast",
|
||||||
|
"miniz_oxide",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "flume"
|
||||||
|
version = "0.10.13"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "1ceeb589a3157cac0ab8cc585feb749bd2cea5cb55a6ee802ad72d9fd38303da"
|
||||||
|
dependencies = [
|
||||||
|
"futures-core",
|
||||||
|
"futures-sink",
|
||||||
|
"nanorand",
|
||||||
|
"pin-project",
|
||||||
|
"spin",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "futures-core"
|
||||||
|
version = "0.3.21"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "0c09fd04b7e4073ac7156a9539b57a484a8ea920f79c7c675d05d289ab6110d3"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "futures-sink"
|
||||||
|
version = "0.3.21"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "21163e139fa306126e6eedaf49ecdb4588f939600f0b1e770f4205ee4b7fa868"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "getrandom"
|
||||||
|
version = "0.2.7"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "4eb1a864a501629691edf6c15a593b7a51eebaa1e8468e9ddc623de7c9b58ec6"
|
||||||
|
dependencies = [
|
||||||
|
"cfg-if",
|
||||||
|
"js-sys",
|
||||||
|
"libc",
|
||||||
|
"wasi",
|
||||||
|
"wasm-bindgen",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "gif"
|
name = "gif"
|
||||||
version = "0.11.4"
|
version = "0.11.4"
|
||||||
@@ -192,6 +270,12 @@ dependencies = [
|
|||||||
"weezl",
|
"weezl",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "half"
|
||||||
|
version = "1.8.2"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "eabb4a44450da02c90444cf74558da904edde8fb4e9035a9a6a4e15445af0bd7"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "heck"
|
name = "heck"
|
||||||
version = "0.3.3"
|
version = "0.3.3"
|
||||||
@@ -212,13 +296,14 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "image"
|
name = "image"
|
||||||
version = "0.23.14"
|
version = "0.24.2"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "24ffcb7e7244a9bf19d35bf2883b9c080c4ced3c07a9895572178cdb8f13f6a1"
|
checksum = "28edd9d7bc256be2502e325ac0628bde30b7001b9b52e0abe31a1a9dc2701212"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"bytemuck",
|
"bytemuck",
|
||||||
"byteorder",
|
"byteorder",
|
||||||
"color_quant",
|
"color_quant",
|
||||||
|
"exr",
|
||||||
"gif",
|
"gif",
|
||||||
"jpeg-decoder",
|
"jpeg-decoder",
|
||||||
"num-iter",
|
"num-iter",
|
||||||
@@ -230,10 +315,16 @@ dependencies = [
|
|||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "indicatif"
|
name = "indenter"
|
||||||
version = "0.15.0"
|
version = "0.3.3"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "7baab56125e25686df467fe470785512329883aab42696d661247aca2a2896e4"
|
checksum = "ce23b50ad8242c51a442f3ff322d56b02f08852c77e4c0b4d3fd684abc89c683"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "indicatif"
|
||||||
|
version = "0.16.2"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "2d207dc617c7a380ab07ff572a6e52fa202a2a8f355860ac9c38e23f8196be1b"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"console",
|
"console",
|
||||||
"lazy_static",
|
"lazy_static",
|
||||||
@@ -245,26 +336,69 @@ dependencies = [
|
|||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "jpeg-decoder"
|
name = "inflate"
|
||||||
version = "0.1.22"
|
version = "0.4.5"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "229d53d58899083193af11e15917b5640cd40b29ff475a1fe4ef725deb02d0f2"
|
checksum = "1cdb29978cc5797bd8dcc8e5bf7de604891df2a8dc576973d71a281e916db2ff"
|
||||||
|
dependencies = [
|
||||||
|
"adler32",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "jpeg-decoder"
|
||||||
|
version = "0.2.6"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "9478aa10f73e7528198d75109c8be5cd7d15fb530238040148d5f9a22d4c5b3b"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"rayon",
|
"rayon",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "js-sys"
|
||||||
|
version = "0.3.58"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "c3fac17f7123a73ca62df411b1bf727ccc805daa070338fda671c86dac1bdc27"
|
||||||
|
dependencies = [
|
||||||
|
"wasm-bindgen",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "lazy_static"
|
name = "lazy_static"
|
||||||
version = "1.4.0"
|
version = "1.4.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646"
|
checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "lebe"
|
||||||
|
version = "0.5.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "7efd1d698db0759e6ef11a7cd44407407399a910c774dd804c64c032da7826ff"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "libc"
|
name = "libc"
|
||||||
version = "0.2.126"
|
version = "0.2.126"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "349d5a591cd28b49e1d1037471617a32ddcda5731b99419008085f72d5a53836"
|
checksum = "349d5a591cd28b49e1d1037471617a32ddcda5731b99419008085f72d5a53836"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "lock_api"
|
||||||
|
version = "0.4.7"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "327fa5b6a6940e4699ec49a9beae1ea4845c6bab9314e4f84ac68742139d8c53"
|
||||||
|
dependencies = [
|
||||||
|
"autocfg",
|
||||||
|
"scopeguard",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "log"
|
||||||
|
version = "0.4.17"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "abb12e687cfb44aa40f41fc3978ef76448f9b6038cad6aef4259d3c095a2382e"
|
||||||
|
dependencies = [
|
||||||
|
"cfg-if",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "memoffset"
|
name = "memoffset"
|
||||||
version = "0.6.5"
|
version = "0.6.5"
|
||||||
@@ -276,30 +410,20 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "miniz_oxide"
|
name = "miniz_oxide"
|
||||||
version = "0.3.7"
|
version = "0.5.3"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "791daaae1ed6889560f8c4359194f56648355540573244a5448a83ba1ecc7435"
|
checksum = "6f5c75688da582b8ffc1f1799e9db273f32133c49e048f614d22ec3256773ccc"
|
||||||
dependencies = [
|
|
||||||
"adler32",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "miniz_oxide"
|
|
||||||
version = "0.4.4"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "a92518e98c078586bc6c934028adcca4c92a53d6a958196de835170a01d84e4b"
|
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"adler",
|
"adler",
|
||||||
"autocfg",
|
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "noisy_float"
|
name = "nanorand"
|
||||||
version = "0.1.15"
|
version = "0.7.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "3deb89f8062c0dce4c805a987daff07f92e17c560f7c3ed631282555af902258"
|
checksum = "6a51313c5820b0b02bd422f4b44776fbf47961755c74ce64afc73bfad10226c3"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"num-traits",
|
"getrandom",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@@ -325,9 +449,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "num-rational"
|
name = "num-rational"
|
||||||
version = "0.3.2"
|
version = "0.4.1"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "12ac428b1cb17fce6f731001d307d351ec70a6d202fc2e60f7d4c5e42d8f4f07"
|
checksum = "0638a1c9d0a3c0914158145bc76cff373a75a627e6ecbfb71cbe6f453a5a19b0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"autocfg",
|
"autocfg",
|
||||||
"num-integer",
|
"num-integer",
|
||||||
@@ -355,9 +479,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "number_prefix"
|
name = "number_prefix"
|
||||||
version = "0.3.0"
|
version = "0.4.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "17b02fc0ff9a9e4b35b3342880f48e896ebf69f2967921fe8646bf5b7125956a"
|
checksum = "830b246a0e5f20af87141b25c173cd1b609bd7779a4617d6ec582abaf90870f3"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "once_cell"
|
name = "once_cell"
|
||||||
@@ -366,15 +490,35 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
|||||||
checksum = "18a6dbe30758c9f83eb00cbea4ac95966305f5a7772f3f42ebfc7fc7eddbd8e1"
|
checksum = "18a6dbe30758c9f83eb00cbea4ac95966305f5a7772f3f42ebfc7fc7eddbd8e1"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "png"
|
name = "pin-project"
|
||||||
version = "0.16.8"
|
version = "1.0.11"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "3c3287920cb847dee3de33d301c463fba14dda99db24214ddf93f83d3021f4c6"
|
checksum = "78203e83c48cffbe01e4a2d35d566ca4de445d79a85372fc64e378bfc812a260"
|
||||||
|
dependencies = [
|
||||||
|
"pin-project-internal",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "pin-project-internal"
|
||||||
|
version = "1.0.11"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "710faf75e1b33345361201d36d04e98ac1ed8909151a017ed384700836104c74"
|
||||||
|
dependencies = [
|
||||||
|
"proc-macro2",
|
||||||
|
"quote",
|
||||||
|
"syn",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "png"
|
||||||
|
version = "0.17.5"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "dc38c0ad57efb786dd57b9864e5b18bae478c00c824dc55a38bbc9da95dde3ba"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"bitflags",
|
"bitflags",
|
||||||
"crc32fast",
|
"crc32fast",
|
||||||
"deflate",
|
"deflate",
|
||||||
"miniz_oxide 0.3.7",
|
"miniz_oxide",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@@ -470,6 +614,21 @@ version = "1.1.0"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "d29ab0c6d3fc0ee92fe66e2d99f700eab17a8d57d1c1d3b748380fb20baa78cd"
|
checksum = "d29ab0c6d3fc0ee92fe66e2d99f700eab17a8d57d1c1d3b748380fb20baa78cd"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "smallvec"
|
||||||
|
version = "1.9.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "2fd0db749597d91ff862fd1d55ea87f7855a744a8425a64695b6fca237d1dad1"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "spin"
|
||||||
|
version = "0.9.4"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "7f6002a767bff9e83f8eeecf883ecb8011875a21ae8da43bffb817a57e78cc09"
|
||||||
|
dependencies = [
|
||||||
|
"lock_api",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "strsim"
|
name = "strsim"
|
||||||
version = "0.8.0"
|
version = "0.8.0"
|
||||||
@@ -534,22 +693,30 @@ dependencies = [
|
|||||||
name = "themis"
|
name = "themis"
|
||||||
version = "1.2.0"
|
version = "1.2.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"anyhow",
|
"eyre",
|
||||||
"image",
|
"image",
|
||||||
"indicatif",
|
"indicatif",
|
||||||
"noisy_float",
|
|
||||||
"rayon",
|
"rayon",
|
||||||
"structopt",
|
"structopt",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "tiff"
|
name = "threadpool"
|
||||||
version = "0.6.1"
|
version = "1.8.1"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "9a53f4706d65497df0c4349241deddf35f84cee19c87ed86ea8ca590f4464437"
|
checksum = "d050e60b33d41c19108b32cea32164033a9013fe3b46cbd4457559bfbf77afaa"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
|
"num_cpus",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "tiff"
|
||||||
|
version = "0.7.2"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "7cfada0986f446a770eca461e8c6566cb879682f7d687c8348aa0c857bd52286"
|
||||||
|
dependencies = [
|
||||||
|
"flate2",
|
||||||
"jpeg-decoder",
|
"jpeg-decoder",
|
||||||
"miniz_oxide 0.4.4",
|
|
||||||
"weezl",
|
"weezl",
|
||||||
]
|
]
|
||||||
|
|
||||||
@@ -583,6 +750,66 @@ version = "0.9.4"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f"
|
checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "wasi"
|
||||||
|
version = "0.11.0+wasi-snapshot-preview1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "wasm-bindgen"
|
||||||
|
version = "0.2.81"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "7c53b543413a17a202f4be280a7e5c62a1c69345f5de525ee64f8cfdbc954994"
|
||||||
|
dependencies = [
|
||||||
|
"cfg-if",
|
||||||
|
"wasm-bindgen-macro",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "wasm-bindgen-backend"
|
||||||
|
version = "0.2.81"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "5491a68ab4500fa6b4d726bd67408630c3dbe9c4fe7bda16d5c82a1fd8c7340a"
|
||||||
|
dependencies = [
|
||||||
|
"bumpalo",
|
||||||
|
"lazy_static",
|
||||||
|
"log",
|
||||||
|
"proc-macro2",
|
||||||
|
"quote",
|
||||||
|
"syn",
|
||||||
|
"wasm-bindgen-shared",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "wasm-bindgen-macro"
|
||||||
|
version = "0.2.81"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "c441e177922bc58f1e12c022624b6216378e5febc2f0533e41ba443d505b80aa"
|
||||||
|
dependencies = [
|
||||||
|
"quote",
|
||||||
|
"wasm-bindgen-macro-support",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "wasm-bindgen-macro-support"
|
||||||
|
version = "0.2.81"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "7d94ac45fcf608c1f45ef53e748d35660f168490c10b23704c7779ab8f5c3048"
|
||||||
|
dependencies = [
|
||||||
|
"proc-macro2",
|
||||||
|
"quote",
|
||||||
|
"syn",
|
||||||
|
"wasm-bindgen-backend",
|
||||||
|
"wasm-bindgen-shared",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "wasm-bindgen-shared"
|
||||||
|
version = "0.2.81"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "6a89911bd99e5f3659ec4acf9c4d93b0a90fe4a2a11f15328472058edc5261be"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "weezl"
|
name = "weezl"
|
||||||
version = "0.1.7"
|
version = "0.1.7"
|
||||||
|
13
Cargo.toml
13
Cargo.toml
@@ -6,9 +6,10 @@ license = "GPL-3.0-only"
|
|||||||
edition = "2018"
|
edition = "2018"
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
image = "0.23.6"
|
image = "0.24.2"
|
||||||
anyhow = "1.0.31"
|
rayon = "1.5.3"
|
||||||
rayon = "1.3.1"
|
indicatif = { version = "0.16.2", features = ["rayon", "improved_unicode"] }
|
||||||
indicatif = { version = "0.15.0", features = ["rayon", "improved_unicode"] }
|
structopt = "0.3.26"
|
||||||
noisy_float = "0.1.12"
|
eyre = "0.6.8"
|
||||||
structopt = "0.3.15"
|
|
||||||
|
[features]
|
||||||
|
7
justfile
Normal file
7
justfile
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
set shell := ["pwsh.exe", "-c"]
|
||||||
|
|
||||||
|
run side *args:
|
||||||
|
cargo run --release -- -i input -t tiles -k -m {{side}} {{args}}
|
||||||
|
|
||||||
|
run-debug side *args:
|
||||||
|
cargo run -- -i input -t tiles -k -m {{side}} {{args}}
|
126
src/main.rs
126
src/main.rs
@@ -2,10 +2,11 @@ use std::collections::{HashMap, HashSet};
|
|||||||
use std::fs;
|
use std::fs;
|
||||||
use std::path::{Path, PathBuf};
|
use std::path::{Path, PathBuf};
|
||||||
|
|
||||||
use anyhow::Result;
|
use eyre::Result;
|
||||||
use image::{DynamicImage, GenericImage, GenericImageView, Pixel, Rgba};
|
use image::{DynamicImage, GenericImage, GenericImageView, Rgba};
|
||||||
use indicatif::{ParallelProgressIterator, ProgressBar, ProgressIterator, ProgressStyle};
|
use indicatif::{
|
||||||
use noisy_float::prelude::*;
|
ParallelProgressIterator, ProgressBar, ProgressFinish, ProgressIterator, ProgressStyle,
|
||||||
|
};
|
||||||
use rayon::prelude::*;
|
use rayon::prelude::*;
|
||||||
use structopt::StructOpt;
|
use structopt::StructOpt;
|
||||||
|
|
||||||
@@ -15,28 +16,26 @@ fn average_color(image: &DynamicImage) -> Rgba<u8> {
|
|||||||
|
|
||||||
let (mut r, mut g, mut b, mut a) = (0., 0., 0., 0.);
|
let (mut r, mut g, mut b, mut a) = (0., 0., 0., 0.);
|
||||||
for (_x, _y, Rgba([pr, pg, pb, pa])) in image.pixels() {
|
for (_x, _y, Rgba([pr, pg, pb, pa])) in image.pixels() {
|
||||||
r += pr as f64;
|
r += pr as f64 * pr as f64;
|
||||||
g += pg as f64;
|
g += pg as f64 * pg as f64;
|
||||||
b += pb as f64;
|
b += pb as f64 * pb as f64;
|
||||||
a += pa as f64;
|
a += pa as f64 * pa as f64;
|
||||||
}
|
}
|
||||||
|
let r = (r / pixel_count).sqrt() as u8;
|
||||||
let r = (r / pixel_count) as u8;
|
let g = (g / pixel_count).sqrt() as u8;
|
||||||
let g = (g / pixel_count) as u8;
|
let b = (b / pixel_count).sqrt() as u8;
|
||||||
let b = (b / pixel_count) as u8;
|
let a = (a / pixel_count).sqrt() as u8;
|
||||||
let a = (a / pixel_count) as u8;
|
|
||||||
Rgba([r, g, b, a])
|
Rgba([r, g, b, a])
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Calculate the euclidean distance between two pixels
|
/// Calculate the distance (squared) between two colors
|
||||||
fn distance(pixel1: Rgba<u8>, pixel2: Rgba<u8>) -> R64 {
|
/// Code adapted from https://stackoverflow.com/a/9085524/13204109
|
||||||
r64(pixel1
|
fn distance(Rgba([r1, g1, b1, _]): Rgba<u8>, Rgba([r2, g2, b2, _]): Rgba<u8>) -> i64 {
|
||||||
.map2(&pixel2, |l, r| if l < r { r - l } else { l - r })
|
let rmean = (i64::from(r1) + i64::from(r2)) / 2;
|
||||||
.channels()
|
let r = i64::from(r1) - i64::from(r2);
|
||||||
.iter()
|
let g = i64::from(g1) - i64::from(g2);
|
||||||
.map(|&n| (n as f64).powi(2))
|
let b = i64::from(b1) - i64::from(b2);
|
||||||
.sum::<f64>()
|
(((512 + rmean) * r * r) >> 8) + 4 * g * g + (((767 - rmean) * b * b) >> 8)
|
||||||
.sqrt())
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Choose the image in the given tileset whose average color is closest to the given pixel
|
/// Choose the image in the given tileset whose average color is closest to the given pixel
|
||||||
@@ -54,6 +53,7 @@ fn pick_image_for_pixel(
|
|||||||
fn load_images<P: AsRef<Path>>(dir: P, tile_side: u32) -> Result<Vec<(DynamicImage, Rgba<u8>)>> {
|
fn load_images<P: AsRef<Path>>(dir: P, tile_side: u32) -> Result<Vec<(DynamicImage, Rgba<u8>)>> {
|
||||||
let dir = fs::read_dir(dir)?.collect::<Result<Vec<_>, _>>()?;
|
let dir = fs::read_dir(dir)?.collect::<Result<Vec<_>, _>>()?;
|
||||||
let len = dir.len();
|
let len = dir.len();
|
||||||
|
|
||||||
Ok(dir
|
Ok(dir
|
||||||
.into_par_iter()
|
.into_par_iter()
|
||||||
.progress_with(make_pbar("images loaded", len as _))
|
.progress_with(make_pbar("images loaded", len as _))
|
||||||
@@ -68,37 +68,52 @@ fn load_images<P: AsRef<Path>>(dir: P, tile_side: u32) -> Result<Vec<(DynamicIma
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Create a styled progress bar
|
/// Create a styled progress bar
|
||||||
fn make_pbar(msg: &str, len: u64) -> ProgressBar {
|
fn make_pbar(msg: &'static str, len: u64) -> ProgressBar {
|
||||||
let bar = ProgressBar::new(len);
|
let bar = ProgressBar::new(len);
|
||||||
bar.set_message(msg);
|
bar.set_message(msg);
|
||||||
bar.set_style(
|
bar.set_style(
|
||||||
ProgressStyle::default_bar()
|
ProgressStyle::default_bar()
|
||||||
.template("[{elapsed_precise}/{eta_precise}] {bar:40.green/red} {pos:>4}/{len:4} {msg}")
|
.template("[{elapsed_precise}/{eta_precise}] {bar:40.green/red} {pos:>4}/{len:4} {msg}")
|
||||||
.progress_chars("##-"),
|
.progress_chars("##-")
|
||||||
|
.on_finish(ProgressFinish::AndLeave),
|
||||||
);
|
);
|
||||||
bar
|
bar
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Create a styled spinner
|
||||||
|
fn make_spinner(msg: &'static str, done_msg: &'static str) -> ProgressBar {
|
||||||
|
let bar = ProgressBar::new(0);
|
||||||
|
bar.set_message(msg);
|
||||||
|
bar.set_style(
|
||||||
|
ProgressStyle::default_bar()
|
||||||
|
.template("{spinner:.yellow} {msg}")
|
||||||
|
.progress_chars("##-")
|
||||||
|
.on_finish(ProgressFinish::WithMessage(done_msg)),
|
||||||
|
);
|
||||||
|
bar.enable_steady_tick(100);
|
||||||
|
bar
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(StructOpt)]
|
#[derive(StructOpt)]
|
||||||
struct Opt {
|
struct Opt {
|
||||||
/// The image to turn into a mosaic
|
/// The image to turn into a mosaic
|
||||||
#[structopt(parse(from_os_str))]
|
#[structopt(short, long, parse(from_os_str))]
|
||||||
image: PathBuf,
|
input_dir: PathBuf,
|
||||||
|
|
||||||
/// The directory containing the tiles to utilize
|
/// The directory containing the tiles to utilize
|
||||||
#[structopt(parse(from_os_str))]
|
#[structopt(short, long, parse(from_os_str))]
|
||||||
tiles_directory: PathBuf,
|
tiles_dir: PathBuf,
|
||||||
|
|
||||||
/// Where to save the finished mosaic
|
/// Where to save the finished mosaic
|
||||||
#[structopt(short, long, parse(from_os_str), default_value = "mosaic.png")]
|
#[structopt(short, long, parse(from_os_str), default_value = "output")]
|
||||||
output: PathBuf,
|
output_dir: PathBuf,
|
||||||
|
|
||||||
/// The side length that the target image'll be resized to.
|
/// The side length that the target image'll be resized to.
|
||||||
#[structopt(short, long, default_value = "128")]
|
#[structopt(short, long, default_value = "128")]
|
||||||
mosaic_size: u32,
|
mosaic_size: u32,
|
||||||
|
|
||||||
/// The side length of each tile.
|
/// The side length of each tile.
|
||||||
#[structopt(short, long, default_value = "26")]
|
#[structopt(long, default_value = "26")]
|
||||||
tile_size: u32,
|
tile_size: u32,
|
||||||
|
|
||||||
/// Keep the image's aspect ratio
|
/// Keep the image's aspect ratio
|
||||||
@@ -108,31 +123,48 @@ struct Opt {
|
|||||||
|
|
||||||
fn main() -> Result<()> {
|
fn main() -> Result<()> {
|
||||||
let Opt {
|
let Opt {
|
||||||
image,
|
input_dir,
|
||||||
tiles_directory,
|
tiles_dir,
|
||||||
mosaic_size,
|
mosaic_size,
|
||||||
tile_size,
|
tile_size,
|
||||||
keep_aspect_ratio,
|
keep_aspect_ratio,
|
||||||
output,
|
output_dir,
|
||||||
} = Opt::from_args();
|
} = Opt::from_args();
|
||||||
|
|
||||||
let possible_tiles = load_images(tiles_directory, tile_size)?;
|
fs::create_dir_all(&output_dir)?;
|
||||||
let image = image::open(image)?;
|
|
||||||
let image = if keep_aspect_ratio {
|
let possible_tiles = load_images(tiles_dir, tile_size)?;
|
||||||
image.thumbnail(mosaic_size, mosaic_size)
|
|
||||||
|
let input_dir = fs::read_dir(input_dir)?.collect::<Result<Vec<_>, _>>()?;
|
||||||
|
|
||||||
|
for image in input_dir {
|
||||||
|
let input_path = image.path();
|
||||||
|
eprintln!("Processing {}", input_path.display());
|
||||||
|
|
||||||
|
let output = output_dir.join(format!(
|
||||||
|
"{}.mosaic{mosaic_size}.png",
|
||||||
|
input_path.file_stem().unwrap().to_string_lossy()
|
||||||
|
));
|
||||||
|
if output.exists() {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
let img = image::open(&input_path)?;
|
||||||
|
let img = if keep_aspect_ratio {
|
||||||
|
img.thumbnail(mosaic_size, mosaic_size)
|
||||||
} else {
|
} else {
|
||||||
image.thumbnail_exact(mosaic_size, mosaic_size)
|
img.thumbnail_exact(mosaic_size, mosaic_size)
|
||||||
};
|
};
|
||||||
|
|
||||||
// For every unique pixel in the image, find its most appropiate tile
|
// For every unique pixel in the image, find its most appropiate tile
|
||||||
let unique_pixels = image
|
let unique_pixels = img
|
||||||
.pixels()
|
.pixels()
|
||||||
.map(|(_x, _y, pixel)| pixel)
|
.map(|(_x, _y, pixel)| pixel)
|
||||||
.collect::<HashSet<_>>();
|
.collect::<HashSet<_>>();
|
||||||
let pbar = make_pbar("pixels", unique_pixels.len() as _);
|
let len = unique_pixels.len();
|
||||||
let tiles = unique_pixels
|
let tiles = unique_pixels
|
||||||
.into_par_iter()
|
.into_par_iter()
|
||||||
.progress_with(pbar)
|
.progress_with(make_pbar("pixels", len as _))
|
||||||
.filter_map(|pixel| {
|
.filter_map(|pixel| {
|
||||||
let tile = pick_image_for_pixel(pixel, &possible_tiles)?;
|
let tile = pick_image_for_pixel(pixel, &possible_tiles)?;
|
||||||
Some((pixel, tile))
|
Some((pixel, tile))
|
||||||
@@ -140,14 +172,18 @@ fn main() -> Result<()> {
|
|||||||
.collect::<HashMap<_, _>>();
|
.collect::<HashMap<_, _>>();
|
||||||
|
|
||||||
// Apply the mapping previously calculated and save the mosaic
|
// Apply the mapping previously calculated and save the mosaic
|
||||||
let mut mosaic = DynamicImage::new_rgba8(image.width() * tile_size, image.height() * tile_size);
|
let mut mosaic = DynamicImage::new_rgba8(img.width() * tile_size, img.height() * tile_size);
|
||||||
for (x, y, pixel) in image.pixels().progress_with(make_pbar(
|
for (x, y, pixel) in img.pixels().progress_with(make_pbar(
|
||||||
"actual pixels",
|
"actual pixels",
|
||||||
u64::from(image.width() * image.height()),
|
u64::from(img.width() * img.height()),
|
||||||
)) {
|
)) {
|
||||||
mosaic.copy_from(&**tiles.get(&pixel).unwrap(), x * tile_size, y * tile_size)?;
|
mosaic.copy_from(&**tiles.get(&pixel).unwrap(), x * tile_size, y * tile_size)?;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let spinner = make_spinner("Saving", "Saved!");
|
||||||
mosaic.save(output)?;
|
mosaic.save(output)?;
|
||||||
|
spinner.finish_using_style();
|
||||||
|
}
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user