Spaces:
Runtime error
Runtime error
import numpy as np | |
import scipy.sparse | |
from numba import njit | |
from ....utils.utils import get_h_w_c | |
def _cf_laplacian(image, epsilon, r, values, indices, indptr, is_known): | |
h, w, d = image.shape | |
assert d == 3 | |
size = 2 * r + 1 | |
window_area = size * size | |
for yi in range(h): | |
for xi in range(w): | |
i = xi + yi * w | |
k = i * (4 * r + 1) ** 2 | |
for yj in range(yi - 2 * r, yi + 2 * r + 1): | |
for xj in range(xi - 2 * r, xi + 2 * r + 1): | |
j = xj + yj * w | |
if 0 <= xj < w and 0 <= yj < h: | |
indices[k] = j | |
k += 1 | |
indptr[i + 1] = k | |
# Centered and normalized window colors | |
c = np.zeros((2 * r + 1, 2 * r + 1, 3)) | |
# For each pixel of image | |
for y in range(r, h - r): | |
for x in range(r, w - r): | |
if np.all(is_known[y - r : y + r + 1, x - r : x + r + 1]): | |
continue | |
# For each color channel | |
for dc in range(3): | |
# Calculate sum of color channel in window | |
s = 0.0 | |
for dy in range(size): | |
for dx in range(size): | |
s += image[y + dy - r, x + dx - r, dc] | |
# Calculate centered window color | |
for dy in range(2 * r + 1): | |
for dx in range(2 * r + 1): | |
c[dy, dx, dc] = ( | |
image[y + dy - r, x + dx - r, dc] - s / window_area | |
) | |
# Calculate covariance matrix over color channels with epsilon regularization | |
a00 = epsilon | |
a01 = 0.0 | |
a02 = 0.0 | |
a11 = epsilon | |
a12 = 0.0 | |
a22 = epsilon | |
for dy in range(size): | |
for dx in range(size): | |
a00 += c[dy, dx, 0] * c[dy, dx, 0] | |
a01 += c[dy, dx, 0] * c[dy, dx, 1] | |
a02 += c[dy, dx, 0] * c[dy, dx, 2] | |
a11 += c[dy, dx, 1] * c[dy, dx, 1] | |
a12 += c[dy, dx, 1] * c[dy, dx, 2] | |
a22 += c[dy, dx, 2] * c[dy, dx, 2] | |
a00 /= window_area | |
a01 /= window_area | |
a02 /= window_area | |
a11 /= window_area | |
a12 /= window_area | |
a22 /= window_area | |
det = ( | |
a00 * a12 * a12 | |
+ a01 * a01 * a22 | |
+ a02 * a02 * a11 | |
- a00 * a11 * a22 | |
- 2 * a01 * a02 * a12 | |
) | |
inv_det = 1.0 / det | |
# Calculate inverse covariance matrix | |
m00 = (a12 * a12 - a11 * a22) * inv_det | |
m01 = (a01 * a22 - a02 * a12) * inv_det | |
m02 = (a02 * a11 - a01 * a12) * inv_det | |
m11 = (a02 * a02 - a00 * a22) * inv_det | |
m12 = (a00 * a12 - a01 * a02) * inv_det | |
m22 = (a01 * a01 - a00 * a11) * inv_det | |
# For each pair ((xi, yi), (xj, yj)) in a (2 r + 1)x(2 r + 1) window | |
for dyi in range(2 * r + 1): | |
for dxi in range(2 * r + 1): | |
s = c[dyi, dxi, 0] | |
t = c[dyi, dxi, 1] | |
u = c[dyi, dxi, 2] | |
c0 = m00 * s + m01 * t + m02 * u | |
c1 = m01 * s + m11 * t + m12 * u | |
c2 = m02 * s + m12 * t + m22 * u | |
for dyj in range(2 * r + 1): | |
for dxj in range(2 * r + 1): | |
xi = x + dxi - r | |
yi = y + dyi - r | |
xj = x + dxj - r | |
yj = y + dyj - r | |
i = xi + yi * w | |
j = xj + yj * w | |
# Calculate contribution of pixel pair to L_ij | |
temp = ( | |
c0 * c[dyj, dxj, 0] | |
+ c1 * c[dyj, dxj, 1] | |
+ c2 * c[dyj, dxj, 2] | |
) | |
value = (1.0 if (i == j) else 0.0) - ( | |
1 + temp | |
) / window_area | |
dx = xj - xi + 2 * r | |
dy = yj - yi + 2 * r | |
values[i, dy, dx] += value | |
def cf_laplacian(image, epsilon=1e-7, radius=1, is_known=None): | |
""" | |
This function implements the alpha estimator for closed-form alpha matting as proposed by :cite:`levin2007closed`. | |
Parameters | |
------------ | |
image: numpy.ndarray | |
Image with shape :math:`h\\times w \\times 3` | |
epsilon: float | |
Regularization strength, defaults to :math:`10^{-7}`. Strong regularization improves convergence but results in smoother alpha mattes. | |
radius: int | |
Radius of local window size, defaults to :math:`1`, i.e. only adjacent pixels are considered. | |
The size of the local window is given as :math:`(2 r + 1)^2`, where :math:`r` denotes the radius. A larger radius might lead to violated color line constraints, but also | |
favors further propagation of information within the image. | |
is_known: numpy.ndarray | |
Binary mask of pixels for which to compute the laplacian matrix. | |
Laplacian entries for known pixels will have undefined values. | |
Returns | |
------- | |
L: scipy.sparse.spmatrix | |
Matting Laplacian | |
""" | |
h, w, _ = get_h_w_c(image) | |
n = h * w | |
if is_known is None: | |
is_known = np.zeros((h, w), dtype=np.bool_) | |
is_known = is_known.reshape(h, w) | |
# Data for matting laplacian in csr format | |
indptr = np.zeros(n + 1, dtype=np.int64) | |
indices = np.zeros(n * (4 * radius + 1) ** 2, dtype=np.int64) | |
values = np.zeros((n, 4 * radius + 1, 4 * radius + 1), dtype=np.float64) | |
_cf_laplacian(image, epsilon, radius, values, indices, indptr, is_known) | |
L = scipy.sparse.csr_matrix((values.ravel(), indices, indptr), (n, n)) | |
return L | |