OpenCV的滚球背景减法算法

时间:2015-03-28 18:29:51

标签: opencv image-processing computer-vision

是否有一个OpenCV(android)实现"滚球"在ImageJ中找到的背景减法算法:处理 - >减去背景?

OpenCV有一个BackgroundSubtractorMOG类,但它用于视频流而非单个独立图像。

这是此方法的作用示例: http://imgur.com/8SN2CFz

以下是该流程的文档:http://imagejdocu.tudor.lu/doku.php?id=gui:process:subtract_background

6 个答案:

答案 0 :(得分:2)

我所知道的OpenCV C库中没有实现,而且Android JNI包装器就是这样 - 围绕主库的包装。

已经说过ImageJ实现的源代码可以在线here获得,因此您应该可以将它直接合并到您的Android图像处理管道中。

关于滚球与例如滚球的相对优点有一些讨论。使用磁盘结构元素( 在OpenCV中可用)here

如果您绝对需要滚球和OpenCV,那么很遗憾它不是“开箱即用”。

答案 1 :(得分:1)

如果有人还在寻找python中的滚球背景校正。对我来说,以下结果非常好。

  1. 加载图像并分别处理每个通道。
  2. 创建加权球结构元素
  3. 使用白色tophat转换
  4. 以下是单色图像的一些代码:

    import scipy.ndimage as scim
    from scipy.misc import imsave
    from skimage.morphology import ball
    # Read image
    im = scim.imread("path")[:,:,0].astype(int)
    # Create 3D ball structure
    s = ball(50)
    # Take only the upper half of the ball
    h = int((s.shape[1] + 1) / 2)
    # Flat the 3D ball to a weighted 2D disc
    s = s[:h, :, :].sum(axis=0)
    # Rescale weights into 0-255
    s = (255 * (s - s.min())) / (s.max()- s.min())
    # Use im-opening(im,ball) (i.e. white tophat transform) (see original publication)
    im_corr = scim.white_tophat(im, structure=s)
    # Save corrected image
    imsave('outfile', im_corr)
    

    这给出了与imagej实现完全相同的结果,但结果非常相似。就我而言,有更好和更差的纠正区域。此外,整体色彩强度更高。

答案 2 :(得分:0)

在@ Xenthor的回答基础上,我想出了这个:

import numpy as np
import scipy.ndimage as ndi
from scipy.ndimage._ni_support import _normalize_sequence

def rolling_ball_filter(data, ball_radius, spacing=None, top=False, **kwargs):
    """Rolling ball filter implemented with morphology operations

    This implenetation is very similar to that in ImageJ and uses a top hat transform
    with a ball shaped structuring element
    https://en.wikipedia.org/wiki/Top-hat_transform

    Parameters
    ----------
    data : ndarray
        image data (assumed to be on a regular grid)
    ball_radius : float
        the radius of the ball to roll
    spacing : int or sequence
        the spacing of the image data
    top : bool
        whether to roll the ball on the top or bottom of the data
    kwargs : key word arguments
        these are passed to the ndimage morphological operations

    Returns
    -------
    data_nb : ndarray
        data with background subtracted
    bg : ndarray
        background that was subtracted from the data
    """
    ndim = data.ndim
    if spacing is None:
        spacing = np.ones_like(ndim)
    else:
        spacing = _normalize_sequence(spacing, ndim)

    radius = np.asarray(_normalize_sequence(ball_radius, ndim))
    mesh = np.array(np.meshgrid(*[np.arange(-r, r + s, s) for r, s in zip(radius, spacing)], indexing="ij"))
    structure = 2 * np.sqrt(1 - ((mesh / radius.reshape(-1, *((1,) * ndim)))**2).sum(0))
    structure[~np.isfinite(structure)] = 0
    if not top:
        # ndi.white_tophat(y, structure=structure, output=background)
        background = ndi.grey_erosion(data, structure=structure, **kwargs)
        background = ndi.grey_dilation(background, structure=structure, **kwargs)
    else:
        # ndi.black_tophat(y, structure=structure, output=background)
        background = ndi.grey_dilation(data, structure=structure, **kwargs)
        background = ndi.grey_erosion(background, structure=structure, **kwargs)

    return data - background, background

答案 3 :(得分:0)

opencv中最近有一个滚球实现,您可以在这里找到

https://pypi.org/project/opencv-rolling-ball/

简而言之

安装pip install opencv-rolling-ball

示例

import cv2
from cv2_rolling_ball import subtract_background_rolling_ball

img = cv2.imread(f'path/to/img.tif', 0)
img, background = subtract_background_rolling_ball(img, 30, light_background=True, use_paraboloid=False, do_presmooth=True)

答案 4 :(得分:0)

ImageJ实现的原始算法来自1983年的论文https://www.computer.org/csdl/magazine/co/1983/01/01654163/13rRUwwJWBB。我看了一下它,它实际上是带有球形灰度结构元素的灰度形态白色大礼帽(请参见https://en.wikipedia.org/wiki/Top-hat_transform)。在ImageJ实现中(此处为https://imagej.nih.gov/ij/developer/source/ij/plugin/filter/BackgroundSubtracter.java.html),根据结构元素的半径对图像进行降采样,然后将其升采样至原始分辨率,并且默认情况下,在计算像素前,使用3x3均值滤波器进行平滑操作背景减去。这可能解释了Xenthor提出的方法所观察到的差异。

如果您使用的是Android,则有多种选择:1)使用ImageJ库,因为它是Java语言,但是您将需要实现OpenCV-ImageJ图像桥; 2)如果您使用Android NDK在C ++中工作,并且由于OpenCV并未为非平坦结构元素实现灰度形态,则可以使用ITK(https://itk.org/)代替来执行Graycale白色礼帽; 3)仍在使用NDK,此处有一个基于OpenCV的算法的C ++端口:https://github.com/folterj/BioImageOperation/tree/master/BioImageOperation,但仍在进行中。

答案 5 :(得分:0)

现在有一个 implementation in scikit-image

from skimage import data, restoration

image = data.coins()
background = restoration.rolling_ball(image)
result = image - background

documentation

中提供了更详细的演练