Reputation: 57
Is there an OpenCV (android) implementation of "rolling ball" background subtraction algorithm found in ImageJ: Process->Subtract Background?
OpenCV has a BackgroundSubtractorMOG class, but it is used for video streams not single, independent images.
This is an example of what this method does: https://i.sstatic.net/mXSLb.jpg
Here is a documentation of the process: http://imagejdocu.tudor.lu/doku.php?id=gui:process:subtract_background
Upvotes: 3
Views: 8207
Reputation: 5364
I realize it's not opencv, but there is an implementation in scikit-image (version ≥ 0.18).
from skimage import data, restoration
image = data.coins()
background = restoration.rolling_ball(image, radius=100)
result = image - background
A more detailed walkthrough is provided in the documentation
Upvotes: 0
Reputation: 447
The original algorithm that ImageJ implements comes from a 1983 paper https://www.computer.org/csdl/magazine/co/1983/01/01654163/13rRUwwJWBB. I took a look at it and it is actually a grayscale morphological white top-hat with a ball-shaped grayscale structuring element (see https://en.wikipedia.org/wiki/Top-hat_transform). In the ImageJ implementation (available here https://imagej.nih.gov/ij/developer/source/ij/plugin/filter/BackgroundSubtracter.java.html), the image is downsampled depending on the structuring elements' radius, then upsampled to the original resolution and, by default, a smoothing operation using a 3x3 mean filter is applied before computing the background to subtract. This likely explains the differences observed with the method proposed by Xenthor.
If you are working on Android, you have several options: 1) using the ImageJ library, since it is in Java, you will however need to implement an OpenCV-ImageJ image bridge; 2) if you work in C++ using the Android NDK and since OpenCV does not implement grayscale morphology for non-flat structuring elements, you can use ITK (https://itk.org/) instead to perform the graycale white top-hat; 3) still using the NDK, there is an OpenCV-based C++ port of the algorithm available here: https://github.com/folterj/BioImageOperation/tree/master/BioImageOperation, however it is still a work in progress.
Upvotes: 0
Reputation: 443
Edit: Before using the method in this post read the comments below and also consider the answers of @renat and @David Hoffman.
In case someone is still looking for rolling ball background correction in python. For me, the following worked out very well.
Here is some code for a monochrome image:
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)
This gives you not the exact same result as the imagej implementation but the results are quite similar. In my case there were both, better and worse corrected regions. Moreover the overall color intensity was higher.
Upvotes: 1
Reputation: 2343
Building on @Xenthor's answer this is what I came up with:
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
Upvotes: 1
Reputation: 33
There is a recent rolling-ball implementation in opencv that you can find here
https://pypi.org/project/opencv-rolling-ball/
In short
Install pip install opencv-rolling-ball
Example
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)
Upvotes: 2
Reputation: 3632
There's no implementation in the OpenCV C libraries that I know of and the Android JNI wrappers are just that - wrappers around the main libraries.
Having said that the source code for the ImageJ implementation is available online here and so you should be able to incorporate this directly into your Android image processing pipeline.
There is some discussion about the relative merits of rolling ball vs. e.g. using a disk structuring element (which is available in OpenCV) here.
If you absolutely require Rolling Ball and OpenCV then unfortunately it's not available 'out of the box'.
Upvotes: 6