Exemple #1
0
def test_aitchison_norm():
    """Test Aitchison norm."""
    # Given
    data = np.array([1/3, 1/3, 1/3])
    # When
    output = coda.aitchison_norm(data[None, :])
    # Then
    assert output == pytest.approx(0)
Exemple #2
0
def simplex_color_balance(bary, center=True, standardize=False,
                          trunc_max=False):
    """Compositional data based method for color balance.

    Highly experimental!

    Parameters
    ----------
    bary: numpy.ndarray
        Barycentric coordinates. Sum of all channels should add up to 1
        (closed).
    center: bool
        Center barycentric coordinates (similar to de-meaning). Single-hue
        dominated images will be balanced to cover all hues.
    standardize: bool
        Standardize barycentric coordinates. Standardized compositions make
        better use of the simplex space dynamic range.
    trunc_max: bool
        Truncate maximum barycentric coordinates to eliminate extreme hues that
        are not prevalent in the image.

    Returns
    -------
    bary: numpy.ndarray
        Processed composition.

    """
    dims = bary.shape
    bary = bary.reshape([np.prod(dims[:-1]), dims[-1]])
    bary = np.nan_to_num(bary)

    # Do not consider values <= 0
    mask = np.prod(bary, axis=-1)
    mask = mask > 0
    temp = bary[mask]

    # Interpretation of centering: Compositions cover the simplex space more
    # balanced across components. Similar to de-mean data.
    if center:
        sample_center = coda.sample_center(temp)
        temp2 = np.full(temp.shape, sample_center)
        temp = coda.perturb(temp, temp2**-1.)
        temp2 = None

    # Interpretation of standardization: Centered compositions cover the
    # dynamic range of simplex space more.
    if standardize:  # Standardize
        totvar = coda.sample_total_variance(temp, sample_center)
        temp = coda.power(temp, np.power(totvar, -1./2.))

    # Interpretation of max truncation: Pull the exterme compositions to
    # threshold distance by using scaling. Scaling factor is determined for
    # each outlier composition to pull more extreme compositions more strongly.
    if trunc_max:
        # Use Aitchison norm and powering to truncate extreme compositions
        anorm = coda.aitchison_norm(temp)
        anorm_thr_min, anorm_thr_max = np.percentile(anorm, [1., 99.])
        # Max truncate
        idx_trunc = anorm > anorm_thr_max
        truncation_power = anorm[idx_trunc] / anorm_thr_max
        correction = np.ones(anorm.shape)
        correction[idx_trunc] = truncation_power
        temp = coda.power(temp, correction[:, None])
        # min truncate
        idx_trunc = anorm < anorm_thr_min
        truncation_power = anorm[idx_trunc] / anorm_thr_min
        correction = np.ones(anorm.shape)
        correction[idx_trunc] = truncation_power
        temp = coda.power(temp, correction[:, None])
    # TODO: Implement this similar to truncate and scpe function but for
    # simplex space. Proportion of dynamic range to the distance of between
    # aitchison norm percentiles gives the global scaling factor. This should
    # be done after truncation though.

    # Put back processed composition
    bary[mask] = temp
    return bary.reshape(dims)
Exemple #3
0
# Do not consider masked values
p_mask = mask.reshape(dims[0] * dims[1] * dims[2])
p_comp = comp[p_mask > 0]

# Centering
center = coda.sample_center(p_comp)
temp = np.ones(p_comp.shape) * center
p_comp = coda.perturb(p_comp, temp**-1.)
# Standardize
totvar = coda.sample_total_variance(p_comp, center)
p_comp = coda.power(p_comp, np.power(totvar, -1. / 2.))

# Use Aitchison norm and powerinf for truncation of extreme compositions
anorm_thr = 3
anorm = coda.aitchison_norm(p_comp)
idx_trunc = anorm > anorm_thr
truncation_power = anorm[idx_trunc] / anorm_thr
correction = np.ones(anorm.shape)
correction[idx_trunc] = truncation_power
comp_bal = coda.power(p_comp, correction[:, None])

# go to hexcone lattice for exports
comp[p_mask > 0] = comp_bal

# lightness balance
light = truncate_range(light, percMin=1, percMax=99)
hexc = comp * light[:, None]

hexc = hexc.reshape(dims[0], dims[1], dims[2], dims[3])
for i in range(hexc.shape[3]):
Exemple #4
0
#     temp = truncate_range(temp)
#     temp = scale_range(temp, scale_factor=1000)
#     comp[:, i] = temp

# Impute
comp[comp == 0] = 1.

# Closure
comp = coda.closure(comp)

# Aitchison inner product
ref = np.ones(comp.shape)
ref[:, 1] = ref[:, 1] * 10
ref = coda.closure(ref)
ip = coda.aitchison_inner_product(comp, ref)

cos_theta = ip / (coda.aitchison_norm(comp) * coda.aitchison_norm(ref))
rad = np.arccos(cos_theta)
deg = rad * (360 / (2*np.pi))

# # Determine sector
# idx_sector2 = comp[:, 1] > comp[:, 2]
# deg[idx_sector2] = 360. - deg[idx_sector2]

# Create output
out = np.zeros(nii1.shape)
out[idx_mask] = deg
img = Nifti1Image(out, affine=nii1.affine)
save(img, os.path.join(dirname, 'theta2.nii.gz'))
print('Finished.')
Exemple #5
0
dims = img.shape

# impute zeros
idx1 = (img[..., 0] <= 0) + (img[..., 1] <= 0) + (img[..., 2] <= 0)
gauss = gaussian(img, sigma=0.5, multichannel=True)
img[idx1, :] = gauss[idx1, :]

# rgb to hsv for control
hsv = color.rgb2hsv(img)
hsv[..., 0] = -np.abs(hsv[..., 0] - 0.5) + 0.5

# coda stuff
angdif_norm_int = np.zeros(img.shape)
temp = img.reshape(dims[0] * dims[1], dims[2]) * 1.0
bary = coda.closure(temp, 100)
anorm = coda.aitchison_norm(bary)

# prepare reference vector for angular difference
ref = np.ones(bary.shape)
ref[:, 0] = ref[:, 0] * 0.8
ref[:, 1] = ref[:, 1] * 0.1
ref[:, 2] = ref[:, 2] * 0.1
# compute aitchion angular difference
ainp = coda.aitchison_inner_product(bary, ref)
ref_norm = coda.aitchison_norm(ref)
ang_dif = np.zeros(anorm.shape)
# deal with zero norms
idx = anorm != 0
# (choose one) wrapped angle range
ang_dif[idx] = np.arccos(ainp[idx]/(anorm[idx] * ref_norm[idx]))
ang_dif[np.isnan(ang_dif)] = 0  # fix nans assigned to bright