# Shouldn't Colour have mathematical operator overloads? [SOLVED]

So I’m a super noob and possibly out of my depth here, but…

I’m trying to apply a convolution matrix on the pixels around a current index.

I want to create a new `Colour` from existing `Colour` values

The psuedo code in my head goes as follows:

``````Image::BitmapData buffer1Data(buffer1, Image::BitmapData::writeOnly);

for (int i = 1; i < rows-1; ++i)
for (int j = 1; j < cols-1; ++j)
{
Colour newColour = (    buffer1Data.getPixelColour(i-1,j) +
buffer1Data.getPixelColour(i+1,j) +
buffer1Data.getPixelColour(i,j-1) +
buffer1Data.getPixelColour(i,j+1) ) / 4;
}
``````

But the `Colour` class doesn’t know how to do addition or division. (It does have `operator=`, `operator==`, `operator!=`)

So instead I had to get around it by writing this:

`Image::BitmapData buffer1Data(buffer1, Image::BitmapData::writeOnly);`

``````Colour c1 = buffer1Data.getPixelColour(i-1,j);
Colour c2 = buffer1Data.getPixelColour(i+1,j);
Colour c3 = buffer1Data.getPixelColour(i,j-1);
Colour c4 = buffer1Data.getPixelColour(i,j+1);

uint8 newR = (c1.getRed() + c2.getRed() + c3.getRed() + c4.getRed()) / 4;
uint8 newG = (c1.getGreen() + c2.getGreen() + c3.getGreen() + c4.getGreen()) / 4;
uint8 newB = (c1.getBlue() + c2.getBlue() + c3.getBlue() + c4.getBlue()) / 4;
``````

Mixing colours is not such a common problem in JUCE? Or am I going about my problem the wrong way?

I haven’t tried it or looked at the code, but I can imagine that using `PixelRGB` or `PixelARGB` instead of `Colour` could make things easier when mixing. It also seems that you have access to the individual bytes using the enums, maybe the `blend` methods already do what you’d like to do.

Edit: After looking a little bit at the code: `blend` won’t do the job

The matter is, what would be the result of a colour multiplication?
You can multiply the RGBA components, you can multiply the HSV components, you can multiply only individual components.

I assume, multiplying or summing the brightness comes closest to what you want to achieve.

Also, if you work pixel by pixel, I would advise against using Colour per pixel, since the ColourHelpers::HSB does already more maths in the constructor alone, than you would expect it to:

Ideally you can work with the individual bytes yourself and try to use only trivial operations.

Here is how JUCE applies convolution to an Image, maybe use that class instead?

2 Likes

Isn’t it clear? Multiply the colour components of a Colour object? But yeah, I thought about using .getBrightness, but then I’d have to migrate to HSV.

Right, this sounds like what I want to do, but where do I learn how to do this. Are the bytes laid out in some kind standard defined by RGB, RGBA, HSV, CMYK etc.? I.e. if I research how these formats hold their data, it will be true for Image::BitmapData::data?

And it looks simple enough to use. My question about working with the individual bytes still stands though, because in the future there may be things I want to do, that I would need to access the bytes for!

Thanks as always

It’s not clear, it’s ambiguous…

1 Like

Luckily, in C++ you can define custom operators, so you can do something like this:

``````namespace custom_ops
{
template <typename Combine>
inline juce::Colour zip (juce::Colour a, juce::Colour b, Combine&& combine)
{
return juce::Colour::fromFloatRGBA (combine (a.getFloatRed(),   b.getFloatRed()),
combine (a.getFloatGreen(), b.getFloatGreen()),
combine (a.getFloatBlue(),  b.getFloatBlue()),
combine (a.getFloatAlpha(), b.getFloatAlpha()));
}

inline juce::Colour operator+ (juce::Colour a, juce::Colour b)
{
return zip (a, b, std::plus<>{});
}

inline juce::Colour operator* (juce::Colour a, juce::Colour b)
{
return zip (a, b, std::multiplies<>{});
}

// etc...
} // namespace custom_ops

int main()
{
using custom_ops::operator+, custom_ops::operator*;
juce::Colour a { 1.0f, 0.0f, 0.0f, 1.0f };
juce::Colour b { 0.0f, 1.0f, 0.0f, 1.0f };
auto c = a + b;
auto d = c * b * a;
}
``````

Note that:

• It’s a good idea to put the custom ops in their own namespace, and to switch the namespace on explicitly when you want to use the new operators.
• It’s rarely a good idea to supply operators unless it’s extremely obvious how they should behave. In the case of `Colour` I think it’s fairly clear - in GLSL the `vec4` type has similar elementwise operators and they’re pretty handy there.
1 Like

Yes! I completely forgot that you can actually define class methods outside of the class declaration!

(for better or worse, I’m a header only kind of guy!)

Great tip. Thank you!