本文介绍了如何为numpy数组创建圆形蒙版?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在尝试在Python中圆形遮罩图像.我在网络上找到了一些示例代码,但是我不确定如何更改数学以正确地圈出我的圈子.

I am trying to circular mask an image in Python. I found some example code on the web, but I'm not sure how to change the maths to get my circle in the correct place.

我有一个类型为(3725, 4797, 3)的类型为numpy.ndarray的图像image_data:

I have an image image_data of type numpy.ndarray with shape (3725, 4797, 3):

total_rows, total_cols, total_layers = image_data.shape
X, Y = np.ogrid[:total_rows, :total_cols]
center_row, center_col = total_rows/2, total_cols/2
dist_from_center = (X - total_rows)**2 + (Y - total_cols)**2
radius = (total_rows/2)**2
circular_mask = (dist_from_center > radius)

我看到这段代码使用欧几里德距离来计算dist_from_center,但是我不理解X - total_rowsY - total_cols部分.这将产生一个四分之一圆的蒙版,以图像的左上角为中心.

I see that this code applies euclidean distance to calculate dist_from_center, but I don't understand the X - total_rows and Y - total_cols part. This produces a mask that is a quarter of a circle, centered on the top-left of the image.

XY在圈子中扮演什么角色?以及如何修改此代码以产生一个在图像中其他位置居中的蒙版?

What role are X and Y playing on the circle? And how can I modify this code to produce a mask that is centered somewhere else in the image instead?

推荐答案

您上线的算法在某种程度上是错误的,至少出于您的目的.如果我们有以下图像,我们希望将其蒙版:

The algorithm you got online is partly wrong, at least for your purposes. If we have the following image, we want it masked like so:

创建这样的蒙版的最简单方法是算法的运行方式,但是它并没有以您想要的方式呈现,也没有使您能够以简单的方式对其进行修改.我们需要做的是查看图像中每个像素的坐标,并获取该像素是否在半径之内的真/假值.例如,这是一张放大的图片,显示了圆半径和严格位于该半径内的像素:

The easiest way to create a mask like this is how your algorithm goes about it, but it's not presented in the way that you want, nor does it give you the ability to modify it in an easy way. What we need to do is look at the coordinates for each pixel in the image, and get a true/false value for whether or not that pixel is within the radius. For example, here's a zoomed in picture showing the circle radius and the pixels that were strictly within that radius:

现在,要弄清楚哪些像素位于圆内,我们需要图像中每个像素的索引.函数 np.ogrid() 给出两个向量,每个向量包含像素位置(或索引):列索引有一个列向量,行索引有一个行向量:

Now, to figure out which pixels lie inside the circle, we'll need the indices of each pixel in the image. The function np.ogrid() gives two vectors, each containing the pixel locations (or indices): there's a column vector for the column indices and a row vector for the row indices:

>>> np.ogrid[:4,:5]
[array([[0],
       [1],
       [2],
       [3]]), array([[0, 1, 2, 3, 4]])]

此格式可用于广播,以便在某些函数中使用它们时,它实际上将创建一个包含所有索引的网格,而不仅仅是这两个向量.因此,我们可以使用np.ogrid()来创建图像的索引(或像素坐标),然后检查每个像素坐标以查看其在圆内还是圆外.为了确定它是否在中心内,我们可以简单地找到从中心到每个像素位置的欧几里得距离,然后如果该距离小于圆半径,则将其标记为包含遮罩中,如果大于该遮罩,我们将将其从遮罩中排除.

This format is useful for broadcasting so that if we use them in certain functions, it will actually create a grid of all the indices instead of just those two vectors. We can thus use np.ogrid() to create the indices (or pixel coordinates) of the image, and then check each pixel coordinate to see if it's inside or outside the circle. In order to tell whether it's inside the center, we can simply find the Euclidean distance from the center to every pixel location, and then if that distance is less than the circle radius, we'll mark that as included in the mask, and if it's greater than that, we'll exclude it from the mask.

现在,我们拥有制作此掩码的函数所需的一切.此外,我们将为其添加一些不错的功能;我们可以输入中心和半径,或者让它自动计算它们.

Now we've got everything we need to make a function that creates this mask. Furthermore we'll add a little bit of nice functionality to it; we can send in the center and the radius, or have it automatically calculate them.

def create_circular_mask(h, w, center=None, radius=None):

    if center is None: # use the middle of the image
        center = (int(w/2), int(h/2))
    if radius is None: # use the smallest distance between the center and image walls
        radius = min(center[0], center[1], w-center[0], h-center[1])

    Y, X = np.ogrid[:h, :w]
    dist_from_center = np.sqrt((X - center[0])**2 + (Y-center[1])**2)

    mask = dist_from_center <= radius
    return mask

在这种情况下,dist_from_center是一个与指定高度和宽度相同的矩阵.它将列和行索引向量广播到一个矩阵中,其中每个位置的值是距中心的距离.如果我们将该矩阵可视化为图像(将其缩放到合适的范围),那么它将是我们指定的从中心放射的渐变:

In this case, dist_from_center is a matrix the same height and width that is specified. It broadcasts the column and row index vectors into a matrix, where the value at each location is the distance from the center. If we were to visualize this matrix as an image (scaling it into the proper range), then it would be a gradient radiating from the center we specify:

因此,当我们将其与radius进行比较时,等同于对该梯度图像进行阈值化.

So when we compare it to radius, it's identical to thresholding this gradient image.

请注意,最后一个掩码是布尔矩阵; True(如果该位置在距指定中心的半径之内),否则为False.因此,我们可以将该掩码用作我们关注的像素区域的指示符,或者可以采用与该布尔值相反的值(numpy中的~)来选择该区域之外的像素.因此,就像我在本文顶部所做的那样,使用此功能为圆形以外的像素上色很简单:

Note that the final mask is a matrix of booleans; True if that location is within the radius from the specified center, False otherwise. So we can then use this mask as an indicator for a region of pixels we care about, or we can take the opposite of that boolean (~ in numpy) to select the pixels outside that region. So using this function to color pixels outside the circle black, like I did up at the top of this post, is as simple as:

h, w = img.shape[:2]
mask = create_circular_mask(h, w)
masked_img = img.copy()
masked_img[~mask] = 0

但是,如果我们想在与中心不同的点上创建圆形蒙版,则可以指定它(请注意,该函数期望中心坐标以x, y顺序而不是索引row, col = y, x顺序):

But if we wanted to create a circular mask at a different point than the center, we could specify it (note that the function is expecting the center coordinates in x, y order, not the indexing row, col = y, x order):

center = (int(w/4), int(h/4))
mask = create_circular_mask(h, w, center=center)

由于我们没有给出半径,因此会给我们最大半径,以便圆仍适合图像边界:

Which, since we're not giving a radius, would give us the largest radius so that the circle would still fit in the image bounds:

或者我们可以让它计算中心但使用指定的半径:

Or we could let it calculate the center but use a specified radius:

radius = h/4
mask = create_circular_mask(h, w, radius=radius)

给我们一个圆心,半径不精确地延伸到最小尺寸:

Giving us a centered circle with a radius that doesn't extend exactly to the smallest dimension:

最后,我们可以指定所需的任何半径和中心,包括延伸到图像边界之外的半径(中心甚至可以在图像边界之外!):

And finally, we could specify any radius and center we wanted, including a radius that extends outside the image bounds (and the center can even be outside the image bounds!):

center = (int(w/4), int(h/4))
radius = h/2
mask = create_circular_mask(h, w, center=center, radius=radius)

您在网上找到的算法的作用等同于将中心设置为(0, 0)并将半径设置为h:

What the algorithm you found online does is equivalent to setting the center to (0, 0) and setting the radius to h:

mask = create_circular_mask(h, w, center=(0, 0), radius=h)

这篇关于如何为numpy数组创建圆形蒙版?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!

09-01 23:22