public static Sym3x3 ComputeWeightedCovariance(int n, Vec3[] points, float[] weights, Vec3 metric) { // compute the centroid float total = 0.0f; var centroid = Vec3.Zero; for (int i = 0; i < n; ++i) { total += weights[i]; centroid += weights[i] * points[i]; } centroid /= total; // accumulate the covariance matrix var covariance = new Sym3x3(0.0f); for (int i = 0; i < n; ++i) { var a = (points[i] - centroid) * metric; var b = weights[i] * a; covariance[0] += a.X * b.X; covariance[1] += a.X * b.Y; covariance[2] += a.X * b.Z; covariance[3] += a.Y * b.Y; covariance[4] += a.Y * b.Z; covariance[5] += a.Z * b.Z; } // return it return(covariance); }
public RangeFit(ColourSet colours, CompressionOptions flags) : base(colours) { // initialise the metric bool perceptual = ((flags & CompressionOptions.ColourMetricPerceptual) != 0); m_metric = perceptual ? new Vec3(0.2126f, 0.7152f, 0.0722f) : Vec3.One; // initialise the best error m_besterror = float.MaxValue; // cache some values var count = m_colours.Count; var values = m_colours.Points; var weights = m_colours.Weights; // get the covariance matrix Sym3x3 covariance = Sym3x3.ComputeWeightedCovariance(count, values, weights); // compute the principle component Vec3 principle = Sym3x3.ComputePrincipleComponent(covariance); // get the min and max range as the codebook endpoints Vec3 start = Vec3.Zero; Vec3 end = Vec3.Zero; if (count > 0) { float min, max; // compute the range start = end = values[0]; min = max = Vec3.Dot(values[0], principle); for (int i = 1; i < count; ++i) { float val = Vec3.Dot(values[i], principle); if (val < min) { start = values[i]; min = val; } else if (val > max) { end = values[i]; max = val; } } } // clamp the output to [0, 1] start = start.Clamp(Vec3.Zero, Vec3.One); end = end.Clamp(Vec3.Zero, Vec3.One); // clamp to the grid and save m_start = (GRID * start + HALF).Truncate() * GRIDRCP; m_end = (GRID * end + HALF).Truncate() * GRIDRCP; }
public ClusterFitAlt(ColourSet colours, CompressionOptions flags) : base(colours) { // initialise the metric bool perceptual = ((flags & CompressionOptions.ColourMetricPerceptual) != 0); m_metric = perceptual ? new Vec4(0.2126f, 0.7152f, 0.0722f, 1) : Vec4.One; m_metricSqr = m_metric * m_metric; // get the covariance matrix var covariance = Sym3x3.ComputeWeightedCovariance(m_colours.Count, m_colours.Points, m_colours.Weights, m_metric.GetVec3()); // compute the principle component m_principle = Sym3x3.ComputePrincipleComponent(covariance); }
public ClusterFit(ColourSet colours, CompressionOptions flags) : base(colours) { // set the iteration count m_iterationCount = (flags & CompressionOptions.ColourIterativeClusterFit) != 0 ? MAXITERATIONS : 1; // initialise the metric bool perceptual = ((flags & CompressionOptions.ColourMetricPerceptual) != 0); m_metric = perceptual ? PERCEPTUAL : Vec4.One; // get the covariance matrix var covariance = Sym3x3.ComputeWeightedCovariance(m_colours.Count, m_colours.Points, m_colours.Weights); // compute the principle component m_principle = Sym3x3.ComputePrincipleComponent(covariance); }
public ClusterFit(ColourSet colours, CompressionOptions flags) : base(colours) { // set the iteration count m_iterationCount = (flags & CompressionOptions.ColourIterativeClusterFit) != 0 ? MAXITERATIONS : 1; // initialise the metric bool perceptual = ((flags & CompressionOptions.ColourMetricPerceptual) != 0); m_metric = perceptual ? new Vec4(0.2126f, 0.7152f, 0.0722f, 0.0f) : Vec4.One; // cache some values var count = m_colours.Count; var values = m_colours.Points; // get the covariance matrix Sym3x3 covariance = Sym3x3.ComputeWeightedCovariance(count, values, m_colours.Weights); // compute the principle component m_principle = Sym3x3.ComputePrincipleComponent(covariance); }
public static Vec3 ComputePrincipleComponent(Sym3x3 matrix) { Vec4 row0 = new Vec4(matrix[0], matrix[1], matrix[2], 0.0f); Vec4 row1 = new Vec4(matrix[1], matrix[3], matrix[4], 0.0f); Vec4 row2 = new Vec4(matrix[2], matrix[4], matrix[5], 0.0f); Vec4 v = new Vec4(1.0f); for (int i = 0; i < 8; ++i) { // matrix multiply Vec4 w = row0 * v.SplatX(); w = row1.MultiplyAdd(v.SplatY(), w); w = row2.MultiplyAdd(v.SplatZ(), w); // get max component from xyz in all channels Vec4 a = Vec4.Max(w.SplatX(), Vec4.Max(w.SplatY(), w.SplatZ())); // divide through and advance v = w * a.Reciprocal(); } return(v.GetVec3()); }