python - 改进图像分割以创建围绕对象的闭合轮廓

标签 python opencv image-processing computer-vision image-segmentation

这是从 Intel Realsense d435 RGB 摄像头拍摄的场景图片。 enter image description here

我希望能够识别图像中的金属物体并在其周围绘制闭合轮廓。这样我就可以引用轮廓内的所有像素以供将来使用。

当前方法

  1. 目前,我正在裁剪场景图像,假装我正在运行一些对象识别软件,允许我在对象周围创建一个边界框。因此,我裁剪该部分并将其应用到空白图像上。

Cropped Image with threshold applied

  • 我遵循 OpenCV 文档并使用形态变换和分水岭算法来分割图像。我最终提取了确定的前景图像并运行了精明的边缘检测和轮廓检测。然而,他们返回的线路相当差。
  • 2.5。目前,我只是使用确定的前景图像并获取所有黑色像素并将它们保存为我的对象,但是,我的确定前景图像中有这些巨大的白点,它们没有被拾取。

    Sure Foreground image with white spots Contours of my edges after filtering (bad)

    如何改进图像分割以获得更好的图像轮廓,以便捕获对象包含的所有(大部分)像素?

    如果有帮助,我可以添加我的代码,但它相当大。

    编辑: 我尝试了 SentDex 教程中的 GrabCut 算法,但是虽然它可以删除一些背景,但分水岭算法随后无法找到准确的前景表示。

    enter image description here enter image description here

    左边的图像是应用 GrabCut 后的图像,然后右边的图像将 GrabCut 算法传递给分水岭算法以找到确定的前景。

    最佳答案

    通过从 RGB 图像的颜色识别和分析切换到相机深度信息的边缘检测,我能够获得更好的物体轮廓。

    以下是我寻找更好的边缘图所采取的一般步骤。

    1. 将我的深度信息保存在 NxMx1 矩阵中。其中 N、M 值是图像分辨率的形状。对于 480,640 图像,我有一个矩阵 (480,640,1),其中每个像素 (i,j) 存储该像素坐标的相应深度值。

    2. 使用 astropy 的卷积方法,使用 2D 高斯核来平滑和填充深度矩阵中的任何缺失数据。

    3. 找到我的深度矩阵的梯度以及梯度中每个像素对应的大小。

    4. 根据统一深度过滤数据。均匀的深度意味着平坦的物体,所以我发现我的幅度的高斯分布(来自深度梯度),并且那些填充在 X 标准差内的值被设置为零。这减少了图像中的一些额外噪音。

    5. 然后我将幅度矩阵的值从 0 标准化为 1,这样我的矩阵就可以被视为 channel 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
    

    使用这个方法/代码我能够得到以下图像。仅供引用,我稍微改变了场景。

    enter image description here

    我在这里问了另一个相关问题:How to identify contours associated with my objects and find their geometric centroid

    这展示了如何在图像中找到对象的轮廓、质心。

    关于python - 改进图像分割以创建围绕对象的闭合轮廓,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/54681136/

    相关文章:

    python - 不能在 Django 中 pickle 字典

    python - 在 Python 中,如何转义将用作 SQL 语句的字符串中的单引号?

    python - 使用 opencv 的 minAreaRect() 去偏斜 MNIST 数据集图像

    visual-studio - 使用 COLUMN-major 矩阵类型扩展 Image Watch

    python - 在 Python CFFI 中声明包含 time_t 字段的结构

    python - Python处理负整数的问题

    algorithm - 打开 Find CornerSubPix 算法

    python - 如何将 Opencv 集成到 Tkinter 窗口中

    python - cv2.imshow() 函数如何在 BGR 模型中工作?

    具有不同光照的 OpenCV 背景减法