Image Processing with Python — Color Isolation for Beginners
By: Tonichi Edeza
Tags: Data Science, Segmentation, Colors, Python, Image Processing

Image Processing with Python — Color Isolation for Beginners

Color Isolates (Image by Author)

The need to isolate specific sections of your image is an essential skill and will serve you well in this field. For this article we discuss some techniques that will isolate specific sections of our image.

Let’s get started!

As always let us begin by importing the required Python Libraries.

import numpy as np

import matplotlib.pyplot as plt

from skimage.io import imshow, imread

from skimage.color import rgb2hsv, hsv2rgb

import cv2

To start off, let us choose a relatively easy picture to work with.

red_girl = imread('red_girl.PNG')

plt.figure(num=None, figsize=(8, 6), dpi=80)

imshow(red_girl);

Red Girl in Angkor Wat (Image by Author)

As we can see this image would be an ideal way to try out image isolation as there is a clear target. So how should we isolate the lady in red?

Well for starters recall that the image is composed of three color channels Red, Green, and Blue. Perhaps we can simply just filter for the Red Channel.

red_filtered_girl = (red_girl[:,:,0] > 150)

plt.figure(num=None, figsize=(8, 6), dpi=80)

imshow(red_filtered_girl, cmap = 'gray');

Filtered Image

This definitely does not look like what we want. Let us apply this mask back into an RGB image and see the result.

red_girl_new = red_girl.copy()

red_girl_new[:, :, 0] = red_girl_new[:, :, 0]*red_filtered_girl

red_girl_new[:, :, 1] = red_girl_new[:, :, 1]*red_filtered_girl

red_girl_new[:, :, 2] = red_girl_new[:, :, 2]*red_filtered_girl

plt.figure(num=None, figsize=(8, 6), dpi=80)

imshow(red_girl_new);

RGB Filtered Image

Though the image looks cool, it is definitely not what we wanted. So what is going on here? Well recall that the image does not consider each color a different “color” per se. All the colors are simply different mixtures of Red, Green, and Blue.

def rgb_splitter(image):

rgb_list = ['Reds','Greens','Blues']

fig, ax = plt.subplots(1, 3, figsize=(15,5), sharey = True)

for i in range(3):

ax[i].imshow(image[:,:,i], cmap = rgb_list[i])

ax[i].set_title(rgb_list[i], fontsize = 15) rgb_splitter(red_girl)

RGB Channels

Notice how despite not being perceivably red to the human eye, there are still red components in many of the other objects in the image. We must take this into account. Below is a code where we specify that the green and blue channels must also be below a certain thresh hold.

red_filtered = (red_girl[:,:,0] > 150) & (red_girl[:,:,1] < 100) & (red_girl[:,:,2] < 110)

plt.figure(num=None, figsize=(8, 6), dpi=80)

red_girl_new = red_girl.copy()

red_girl_new[:, :, 0] = red_girl_new[:, :, 0] * red_filtered

red_girl_new[:, :, 1] = red_girl_new[:, :, 1] * red_filtered

red_girl_new[:, :, 2] = red_girl_new[:, :, 2] * red_filtered

imshow(red_girl_new);

Red Filtered Image

This is much better, we can clearly see that the red girl is isolated from the rest of the image.

Note though that this method is only preferred when are required to target objects that have very distinct Red, Green, and Blue channels. To better isolate these colors, we can make use of the HSV Color Space.

def display_as_hsv(image):



img = cv2.imread(image)

img_hsv = cv2.cvtColor(img, cv2.COLOR_BGR2HSV)



hsv_list = ['Hue','Saturation','Value']

fig, ax = plt.subplots(1, 3, figsize=(15,7), sharey = True)



ax[0].imshow(img_hsv[:,:,0], cmap = 'hsv')

ax[0].set_title(hsv_list[0], fontsize = 20)

ax[0].axis('off')





ax[1].imshow(img_hsv[:,:,1], cmap = 'Greys')

ax[1].set_title(hsv_list[1], fontsize = 20)

ax[1].axis('off')





ax[2].imshow(img_hsv[:,:,2], cmap = 'gray')

ax[2].set_title(hsv_list[2], fontsize = 20)

ax[2].axis('off')



fig.tight_layout() display_as_hsv('red_girl.PNG')

HSV Channels

Unlike the RGB color space, the HSV color space explicitly segregates the color hue channel from both saturation and value. This allows us to target specific colors with ease. To aid us target specific colors, let us display the picture’s color bar.

plt.figure(num=None, figsize=(8, 6), dpi=80)

plt.imshow(red_girl_hsv[:,:,0], cmap='hsv')

plt.colorbar();

Hue Image with Color Bar

We can see that each color refers to a specific range on the color spectrum. Let us try to isolate red.

lower_mask = red_girl_hsv [:,:,0] > 0.90

upper_mask = red_girl_hsv [:,:,0] < 1.00

mask = upper_mask*lower_mask red = red_girl[:,:,0]*mask

green = red_girl[:,:,1]*mask

blue = red_girl[:,:,2]*mask

red_girl_masked = np.dstack((red,green,blue))

plt.figure(num=None, figsize=(8, 6), dpi=80)

imshow(red_girl_masked);

Hue Masked Image

We can see that the image clearly isolates the red lady. However, it also pics up several specks. If we compare it to the hue channel of the HSV color space, we see that these specks are also considered red even though they seem grey/brown. To alleviate this, let us add another filter for saturation.

lower_mask = red_girl_hsv [:,:,0] > 0.90

upper_mask = red_girl_hsv [:,:,0] < 1.00

saturation = red_girl_hsv [:,:,1] > 0.50 mask = upper_mask*lower_mask*saturation red = red_girl[:,:,0]*mask

green = red_girl[:,:,1]*mask

blue = red_girl[:,:,2]*mask

red_girl_masked = np.dstack((red,green,blue))

plt.figure(num=None, figsize=(8, 6), dpi=80)

imshow(red_girl_masked);

Added Saturation Filter

Excellent! We were able to successfully isolate the red lady by using the HSV channel. Let us try to isolate different colors. The code below does that for three different color settings.

def color_isolates(image):



image_hsv = rgb2hsv(image[:,:,:-1])

titles = ['Mask 1','Mask 2','Mask 3']

f_size = 22



#Sky Filter

lower_mask_1 = image_hsv [:,:,0] > 0.45

upper_mask_1 = image_hsv [:,:,0] < 0.75

saturation_1 = image_hsv [:,:,1] > 0.15

mask_1= lower_mask_1*upper_mask_1*saturation_1



#Red Filter

lower_mask_2 = image_hsv [:,:,0] > 0.90

upper_mask_2 = image_hsv [:,:,0] < 1.00

saturation_2 = image_hsv [:,:,1] > 0.50

mask_2= lower_mask_2*upper_mask_2*saturation_2





#Earth Fikter

lower_mask_3 = image_hsv [:,:,0] > 0.05

upper_mask_3 = image_hsv [:,:,0] < 0.15

saturation_3 = image_hsv [:,:,1] < 0.75

value_3 = image_hsv [:,:,2] < 0.70

mask_3= lower_mask_3*upper_mask_3*saturation_3*value_3 sky_filtered = np.dstack((image[:,:,0]*mask_1,

image[:,:,1]*mask_1,

image[:,:,2]*mask_1))



red_filtered = np.dstack((image[:,:,0]*mask_2,

image[:,:,1]*mask_2,

image[:,:,2]*mask_2))



earth_filtered = np.dstack((image[:,:,0]*mask_3,

image[:,:,1]*mask_3,

image[:,:,2]*mask_3))



images = [sky_filtered,red_filtered,earth_filtered]



fig, ax = plt.subplots(1, 3, figsize=(15,12))

for n, ax in enumerate(ax.flatten()):

ax.set_title(f'{titles[n]}', fontsize = f_size)

ax.imshow(images[n])

ax.set_axis_off()



fig.tight_layout()





color_isolates(red_girl)

Different Color Isolates

Of course one can easily see the issue of manually adjusting. It requires each image to be treated differently. If we were dealing with hundreds of images this methodology would not be feasible.

In Conclusion

We see that problems that seem complex at first, such as telling the machine to isolate specific colors, can be handled relatively easily. We learned the importance of not limiting yourself to dealing solely with the RGB color space. Knowledge of the HSV color space is extremely helpful when tackling problems that require color identification. In future we shall learn how to create scripts to identify similar colors and group them together, but for now I hope that you were able to get an idea of the many possibilities of image segmentation.