def transform_Dlt_on_Moments(dlt_tfm, moments): '''Transform the Moments using an affine transformation. Parameters ---------- dlt_tfm : Dlt general dilatation moments : Moments general moments Returns ------- Moments affined-transformed moments ''' a = dlt_tfm.scale A = np.diag(a) old_m0 = moments.m0 old_mean = moments.mean old_cov = moments.cov new_mean = a*old_mean + dlt_tfm.offset new_cov = A @ old_cov @ A.T new_m0 = old_m0*abs(np.prod(a)) new_m1 = new_m0*new_mean new_m2 = new_m0*(np.outer(new_mean, new_mean) + new_cov) return Moments(new_m0, new_m1, new_m2)
def __init__(self, aff_tfm, make_normalised=True): '''Initialises a hyperellipsoid with an affine transformation.''' if not isinstance(aff_tfm, Aff): raise ValueError("Only an instance of class `Aff` is accepted.") if make_normalised: U, S, VT = np.linalg.svd(aff_tfm.weight, full_matrices=False) aff_tfm = Aff(bias=aff_tfm.bias, weight=U @ np.diag(S)) self.aff_tfm = aff_tfm
def __init__(self, aff_tfm, make_normalised=True): '''Initialises an ellipse with an affine transformation.''' if not isinstance(aff_tfm, Aff2d): raise ValueError("Only an instance of class `Aff2d` is accepted.") if make_normalised: U, S, VT = np.linalg.svd(aff_tfm.weight, full_matrices=False) aff_tfm = Aff2d(offset=aff_tfm.offset, linear=Lin2d.from_matrix(U @ np.diag(S))) self.aff_tfm = aff_tfm
def approx_Moments2d_to_Ellipse(obj): '''Approximates a Moments2d instance with a normalised Ellipse that has the same mean and covariance as the mean and covariance of the instance.''' # A AAT = obj.cov * 4 w, v = np.linalg.eig(AAT) A = v @ np.diag(np.sqrt(w)) # aff_tfm aff_tfm = Aff2d(offset=obj.mean, linear=Lin2d.from_matrix(A)) return Ellipse(aff_tfm)
def weight(self): return np.diag(self.scale)
if not isinstance(other, Dlt): return super(Dlt, self).multiply(other) return Dlt(self << other.offset, self.scale*other.scale) multiply.__doc__ = Aff.multiply.__doc__ def invert(self): return Dlt(-self.offset/self.scale, 1/self.scale) invert.__doc__ = Aff.invert.__doc__ # ----- casting ----- _bc.register_cast(Dlt, Aff, lambda x: Aff(weight=x.weight, bias=x.bias, check_shapes=False)) _bc.register_cast(Aff, Dlt, lambda x: Dlt(offset=x.bias, scale=np.diagonal(x.weight))) _bc.register_castable(Aff, Dlt, lambda x: np.count_nonzero(x.weight - np.diag(np._diagonal(x.weight))) > 0) # ----- transform functions ----- def transform_Dlt_on_Moments(dlt_tfm, moments): '''Transform the Moments using an affine transformation. Parameters ---------- dlt_tfm : Dlt general dilatation moments : Moments general moments
return Dltra(offset=t, scale=s) def pow(self, k: float): """Raises the Dltra to a scalar power.""" u, v = self.logm() return Dltra.expm(u * k, v * k) # ----- casting ----- _bc.register_cast(Dltra, Dliso, lambda x: Dliso(offset=x.offset, scale=x.scale)) _bc.register_cast( Dltra, Dlt, lambda x: Dlt(offset=x.offset, scale=np.diag(x.scale), check_shapes=False), ) # ----- approximation ------ def approx_Dliso_to_Dltra(obj): """Approximates an Dliso instance with a Dltra by ignoring the unitary part.""" return Dltra(offset=obj.offset, scale=obj.scale) register_approx(Dliso, Dltra, approx_Dliso_to_Dltra) def approx_Dlt_to_Dltra(dlt): """Approximates a Dlt instance with a Dltra.