In this example, we will try to isolate the red-orange tips of the fence in the previous image, using manual thresholding of all channels. The ultimate goal is to acquire a binary image with only pixels belonging in the area we want, being equal to one. Let's start by using imtool
to get a better idea of what the RGB values of the pixels we want to isolate are.
imtool
:>> img = imread('my_image_color.bmp'), >> imtool(img);
Then, we will choose Inspect Pixel Values by clicking on the second icon from the left and placing our cursor on one of the red tips to see the RGB values of its neighbor pixels. We can repeat the process for other tips and also for getting samples from other image areas.
imtool
, we can set a general thresholding rule for our ROIs, which would be something like: "we want to keep pixels with high R values and low G and B values". The implementation of this rule could be something like this:>> red_binary = img(:,:,1) > 150; >> green_binary = img(:,:,2) < 150; >> blue_binary = img(:,:,3) < 150;
Now, we can mix the three binary images using the AND operator and display the result on a new figure:
>> final_mask = red_binary & green_binary & blue_binary; >> figure, imshow(final_mask)
RGBThreshold.m
:function [output] = RGBThreshold(input,thresholds) % Function that performs color image thresholding using % user-defined threshold values. Emphasises red areas. % Inputs: % input - Input image % thresholds – 1x3 matrix with the threshold values % for the R, G and B color channels. % Output: % output - Output image (binary) red_bin = input(:,:,1) > thresholds(1); % Red thresholding green_bin = input(:,:,2) < thresholds(2); % Green thresholding blue_bin = input(:,:,3) < thresholds(3); % Blue thresholding output = red_bin & green_bin & blue_bin; % Final image
>> [output1] = RGBThreshold(img,[150 150 150]); >> [output2] = RGBThreshold(img,[160 130 130]); >> [output3] = RGBThreshold(img,[180 140 140]); >> subplot(1,3,1),imshow(output1),title('Using [150 150 150]') >> subplot(1,3,2),imshow(output2),title('Using [160 130 130]') >> subplot(1,3,3),imshow(output3),title('Using [180 140 140]')
output2
, which apparently needs dilation to expand the ROIs to the size we would want. First, we will set the pixels above the line 100 to zero, to exclude unneeded areas. Then, we can use imdilate
with a structuring element like a diamond of size 5px, to see what happens (we'll show the result next to the original image):>> output2(1:100,:) = 0; >> final = imdilate(output2,strel('disk', 5)); >> figure, subplot(1,2,1), imshow(img), title('Original Image') >> subplot(1,2,2), imshow(final), title('Final binary mask')
In this example, we combined several methods presented so far for grayscale images to generate a modified masking example for color images. We used imtool
to acquire a feel of what the pixel values are for several regions of the image, including the region that we want to isolate. Then, we wrote a function to perform thresholding using user-defined threshold values for all the three color channels. With a trial-and-error process, we selected the most suitable thresholds (step 4), cleaned the areas we did not wish to include, and then dilated the binary result to acquire the final binary image (step 5).
A useful conclusion derived from this example would be that RGB images can be thresholded, but the process should really be performed in all color channels in order to optimize our result. This has to do with the fact that the RGB color space channels are highly correlated to each other, meaning that all three values are required to describe a given color. This results in the counterintuitive deduction, that we usually cannot just threshold the R channel to isolate red pixels, but would need to combine the R channel mask with the G and B channel masks to produce optimal results.