改进图像分割以创建围绕我的对象的闭合轮廓
Improve image segmentation to create a closed contour surrounding my object
这是我使用 Intel Realsense d435 rgb 相机拍摄的场景照片。
我希望能够识别图像中的金属物体并在其周围绘制闭合轮廓。这样我就可以参考轮廓内的所有像素以供将来使用。
当前方法论
- 目前,我正在裁剪场景图像,假装我有一些物体识别软件 运行 允许我在我的物体周围创建一个边界框。所以我裁剪该部分并将其应用到空白图像上。
- 我遵循 OpenCV 文档并使用形态学变换和分水岭算法来分割图像。我最终提取了确定的前景图像和 运行 精明的边缘检测和轮廓检测。然而,他们 return 的台词相当糟糕。
2.5。目前,我只是使用确定的前景图像并将所有黑色像素保存为我的对象,但是,我的确定前景图像中有这些未被拾取的巨大白点向上.
如何改进我的图像分割以获得更好的图像轮廓,以便我可以抓取对象所包围的所有像素(大部分)?
如果有帮助,我可以添加我的代码,但它非常大。
编辑:
我尝试了 SentDex 教程中的 GrabCut 算法,但是虽然它可以删除一些背景,但分水岭算法之后无法找到准确的前景表示。
左边的图像是应用GrabCut之后,然后右边的图像将GrabCut算法传递给分水岭算法以找到确定的前景。
在找到轮廓之前扩张然后腐蚀怎么样:
element = cv2.getStructuringElement(shape=cv2.MORPH_RECT, ksize=(21, 21))
dilate = cv2.dilate(gray,element,1)
cv2.imshow("dilate",dilate)
erode = cv2.erode(dilate,element,1)
#use erode as a mask to extract the object from the original image
erode = cv2.bitwise_not(erode)
erode = cv2.cvtColor(erode, cv2.COLOR_GRAY2BGR)
res = cv2.add(original,erode)
我没有你使用的图像和物体识别软件,所以我只是展示如何应用蒙版。
通过从对 RGB 图像的颜色识别和分析切换到对来自相机的深度信息的边缘检测,我能够获得更好的对象轮廓。
以下是我为找到更好的边缘图所采取的一般步骤。
将我的深度信息保存在 NxMx1 矩阵中。其中 N,M 值是我的图像分辨率的形状。对于 480,640 图像,我有一个矩阵 (480,640,1),其中每个像素 (i,j) 存储该像素坐标的相应深度值。
使用 2D 高斯核来平滑和填充我的深度矩阵中的任何缺失数据,使用 astropy 的卷积方法。
求出我的深度矩阵的梯度和梯度中每个像素对应的量级
根据均匀深度过滤数据。均匀深度意味着平坦的物体,所以我找到了我的幅度(来自深度梯度)的高斯分布,并且那些在 X 标准偏差内填充的分布被设置为零。这减少了图像中的一些额外噪声。
然后我将幅度矩阵的值从 0 归一化为 1,因此我的矩阵可以被视为通道 1 图像矩阵。
因此,由于我的深度矩阵的形式为 (480,640,1),当我发现相应的梯度矩阵也是 (480,640,1) 时,我将值 (:,:,1) 缩放为0 到 1。这样我可以稍后将其表示为灰度或二值图像。
def gradient_demo(self, Depth_Mat):
"""
Gradient display entire image
"""
shape = (Depth_Mat.shape)
bounds = ( (0,shape[0]), (0, shape[1]) )
smooth_depth = self.convolve_smooth_Depth(Depth_Mat, bounds)
gradient, magnitudes = self.depth_gradient(smooth_depth, bounds)
magnitudes_prime = magnitudes.flatten()
#hist, bin = np.histogram(magnitudes_prime, 50) # histogram of entire image
mean = np.mean(magnitudes_prime)
variance = np.var(magnitudes_prime)
sigma = np.sqrt(variance)
# magnitudes_filtered = magnitudes[(magnitudes > mean - 2 * sigma) & (magnitudes < mean + 2 * sigma)]
magnitudes[(magnitudes > mean - 1.5 * sigma) & (magnitudes < mean + 1.5 * sigma)] = 0
magnitudes = 255*magnitudes/(np.max(magnitudes))
magnitudes[magnitudes != 0] = 1
plt.title('magnitude of gradients')
plt.imshow(magnitudes, vmin=np.nanmin(magnitudes), vmax=np.amax(magnitudes), cmap = 'gray')
plt.show()
return magnitudes.astype(np.uint8)
def convolve_smooth_Depth(self, raw_depth_mtx, bounds):
"""
Iterate over subimage and fill in any np.nan values with averages depth values
:param image:
:param bounds: ((ylow,yhigh), (xlow, xhigh)) -> (y,x)
:return: Smooted depth values for a given square
"""
ylow, yhigh = bounds[0][0], bounds[0][1]
xlow, xhigh = bounds[1][0], bounds[1][1]
kernel = Gaussian2DKernel(1) #generate kernel 9x9 with stdev of 1
# astropy's convolution replaces the NaN pixels with a kernel-weighted interpolation from their neighbors
astropy_conv = convolve(raw_depth_mtx[ylow:yhigh, xlow:xhigh], kernel, boundary='extend')
# extended boundary assumes original data is extended using a constant extrapolation beyond the boundary
smoothedSQ = (np.around(astropy_conv, decimals= 3))
return smoothedSQ
def depth_gradient(self, smooth_depth, bounds):
"""
:param smooth_depth:
:param shape: Tuple with y_range and x_range of the image.
shape = ((0,480), (0,640)) (y,x) -> (480,640)
y_range = shape[0]
x_range = shape[1]
:return:
"""
#shape defines the image array shape. Rows and Cols for an array
ylow, yhigh = bounds[0][0], bounds[0][1]
xlow, xhigh = bounds[1][0], bounds[1][1]
gradient = np.gradient(smooth_depth)
x,y = range(xlow, xhigh), range(ylow, yhigh)
xi, yi = np.meshgrid(x, y)
magnitudes = np.sqrt(gradient[0] ** 2 + gradient[1] ** 2)
return gradient, magnitudes
使用这个 method/code 我得到了下面的图像。仅供参考,我稍微改变了场景。
我在这里问了另一个相关问题:
这说明了如何在图像中找到我的对象的轮廓和质心。
这是我使用 Intel Realsense d435 rgb 相机拍摄的场景照片。
我希望能够识别图像中的金属物体并在其周围绘制闭合轮廓。这样我就可以参考轮廓内的所有像素以供将来使用。
当前方法论
- 目前,我正在裁剪场景图像,假装我有一些物体识别软件 运行 允许我在我的物体周围创建一个边界框。所以我裁剪该部分并将其应用到空白图像上。
- 我遵循 OpenCV 文档并使用形态学变换和分水岭算法来分割图像。我最终提取了确定的前景图像和 运行 精明的边缘检测和轮廓检测。然而,他们 return 的台词相当糟糕。
2.5。目前,我只是使用确定的前景图像并将所有黑色像素保存为我的对象,但是,我的确定前景图像中有这些未被拾取的巨大白点向上.
如何改进我的图像分割以获得更好的图像轮廓,以便我可以抓取对象所包围的所有像素(大部分)?
如果有帮助,我可以添加我的代码,但它非常大。
编辑: 我尝试了 SentDex 教程中的 GrabCut 算法,但是虽然它可以删除一些背景,但分水岭算法之后无法找到准确的前景表示。
左边的图像是应用GrabCut之后,然后右边的图像将GrabCut算法传递给分水岭算法以找到确定的前景。
在找到轮廓之前扩张然后腐蚀怎么样:
element = cv2.getStructuringElement(shape=cv2.MORPH_RECT, ksize=(21, 21))
dilate = cv2.dilate(gray,element,1)
cv2.imshow("dilate",dilate)
erode = cv2.erode(dilate,element,1)
#use erode as a mask to extract the object from the original image
erode = cv2.bitwise_not(erode)
erode = cv2.cvtColor(erode, cv2.COLOR_GRAY2BGR)
res = cv2.add(original,erode)
我没有你使用的图像和物体识别软件,所以我只是展示如何应用蒙版。
通过从对 RGB 图像的颜色识别和分析切换到对来自相机的深度信息的边缘检测,我能够获得更好的对象轮廓。
以下是我为找到更好的边缘图所采取的一般步骤。
将我的深度信息保存在 NxMx1 矩阵中。其中 N,M 值是我的图像分辨率的形状。对于 480,640 图像,我有一个矩阵 (480,640,1),其中每个像素 (i,j) 存储该像素坐标的相应深度值。
使用 2D 高斯核来平滑和填充我的深度矩阵中的任何缺失数据,使用 astropy 的卷积方法。
求出我的深度矩阵的梯度和梯度中每个像素对应的量级
根据均匀深度过滤数据。均匀深度意味着平坦的物体,所以我找到了我的幅度(来自深度梯度)的高斯分布,并且那些在 X 标准偏差内填充的分布被设置为零。这减少了图像中的一些额外噪声。
然后我将幅度矩阵的值从 0 归一化为 1,因此我的矩阵可以被视为通道 1 图像矩阵。
因此,由于我的深度矩阵的形式为 (480,640,1),当我发现相应的梯度矩阵也是 (480,640,1) 时,我将值 (:,:,1) 缩放为0 到 1。这样我可以稍后将其表示为灰度或二值图像。
def gradient_demo(self, Depth_Mat):
"""
Gradient display entire image
"""
shape = (Depth_Mat.shape)
bounds = ( (0,shape[0]), (0, shape[1]) )
smooth_depth = self.convolve_smooth_Depth(Depth_Mat, bounds)
gradient, magnitudes = self.depth_gradient(smooth_depth, bounds)
magnitudes_prime = magnitudes.flatten()
#hist, bin = np.histogram(magnitudes_prime, 50) # histogram of entire image
mean = np.mean(magnitudes_prime)
variance = np.var(magnitudes_prime)
sigma = np.sqrt(variance)
# magnitudes_filtered = magnitudes[(magnitudes > mean - 2 * sigma) & (magnitudes < mean + 2 * sigma)]
magnitudes[(magnitudes > mean - 1.5 * sigma) & (magnitudes < mean + 1.5 * sigma)] = 0
magnitudes = 255*magnitudes/(np.max(magnitudes))
magnitudes[magnitudes != 0] = 1
plt.title('magnitude of gradients')
plt.imshow(magnitudes, vmin=np.nanmin(magnitudes), vmax=np.amax(magnitudes), cmap = 'gray')
plt.show()
return magnitudes.astype(np.uint8)
def convolve_smooth_Depth(self, raw_depth_mtx, bounds):
"""
Iterate over subimage and fill in any np.nan values with averages depth values
:param image:
:param bounds: ((ylow,yhigh), (xlow, xhigh)) -> (y,x)
:return: Smooted depth values for a given square
"""
ylow, yhigh = bounds[0][0], bounds[0][1]
xlow, xhigh = bounds[1][0], bounds[1][1]
kernel = Gaussian2DKernel(1) #generate kernel 9x9 with stdev of 1
# astropy's convolution replaces the NaN pixels with a kernel-weighted interpolation from their neighbors
astropy_conv = convolve(raw_depth_mtx[ylow:yhigh, xlow:xhigh], kernel, boundary='extend')
# extended boundary assumes original data is extended using a constant extrapolation beyond the boundary
smoothedSQ = (np.around(astropy_conv, decimals= 3))
return smoothedSQ
def depth_gradient(self, smooth_depth, bounds):
"""
:param smooth_depth:
:param shape: Tuple with y_range and x_range of the image.
shape = ((0,480), (0,640)) (y,x) -> (480,640)
y_range = shape[0]
x_range = shape[1]
:return:
"""
#shape defines the image array shape. Rows and Cols for an array
ylow, yhigh = bounds[0][0], bounds[0][1]
xlow, xhigh = bounds[1][0], bounds[1][1]
gradient = np.gradient(smooth_depth)
x,y = range(xlow, xhigh), range(ylow, yhigh)
xi, yi = np.meshgrid(x, y)
magnitudes = np.sqrt(gradient[0] ** 2 + gradient[1] ** 2)
return gradient, magnitudes
使用这个 method/code 我得到了下面的图像。仅供参考,我稍微改变了场景。
我在这里问了另一个相关问题:
这说明了如何在图像中找到我的对象的轮廓和质心。