Page 1 of 1

Test if image has ALL the given colors?

Posted: 2013-09-18T19:56:48-07:00
by anthony
Okay I have been running a program that remotely controls an application, grabs screen shots, and looks for specific (exact) colors in that screen shot.

ASIDE: the colors represent biomes in a randomised world generator.

This is the code I am currently using (ignoring the image source and other irrelevent stuff)

Code: Select all

color1='magenta'
color2='#B4DCDC'
color3='#FF6D3D'
color4='#E5DA87'

search=`convert image.png \
              -fill black -opaque "white" \
              -fill white -opaque "$color1" \
              -fill white -opaque "$color2" \
              -fill white -opaque "$color3" \
              -fill white -opaque "$color4" \
              -fill black +opaque "white" \
              -scale 1x1 \
              -depth 16 txt:- |
            sed '1d; /black/d'`
if [ "X$search" != "X" ]; then
    echo "===================Found One================"
    # ....
fi
If the resulting single pixel image is not black then we have found a image that contains at least one of the four colors. The 'sed' command returns a non-blank string if this is the case.

Now the above is straight forward. but what I now need is a similar test for an image that contains ALL of these colors, not just any one of them. Logically a test for an image containing a 'AND' of the colors, not just a 'OR'.

I am a little stumped by the problem. perhaps I am just having a brain block as I am usually pretty good at solving it.

Re: Test if image has ALL the given colors?

Posted: 2013-09-18T21:08:12-07:00
by snibgo
Your code will return a false negative if, say, you have one pixel of a chosen colour but the image is more than 65536 pixels. I'll ignore that problem.

I think this returns a black image if none of the colours are present. If they are all present, it returns non-black.

Code: Select all

convert image.png \
  -fill black -opaque "white" \
  ( -clone 0 -fill Black +opaque "$color1" -fill white -opaque "$color1" -scale 1x1 ) \
  ( -clone 0 -fill Black +opaque "$color2" -fill white -opaque "$color2" -scale 1x1 ) \
  ( -clone 0 -fill Black +opaque "$color3" -fill white -opaque "$color3" -scale 1x1 ) \
  ( -clone 0 -fill Black +opaque "$color4" -fill white -opaque "$color4" -scale 1x1 ) \
  -delete 0 \
  -compose Darken -composite \
  txt:
EDIT: Hmm, I think I don't need: -fill black -opaque "white" \

Re: Test if image has ALL the given colors?

Posted: 2013-09-18T23:41:26-07:00
by anthony
snibgo wrote:Your code will return a false negative if, say, you have one pixel of a chosen colour but the image is more than 65536 pixels. I'll ignore that problem.
not a problem, areas are never just one pixel. and the image screen dump crops are not that big.
snibgo wrote:I think this returns a black image if none of the colours are present. If they are all present, it returns non-black.

Code: Select all

convert image.png \
  -fill black -opaque "white" \
  ( -clone 0 -fill Black +opaque "$color1" -fill white -opaque "$color1" -scale 1x1 ) \
  ( -clone 0 -fill Black +opaque "$color2" -fill white -opaque "$color2" -scale 1x1 ) \
  ( -clone 0 -fill Black +opaque "$color3" -fill white -opaque "$color3" -scale 1x1 ) \
  ( -clone 0 -fill Black +opaque "$color4" -fill white -opaque "$color4" -scale 1x1 ) \
  -delete 0 \
  -compose Darken -composite \
  txt:
EDIT: Hmm, I think I don't need: -fill black -opaque "white" \
It will be needed if white is present and not one of the desired colors (which it isn't).

That may do it. Result is linearly equivalent to the smallest area covered by a specific color, so if one color is missing the smallest is zero and you get black (for false or fail).

There may be a better solution though.

Re: Test if image has ALL the given colors?

Posted: 2013-09-29T19:07:03-07:00
by anthony
Just as a FYI...
This is my final solution...

It did not need any clones, and even reports the number of the colors found in the resulting image, and which of the given colors actually matched. Yes that is more than was needed, but it is faster and more useful result.

The solution was to map each 'search color' to transparency, then negate the alpha channel, and set the color of all non-matching (now transparent after negation) colors to something else (black). -unique-colors is then used to reduce the output image size to number of matching colors (plus black). The use of transparency effectivally provides a in-image mask that also preserves what color added to that mask.

It was even already in IM examples but in 'fuzzy color matching', and not where I expected it for 'exact color matching.
http://www.imagemagick.org/Usage/color_basics/#fuzz
The last example in that area, generating the image opaque_multi_inv.png

Note this will fail for images that only contain searched for colors, and does not work for images with existing transparency, but that is not a problem in this case.

Code: Select all

name1=mushroom color1='magenta'    # Mushroom Biome
name2=ice      color2='#B4DCDC'    # Ice Pinacles
name3=bryce    color3='#FF6D3D'    # Mesa Bryce
name4=savanna  color4='#CFC58C'    # Savanna Plateau Mountain


  capture="x:$id[630x630+80+80]"
  results=`convert "$capture" -alpha opaque \
              -transparent "$color1" \
              -transparent "$color2" \
              -transparent "$color3" \
              -transparent "$color4" \
              -channel Alpha -negate +channel \
              -background black -alpha remove \
              -unique-colors -depth 8 txt:-`

  # rare_biomes = image length -1
  biome_count=`echo "$results" | sed -n 's/.*enumeration: \([0-9]\),.*/\1/p'`
  : $(( biome_count-- ))

  # get biome type list
  biome_list=`echo "$results" |
      sed -n 's/.*'$color1'.*/'$name1'/p;
              s/.*'$color2'.*/'$name2'/p;
              s/.*'$color3'.*/'$name3'/p;
              s/.*'$color4'.*/'$name4'/p;
             '`

  # Debugging
  echo $seed : $biome_count $biome_list    # no quotes!