-
Notifications
You must be signed in to change notification settings - Fork 60
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Add rand
integration
#174
Comments
FeaturesWe need to figure out the bare minimum of Here's the rand book
default = ["std", "std_rng"]
# Option (enabled by default): without "std" rand uses libcore; this option
# enables functionality expected to be available on a standard platform.
std = ["rand_core/std", "rand_chacha/std", "alloc", "getrandom", "libc"]
# Option: "alloc" enables support for Vec and Box when not using "std"
alloc = ["rand_core/alloc"]
# Option (enabled by default): enable StdRng
std_rng = ["rand_chacha", "rand_hc"] Seeding, PRNGs, and CSPRNGshttps://rust-random.github.io/book/guide-rngs.html#basic-pseudo-random-number-generators-prngs PRNGs are faster and take up less memory but I don't believe they can be seeded in I think nonseedable and seedable rngs should both be available so users don't have to take a hit if they don't need it. I wouldn't grab seedable every time but I'd expect it to be there if I looked for it.
|
Thanks for taking a closer look at it. The portability seem to be a relatively small problem. Only
I think the overall direction should be to make things as generic as possible, regarding which RNG is used, just like For impl<T: SampleUniform, S> SampleUniform for Rgb<S, T> {
type Sampler = RgbSampler<S, T>;
} and Getting I think you are spot on when it comes to how to generate the component values. Hues cannot be inclusive, I think, because that would double count 0 (a.k.a. 360 degrees). Cylinders and cubes/blocks are a solved problem. HSV and HSL may need to be sampled as cone and bicone to avoid having an overrepresentation of grays (they are of course ambiguous enough to have arguments for both). Generating a point inside a symmetric bicone would be the same as generating a point inside either the top or bottom cone. A quick search gave me this, but we will have to transform the limits we give to HWB is weird, but I suspect it may just be a different representation of HSL. In that case one can piggyback on the other. That need to be looked into, though! I'm pretty sure Lch is just a plain cylinder within the Lab cube, so that one is fine. I think the rest that are tristimulus are cubes or blocks and Luma is a line.
I think I managed to get "normal" and "standard" mixed up in my head. As I wrote above, let's not care about the more fancy distributions for now. I will edit the issue description.
I think those are some nice ideas. They are technically covered by I'll edit the issue description continuously to reflect what we have discussed. |
I misunderstood and was getting caught up in higher level details of using rand, not implementing it 😅. I read more about the traits from rand and understand that the user will be the one interacting with the RNG. I also came across that SO answer which should be helpful. Thinking about HWB and playing with a color picker, I believe it can be represented the same as the HSV cone in the image above with the white and 100% saturation colors inverted. That is, the most saturated colors are located in the middle of the circle and the outside of the circle is white. Whiteness is the radius component and blackness the height component. Looking at the equations now that makes sense. In that case you might want more samples to be closer to the center of the circle. H = H
W = (1 - S)V
B = 1 - V It looks like start with UniformSampler, then SampleUniform, and then (optionally?) SampleBorrow. The UnitCircle was the simplest example I could find. It doesn't seem that hard to make distributions. I imagine RGB would look something like this. impl Distribution<Rgb<S, T>> for Uniform<Rgb<S, T>>
where
S: RgbStandard,
T: Component,
{
fn sample<R: Rng + ?Sized>(&self, rng: &mut R) -> Rgb<S, T> {
let uniform = Uniform::new_inclusive(0., 1.);
Rgb {
red: uniform.sample(rng),
green: uniform.sample(rng),
blue: uniform.sample(rng),
standard: PhantomData,
}
}
} It couldn't hurt to have a checklist of all the color types under the Distribution and SampleUniform checkpoints. Another question I have is how do we test/verify this? |
It seems like HWB is designed for color pickers, or at least the model doesn't necessarily care how the components are mixed. They can be normalized to still make sense. But I think it clicked for me now. HWB is HSV transformed into the cone shape. The multiplication with V for W is what turns it into a cone. That could mean that we can sample HWB as a cone where W is the inverse of the distance to the center and B is the distance from the base.
We will have to create our own samplers (implementing
Pretty much, but I think
I'll add them. 🙂
Oh, good question. Faking an RNG to give predictable values? We can control the input, so that's an option. At least to verify that the output is correct for some input. |
For your information, the paper on HWB is: Smith, A.R. and Lyons, E.R., 1996. HWB—A more intuitive hue-based color model. Journal of Graphics Tools 1(1), pp. 3-17. According to that paper, HWB is designed to be a more intuitive color model than HSV (which I believe was also invented by Smith), and is not a perception-based model. |
HSVI was wondering how we could sample HSV as a cone since all the cylinder values are valid. HSV color pickers often offer the option of a hue triangle or cube, so in our case I believe we can sample a 1-1-√2 triangle (with rejection testing) for saturation and value. We'd scale the saturation in proportion to its distance between the height edge of the triangle (value) and the hypotenuse. The hue angle would be
I think the saturation for the point HSL
Extending this to the HSL bicone, I think sampling from -1 to 1 for the height makes sense with 0 to 1 for saturation. If in the negative half, saturation will be roughly the same calculation for scaling HSV. First Lightness might need to be scaled from [-1,0] to [0,1] for saturation calculation then from [-1, 1] to [0,1] for the actual Lightness. If in the positive portion, the equation becomes Testing/validationI thought we could make example programs to output images then visually verify the samples looked uniform in a triangle, bicone radius slice/half-section, circle, and square. |
@peteroupc Thanks! I hadn't seen there was a paper, but will look into it. It may have some useful info. @okaneco Right, so what we really want to do is not to sample a cone within the HSV space, but warp the probability distribution to give more weight to the parts with higher If we would sample a triangle, we would get the probability right, as I understand it, but since we have a 3D shape it becomes a cone. If it's not a cone, but a triangular prism, we will get a similar overrepresentation of white and light colors. We could sample a cone with radius 1 and height 1, similar to your triangle. The SO link suggest calculating the radius (saturation) as The result, if I got it correctly, is
Not too bad. For HSL, my reasoning is that we have two cones. The probability to end up in either cone is equal, so it's basically |
I had to write out the triangle examples to help conceptualize it but the cone math makes a lot more sense now. And yes, HSL seems to boil down to a bool and then the only difference is lightness in the branches. That's really clean and it didn't seem to be so simple yesterday. And so HWB would look like this. The blackness remains because it stays a cone and we don't normalize to a cylinder.
In what manner should we go about PRs for this? Everything seems sorted out conceptually. |
HWB is still strange to me. Part of me want to go via HSV for that one. They are the same thing, according to the HWB paper:
Also HSV and HSL are apparently hexagonal. 😬
😵 That paper has a lot of good info! Thanks again, @peteroupc. I would suggest starting with one of the easier spaces (like RGB) and get the fundamentals in place, if you or anyone else want to get started with this. I'll keep track of progress with this issue. |
As discussed in #173, it would be helpful to have official support for generating random colors. Possibly also with min/max values for the components. The benefit of having it built into the library would be to make it easier to get uniformly distributed samples in each color space. Spaces like
Hsv
andLch
would sample within a cone and cylinder, for example.Here's a preliminary check list for the parts of this feature:
Distribution<T> for Standard
for each color space. Some will be more complicated than others, as their geometry are different. See the discussion below.Hsl
Hsv
Hwb
Lab
Lch
Luma
Rgb
Yxy
Xyz
Alpha
SampleUniform
for each color space. Will likely be able to share code with theDistribution
implementations.Hsl
Hsv
Hwb
Lab
Lch
Luma
Rgb
Yxy
Xyz
Alpha
Each part can be implemented separately, but probably best in top-to-bottom order.
Geometry:
Hsv
andHwb
- Cone. Seem to be the same space, but expressed differently.Hsl
- Bicone. Should be possible to sample as a random selection between two cones.Lab
,Rgb
,Xyz
andYxy
- Cubes and blocks. Each component can be sampled independently.Luma
- A line. Just a single value.Alpha
- Samples the contained color and the alpha channel independently.Other preferences and requirements:
#[no_std]
support.The text was updated successfully, but these errors were encountered: