'using histogram to determine colored object presence?

I'm trying to determine if portion of the picture contains red-white striped object (liftramp). If it is present, it looks like this: present, and when not like this: none

The naive approach was to extract histogram, and count if there is more red pixels than blue/green ones:

use Image::Magick;

my $image = Image::Magick->new;
my $rv = $image->Read($picture);
#$rv = $image->Crop(geometry=>'26x100+484+40');

my @hist_data = $image->Histogram;
my @hist_entries;

# Histogram returns data as a single list, but the list is actually groups of 5 elements. Turn it into a list of useful hashes.
while (@hist_data) {
    my ($r, $g, $b, $a, $count) = splice @hist_data, 0, 5;
    push @hist_entries, { r => $r, g => $g, b => $b, alpha => $a, count => $count };
}

my $total=0;
foreach my $v (@hist_entries) {
        if ($$v{r}>($$v{g}+$$v{b})) { $total +=$$v{count}; }
}

and then comparing if $total > 10 (arbitrary threshold). While that seems to work nice for relatively sunny day (giving 50-180 for presence vs 0-2 for not present), heavy clouds and dusk make the detection always say the liftramp is not present.

I guess there must be smarter way to detect if red-white object is present. So the question is how to do that detection more reliably?

Note that grayish/green background might change with seasons to more of gray-brown or something. I also cannot count on pixel precision as it might move a little (or I'd just crop a 3-4 pixels and look if they are red) - but it should mostly fit it he cropped box.



Solution 1:[1]

Another way to do it that would be more insensitive to lighting would be to look for red hues after converting to HSV colorspace. But since red has the same 0 hue as black/gray/white, I would invert the image so that red becomes cyan. So histogram the hue channel after inverting and converting to HSV and look for values at cyan hue near 180 degrees or its equivalent of 50% gray or 128 in the range of 0 to 255. In imagemagick, you would do

convert XqG0F.png -negate -colorspace HSV -channel red -separate +channel -define histogram:unique-colors=false histogram:without_hist.png

enter image description here

convert x5hWF.png -negate -colorspace HSV -channel red -separate +channel -define histogram:unique-colors=false histogram:with_hist.png

enter image description here

So you can see in the second image (for the red bar), there is a substantial broad peak near mid-way i.e., 50% (horizontally), but none in the first image in that region.

Solution 2:[2]

You could do an FFT to get the spectrum of each image. The image with the striped bar has a repetitive pattern that should show up in the spectrum. Using ImageMagick:

Without the bar:

convert XqG0F.png -fft +delete -evaluate log 100000 without.png

enter image description here

With bar:

convert x5hWF.png -fft +delete -evaluate log 100000 with.png

enter image description here

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1
Solution 2 fmw42