SixLabors / ImageSharp

:camera: A modern, cross-platform, 2D Graphics library for .NET
https://sixlabors.com/products/imagesharp/
Other
7.41k stars 852 forks source link

Add additional color spaces. #4

Closed JimBobSquarePants closed 5 years ago

JimBobSquarePants commented 7 years ago

From @JimBobSquarePants on December 1, 2015 12:29

More a nice to have than anything but I believe that if we are to do this properly we shouldbe able to convert where possible between different color spaces.

Currently we have the following.

Inspiration could be taken from the following:

http://colormine.org/ https://github.com/scijs/color-space

Copied from original issue: JimBobSquarePants/ImageProcessor#260

JimBobSquarePants commented 7 years ago

From @christopherbauer on January 11, 2016 3:50

Looks like we have the two missing color spaces merged into the v3 branch.

JimBobSquarePants commented 7 years ago

Yup... Forgot to close this. Thanks!

JimBobSquarePants commented 7 years ago

From @tompazourek on January 16, 2016 14:19

I wrote a .NET library that deals with color spaces. Might be useful:

https://github.com/tompazourek/Colourful

JimBobSquarePants commented 7 years ago

Hi Tom,

I'm sure that would be very useful. Would it be possible for you to cast your eye over the work we have done already to see if we have done anything daft?

Cheers

James

JimBobSquarePants commented 7 years ago

From @tompazourek on January 17, 2016 13:14

Hi James,

I had a brief look at the color conversions. Just few observations and notes:

For verifying if the conversions are correct, I always used this website, since I believe it yields good results: http://www.brucelindbloom.com/index.html?Eqn_RGB_XYZ_Matrix.html (the RGB you use will probably be sRGB, the white point of XYZ/LAB will be probably either D65 or D50 in your case). This might be useful for some tests that the numbers are alright.

Note that if you'd decide to implement all this hassle with white points, you might for example be able to easily do things like white balance correction. However the white-point-aware and RGB-workin-space-aware conversions require more work and might not perform well and be more difficult to optimize.

JimBobSquarePants commented 7 years ago

Thanks Tom,

This is all excellent feedback which I really appreciate! :+1: I'll annotate your input with my response to make it clear for anyone following what we are talking about.

Note that in the RGB color space the color is unambiguous only if accompanied by an RGB color space (working space). For, example this means that when you have an RGB triplet (0.6, 0.7, 0.1), it will represent slightly different colors if you say that the color space is sRGB or other (Apple RGB, Adobe RGB, CIE RGB). But I guess that for simplicity, you can just assume that all RGB triplets are in sRGB. Each of these RGB color spaces can have different reference colors, reference white

The Color struct defaults to the sRGB colorspace. I chose this since jpeg uses that as default (bitmap too?) and it's by far the most common format. Realistically I should be specifying the color format since gif or png files do not require gamma correction for interpolation etc in order to produce the correct output. This, at present, is leading me to perform unnecessary conversion to linear RGB when working with those image formats.

For XYZ and LAB color spaces, the color is unambiguous only if the reference white point is specified since the XYZ and LAB triplets are always relative to it. So if you have an XYZ triplet relative to D65 white point and the same triplet relative to D50 white point, each of these represent a different color since the D65 white is a bit more bluer than D50 white. If you don't have the white point, you cannot really tell what color it is, you can only assume that it might be D65 or D50 since these two are very common and these two are also used in most of the RGB spaces. If you convert from RGB and don't perform any transformation that would change the white point (these transformations are called chromatic adaptations - like Bradford chromatic adaptation), the target reference white point will be the same as the RGB white point (in sRGB space it is D65). It's possible that the coefficients that you use for conversion already contain some chromatic adaptation that will make the output white point different than D65 from sRGB. I didn't investigate that far.

I'll need to investigate this further as I didn't write the conversion code for those color spaces. Tests do seem to pass however, I do want to get all this correct.

When you're converting from RGB triplet to XYZ/LAB triplet, the RGB channels have to be linear before conversion, otherwise the results will not be correct. It's possible that the coefficients that you use for conversion already have the transformation from normal RGB to linear RGB in them. I didn't investigate that far. To battle the issue where I don't know if an RGB color is linear or compressed, I separated those in two color spaces in my library: RGBColor and LinearRGBColor. Not sure if this is possible or good decision in ImageProcessor.

The Color struct contains two methods Compress and Expand which performs companding from sRGB to linear RGB. We are definitely performing the correct calculation in our implicit casting in regards to that. As for separation of the structures.... Well truth be told I don't know whether that would be wise or not. Thinking about it there is no reason, that I can think of, for me to not simply use linear color throughout and then use each IImageFormat to convert the color to it's respective color space on decode/encode. I'm already premultiplying any alpha that way. That would greatly reduce any overheads inherent in multiple conversion and hopefully reduce confusion for developers using the software.

There's a lot to think about now. I'm definitely edging towards linear throughout. I'm not so worried about conversion performance, clever use of vectors should help with that and a developer wanting to perform those type of conversions will understand the overheads involved.

If you would like to get involved in the project you expertise would be most welcome!

JimBobSquarePants commented 7 years ago

Reopening this as I want to get it exactly right. I want to cater for Whitepoint etc.

JimBobSquarePants commented 7 years ago

From @manu-rv on June 30, 2016 20:29

I wanted to understand the code base before moving to complex features. Since this is unassigned, I would like to take up this feature.

JimBobSquarePants commented 7 years ago

@manu-rv Awesome! Most of the code is there already but still need the additional white point work added.

JimBobSquarePants commented 7 years ago

From @Ciantic on October 26, 2016 10:59

Umm, what does the checkmarks represent? Are they implemented already?

I'm having a problems with a one CMYK png image which I convert to resized JPG. It seems to come out as incorrect single color image. I'm trying to come up a simple repro as I look this problem further.

JimBobSquarePants commented 7 years ago

@Ciantic The checkmarks mean I have created structs that represent each colorspace and conversion between them.

I'm having a problems with a one CMYK png image which I convert to resized JPG. It seems to come out as incorrect single color image. I'm trying to come up a simple repro as I look this problem further.

Png's don't support CMYK so I don't know what you mean?

https://en.wikipedia.org/wiki/Portable_Network_Graphics

p.s. I'm assuming you mean using the core library yeah?

iamcarbon commented 7 years ago

How about DCI-P3 / for wide color images on Safari?

JimBobSquarePants commented 7 years ago

Hi @iamcarbon

Adding support for P3 is a separate process from these colorspaces.

It would require adding the ability to read/write color profiles to jpeg which is something I'd like to support but haven't gotten around to. it. I've raised another issue #74 to cover this requirement.

Cheers

James

SepiaGroup commented 7 years ago

@JimBobSquarePants

I don't know if this is the right spot to ask this question...

i have an image that i know i saved in RGB space from photoshop. when i resize it i can tell it has been moved to sRGB because the colors are muted. reading this thread you say that you default SaveAsJpg to sRGB color space so this is not a surprise.

is there a way to save a jpg using another color space? also when i looked at this image Exif data there was none. so even if there was a way to save in RBG space how would i know to do that?

i am just a bit confused on this and cannot find any info to help me.

thanks

JimBobSquarePants commented 7 years ago

I don't know if this is the right spot to ask this question...

Hi @SepiaGroup I suspect you know the answer to this... Not really as it's unrelated.

Jpeg's are generally not saved in RGB colorspaces but in a YCbCr representation of the sRGB colorspace. System Drawing does this as do most others. I suspect what you are actually seeing is the result of our current lack of support for ICC color profiles #74.

If you could add your image to that issue it would be most useful.

JimBobSquarePants commented 7 years ago

Hi @tompazourek it's been a while since we chatted but...

I'm starting to look into color conversion based on ICC profiles and it looks to me like a large portion of your Colourful.NET codebase would help me greatly in making the color management side a possibility. I wouldn't be able to simply reference your library as there are changes I would have to make and a lot of deep integration required so I wanted to make sure it was ok that I used your library as a base for my work.

I know your license is MIT but I wanted your approval first.

Cheers

James

tompazourek commented 7 years ago

Hi James, no problem, I'm happy it can contribute to something 😄

The library is not really optimized for performance, it's more a demonstration of some algorithms at this point, so I am not sure how helpful it will be when some of the conversions are applied to full images. I think some of the things that are possible to optimize are to use linear transformations in more places (even if it would mean losing some precision), but unfortunately I'm not that good at math to figure those out by myself. Also I do all the linear transformations that are there by trivial matrix multiplication algorithms I wrote, which I'm sure can be optimized somehow to utilize CPU/GPU better.

But feel free to use it as you need, I've licensed it as MIT for a reason.

Cheers, Tom

JimBobSquarePants commented 7 years ago

Thanks Tom, that's brilliant!

I can do some optimization on the color classes (convert to structs, use vectors etc) so I can add some speed there and make better use of CPU caches.

I'll give you a shout if I get stuck. 😄

Cheers!

James

JimBobSquarePants commented 5 years ago

Closing this now we have the ColorspaceConverter in dev. Many, many thanks to all involved who made that possible.