I would like to implement a search where images can be filtered by colors. My image-model contains up to 10 UIColors that occur in that specific image, now I would like to have a filter with e.g. blue, green, red, yellow. How can I check (with a specified tolerance) if that specific image contains blue/green/...?
I tried with CIE94-difference, but that doesn't not match the perceived similarity by the human eye. I also tried to compare the hue and saturation value, but that doesn't work either.
As an example:
`#23567E` should be blue
`#7A010B` should be red as well as `#FD4E57`
`#0F8801` should be found for green as well as `#85FE97`
I have a specific instance of UIColor, e.g.
[UIColor colorWithRed:0.137 green:0.337 blue:0.494 alpha:1] // #23567E
this should be "equal" to .blue
[UIColor colorWithRed:0.478 green:0.00392 blue:0.0431 alpha:1] // #7A010B
should be "equal" to .red
and so on...
If your intend is only to check which color is your UIColor you can simply get your HSB color components and compare its hue value:
You will need a helper to convert your hexa string to UIColor
extension UIColor {
    convenience init?(hexString: String) {
        var chars = Array(hexString.hasPrefix("#") ? hexString.dropFirst() : hexString[...])
        switch chars.count {
        case 3: chars = chars.flatMap { [$0, $0] }; fallthrough
        case 6: chars = ["F","F"] + chars
        case 8: break
        default: return nil
        }
        self.init(red: .init(strtoul(String(chars[2...3]), nil, 16)) / 255,
                green: .init(strtoul(String(chars[4...5]), nil, 16)) / 255,
                 blue: .init(strtoul(String(chars[6...7]), nil, 16)) / 255,
                alpha: .init(strtoul(String(chars[0...1]), nil, 16)) / 255)
    }
}
And some helpers to extract its hue component:
extension UIColor {
    enum Color {
        case red, orange, yellow, yellowGreen, green, greenCyan, cyan, cyanBlue, blue, blueMagenta, magenta, magentaRed
    }
    func color(tolerance: Int = 15) -> Color? {
        precondition(0...15 ~= tolerance)
        guard let hsb = hsb else { return nil }
        if hsb.saturation == 0 { return nil }
        if hsb.brightness == 0 { return nil }
        let hue = Int(hsb.hue * 360)
        switch hue {
        case 0 ... tolerance: return .red
        case 30 - tolerance ... 30 + tolerance: return .orange
        case 60 - tolerance ... 60 + tolerance: return .yellow
        case 90 - tolerance ... 90 + tolerance: return .yellowGreen
        case 120 - tolerance ... 120 + tolerance: return .green
        case 150 - tolerance ... 150 + tolerance: return .greenCyan
        case 180 - tolerance ... 180 + tolerance: return .cyan
        case 210 - tolerance ... 210 + tolerance: return .cyanBlue
        case 240 - tolerance ... 240 + tolerance: return .blue
        case 270 - tolerance ... 270 + tolerance: return .blueMagenta
        case 300 - tolerance ... 300 + tolerance: return .magenta
        case 330 - tolerance ... 330 + tolerance: return .magentaRed
        case 360 - tolerance ... 360 : return .red
        default: break
        }
        return nil
    }
    var hsb: (hue: CGFloat, saturation: CGFloat, brightness: CGFloat, alpha: CGFloat)? {
        var hue: CGFloat = 0, saturation: CGFloat = 0, brightness: CGFloat = 0, alpha: CGFloat = 0
        guard getHue(&hue, saturation: &saturation, brightness: &brightness, alpha: &alpha) else {
            return nil
        }
        return (hue, saturation, brightness, alpha)
    }
}
Playground testing:
let blue: UIColor.Color? = UIColor(hexString: "#23567E").color()    // r 0.137 g 0.337 b 0.494 a 1.0
let red1: UIColor.Color? = UIColor(hexString: "#7A010B").color()    // r 0.478 g 0.004 b 0.043 a 1.0
let red2: UIColor.Color? = UIColor(hexString: "#FD4E57").color()    // r 0.992 g 0.306 b 0.341 a 1.0
let green1: UIColor.Color? = UIColor(hexString: "#0F8801").color()  // r 0.059 g 0.533 b 0.004 a 1.0
let green2: UIColor.Color? = UIColor(hexString: "#85FE97").color()  // t 0.522 g 0.996 b 0.592 a 1.0
UIColor(hue: 90/360, saturation: 0, brightness: 1, alpha: 1).color()  // nil
UIColor(hue: 90/360, saturation: 1, brightness: 0, alpha: 1).color()  // nil
UIColor(hue: 90/360, saturation: 0, brightness: 0, alpha: 1).color()  // nil
UIColor.black.color()       // nil
UIColor.white.color()       // nil
UIColor.lightGray.color()   // nil
UIColor.darkGray.color()    // nil
UIColor.red.color()     // 0...15 && 346...360 = red
UIColor.orange.color()  // 16...45 = orange
UIColor.yellow.color()  // 46...75 = yellow
UIColor(hue: 90/360, saturation: 1, brightness: 1, alpha: 1).color()   // 76...105 yellowGreen
UIColor.green.color()   // 106...135 = green
UIColor(hue: 150/360, saturation: 1, brightness: 1, alpha: 1).color()  // 136...165 greenCyan
UIColor.cyan.color()    // 166...195 = cyan
UIColor(hue: 210/360, saturation: 1, brightness: 1, alpha: 1).color()  // 196...225 cyanBlue
UIColor.blue.color()    // 226...255 = blue
UIColor(hue: 270/360, saturation: 1, brightness: 1, alpha: 1).color() // 256...285 blueMagenta
UIColor.magenta.color()  // 286...315 = magenta
UIColor(hue: 330/360, saturation: 1, brightness: 1, alpha: 1).color()  // 316...345 = magentaRed
 
        
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With