14

I am trying to color in black the outside region of a contours using openCV and python language. Here is my code :

contours, hierarchy = cv2.findContours(copy.deepcopy(img_copy),cv2.RETR_TREE,cv2.CHAIN_APPROX_SIMPLE)
areas = [cv2.contourArea(c) for c in contours]
max_index = np.argmax(areas)
cnt=contours[max_index]
# how to fill of black the outside of the contours cnt please? `
Jeru Luke
  • 20,118
  • 13
  • 80
  • 87
Bill
  • 143
  • 1
  • 1
  • 5

1 Answers1

34

Here's how you can fill an image with black color outside of a set of contours:

import cv2
import numpy
img = cv2.imread("zebra.jpg")
stencil = numpy.zeros(img.shape).astype(img.dtype)
contours = [numpy.array([[100, 180], [200, 280], [200, 180]]), numpy.array([[280, 70], [12, 20], [80, 150]])]
color = [255, 255, 255]
cv2.fillPoly(stencil, contours, color)
result = cv2.bitwise_and(img, stencil)
cv2.imwrite("result.jpg", result)

enter image description here enter image description here

UPD.: The code above exploits the fact that bitwise_and with 0-s produces 0-s, and won't work for fill colors other than black. To fill with an arbitrary color:

import cv2
import numpy

img = cv2.imread("zebra.jpg")

fill_color = [127, 256, 32] # any BGR color value to fill with
mask_value = 255            # 1 channel white (can be any non-zero uint8 value)

# contours to fill outside of
contours = [ numpy.array([ [100, 180], [200, 280], [200, 180] ]), 
             numpy.array([ [280, 70], [12, 20], [80, 150]])
           ]

# our stencil - some `mask_value` contours on black (zeros) background, 
# the image has same height and width as `img`, but only 1 color channel
stencil  = numpy.zeros(img.shape[:-1]).astype(numpy.uint8)
cv2.fillPoly(stencil, contours, mask_value)

sel      = stencil != mask_value # select everything that is not mask_value
img[sel] = fill_color            # and fill it with fill_color

cv2.imwrite("result.jpg", img)

enter image description here

Can fill with another image as well, for example, using img[sel] = ~img[sel] instead of img[sel] = fill_color would fill it with the same inverted image outside of the contours:

enter image description here

Headcrab
  • 6,838
  • 8
  • 40
  • 45
  • 1
    Thanks bro', I appreciate. Whenever, you're in denver, ping me I'll make you a favor – Bill Jun 20 '16 at 08:11
  • @Bill please accept / upvote if this answer your question. No need to make favours ;D – Miki Jun 20 '16 at 08:23
  • 2
    @Miki, hands off my favours, decline yours when you get them! :) – Headcrab Jun 20 '16 at 08:38
  • 1
    @Headcrab I'm truly sorry... Whenever you are in Milan, ping me.. I'll make you a favor ;D – Miki Jun 20 '16 at 08:39
  • @Mvk1312 That depends on the image type. Why, do you want to fill with white instead of black? – Headcrab Feb 17 '20 at 00:34
  • Hey @Headcrab actually i'm trying to detect the shape region(table) on an image.Afterwards, has to return only that region and excluded non shape region from an image. – MathanKumar Feb 17 '20 at 05:38
  • @Mvk1312 If you just load an average jpeg with `cv2.imread()` function, white is probably going to be `[255, 255, 255]`. Or, for a single channel image, just `255`. – Headcrab Feb 17 '20 at 06:47
  • @Headcrab , Actually i tried your solution. The result is different from my requirements. My need is except detected table region , all regions should be in white background. Could you help me! – MathanKumar Feb 17 '20 at 07:06
  • @Mvk1312 If you have a shape/contour and want to fill everything else with a background color - see the second (updated) piece of code in my answer. Otherwise, I don't quite understand your requirements, try asking a separate question, then. – Headcrab Feb 17 '20 at 07:33
  • Okay i will try that solution @Headcrab and can you tell me the array values for white colour to fill outside regions – MathanKumar Feb 17 '20 at 09:19