1

The problem is relatively simple.

I have an image and I know a background color of the image. Given that I want to create foreground mask of the image.

I tried this:

background_color = np.array([255, 255, 255], dtype=np.uint8)

foreground = image != background_color

What I expect is a boolean matrix with the shape of HxWx1 with True where colors are matching and False where they are not matching.

But this operation compare not the color, but all three color components and I'm getting HxWx3 sized matrix with True where color components matching and False where they're not matching.

I created a temporary solution with for loop:

foreground = np.zeros(shape=(height, width, 1), dtype=np.bool)
    for y in range(height):
        for x in range(width):
            if not np.array_equal(image[y, x], background_color):
                foreground[y, x] = True

But that, of course, works slowly. My question is the following: Is there a proper way of doing such kind of comparison with the help of numpy or OpenCV methods?

Jeru Luke
  • 20,118
  • 13
  • 80
  • 87
Ruslan
  • 122
  • 1
  • 14
  • `CV - Extract differences between two images`: https://stackoverflow.com/questions/27035672/cv-extract-differences-between-two-images/47938979#47938979 – Kinght 金 Aug 21 '18 at 02:57

1 Answers1

2

I don't know any numpy function for that, but you could chain a np.any() call:

foreground = np.any(image != background_color, axis=-1)

The shape of foreground will be equal to image.shape[:-1]. If you want the extra dimension back, you could use:

foreground = np.any(image != background_color, axis=-1)[..., np.newaxis]

I kinda feel like there may exist a better (more numpy-like) way to do this...

Berriel
  • 12,659
  • 4
  • 43
  • 67
  • Thank you, @Berriel. You probably has in mind np.any() instead of np.all()? With your solution this operation takes only 6ms instead of 1720ms, as before. That's perfectly suits me. – Ruslan Aug 21 '18 at 10:16
  • @Ruslan if you use `np.any()` the mask will be `True` even if only one channel is equal. If you need your mask to be `True` only if the values are equal in all channels, then `np.all()` is the way to go. – Berriel Aug 21 '18 at 15:50
  • That will be true if you have image == background_color, but here we are doing image != background_color and result must be False if any of the component does not match. – Ruslan Aug 21 '18 at 17:43
  • @Ruslan Ohh, I tried `==` in my local examples, and forgot your example was actually `!=` :) Sorry. – Berriel Aug 21 '18 at 20:32