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()
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
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"/)
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
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])