OpenCV的滚球背景减除算法

pb3s4cty  于 11个月前  发布在  其他
关注(0)|答案(6)|浏览(216)

在ImageJ:Process->Subtract Background中是否有OpenCV(android)实现“rolling ball”背景减除算法?
OpenCV有一个BackgroundSubtractorMOG类,但它用于视频流,而不是单个独立的图像。
下面是该方法的一个示例:https://i.stack.imgur.com/mXSLb.jpg
以下是该过程的文档:http://imagejdocu.tudor.lu/doku.php?id=gui:process:subtract_background

c86crjj0

c86crjj01#

据我所知,OpenCV C库中没有实现,Android JNI Package 器只是围绕主库的 Package 器。
尽管如此,ImageJ实现的源代码可以在here在线获得,因此您应该能够将其直接纳入Android图像处理管道。
有一些关于滚球与使用磁盘结构元素(在OpenCV中可用)here的相对优点的讨论。
如果你绝对需要Rolling Ball和OpenCV,那么不幸的是,它无法“开箱即用”。

mtb9vblg

mtb9vblg2#

在opencv中有一个最近的rolling-ball实现,您可以在这里找到
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)

字符串

mrfwxfqh

mrfwxfqh3#

基于@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 = 1

    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(data, structure=structure, output=background)
        background = ndi.grey_erosion(data, structure=structure, **kwargs)
        background = ndi.grey_dilation(background, structure=structure, **kwargs)
    else:
        # ndi.black_tophat(data, structure=structure, output=background)
        background = ndi.grey_dilation(data, structure=structure, **kwargs)
        background = ndi.grey_erosion(background, structure=structure, **kwargs)

    return data - background, background

字符串

ih99xse1

ih99xse14#

**编辑:**在使用本文中的方法之前,请阅读下面的评论,并考虑@renat和@大卫霍夫曼的答案。

如果有人还在寻找python中的滚动球背景校正。对我来说,下面的工作非常好。
1.加载图像并单独处理每个通道。
1.创建加权球结构元素
1.使用白色礼帽变换
下面是一些单色图像的代码:

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 with radius of 50 and a diameter of 2*50+1
s = ball(50)

# Take only the upper half of the ball
h = s.shape[1] // 2 + 1  # 50 + 1

# Flatten 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实现不完全相同,但结果非常相似。在我的例子中,有更好和更差的校正区域。此外,整体颜色强度更高。

but5z9lq

but5z9lq5#

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),根据结构元素的半径对图像进行下采样,然后上采样到原始分辨率,默认情况下,在计算要减去的背景之前,应用使用3 × 3均值滤波器的平滑操作。2这可能解释了用Xenthor提出的方法观察到的差异。
如果你在Android上工作,你有几个选择:1)使用ImageJ库,因为它是在Java中,你将需要实现一个OpenCV-ImageJ图像桥; 2)如果你在C中使用Android NDK工作,因为OpenCV不为非平面结构元素实现灰度形态,你可以使用ITK(https://itk.org/)来执行灰度白色礼帽; 3)仍然使用NDK,这里有一个基于OpenCV的算法的C端口:https://github.com/folterj/BioImageOperation/tree/master/BioImageOperation,但它仍然是一个正在进行的工作。

dl5txlt9

dl5txlt96#

我知道它不是opencv,但在scikit-image(版本≥ 0.18)中有一个实现。

from skimage import data, restoration

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

字符串
documentation中提供了更详细的演练

相关问题