CofeehousePy/deps/scikit-image/skimage/feature/_basic_features.py

173 lines
5.9 KiB
Python

from itertools import combinations_with_replacement
import itertools
import numpy as np
from skimage import filters, feature
from skimage import img_as_float32
from concurrent.futures import ThreadPoolExecutor
def _texture_filter(gaussian_filtered):
H_elems = [
np.gradient(np.gradient(gaussian_filtered)[ax0], axis=ax1)
for ax0, ax1 in combinations_with_replacement(range(gaussian_filtered.ndim), 2)
]
eigvals = feature.hessian_matrix_eigvals(H_elems)
return eigvals
def _singlescale_basic_features_singlechannel(
img, sigma, intensity=True, edges=True, texture=True
):
results = ()
gaussian_filtered = filters.gaussian(img, sigma)
if intensity:
results += (gaussian_filtered,)
if edges:
results += (filters.sobel(gaussian_filtered),)
if texture:
results += (*_texture_filter(gaussian_filtered),)
return results
def _mutiscale_basic_features_singlechannel(
img,
intensity=True,
edges=True,
texture=True,
sigma_min=0.5,
sigma_max=16,
num_sigma=None,
num_workers=None,
):
"""Features for a single channel nd image.
Parameters
----------
img : ndarray
Input image, which can be grayscale or multichannel.
intensity : bool, default True
If True, pixel intensities averaged over the different scales
are added to the feature set.
edges : bool, default True
If True, intensities of local gradients averaged over the different
scales are added to the feature set.
texture : bool, default True
If True, eigenvalues of the Hessian matrix after Gaussian blurring
at different scales are added to the feature set.
sigma_min : float, optional
Smallest value of the Gaussian kernel used to average local
neighbourhoods before extracting features.
sigma_max : float, optional
Largest value of the Gaussian kernel used to average local
neighbourhoods before extracting features.
num_sigma : int, optional
Number of values of the Gaussian kernel between sigma_min and sigma_max.
If None, sigma_min multiplied by powers of 2 are used.
num_workers : int or None, optional
The number of parallel threads to use. If set to ``None``, the full
set of available cores are used.
Returns
-------
features : list
List of features, each element of the list is an array of shape as img.
"""
# computations are faster as float32
img = np.ascontiguousarray(img_as_float32(img))
if num_sigma is None:
num_sigma = int(np.log2(sigma_max) - np.log2(sigma_min) + 1)
sigmas = np.logspace(
np.log2(sigma_min),
np.log2(sigma_max),
num=num_sigma,
base=2,
endpoint=True,
)
with ThreadPoolExecutor(max_workers=num_workers) as ex:
out_sigmas = list(
ex.map(
lambda s: _singlescale_basic_features_singlechannel(
img, s, intensity=intensity, edges=edges, texture=texture
),
sigmas,
)
)
features = itertools.chain.from_iterable(out_sigmas)
return features
def multiscale_basic_features(
image,
multichannel=False,
intensity=True,
edges=True,
texture=True,
sigma_min=0.5,
sigma_max=16,
num_sigma=None,
num_workers=None,
):
"""Local features for a single- or multi-channel nd image.
Intensity, gradient intensity and local structure are computed at
different scales thanks to Gaussian blurring.
Parameters
----------
image : ndarray
Input image, which can be grayscale or multichannel.
multichannel : bool, default False
True if the last dimension corresponds to color channels.
intensity : bool, default True
If True, pixel intensities averaged over the different scales
are added to the feature set.
edges : bool, default True
If True, intensities of local gradients averaged over the different
scales are added to the feature set.
texture : bool, default True
If True, eigenvalues of the Hessian matrix after Gaussian blurring
at different scales are added to the feature set.
sigma_min : float, optional
Smallest value of the Gaussian kernel used to average local
neighbourhoods before extracting features.
sigma_max : float, optional
Largest value of the Gaussian kernel used to average local
neighbourhoods before extracting features.
num_sigma : int, optional
Number of values of the Gaussian kernel between sigma_min and sigma_max.
If None, sigma_min multiplied by powers of 2 are used.
num_workers : int or None, optional
The number of parallel threads to use. If set to ``None``, the full
set of available cores are used.
Returns
-------
features : np.ndarray
Array of shape ``image.shape + (n_features,)``
"""
if not any([intensity, edges, texture]):
raise ValueError(
"At least one of ``intensity``, ``edges`` or ``textures``"
"must be True for features to be computed."
)
if image.ndim < 3:
multichannel = False
if not multichannel:
image = image[..., np.newaxis]
all_results = (
_mutiscale_basic_features_singlechannel(
image[..., dim],
intensity=intensity,
edges=edges,
texture=texture,
sigma_min=sigma_min,
sigma_max=sigma_max,
num_sigma=num_sigma,
num_workers=num_workers,
)
for dim in range(image.shape[-1])
)
features = list(itertools.chain.from_iterable(all_results))
return np.stack(features, axis=-1)