# Filtering pixels of a certain color

What is the best way to filter an image so that only the pixels close to a certain color are left?

I've downloaded some satellite images from the web where a specific pixel color corresponds to a some type of crop. Thus I would like to filter out with Mathematica those pixels that are specifically for that color so I can next run ComponentMeasurements to obtain the area covered by those pixels.

I was trying to figure out what function to use or build that would just return an image with the pixels that match or are truly similar to the color provided.

• Is your question a general image-processing question or specific to Mathematica?
– rm -rf
May 9, 2012 at 17:53
• See this post, it might give you some ideas where to start. May 9, 2012 at 18:05
• What definition of "color" do you want to use? May 9, 2012 at 20:41
• Here's another implementation (an earlier answer of mine). May 11, 2012 at 7:23

i = Import["http://i.stack.imgur.com/zzUdB.gif"];

{h, s, b} = ColorSeparate[i, "HSB"];

Manipulate[
Column[
{
Graphics[{Hue[c], Rectangle[]}, ImageSize -> 40],
ImageMultiply[i,
Binarize[Abs[Mod[ImageData[h] - c, 1, -1/2]] // Image,
tolerance] // ColorNegate]
}
],
{c, 0, 1},
{{tolerance, 0.1}, 0, 0.5}
]    • Very nice. Version 7 users will need: {h, s, b} = ColorSeparate@ColorConvert[i, "HSB"]; May 9, 2012 at 21:47
• @Mr.Wizard Good catch! The second argument (the color space) of ColorSeparate is a version 8 addition. May 9, 2012 at 21:51
• @mr.wizard Didn't cross my mind, but makes sense. Done. May 9, 2012 at 22:07
• Note that since Hue is periodic with period 1 you might want to apply a function to the image data of h that reflects this periodicity. For example you could do something like Abs[Mod[ImageData[h] - c, 1, -1/2]]. This way, when filtering on Hue (which is equal to Hue) you'll not only catch the points with hue 0 <= hue < tol but also 1-tol < hue <= 1. May 9, 2012 at 22:19
• +1 Great, but your current code has only 1 slider while images of interfaces have 2. May 9, 2012 at 22:38

I investigated an alternative approach - a simple brute force technique, not as good as Sjoerd's.

satImage = ImageResize[
/a/ac/Bananal-Island-North-End-Landsat-25-07-1992.gif"], 300] find[pixel_, color_, tolerance_] := If[
And[
Abs[color[] - pixel[]] < tolerance ,
Abs[color[] - pixel[]] < tolerance ,
Abs[color[] - pixel[]] < tolerance ], pixel, {0, 0, 0}];

Manipulate[
im = ImageApply[find[#, col, tolerance] &, satImage],
{col, Blue},
{{tolerance, 0.2}, 0.1, 1, Appearance -> "Labeled"}] An answer to this question also appears in this other answer, albeit somewhat hidden. So I've taken the relevant part of my answer there and put it into this function which extracts the desired color by setting all other colors transparent:

colorExpose[im_, col_, tol_: .005] := Module[
{
color = Apply[List, ColorConvert[col, "RGB"]],
r = If[
ImageColorSpace[im] != "RGB",
ColorConvert[im, "RGB"], im
]
},
SetAlphaChannel[r,
Binarize[r, (Norm[# - color] < tol) &]
]
]


Here are some examples of how the function can be used:

ra = Import["http://i.stack.imgur.com/zzUdB.gif"]
colorExpose[ColorConvert[ra, "CMYK"], Yellow]
colorExpose[ra, Hue[.5]]


These forms show that the colorspace doesn't matter for the supplied image or the color, because the function always converts to RGBColor before doing the comparisons. The tolerance for the color matching is supplied as a third (optional) argument.