× {{alert.msg}} Never ask again
Get notified about new tutorials RECEIVE NEW TUTORIALS

# Change color of a specific region in eye image [Matlab]

Ray Phan
Feb 02, 2015
<p>Unfortunately, you don't have a choice but to detect where the pupil is located and fill those pixels in with your desired colour. Simply thresholding will not work because the eyelashes have roughly the same intensity distribution as the pupil.</p> <p>What we can do is do some post-processing <strong>after</strong> you threshold the image. However, what I am suggesting will require the Image Processing Toolbox in MATLAB. If you don't have this, then unfortunately my solution won't work.</p> <p>Assuming that you do have access to this, what I can suggest is use <a href="http://www.mathworks.com/help/images/ref/regionprops.html" rel="nofollow"><code>regionprops</code></a> to detect unique shapes in your image. This is assuming that you threshold the image properly. I'm going to specifically look at the <code>'Area'</code> and <code>'PixelList'</code> attributes. Once we threshold the image, we should expect predominantly two areas of clustered pixels: The eyelashes and the pupil. The eyelashes will probably have the largest amount of area while the pupil the second largest. As such, let's take a look at the <code>Area</code> attribute and determine the object in your image that has the second largest area. Once we find this object, we will set these pixels where this area is located to whatever colour you wish. However, we're going to have to do a bit of post-processing to ensure that the entire pupil gets filled in. You see that there is a white spot in the middle of the pupil most likely due to the flash of the camera. We would essentially need to ensure that the entire detected pupil is a closed contour, then fill in the shape. Once we fill in this shape, we simply use these pixels and set them to whatever colour you wish in the output image.</p> <hr> <p>Now, the first step is to threshold the image properly. First, I read in the image directly from StackOverflow. However, this image is a RGB image, and I want the grayscale equivalent. We can use <a href="http://www.mathworks.com/help/matlab/ref/rgb2gray.html" rel="nofollow"><code>rgb2gray</code></a> to accomplish that for us. Once that's done, I used a threshold of intensity 35, then ran through <code>regionprops</code> like so:</p> <pre><code>im = imread('http://i.stack.imgur.com/d3hy5.jpg'); im = rgb2gray(im); s = regionprops(im &lt; 35, 'Area', 'PixelList'); </code></pre> <p><code>s</code> will contain a structure of information, where each element tells you the area and the pixels that belong to each unique object that was detected in your image. Let's take a look at the area:</p> <pre><code>areas = [s.Area].' areas = 1 2 1 2 5 3 1 19 3 1 2 2 1 23 1224 1 2 41 12 2 1 2 1 5 2 33 480 3 6 1 2 1 1 2 1 </code></pre> <p>You can see that there are a lot of spurious isolated pixels that result after we threshold, which makes sense. You will also see that we have a couple of patches that have a significantly larger area than the majority of the patches. There is one patch that has an area of 1433, while another 480. The area with 1433 is most likely the pixels that belong to the eyelashes, as they more or less share the same intensity distribution as that of your pupil. The pupil will lost likely be the second highest area. As such, let's take a look at the patch that has the <strong>second highest area</strong>. To figure out where this is, use <a href="http://www.mathworks.com/help/matlab/ref/find.html" rel="nofollow"><code>find</code></a>:</p> <pre><code>ind = find(areas == 480); </code></pre> <p>Now that we know where this is located in <code>s</code>, let's pull this out and get out the <code>PixelList</code> attribute. This gives you a list of pixels that belong to the object:</p> <pre><code>pix = s(ind).PixelList; </code></pre> <p>The first column denotes the column position of each pixel belonging to the object while the second column denotes the row position. What I'm going to do next is take these pixels and create a <strong>mask</strong> that only contains these detected pixels. I will use this mask to index into the original image and set those pixels to whatever colour you want. As such:</p> <pre><code>mask = logical(full(sparse(pix(:,2), pix(:,1), 1, size(im,1), size(im,2)))); </code></pre> <p>The code uses <a href="http://www.mathworks.com/help/matlab/ref/sparse.html" rel="nofollow"><code>sparse</code></a> to create a sparse matrix where every value is 0 <strong>except</strong> for those pixel locations defined in <code>pix</code>. This is an easier way of creating matrix of 1s only at specified locations and 0 otherwise. Because this is <code>sparse</code>, I need to change this to a <a href="http://www.mathworks.com/help/matlab/ref/full.html" rel="nofollow"><code>full</code></a> numeric matrix that we can use, and we finally need to cast using <code>logical</code> to ensure a proper mask.</p> <p>If we show this mask using <code>imshow</code>, this is what we get:</p> <p><img src="http://i.stack.imgur.com/HFry3.png" alt="enter image description here"></p> <p>You can see that there is a gap due to the white spot of the pupil in the original image, which makes sense. You will also notice that the contour of the pupil isn't entirely closed. As such, I'm going to perform morphological closing by <a href="http://www.mathworks.com/help/images/ref/imclose.html" rel="nofollow"><code>imclose</code></a> by choosing a disk structuring element to close the gaps. Once we close the gaps, we can use <a href="http://www.mathworks.com/help/images/ref/imfill.html" rel="nofollow"><code>imfill</code></a> and choose the <code>'holes'</code> flag to fill in these holes.</p> <p>We now have a fully filled in mask that we can finally use to index into the original image and set our colours. As such:</p> <pre><code>mask = imclose(mask, strel('disk', 4, 4)); mask = imfill(mask, 'holes'); </code></pre> <p>Here's what the mask looks like now:</p> <p><img src="http://i.stack.imgur.com/EXdgV.png" alt="enter image description here"></p> <p>Cool! Now the last thing you need to do is colour in those pixels with whatever colour you wish. To do this, you'll need to make a RGB version of your image. As such, simply create red, green and blue channels that replicate the grayscale content of your image and set each channel with the appropriate colour using the pixels defined in the mask. </p> <pre><code>red = im; red(mask) = 255; green = im; green(mask) = 0; blue = im; blue(mask) = 0; out = cat(3, red, green, blue); imshow(out); </code></pre> <p>Remember that for grayscale images, the RGB equivalent has all of the red, green and blue values the same. Once we set the colour for the pupil, stack all of these together as a 3D matrix using <a href="http://www.mathworks.com/help/matlab/ref/cat.html" rel="nofollow"><code>cat</code></a> and we finally show the image. I've also set the colour of the pupil to red. You can change the RGB value to whatever you desire by changing the constant assignment <code>(255, 0, 0)</code> to be your desired colour.</p> <p>This is what we get:</p> <p><img src="http://i.stack.imgur.com/3OCax.png" alt="enter image description here"></p> <hr> <p>For your copying and pasting pleasure, this is the full code from start to finish:</p> <pre><code>im = imread('http://i.stack.imgur.com/d3hy5.jpg'); im = rgb2gray(im); s = regionprops(im &lt; 35, 'Area', 'PixelList'); areas = [s.Area].'; ind = find(areas == 480); pix = s(ind).PixelList; mask = logical(full(sparse(pix(:,2), pix(:,1), 1, size(im,1), size(im,2)))); mask = imclose(mask, strel('disk', 4, 4)); mask = imfill(mask, 'holes'); red = im; red(mask) = 255; green = im; green(mask) = 0; blue = im; blue(mask) = 0; out = cat(3, red, green, blue); imshow(out); </code></pre> <p>This tip was originally posted on <a href="http://stackoverflow.com/questions/27550252/Change%20color%20of%20a%20specific%20region%20in%20eye%20image%20%5BMatlab%5D/27551780">Stack Overflow</a>.</p>

New tutorials will be sent to your Inbox once a week.

comments powered by Disqus