0

I am doing a detection with Mask R-CNN of one model available at Train Mask R-CNN for Image Segmentation.

  • Code I
# Load Image
img = cv2.imread("/content/image.jpg")

test_model, inference_config = load_inference_model(1, "/content/mask_rcnn.h5")
image = cv2.cvtColor(img, cv2.COLOR_BGR2RGB)

# Detect results
r = test_model.detect([image])[0]
colors = random_colors(80)

# Get Coordinates and show it on the image
object_count = len(r["class_ids"])
for i in range(object_count):
    # 1. Mask
    mask = r["masks"][:, :, i]
    contours = get_mask_contours(mask)
    for cnt in contours:
        cv2.polylines(img, [cnt], True, colors[i], 2)
        img = draw_mask(img, [cnt], colors[i])
  • First attempt

After training I tried to change the background color of the image using the code available at Change the Background of Any Image with 5 Lines of Code. Although it is working, it is not worth it for me to use another model to change the background.

  • Second attempt

Using a suggestion that is also available at Can anyone tell me how can I change mask the foreground if I know the color range of background in RGB?. I added the following line of code img2[ ~mask ] = [0,0,0].

This solution works if for the detected object is only one mask, otherwise it will not work so well. Example:

Example

To solve this problem I created an empty list and did the operation inside of the for loop, but it didn't work.

I noticed that in the current way, only the last mask is taken. Is there a way to get all masks? because if there is more than one object in the image this code doesn't work either.

Diego A
  • 155
  • 7
  • I can't test it but if you have mask as numpy.array with the same size as image then you can use it to replace pixels in image `image[ ~mask ] = [0,0,0]` ie. [python - Can anyone tell me how can I change mask the foreground if I know the color range of background in RGB? - Stack Overflow](https://stackoverflow.com/questions/74186362/can-anyone-tell-me-how-can-i-change-mask-the-foreground-if-i-know-the-color-rang?noredirect=1#comment130984248_74186362) – furas Oct 25 '22 at 10:57
  • @furas your suggestion works if the segmentation of the object is perfect, otherwise it won't work, in the attempts I made only the last mask was taken. – Diego A Oct 25 '22 at 15:35
  • if you have more masks then maybe you should do operatioon `OR` on all masks to create one mask - like `full_mask = mask1 | mask2 | mask3` - or in loop `full_mask = r["masks"][:, :, 0]` and `for i in range(1, object_count): full_mask |= r["masks"][:, :, i]` – furas Oct 25 '22 at 15:45
  • It worked perfectly, thanks for helping me one more time. – Diego A Oct 25 '22 at 17:59

1 Answers1

1

I can't test it but if you have mask as numpy.array with the same size as image then you can use it to replace pixels in image

image[ ~mask ] = [0,0,0]

For example

python - Can anyone tell me how can I change mask the foreground if I know the color range of background in RGB? - Stack Overflow

Finding red color in image using Python & OpenCV - Stack Overflow


If you have more masks then you can use operation OR on all masks to create one mask

final_mask = mask1 | mask2 | mask3 

In your code it could be

final_mask = r["masks"][:, :, 0] | r["masks"][:, :, 1] | r["masks"][:, :, 2]

or using loop (to make it more universal)

final_mask = r["masks"][:, :, 0] 

for i in range(1, object_count): 
    final_mask |= r["masks"][:, :, i]

If you would have list of masks then you could use

final_mask = masks[0] | masks[1] | masks[2]

or you could use function functools.reduce() (to make it more universal)

from functools import reduce

def or_masks(a, b):
    return a | b

final_mask = reduce(or_masks, masks)

or shorter

from functools import reduce

final_mask = reduce(lambda a,b:a|b, masks)
furas
  • 134,197
  • 12
  • 106
  • 148