### The first attempt

Working on a project where users can customise background colour for their profile, I needed a way to test if a background colour is light or dark in order to choose an appropriate text colour – black on light colours and white on dark ones. My search for a solution began with me calculating the greyscale of colour, but any algorithm I tried produced mixed results that didn’t satisfy my needs.

Then I changed my approach and started to consider RGB colours as points in 3D space where r, g, n are the axes. In this case, black is a point represented by the coordinate (0, 0, 0). A colour is darker the closer it is to this “black” point. So, calculating the brightness of the colour became a question of calculating distance in 3D space, which could be answered with the formula:

sqrt(dx^2+dy^2+dz^2)

or in our case simply,

sqrt(x^2+y^2+z^2)

because black is (0, 0, 0).

### Still not right

This solution, however, was not perfect. One of the problems that arose was related to the fact that red, green and blue have different wavelengths and consequently they have three different contributions in the formation of the final colour. The colour red has the longest wavelength of the three colours, while green has a shorter wavelength than red. Not only this, but green is also the colour that produces a more soothing effect on the eyes. This means we have to decrease the contribution of the red colour and increase the contribution of the green colour. In other words, we needed to find a way to adjust colour weight.

### The final solution

There is no unique way to choose colour weight, so we decided to use the same algorithm for converting RGB to YIQ colour space used in standard colour TV and video systems in North America. Weights for red, green and blue are 0.299, 0.587 and 0.114. Knowing how to choose the right weight for each colour component required knowledge of photometry, however, this is beyond the scope of this blog.

Combining the colour weights and the distance formula presented earlier, we came up with a final solution. Below is the solution we implemented in ruby:

```def brightness(pixel)
Math.sqrt(
0.299 * pixel.red**2 +
0.587 * pixel.green**2 +
0.114 * pixel.blue**2
).to_i
end```

Because brightness can be considered as a grayscale, we can use the same formula for converting coloured images into black-and-white. We have to replace each r, g, b component in every pixel with pixel brightness. Below is a ruby implementation and what we got as a result.

```require 'RMagick'

def brightness(pixel)
Math.sqrt(
0.299 * pixel.red**2 +
0.587 * pixel.green**2 +
0.114 * pixel.blue**2
).to_i
end

image.each_pixel do |pixel, c, r|
pixel.red = pixel.green = pixel.blue = brightness(pixel)
image.pixel_color(c, r, pixel)
end

image.write("gray.jpg")```

For reading image from file and saving to file solution using ImageMagick image processing library (check it out here) and RMagick gem (check it out here)

In the era of financial services’ transformation, where digitalization has become inevitable, the market is flooded with Fintech apps. It’s rare to find someone who hasn’t used at least one daily. Whether your app is geared towards investment management or streamlining buying and selling processes, our previous experience has highlighted…
Introduction One of the most widely used tools in the application management field is Kubernetes. However, it's essential to monitor activity within your Kubernetes cluster. The Go Informers package fulfills that need. It functions as a helpful assistance to help you stay informed about the activities happening in Kubernetes clusters.…
When and why do we need background jobs? Nowadays, background job processing is indispensable in the world of web development. The need for background jobs stems from the fact that synchronous execution of time-consuming and resource-intensive tasks would heavily impact an application's  performance and user experience.  Even though Elixir is…