# Arithmetic on colors

**URL:** <https://discourse.julialang.org/t/arithmetic-on-colors/85297>\
**Category:** General Usage\
**Tags:** colors\
**Created:** [August 4, 2022, 11:43am UTC](https://discourse.julialang.org/t/arithmetic-on-colors/85297 "2022-08-04T11:43:26Z")\
**Posts on this page:** 17\
**Page:** 1

<div class="post-metadata">

**Author:** ![rakeshvar](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/rakeshvar/32/3613_2.png) [@rakeshvar](https://discourse.julialang.org/u/rakeshvar)\
**Post date:** [August 4, 2022, 11:43am UTC](https://discourse.julialang.org/t/arithmetic-on-colors/85297/1 "2022-08-04T11:43:26Z")

</div>

Hello there,  
I want to find the total Sum of Squared Errors of a set of colors from their mean. `Using Colors`.  
The colors and the mean look something like this, where `m = mean(cols)`.

```julia
cols[1:10] = RGB{FixedPointNumbers.Normed{UInt8,8}}[RGB{N0f8}(0.086,0.051,0.024), RGB{N0f8}(0.094,0.059,0.031), RGB{N0f8}(0.106,0.071,0.051), RGB{N0f8}(0.141,0.106,0.086), RGB{N0f8}(0.102,0.067,0.047), RGB{N0f8}(0.141,0.106,0.086), RGB{N0f8}(0.176,0.149,0.125), RGB{N0f8}(0.078,0.051,0.027), RGB{N0f8}(0.114,0.086,0.063), RGB{N0f8}(0.149,0.122,0.098)]
m = RGB{Float64}(0.5797770398481967,0.5710550284629976,0.5525899746995568)

```

But

```julia
sse = sum(abs2, cols .- m)

```

throws error  
`  
ERROR: LoadError: MethodError: no method matching depwarn(::String, ::Symbol; force=false)

`

I am wondering how to do it? I will be finding SSE of sections of image over and over again. What is the best way to do it? Convert the original image to Floats? I will also be using `hex(m)` to save the mean color to an svg image.

Edit MWE:

```julia
cols = rand(RGB{Float64}, 4, 4)
m = mean(cols)
cols .- m # Also a Matrix of RGB{Float64} with some negative values!!!
sum(abs2, cols .- m) # Errors out

```

Thanks.

---

<div class="post-metadata">

**Author:** ![DNF](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/dnf/32/10191_2.png) [@DNF](https://discourse.julialang.org/u/DNF)\
**Post date:** [August 4, 2022, 11:58am UTC](https://discourse.julialang.org/t/arithmetic-on-colors/85297/2 "2022-08-04T11:58:06Z")

</div>

The error has nothing to do with colors. It’s just that you cannot take `abs2` of an array, it only works on scalars:

```julia
julia> abs2([-2, 0, 1])
ERROR: MethodError: no method matching abs2(::Vector{Int64})

```

In order to work on arrays, you must broadcast or map the function over the array (or loop):

```julia
julia> abs2.([-2, 0, 1])
3-element Vector{Int64}:
 4
 0
 1

julia> map(abs2, [-2, 0, 1])
3-element Vector{Int64}:
 4
 0
 1

```

---

<div class="post-metadata">

**Author:** ![rakeshvar](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/rakeshvar/32/3613_2.png) [@rakeshvar](https://discourse.julialang.org/u/rakeshvar)\
**Post date:** [August 4, 2022, 11:58am UTC](https://discourse.julialang.org/t/arithmetic-on-colors/85297/3 "2022-08-04T11:58:52Z")

</div>

Sorry, just realized my mistake and updated the post as you were typing yours.

---

<div class="post-metadata">

**Author:** ![DNF](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/dnf/32/10191_2.png) [@DNF](https://discourse.julialang.org/u/DNF)\
**Post date:** [August 4, 2022, 12:02pm UTC](https://discourse.julialang.org/t/arithmetic-on-colors/85297/4 "2022-08-04T12:02:34Z")

</div>

Yeah, I saw that. Just poor timing. But maybe you can make the example self contained? Make a code snippet with `using Colors` and then generate a random color vector. It’s so much easer if I can just copy-paste your example directly into my REPL. It’s called ‘making a minimum working example’, and is extremely useful.

---

<div class="post-metadata">

**Author:** ![rakeshvar](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/rakeshvar/32/3613_2.png) [@rakeshvar](https://discourse.julialang.org/u/rakeshvar)\
**Post date:** [August 4, 2022, 12:05pm UTC](https://discourse.julialang.org/t/arithmetic-on-colors/85297/5 "2022-08-04T12:05:00Z")

</div>

Did not feel like this deserved an MWE. Just that `RGB{Float64} does not have abs2 defined!` That’s it. If I do

```julia
abs3(a) = a.r*a.r+a.g*a.g+a.b*a.b
sum(abs3, cols)

```

works. I feel I should not have to do this.

---

<div class="post-metadata">

**Author:** ![DNF](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/dnf/32/10191_2.png) [@DNF](https://discourse.julialang.org/u/DNF)\
**Post date:** [August 4, 2022, 12:07pm UTC](https://discourse.julialang.org/t/arithmetic-on-colors/85297/6 "2022-08-04T12:07:02Z")

</div>

I don’t think `abs2` makes sense for colors. What is the absolute value of a color? Are there negative colors?

There should almost always be an MWE. Especially this time, it would have simplified the interaction considerably.

---

<div class="post-metadata">

**Author:** ![rakeshvar](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/rakeshvar/32/3613_2.png) [@rakeshvar](https://discourse.julialang.org/u/rakeshvar)\
**Post date:** [August 4, 2022, 12:08pm UTC](https://discourse.julialang.org/t/arithmetic-on-colors/85297/7 "2022-08-04T12:08:14Z")

</div>

Sorry again. Back to the original use case.  
It definitely makes sense to calculate the SSE of a bunch of colors from their mean.

---

<div class="post-metadata">

**Author:** ![DNF](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/dnf/32/10191_2.png) [@DNF](https://discourse.julialang.org/u/DNF)\
**Post date:** [August 4, 2022, 12:12pm UTC](https://discourse.julialang.org/t/arithmetic-on-colors/85297/8 "2022-08-04T12:12:26Z")

</div>

While I cannot answer this question off the top of my head, in the sense of explaining why `abs2` doesn’t work, I perhaps could if I looked at the data. But without an MWE, I’m not getting anywhere.

If I do

```julia
julia> using Colors

julia> cols = RGB{FixedPointNumbers.Normed{UInt8,8}}[RGB{N0f8}(0.086,0.051,0.024), RGB{N0f8}(0.094,0.059,0.031), RGB{N0f8}(0.106,0.071,0.051), RGB{N0f8}(0.141,0.106,0.086), RGB{N0f8}(0.102,0.067,0.047), RGB{N0f8}(0.141,0.106,0.086), RGB{N0f8}(0.176,0.149,0.125), RGB{N0f8}(0.078,0.051,0.027), RGB{N0f8}(0.114,0.086,0.063), RGB{N0f8}(0.149,0.122,0.098)]
ERROR: UndefVarError: FixedPointNumbers not defined

```

I just get an error.

There _really_ needs to be an MWE here.

---

<div class="post-metadata">

**Author:** ![DNF](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/dnf/32/10191_2.png) [@DNF](https://discourse.julialang.org/u/DNF)\
**Post date:** [August 4, 2022, 12:23pm UTC](https://discourse.julialang.org/t/arithmetic-on-colors/85297/9 "2022-08-04T12:23:11Z")

</div>

So, I installed Images.jl, and took a look. Now I can show you why `abs2` doesn’t make sense:

```julia
julia> using Images

julia> cols = [RGB{N0f8}(0.086,0.051,0.024), RGB{N0f8}(0.094,0.059,0.031)]
2-element Array{RGB{N0f8},1} with eltype RGB{N0f8}:
 RGB{N0f8}(0.086,0.051,0.024)
 RGB{N0f8}(0.094,0.059,0.031)

julia> x = cols[1] - cols[2]
RGB{N0f8}(0.996,0.996,0.996)

julia> y = cols[2] - cols[1]
RGB{N0f8}(0.008,0.008,0.008)

julia> x.r^2 + x.g^2 + x.b^2
0.969N0f8

julia> y.r^2 + y.g^2 + y.b^2
0.0N0f8

```

As you can see, there are no negative colors, the values just wrap around. As a consequence `abs2(cols[1] - cols[2])` is different from `abs2(cols[2] - cols[1])` (if we defined `abs2` as the sum of the squares of the rgb channels). That’s not what you want.

If you want a distance measure, it needs to be defined differently, because subtraction is not behaving as you expect on colors.

As you can see, there are a few things going on here. This is what MWEs are for.

---

<div class="post-metadata">

**Author:** ![stevengj](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/stevengj/32/71_2.png) [@stevengj](https://discourse.julialang.org/u/stevengj)\
**Post date:** [August 4, 2022, 12:24pm UTC](https://discourse.julialang.org/t/arithmetic-on-colors/85297/10 "2022-08-04T12:24:00Z")

</div>

> [@rakeshvar](#):
>
> `sse = sum(abs2, cols .- m)`

This is provided by [ColorVectorSpace.jl](https://github.com/JuliaGraphics/ColorVectorSpace.jl):

```julia
julia> sse = sum(abs2, cols .- m)
6.888337554125739

```

Better yet, use the `norm` function (which is the same thing divided by `3` for RGB colors, because it is normalized to be the same for grayscale and color images):

```julia
julia> norm(cols .- m)^2 * 3
6.888337554125741

```

---

<div class="post-metadata">

**Author:** ![DNF](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/dnf/32/10191_2.png) [@DNF](https://discourse.julialang.org/u/DNF)\
**Post date:** [August 4, 2022, 12:30pm UTC](https://discourse.julialang.org/t/arithmetic-on-colors/85297/11 "2022-08-04T12:30:39Z")

</div>

But I get:

```julia
julia> ColorVectorSpace.norm(cols[2] .- cols[1])^2 * 3
0.0

julia> ColorVectorSpace.norm(cols[1] .- cols[2])^2 * 3
2.976470717669955

```

Is this the right behaviour for color distance?

---

<div class="post-metadata">

**Author:** ![stevengj](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/stevengj/32/71_2.png) [@stevengj](https://discourse.julialang.org/u/stevengj)\
**Post date:** [August 4, 2022, 12:48pm UTC](https://discourse.julialang.org/t/arithmetic-on-colors/85297/12 "2022-08-04T12:48:09Z")

</div>

> [@DNF](#):
>
> But I get:
> 
> ```julia
> julia> ColorVectorSpace.norm(cols[2] .- cols[1])^2 * 3
> 0.0
> 
> ```

Looks like this is underflow due to the fixed-point precision:

```julia
julia> cols[2] - cols[1]
RGB{N0f8}(0.008,0.008,0.008)

julia> norm(cols[2] - cols[1])
0.0

julia> norm(RGB{Float64}(cols[2] - cols[1]))
0.00784313725490196

```

In particular, the problem stems from the underflow:

```julia
julia> N0f8(0.008)^2
0.0N0f8

```

Arguably, this should be changed — since the output of `norm` is a `Float64`, this computation should be performed by promoting operands to the output precision. Or at the very least some scaling should be done to prevent spurious overflow/underflow (similar to what `norm` and `hypot` do for floating-point vectors).

(_Update_: Filed issue [ColorVectorSpace.jl#183](https://github.com/JuliaGraphics/ColorVectorSpace.jl/issues/183).)

---

<div class="post-metadata">

**Author:** ![DNF](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/dnf/32/10191_2.png) [@DNF](https://discourse.julialang.org/u/DNF)\
**Post date:** [August 4, 2022, 12:59pm UTC](https://discourse.julialang.org/t/arithmetic-on-colors/85297/13 "2022-08-04T12:59:36Z")

</div>

The concept of arithmetic on colors is a bit fuzzy to me. It makes sense to add (mix) colors. So I guess subtraction also might work. But what should happen when you subtract a strong color from a weak color? Should it wrap around, or saturate, or return negative values?

A distance function seems like it should do something like subtracting the minimum from the maximum instead of taking the absolute or square of the difference.

---

<div class="post-metadata">

**Author:** ![rafael.guerra](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/rafael.guerra/32/216610_2.png) [@rafael.guerra](https://discourse.julialang.org/u/rafael.guerra)\
**Post date:** [August 4, 2022, 3:05pm UTC](https://discourse.julialang.org/t/arithmetic-on-colors/85297/14 "2022-08-04T15:05:23Z")

</div>

I guess that in the physical world, if we have no red and try to subtract red, we should always end up with no red. However, using the ColorVectorSpace, we get a “negative” red:

` RGB{Float64}(0,1,1) - RGB{Float64}(1,1,1) == RGB{Float64}(-1.0,0.0,0.0)`

Such colors live only in the “mathematical world” and are invalid for display purposes? They would need to be saturated/confined to 0-1 limits, in order to be plotted.

---

<div class="post-metadata">

**Author:** ![rakeshvar](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/rakeshvar/32/3613_2.png) [@rakeshvar](https://discourse.julialang.org/u/rakeshvar)\
**Post date:** [August 4, 2022, 3:10pm UTC](https://discourse.julialang.org/t/arithmetic-on-colors/85297/15 "2022-08-04T15:10:31Z")

</div>

Arthmetic on colors, especially the use-case given here, is very fundamental to image and video storage. All your jpgs and pngs do it thousands or millions of times. They replace a blob with a single color and see how well it fits (at some level). Wavelets, compressed sensing they all do this. Not every mathematical operation needs to map to the real world. Case in point: “Imaginary” numbers.  
I feel this is a bug in Colours.jl and need to be thought through.

---

<div class="post-metadata">

**Author:** ![DNF](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/dnf/32/10191_2.png) [@DNF](https://discourse.julialang.org/u/DNF)\
**Post date:** [August 4, 2022, 3:28pm UTC](https://discourse.julialang.org/t/arithmetic-on-colors/85297/16 "2022-08-04T15:28:53Z")

</div>

That doesn’t mean that one shouldn’t strive to make the operations internally consistent.

> [@rakeshvar](#):
>
> I feel this is a bug in Colours.jl

So what’s the right behavior of `RGB{N0f8}` under subtraction, then? They are based on `UInt8` which are unsigned, and therefore incapable of holding negative values. Which makes sense for storing color values, but makes subtraction (and many other types of arithmetic) problematic.

> [@rakeshvar](#):
>
> and need to be thought through.

That was exactly my point.

---

<div class="post-metadata">

**Author:** ![DNF](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/dnf/32/10191_2.png) [@DNF](https://discourse.julialang.org/u/DNF)\
**Post date:** [August 4, 2022, 3:40pm UTC](https://discourse.julialang.org/t/arithmetic-on-colors/85297/17 "2022-08-04T15:40:28Z")

</div>

I now see you made an MWE using `RGB{Float64}`. That’s probably the right approach. Doing what you want in unsigned arithmetic is probably needlessly complicated.
