GithubHelp home page GithubHelp logo

okaneco / rscolorq Goto Github PK

View Code? Open in Web Editor NEW
57.0 57.0 2.0 736 KB

Spatial color quantization in Rust

License: Apache License 2.0

Rust 100.00%
color-palette color-quantization dithering image-processing rust scolorq spatial-color-quantization

rscolorq's People

Contributors

ksmoore17 avatar okaneco avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar

Forkers

pierogis iq-scm

rscolorq's Issues

Bias towards the color black.

I'm trying to quantize this image. But it is biased towards darker colors, which are less appealing the the brighter colors. And it would make more sense to have more brighter colors in the limited palette. Do you have any idea if I'm setting this incorrectly?
image

  1. Run
rscolorq -i image.png -o image-32-lab.png --op image-32pal-lab.png -n 32 --lab -p --auto -s 0
  1. Results
13191b,000b08,000000,70493f,000000,3d2c20,b1a9c6,434348,2d1c23,1c1011,957384,32292b,1e2d33,231e1b,282924,282428,ae5670,67475c,33302e,44323c,485974,9c3041,fdf0ea,000505,0f0409,3e1920,528dd3,000100,656256,303e7e,f396a1,1c2141

image-32pal-lab
image-32-lab

And it's way worse without the --lab color space

  1. Run
rscolorq -i image.png -o image-32.png --op image-32pal.png -n 32 -p --auto -s 0
  1. Results
000000,000000,000000,fce8e5,000000,000000,313a76,dc6676,000000,000000,000000,000000,000000,000000,422023,487fc8,000000,000000,000000,90526d,000000,5b5551,000000,37525f,000000,000000,000000,1a1f3c,000000,000000,000000,8f2c38

image-32pal
image-32

Isn't it supposed to generate 32 distinct colors? Instead the color black is repeated multiple times.

Cannot install from cargo

Upstream changes in image cause the crate to fail to build when installing from crates.io.

See
okaneco/kmeans-colors#35
okaneco/kmeans-colors#36

What happens

error[E0433]: failed to resolve: could not find `CompressionType` in `png`
  --> C:\Users\user\.cargo\registry\src\github.com-1ecc6299db9ec823\rscolorq-0.1.0\src\bin\rscolorq\utils.rs:76:21
   |
76 |         image::png::CompressionType::Best,
   |                     ^^^^^^^^^^^^^^^ could not find `CompressionType` in `png`

error[E0433]: failed to resolve: could not find `FilterType` in `png`
  --> C:\Users\user\.cargo\registry\src\github.com-1ecc6299db9ec823\rscolorq-0.1.0\src\bin\rscolorq\utils.rs:77:21
   |
77 |         image::png::FilterType::NoFilter,
   |                     ^^^^^^^^^^ could not find `FilterType` in `png`

error: aborting due to 2 previous errors

How to fix it

The image dependency should be bumped along with the lines of code that don't work. A new version of the crate should be published.

thread '<unnamed>' panicked at 'attempt to add with overflow' when using as lib

Hi,

This package is awesome, thanks for porting it. I'm trying to wrap it in python and getting an overflow panic when using it as a lib despite no problems using the cli.

I've used the flow described in lib.rs and compared to main.rs and it seems like I'm passing the correct objects to the spatial_color_quantization function, but there is an overflow error caused by the utility::b_value and matrix::get functions. I can't tell exactly at which place in spatial_color_quantization this is being triggered.

The problem is that b_value calculates indices to use in a get call to a matrix, and the indices that it calculates can sometimes be negative.

pub fn b_value<T>(b: &Matrix2d<T>, i_x: isize, i_y: isize, j_x: isize, j_y: isize) -> T
where
T: Clone + Default + Copy,
{
let radius_width = b.width().saturating_sub(1) / 2;
let radius_height = b.height().saturating_sub(1) / 2;
let k_x = j_x - i_x + radius_width as isize;
let k_y = j_y - i_y + radius_height as isize;
if let Some(val) = b.get(k_x as usize, k_y as usize) {

They are converted to usize to index the array and if negative they wraparound. The overflow occurs when this index i at the max value is added to the calculation for the index in the flattened row.

rscolorq/src/matrix.rs

Lines 48 to 50 in 8cce948

pub fn get(&self, i: usize, j: usize) -> Option<&T> {
self.data.get(j * self.width + i)
}

I've added some print statements to watch this and it seems like in the cli program, the wraparound occurs but the panic and overflow doesn't seem to. I don't know why my use of the library doesn't work.

The fix to it that I found was changing the get functions on the Matrix

https://github.com/pierogis/rscolorq/blob/e833cb7cdb6a509361308c6b0577644a4302dbee/src/matrix.rs#L47-L55

The wrapping methods on the usize objects work with the overflow and the output images are the same.

Something else kinda tangential to this issue: I think it would be good to swap the Matrix for the ndarray crate as it provides a more stable and well documented implementation of the same thing. ndarray also makes it really easy to do parallel with rayon if the algorithm could benefit from that anywhere. Would you be interested in a PR for that if I can get it working?

Investigate possible performance gains

It was brought up in #4 about using ndarray and a parallelization library to speed up calculations. It makes sense to use an external crate for matrix features instead of rolling our own. I'm not sure how much performance there is to gain so I'd like to see measurements; the algorithms may not be amenable to easy parallelization.

Benching/Testing

I'm fine with using the nightly cargo bench instead of bringing in criterion for now. Experimentation will need to be done wiring up the benches and figuring out what size image makes sense to iterate on (CC0 images preferred). The benches shouldn't take too long to run but hopefully run long enough to make reasonable deductions on performance changes.

Many of the calculations are operating on nested loop indices and not the matrix collection elements themselves. Based on that detail, I'm not sure if an external matrix library would add more overhead or improve performance. For multi-threading, we need to make sure we're not changing calculations that rely on being computed in an order.

The crate could use some better test coverage but the quantization functions are fairly opaque to me.

Things to do

Avenues of exploration

  • Add benchmarks, add image file(s), tests
    • Exclude the image data folder from Cargo.toml
  • External crates like ndarray and rayon should be behind optional feature gates at first
  • Investigate where parallelization would help in the quant or quant::utility functions

This comment will be updated with any changes or suggestions.

Filter 5 infinite loop

After a few temperature drops, the visit queue doesn't empty when running with filter size 5. There's a step counter and a debug print!() that can be uncommented to monitor the length. The black to white gradient that's 135x135 converges depending on the rng seed, and I've had the rainbow gradient converge as well. From watching the queue lengths that print out, it seems like the rng may stop adequately shuffling since it gets called so many times. The while loop clears out the queue length when it gets too large but the queue never seems to empty. I've gone over the code many times comparing it to the original and nothing obvious stood out but I assume the bug is in my implementation. I tried chacha and hc but those had the same issue. I'm not sure what criteria to use to reseed the rng or if that would even help.

step counter

// let mut steps = 0u32;

visit_queue
while !visit_queue.is_empty() {

print debug

rscolorq/src/quant.rs

Lines 458 to 462 in ce42053

// steps += 1;
// if steps % 10_000 == 0 {
// print!("{},", visit_queue.len());
// std::io::Write::flush(&mut std::io::stdout()).unwrap();
// }

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.