在 Python 中使用 OpenCV 访问轮廓边界内的像素值
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/33234363/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Access pixel values within a contour boundary using OpenCV in Python
提问by Kaya311
I'm using OpenCV 3.0.0 on Python 2.7.9. I'm trying to track an object in a video with a still background, and estimate some of its properties. Since there can be multiple moving objects in an image, I want to be able to differentiate between them and track them individually throughout the remaining frames of the video.
我在 Python 2.7.9 上使用 OpenCV 3.0.0。我试图在具有静止背景的视频中跟踪一个对象,并估计它的一些属性。由于图像中可以有多个移动对象,我希望能够区分它们并在视频的其余帧中单独跟踪它们。
One way I thought I could do that was by converting the image to binary, getting the contours of the blobs (tracked object, in this case) and get the coordinates of the object boundary. Then I can go to these boundary coordinates in the grayscale image, get the pixel intensities surrounded by that boundary, and track this color gradient/pixel intensities in the other frames. This way, I could keep two objects separate from each other, so they won't be considered as new objects in the next frame.
我认为可以做到的一种方法是将图像转换为二进制,获取 blob 的轮廓(在本例中为跟踪对象)并获取对象边界的坐标。然后我可以转到灰度图像中的这些边界坐标,获取该边界周围的像素强度,并在其他帧中跟踪此颜色渐变/像素强度。这样,我可以将两个对象彼此分开,这样它们就不会被视为下一帧中的新对象。
I have the contour boundary coordinates, but I don't know how to retrieve the pixel intensities within that boundary. Could someone please help me with that?
我有轮廓边界坐标,但我不知道如何检索该边界内的像素强度。有人可以帮我吗?
Thanks!
谢谢!
采纳答案by rayryeng
Going with our comments, what you can do is create a list of numpy
arrays, where each element is the intensities that describe the interior of the contour of each object. Specifically, for each contour, create a binary mask that fills in the interior of the contour, find the (x,y)
coordinates of the filled in object, then index into your image and grab the intensities.
根据我们的评论,您可以做的是创建一个numpy
数组列表,其中每个元素是描述每个对象轮廓内部的强度。具体来说,对于每个轮廓,创建一个填充轮廓内部的二进制蒙版,找到(x,y)
填充对象的坐标,然后索引到您的图像并获取强度。
I don't know exactly how you set up your code, but let's assume you have an image that's grayscale called img
. You may need to convert the image to grayscale because cv2.findContours
works on grayscale images. With this, call cv2.findContours
normally:
我不知道您是如何设置代码的,但假设您有一个灰度图像,称为img
. 您可能需要将图像转换为灰度图像,因为它cv2.findContours
适用于灰度图像。有了这个,cv2.findContours
正常调用:
import cv2
import numpy as np
#... Put your other code here....
#....
# Call if necessary
#img = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
# Call cv2.findContours
contours,_ = cv2.findContours(img, cv2.RETR_LIST, cv2.cv.CV_CHAIN_APPROX_NONE)
contours
is now a list of 3D numpy
arrays where each is of size N x 1 x 2
where N
is the total number of contour points for each object.
contours
现在三维列表numpy
阵列,其中每个是大小为N x 1 x 2
其中N
是针对每个对象轮廓点的总数。
As such, you can create our list like so:
因此,您可以像这样创建我们的列表:
# Initialize empty list
lst_intensities = []
# For each list of contour points...
for i in range(len(contours)):
# Create a mask image that contains the contour filled in
cimg = np.zeros_like(img)
cv2.drawContours(cimg, contours, i, color=255, thickness=-1)
# Access the image pixels and create a 1D numpy array then add to list
pts = np.where(cimg == 255)
lst_intensities.append(img[pts[0], pts[1]])
For each contour, we create a blank image then draw the filled-incontour in this blank image. You can fill in the area that the contour occupies by specifying the thickness
parameter to be -1. I set the interior of the contour to 255. After, we use numpy.where
to find all row and column locations in an array that match a certain condition. In our case, we want to find the values that are equal to 255. After, we use these points to index into our image to grab the pixel intensities that are interior to the contour.
对于每个轮廓,我们创建一个空白图像,然后在这个空白图像中绘制填充轮廓。您可以通过将thickness
参数指定为-1来填充轮廓所占据的区域。我将轮廓的内部设置为 255。之后,我们使用numpy.where
查找匹配某个条件的数组中的所有行和列位置。在我们的例子中,我们想要找到等于 255 的值。之后,我们使用这些点来索引我们的图像以获取轮廓内部的像素强度。
lst_intensities
contains that list of 1D numpy
arrays where each element gives you the intensities that belong to the interior of the contour of each object. To access each array, simply do lst_intensities[i]
where i
is the contour you want to access.
lst_intensities
包含一维numpy
数组列表,其中每个元素为您提供属于每个对象轮廓内部的强度。访问每个阵列,根本就lst_intensities[i]
在那里i
为你要访问的轮廓。
回答by Jundong
Answer from @rayryeng is excellent!
@rayryeng 的回答非常好!
One small thing from my implementation is:
The np.where()
returns a tuple, which contains an array of row indices and an array of column indices. So, pts[0]
includes a list of row indices
, which correspond to height of the image, pts[1]
includes a list of column indices
, which correspond to the width of the image. The img.shape
returns (rows, cols, channels)
. So I think it should be img[pts[0], pts[1]]
to slice the ndarray
behind the img.
我的实现中的一件小事是:np.where()
返回一个元组,其中包含一个行索引数组和一个列索引数组。因此,pts[0]
包含一个列表row indices
,对应于图像的高度,pts[1]
包含一个列表column indices
,对应于图像的宽度。的img.shape
回报(rows, cols, channels)
。所以我觉得应该是img[pts[0], pts[1]]
把ndarray
后面的img切片。
回答by Jaime Finat
I am sorry I cannot add this as a comment in the first correct answer since I have not enough reputation to do so.
很抱歉,我无法将其添加为第一个正确答案的评论,因为我没有足够的声誉来这样做。
Actually, there is a little improvement in the nice code from above: we can skip the line in which we were getting the points because of both grayscale image and np.zeros temp image have the same shape, we could use that 'where' inside the brackets directly. Something like this:
实际上,上面的漂亮代码有一点改进:我们可以跳过获得点的行,因为灰度图像和 np.zeros 临时图像具有相同的形状,我们可以在里面使用“where”直接上括号。像这样的东西:
# (...) opening image, converting into grayscale, detect contours (...)
intensityPer = 0.15
for c in contours:
temp = np.zeros_like(grayImg)
cv2.drawContours(temp, [c], 0, (255,255,255), -1)
if np.mean(grayImg[temp==255]) > intensityPer*255:
pass # here your code
By this sample, we assure the mean intensity of the area within the contour will be at least 15% of the maximum intensity
通过这个样本,我们确保轮廓内区域的平均强度至少是最大强度的 15%