Reputation:
I'd like to do some kind of special color comparison. During my research I found out that the comparison should not be done using RGB spectrum because some different spectres like HSL & HSV are designed to "more closely align with the way human vision perceives color-making attributes" (quote wikipedia).
So I need a way to convert different colorSystems into each other.
One of the most important conversion for my purposes would be to convert HEX to HSL (using Swift)
Because I'm a bloody beginner this code is all that I've got so far:
// conversion HEX to HSL
HexToHSL("#F23CFF") // HSL should be "HSL: 296° 100% 62%"
func HexToHSL(_ hex: String) {
let rgb = HexToRgb(hex)
let r = rgb[0],
g = rgb[1],
b = rgb[2],
a = rgb[3]
}
func RgbToHSL(r: Int, g: Int, b: Int) -> [Int] {
let r = r/255, g = g/255, b = b/255;
let max = [r, g, b].max()!, min = [r, g, b].min()!;
let (h, s, l) = Double(max + min)*0.5; // "Expression type 'Double' is ambiguous without more context"
if (max == min) {
h = s = 0;
} else {
let d = max - min;
s = l > 0.5 ? d / (2 - max - min) : d / (max + min);
h /= 6;
}
return [ h, s, l ];
}
func HexToRgb(_ hex: String) -> [Int] {
let hex = hex.substring(fromIndex: 1)
var rgbValue:UInt32 = 0
Scanner(string: hex).scanHexInt32(&rgbValue)
let red = Int((rgbValue & 0xFF0000) >> 16),
green = Int((rgbValue & 0x00FF00) >> 8),
blue = Int(rgbValue & 0x0000FF),
alpha = Int(255.0)
return [red, green, blue, alpha]
}
Any help how to fix the color conversion from HEX to HSL would be very appreciated, thanks in advance!
Note: Theres also a javascript sample for some kind of color conversion. Maybe it's helpful :)
Edit: I have fixed the code for rgb to hsl like this:
func RgbToHSL(_ rgb: [Int]) -> [Double] {
let r = Double(rgb[0])/255, g = Double(rgb[1])/255, b = Double(rgb[2])/255;
let max = [r, g, b].max()!, min = [r, g, b].min()!;
var h = Double(max + min)*0.5,
s = Double(max + min)*0.5,
l = Double(max + min)*0.5;
if (max == min) {
h = 0
s = 0
l = 0
} else {
let d = max - min;
s = l > 0.5 ? d / (2 - max - min) : d / (max + min);
switch (max) {
case r: h = (g - b) / d + (g < b ? 6 : 0); break;
case g: h = (b - r) / d + 2; break;
case b: h = (r - g) / d + 4; break;
default: break;
}
h /= 6;
}
return [ h, s, l ];
}
... but the result for rgb = [242, 60, 255]
will be [0.8222222222222223, 1.0, 0.61764705882352944]
-- doesn't looks fine because it should be 296° 100% 62%
! :o
Upvotes: 2
Views: 283
Reputation: 4070
In order to compare colours, thus perform colour differences you need to use a perceptually uniform colourspace.
HSL and HSV are actually very poor colourspaces to do so, they should not be used for proper colorimetric computations because their Lightness and Value axis are not actual perceptual representation of Luminance contrary to colourspaces such as CIE L*a*b* and CIE L*u*v*.
There are multiple ways to compute colour difference in colour science, usually the simplest and the one assuming you are using a uniform colourspace is euclidean distance.
This is what DeltaE CIE 1976 does using the CIE L*a*b* colourspace. The CIE noticed that some colours with low DeltaE values were actually appearing quite different, this was a side effect of CIE L*a*b* colourspace not being perceptually uniform enough. From there research has produced many new colour difference formulas and new perceptually uniform colourspaces.
Here is a non-exhaustive list from oldest to most recent of notable colour difference formulas and perceptually uniform colourspaces, notice the implementation complexity almost follows the list order:
I would suggest to look at something like ICTCP or JzAzBz which offer good performance and are not super complex to implement or at the very least use CIE L*a*b* with euclidean distance but avoid using HSL and HSV.
We have reference implementations for everything mentioned here in Colour.
Upvotes: 1