how to mask outside or inside an arbitrary shape in python?

  • Last Update :
  • Techknowledgy :

We can get the shape we want to mask using:

from scipy
import interpolate
import matplotlib.pyplot as plt
import numpy as np
import cv2
a = np.arange(1, 9)
filename = 'image_file_0.tiff'
img = cv2.imread('image_left.png', cv2.IMREAD_COLOR)
x = np.array([289, 292, 125, 111, 40, 80, 94, 210])
y = np.array([84, 181, 265, 241, 133, 88, 27, 40])
x = np.r_[x, x[0]]
y = np.r_[y, y[0]]
tck, u = interpolate.splprep([x, y], s = 0, per = True)
xi, yi = interpolate.splev(np.linspace(0, 1, 1000), tck)

plt.imshow(img[: ,: , [2, 1, 0]])
plt.scatter(xi, yi)
plt.show()

Now the masking can be done using:

contour = np.array([
   [xii, yii]
   for xii, yii in zip(xi.astype(int), yi.astype(int))
])
mask = np.zeros_like(img)
cv2.fillPoly(mask, pts = [contour], color = (255, 255, 255))
masked_img = cv2.bitwise_and(img, mask)

Using the inverted mask you manipulate the outer pixels as you wish:

mask = np.ones_like(img) * 255
cv2.fillPoly(mask, pts = [contour], color = (0, 0, 0))
masked_img = cv2.bitwise_and(img, mask)
import numpy as np
import cv2
from scipy
import interpolate

# Load image, make blank mask, define rough contour points
image = cv2.imread('1.jpg')
mask = np.zeros(image.shape, dtype = np.uint8)
x = np.array([192, 225, 531, 900, 500])
y = np.array([154, 281, 665, 821, 37])
x = np.r_[x, x[0]]
y = np.r_[y, y[0]]

# Smooth contours
tck, u = interpolate.splprep([x, y], s = 0, per = True)
x_new, y_new = interpolate.splev(np.linspace(0, 1, 1000), tck)
smooth_contour = np.array([
   [
      [int(i[0]), int(i[1])]
   ]
   for i in zip(x_new, y_new)
])

# Draw contour onto blank mask in white
cv2.drawContours(mask, [smooth_contour], 0, (255, 255, 255), -1)
result1 = cv2.bitwise_and(image, mask)
result2 = cv2.bitwise_and(image, 255 - mask)

cv2.imshow('image', image)
cv2.imshow('mask', mask)
cv2.imshow('result1', result1)
cv2.imshow('result2', result2)
cv2.waitKey()

Suggestion : 2

by Adrian Rosebrock on January 19, 2021

Luckily, OpenCV is pip-installable:

$ pip install opencv - contrib - python

Your project folder should look like the following:

$ tree.--dirsfirst
   .├──adrian.png└── opencv_masking.py

0 directories, 2 files

Open the opencv_masking.py file in your project directory structure, and let’s get to work:

#
import the necessary packages
import numpy as np
import argparse
import cv2

# construct the argument parser and parse the arguments
ap = argparse.ArgumentParser()
ap.add_argument("-i", "--image", type = str,
   default = "adrian.png",
   help = "path to the input image")
args = vars(ap.parse_args())

Let’s look at another example, but this time using a non-rectangular mask:

# now,
let 's make a circular mask with a radius of 100 pixels and
# apply the mask again
mask = np.zeros(image.shape[: 2], dtype = "uint8")
cv2.circle(mask, (145, 200), 100, 255, -1)
masked = cv2.bitwise_and(image, image, mask = mask)

# show the output images
cv2.imshow("Circular Mask", mask)
cv2.imshow("Mask Applied to Image", masked)
cv2.waitKey(0)

From there, open a shell and execute the following command:

$ python opencv_masking.py

Suggestion : 3

This particular example reads a shapefile to get an outline of the Mississippi River Basin. You then have the option of masking out all areas inside or outside this outline. , A Python version of this projection is available here. , A Python version of this projection is available here. , This example is similar to mask_16.ncl, except it uses precipitation data read off a NetCDF file. See the description above for a description of how the map is being masked.

  mpres @mpDataBaseVersion = "MediumRes"
  mpres @mpMaskAreaSpecifiers = (/"China:states","Taiwan"/)

Suggestion : 4

Create the mask specifying the size of the image.,Specify the x- and y-coordinates of the polygon.,y-coordinate of polygon vertices, specified as a numeric vector. The length of xi and yi must match.,x-coordinate of polygon vertices, specified as a numeric vector. The length of xi and yi must match.

x = [63 186 54 190 63];
y = [60 60 209 204 60];
bw = poly2mask(x, y, 256, 256);
imshow(bw)
hold on
plot(x, y, 'b', 'LineWidth', 2)
hold off
x = 256 * rand(1, 4);
y = 256 * rand(1, 4);
x(end + 1) = x(1);
y(end + 1) = y(1);
x = [4 10 10 4 4];
y = [4 4 10 10 4];
mask = poly2mask(x, y, 12, 12)
mask =

   0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 1 1 1 1 1 1 0 0
0 0 0 0 1 1 1 1 1 1 0 0
0 0 0 0 1 1 1 1 1 1 0 0
0 0 0 0 1 1 1 1 1 1 0 0
0 0 0 0 1 1 1 1 1 1 0 0
0 0 0 0 1 1 1 1 1 1 0 0
0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0

Suggestion : 5

Active contours without edges implemented with morphological operators. It can be used to segment objects in images and volumes without well defined borders. It is required that the inside of the object looks different on average than the outside (i.e., the inner area of the object should be darker or lighter than the outer area on average).,The width of the border examined. By default, only objects that touch the outside of the image are removed.,Areas of the image with a value smaller than this threshold will be considered borders. The evolution of the contour will stop in this areas.,An array with the same shape as image is returned, with values in areas connected to and equal (or within tolerance of) the seed point replaced with new_value.

>>> from skimage.draw
import circle_perimeter
   >>>
   from skimage.filters
import gaussian
>>> img = np.zeros((100, 100)) >>>
   rr, cc = circle_perimeter(35, 45, 25) >>>
   img[rr, cc] = 1 >>>
   img = gaussian(img, 2, preserve_range = False)
>>> s = np.linspace(0, 2 * np.pi, 100) >>>
   init = 50 * np.array([np.sin(s), np.cos(s)]).T + 50
>>> snake = active_contour(img, init, w_edge = 0, w_line = 1, coordinates = 'rc') >>>
   dist = np.sqrt((45 - snake[: , 0]) ** 2 + (35 - snake[: , 1]) ** 2) >>>
   int(np.mean(dist))
25
>>>
import numpy as np
   >>>
   from skimage.segmentation
import clear_border
   >>>
   labels = np.array([
      [0, 0, 0, 0, 0, 0, 0, 1, 0],
      ...[1, 1, 0, 0, 1, 0, 0, 1, 0],
      ...[1, 1, 0, 1, 0, 1, 0, 0, 0],
      ...[0, 0, 0, 1, 1, 1, 1, 0, 0],
      ...[0, 1, 1, 1, 1, 1, 1, 1, 0],
      ...[0, 0, 0, 0, 0, 0, 0, 0, 0]
   ]) >>>
   clear_border(labels)
array([
      [0, 0, 0, 0, 0, 0, 0, 0, 0],
      [0, 0, 0, 0, 1, 0, 0, 0, 0],
      [0, 0, 0, 1, 0, 1, 0, 0, 0],
      [0, 0, 0, 1, 1, 1, 1, 0, 0],
      [0, 1, 1, 1, 1, 1, 1, 1, 0],
      [0, 0, 0, 0, 0, 0, 0, 0, 0]
   ]) >>>
   mask = np.array([
      [0, 0, 1, 1, 1, 1, 1, 1, 1],
      ...[0, 0, 1, 1, 1, 1, 1, 1, 1],
      ...[1, 1, 1, 1, 1, 1, 1, 1, 1],
      ...[1, 1, 1, 1, 1, 1, 1, 1, 1],
      ...[1, 1, 1, 1, 1, 1, 1, 1, 1],
      ...[1, 1, 1, 1, 1, 1, 1, 1, 1]
   ]).astype(bool) >>>
   clear_border(labels, mask = mask)
array([
   [0, 0, 0, 0, 0, 0, 0, 1, 0],
   [0, 0, 0, 0, 1, 0, 0, 1, 0],
   [0, 0, 0, 1, 0, 1, 0, 0, 0],
   [0, 0, 0, 1, 1, 1, 1, 0, 0],
   [0, 1, 1, 1, 1, 1, 1, 1, 0],
   [0, 0, 0, 0, 0, 0, 0, 0, 0]
])
>>> labels = np.array([0, 1, 0, 0, 0, 0, 2]) >>>
   expand_labels(labels, distance = 1)
array([1, 1, 1, 0, 0, 2, 2])