pg has asked for the wisdom of the Perl Monks concerning the following question:

For a project I am working on, I need to figure out the outline (boundary) of each subject on a photo. One way to do this is, for each pixel, to calculate the difference between its color and the color of surrounding pixels. (Assume the picture is reasonably clear, I am not interested in background noise at this point.)

The first thing I tried was to calculate the difference base on RGB:

$diff = abs($r1 - $r2) + abs($g1 - $g2) + abs($b1 - $b2);

Or I can do something like:

$diff = ($r1 - $r2) ** 2 + ($g1 - $g2) ** 2 + ($b1 - $b2) ** 2; (or I can make this more std like)

Whether to use abs() or **2 does not seem to be important at this point.

At this point, I compare each point with all 8 surrounding pixels, and pick the largest difference as the difference between this pixel and its surrounding. (obviously I can compare with more surrounding pixels, or give different weight to pixels base on their distance to this pixel.)

This actually works for me to a level.

Then I started to think whether RGB is indeed the right way to describe color for what I am doing, so the next thing I tried is to use

my $ll = 0.212671 * $r + 0.715160 * $g + 0.072169 * $b;

as the "color", and calculate the difference.

Again this worked to a level.

There must be more alternative ways, and I am interested in hearing them and trying them out, and see what the best way is, or best ways are. Thanks.

Replies are listed 'Best First'.
Re: the difference between two colors, and how to describe a color
by kvale (Monsignor) on Oct 28, 2004 at 04:37 UTC
    To get a boundary, image processing folks use a technique called Sobel filtering. The basic idea is to create an isotropic version of a gradient. First, convolve each pixel with the matrices
    Vertical Kernel: -1 -2 -1 0 0 0 +1 +2 +1 Horizontal kernel: -1 0 +1 -2 0 +2 -1 0 +1
    Take the results of the two convolutions, square them and add them. If the result is greater than a user-determined threshold, set the pixel black, otherwise white.

    This works for 1-D, e.g., grayscale images. For color images, decide what you want to be the boundary: Brightness? Hue? Saturation? Then segnemt according to that property, Just taking the 3-D RGB vector distance isn't the greatest idea, because humans don't differentiate colors according to that metric. All other things being the same, I'd probably try the grayscale (brightness) metric first.

    Update: I concur with blokhead that there are many edge detection algorithms, none unviersally applicable. The Sobel algorithm is fairly good on a wide range of images, so is worth a try.

    -Mark

      For colour images the first step would be to convert to grayscale. The liminance formula used in the GIMP is pretty similar to the OPs formula:

      Y = 0.3R + 0.59G + 0.11B;
      see Re: convert image to greyscale (color to black and white) and particularly the link showing the effects of various grayscaling approaches.

      cheers

      tachyon

        "For colour images the first step would be to convert to grayscale"

        That's what was in my mind over night. When I used that formular, I kept thinking that I am calculating luminous.

        My major in university is related to this, and I kept thinking what's the difference now and then. One thing I remembered is that, the equipment we used only take black and white pictures, so I started to think that first thing today is to convert picture to black and white.

        Now your post is a great remind to me, and confirmed my thought. Thank you!

      "Brightness? Hue? Saturation? Then segnemt according to that property, Just taking the 3-D RGB vector distance isn't the greatest idea, because humans don't differentiate colors according to that metric."

      This concurs with what others said, so we are all pointing to the same direction that, RGB is not what human being used to find out edges. This is actually sort of AI, as part of it is to understand human behavior, and then think of how to repeat/simulate it.

Re: the difference between two colors, and how to describe a color
by blokhead (Monsignor) on Oct 28, 2004 at 04:29 UTC
    Edge detection is not a trivial task. Just google for edge detection and see the many varied techniques. Instead of doing this yourself, why aren't you delegating out to ImageMagick or Gimp (both have edge-detection filters)? You get the advantage of having adjustable parameters so you can tune things for your data. You will still probably have to get the locations of the edges into Perl by looking at the pixels by hand, but it's much easier from the output of the edge-detection algorithm -- the result will be grayscale and the edges will correspond to very clear jumps in intensity that are easy to notice.

    If you're hell-bent on doing this by hand the way you've suggested, I'd look to see how programs like Gimp calculate deltas between pixels. For instance, Gimp's Selective Gaussian Blur will blur pixels only within a certain delta "difference" and it seems to do a good job. From the source code, it's not clear how this is calculated, but it probably relies on Gimp's internal colorspace. Maybe there is an Gimp IRC channel you could consult to get pointers to the math they use.

    In any case, just using luminosity (as in your last example) won't find many types of boundaries in between solid colors. The two 3-dimensional RGB metrics you use are probably better (and probably not too different from each other).

    blokhead

Re: the difference between two colors, and how to describe a color
by bart (Canon) on Oct 28, 2004 at 15:36 UTC
    Then I started to think whether RGB is indeed the right way to describe color for what I am doing, so the next thing I tried is to use
    my $ll = 0.212671 * $r + 0.715160 * $g + 0.072169 * $b;
    as the "color", and calculate the difference.
    That seems like a way to calculate the graylevel of a color, as being used in color TV transmission (at least for PAL), and which is responsible for the fact that a B&W TV can show a color TV signal rather well (that as an aside, for the curious). I'm not exactly sure on the weights, I thought the value for blue was closer to 0.11. And indeed, looking at 3.3.3. Color Models in Video - YUV Color Model, I see:
    Y = 0.299R + 0.587G + 0.114B

    But why are you throwing away the other 2 values? You could use the whole of YUV, where Y is your above gray value, and U and V are the two other color components. Surely, a change in color tint is as important as a change in brightness.

    And then there is HSV, another somewhat similar color value triplet.

      "the value for blue was closer to 0.11"

      The weight you gave here is very close to what tachyon had, and I will try this. Thanks for that link, I think you are right, I will look into it, and find a way to use YUV.

      The diffculty for me was not really the calculation of the difference, as that part seems to work okay. The problem is really that, for certain color combinations (background and foreground), the result is poor, that's why I am getting into the big question "what is color?". Your post and links are very useful and helpful. Thanks.

      Surely, a change in color tint is as important as a change in brightness.

      Both matter, but all else being equal a change in brightness is often more important. Of course, a small or gradual change in brightness is much less important than a sudden marked change in hue. It's a complicated issue. I tend to agree with the poster who said delegate it to a module that has an edge detection routine or filter.


      "In adjectives, with the addition of inflectional endings, a changeable long vowel (Qamets or Tsere) in an open, propretonic syllable will reduce to Vocal Shewa. This type of change occurs when the open, pretonic syllable of the masculine singular adjective becomes propretonic with the addition of inflectional endings."  — Pratico & Van Pelt, BBHG, p68
Re: the difference between two colors, and how to describe a color
by tilly (Archbishop) on Oct 28, 2004 at 17:51 UTC
    There is no best way.

    There are many good ways. Each is appropriate for different situations. The ones that I know a bit about are wavelet-based, so I'd probably do something based on that if I had to hand-roll something. (I'd look for pre-built solutions first though.)

Re: the difference between two colors, and how to describe a color
by theorbtwo (Prior) on Nov 01, 2004 at 12:32 UTC

    The answer for this, like many other questions, is "it depends". Humans don't do it like this at all -- we try to recognize the subject first, then find it's edges. (I suspect.) It's difficult to define what the subject /is/ in many photographs. The best way to find a method is probably to load up your stuff into an image editor, try it's various edge-detecting methods, and decide which one does the best job. Then either find a method to simply use the graphics program in question (Hint: Gimp), or do some research and find out what method the graphics program used, and how to program it in perl (Hint: PDL).

    The problem is really /much/ harder then you think, though. Look at The Kiss (Safe For Work, unless you have a very strict work), for example. It's even already monochrome. The hardest border, though, is between the girls' hair and the bed. Does that mean their hair is the subject of the photograph? No, in order to find the subject, you need to follow the borders of both girls -- even where there isn't much contrast, such as between the white shirts (esp on the girl on the right) and panties and the white bed.

    Update: better link.


    Warning: Unless otherwise stated, code is untested. Do not use without understanding. Code is posted in the hopes it is useful, but without warranty. All copyrights are relinquished into the public domain unless otherwise stated. I am not an angel. I am capable of error, and err on a fairly regular basis. If I made a mistake, please let me know (such as by replying to this node).