public static Sym3x3 ComputeWeightedCovariance(int n, Vector3[] points, float[] weights) { // compute the centroid float total = 0.0f; Vector3 centroid = new Vector3(0.0f); for (int i = 0; i < n; ++i) { total += weights[i]; centroid += weights[i] * points[i]; } if (total > float.Epsilon) { centroid /= total; } // accumulate the covariance matrix Sym3x3 covariance = new Sym3x3(0.0f); for (int i = 0; i < n; ++i) { Vector3 a = points[i] - centroid; Vector3 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 static Sym3x3 ComputeWeightedCovariance(int n, Vector3[] points, float[] weights) { // compute the centroid float total = 0.0f; Vector3 centroid = new Vector3(0.0f); for (int i = 0; i < n; ++i) { total += weights[i]; centroid += weights[i] * points[i]; } if (total > float.Epsilon) { centroid /= total; } // accumulate the covariance matrix Sym3x3 covariance = new Sym3x3(0.0f); for (int i = 0; i < n; ++i) { Vector3 a = points[i] - centroid; Vector3 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 ClusterFit(ColourSet colours, SquishFlags flags, float?metric) : base(colours, flags) { // set the iteration count m_iterationCount = ((m_flags & SquishFlags.kColourIterativeClusterFit) != 0 ? 8 : 1); // initialise the metric (old perceptual = 0.2126f, 0.7152f, 0.0722f) if (metric != null) { //m_metric = Vec4( metric[0], metric[1], metric[2], 1.0f ); } else { m_metric = new Vector4(1.0f); } // initialise the best error m_besterror = new Vector4(float.MaxValue); // cache some values int count = m_colours.Count; Vector3[] 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); }
protected ClusterFit(ColourSet colours, SquishOptions flags) : base(colours, flags) { // Set the iteration count. this._IterationCount = flags.HasFlag(SquishOptions.ColourIterativeClusterFit) ? MaxIterations : 1; // Initialise the best error. this._BestError = new Vector4(float.MaxValue); // Initialize the metric var perceptual = flags.HasFlag(SquishOptions.ColourMetricPerceptual); if (perceptual) { this._Metric = new Vector4(0.2126f, 0.7152f, 0.0722f, 0.0f); } else { this._Metric = new Vector4(1.0f); } // Get the covariance matrix. var covariance = Sym3x3.ComputeWeightedCovariance(colours.Count, colours.Points, colours.Weights); // Compute the principle component this._Principle = Sym3x3.ComputePrincipledComponent(covariance); }
public static Sym3x3 ComputeWeightedCovariance(int n, Vector3[] points, float[] weights) { // Compute the centroid. var total = 0f; var centroid = new Vector3(0f); 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(0f); for (int i = 0; i < n; ++i) { var a = points[i] - centroid; 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(covariance); }
private static Vector3 GetMultiplicity1Evector(Sym3x3 matrix, float evalue) { // Compute M var m = new Sym3x3(); m[0] = matrix[0] - evalue; m[1] = matrix[1]; m[2] = matrix[2]; m[3] = matrix[3] - evalue; m[4] = matrix[4]; m[5] = matrix[5] - evalue; // Compute U var u = new Sym3x3(); u[0] = (m[3] * m[5]) - (m[4] * m[4]); u[1] = (m[2] * m[4]) - (m[1] * m[5]); u[2] = (m[1] * m[4]) - (m[2] * m[3]); u[3] = (m[0] * m[5]) - (m[2] * m[2]); u[4] = (m[1] * m[2]) - (m[4] * m[0]); u[5] = (m[0] * m[3]) - (m[1] * m[1]); // Find the largest component. var mc = Math.Abs(u[0]); var mi = 0; for (int i = 1; i < 6; ++i) { var c = Math.Abs(u[i]); if (c > mc) { mc = c; mi = i; } } // Pick the column with this component. switch (mi) { case 0: return(new Vector3(u[0], u[1], u[2])); case 1: case 3: return(new Vector3(u[1], u[3], u[4])); default: return(new Vector3(u[2], u[4], u[5])); } }
private static Vector3 GetMultiplicity2Evector(Sym3x3 matrix, float evalue) { // Compute M var m = new Sym3x3(); m[0] = matrix[0] - evalue; m[1] = matrix[1]; m[2] = matrix[2]; m[3] = matrix[3] - evalue; m[4] = matrix[4]; m[5] = matrix[5] - evalue; // Find the largest component. var mc = Math.Abs(m[0]); var mi = 0; for (int i = 1; i < 6; ++i) { var c = Math.Abs(m[i]); if (c > mc) { mc = c; mi = i; } } // pick the first eigenvector based on this index switch (mi) { case 0: case 1: return(new Vector3(-m[1], m[0], 0.0f)); case 2: return(new Vector3(m[2], 0.0f, -m[0])); case 3: case 4: return(new Vector3(0.0f, -m[4], m[3])); default: return(new Vector3(0.0f, -m[5], m[4])); } }
public static Vector3 ComputePrincipleComponent(Sym3x3 matrix) { Vector4 row0 = new Vector4(matrix[0], matrix[1], matrix[2], 0.0f); Vector4 row1 = new Vector4(matrix[1], matrix[3], matrix[4], 0.0f); Vector4 row2 = new Vector4(matrix[2], matrix[4], matrix[5], 0.0f); Vector4 v = new Vector4(1.0f); for (int i = 0; i < 8; ++i) { // matrix multiply Vector4 w = row0 * v.SplatX(); w = Helpers.MultiplyAdd(row1, v.SplatY(), w); w = Helpers.MultiplyAdd(row2, v.SplatZ(), w); // get max component from xyz in all channels Vector4 a = Vector4.Max(w.SplatX(), Vector4.Max(w.SplatY(), w.SplatZ())); // divide through and advance v = w * Helpers.Reciprocal(a); } return v.ToVector3(); }
public static Vector3 ComputePrincipleComponent(Sym3x3 matrix) { Vector4 row0 = new Vector4(matrix[0], matrix[1], matrix[2], 0.0f); Vector4 row1 = new Vector4(matrix[1], matrix[3], matrix[4], 0.0f); Vector4 row2 = new Vector4(matrix[2], matrix[4], matrix[5], 0.0f); Vector4 v = new Vector4(1.0f); for (int i = 0; i < 8; ++i) { // matrix multiply Vector4 w = row0 * v.SplatX(); w = Helpers.MultiplyAdd(row1, v.SplatY(), w); w = Helpers.MultiplyAdd(row2, v.SplatZ(), w); // get max component from xyz in all channels Vector4 a = Vector4.Max(w.SplatX(), Vector4.Max(w.SplatY(), w.SplatZ())); // divide through and advance v = w * Helpers.Reciprocal(a); } return(v.ToVector3()); }
private static Vector3 GetMultiplicity2Evector(Sym3x3 matrix, float evalue) { // Compute M var m = new Sym3x3(); m[0] = matrix[0] - evalue; m[1] = matrix[1]; m[2] = matrix[2]; m[3] = matrix[3] - evalue; m[4] = matrix[4]; m[5] = matrix[5] - evalue; // Find the largest component. var mc = Math.Abs(m[0]); var mi = 0; for (int i = 1; i < 6; ++i) { var c = Math.Abs(m[i]); if (c > mc) { mc = c; mi = i; } } // pick the first eigenvector based on this index switch (mi) { case 0: case 1: return new Vector3(-m[1], m[0], 0.0f); case 2: return new Vector3(m[2], 0.0f, -m[0]); case 3: case 4: return new Vector3(0.0f, -m[4], m[3]); default: return new Vector3(0.0f, -m[5], m[4]); } }
private static Vector3 GetMultiplicity1Evector(Sym3x3 matrix, float evalue) { // Compute M var m = new Sym3x3(); m[0] = matrix[0] - evalue; m[1] = matrix[1]; m[2] = matrix[2]; m[3] = matrix[3] - evalue; m[4] = matrix[4]; m[5] = matrix[5] - evalue; // Compute U var u = new Sym3x3(); u[0] = (m[3] * m[5]) - (m[4] * m[4]); u[1] = (m[2] * m[4]) - (m[1] * m[5]); u[2] = (m[1] * m[4]) - (m[2] * m[3]); u[3] = (m[0] * m[5]) - (m[2] * m[2]); u[4] = (m[1] * m[2]) - (m[4] * m[0]); u[5] = (m[0] * m[3]) - (m[1] * m[1]); // Find the largest component. var mc = Math.Abs(u[0]); var mi = 0; for (int i = 1; i < 6; ++i) { var c = Math.Abs(u[i]); if (c > mc) { mc = c; mi = i; } } // Pick the column with this component. switch (mi) { case 0: return new Vector3(u[0], u[1], u[2]); case 1: case 3: return new Vector3(u[1], u[3], u[4]); default: return new Vector3(u[2], u[4], u[5]); } }
public static Sym3x3 ComputeWeightedCovariance(int n, Vector3[] points, float[] weights) { // Compute the centroid. var total = 0f; var centroid = new Vector3(0f); 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(0f); for (int i = 0; i < n; ++i) { var a = points[i] - centroid; 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 covariance; }
public static Vector3 ComputePrincipledComponent(Sym3x3 matrix) { // Compute the cubic coefficients var c0 = (matrix[0] * matrix[3] * matrix[5]) + (matrix[1] * matrix[2] * matrix[4] * 2f) - (matrix[0] * matrix[4] * matrix[4]) - (matrix[3] * matrix[2] * matrix[2]) - (matrix[5] * matrix[1] * matrix[1]); var c1 = (matrix[0] * matrix[3]) + (matrix[0] * matrix[5]) + (matrix[3] * matrix[5]) - (matrix[1] * matrix[1]) - (matrix[2] * matrix[2]) - (matrix[4] * matrix[4]); var c2 = matrix[0] + matrix[3] + matrix[5]; // Compute the quadratic coefficients var a = c1 - ((1f / 3f) * c2 * c2); var b = ((-2f / 27f) * c2 * c2 * c2) + ((1f / 3f) * c1 * c2) - c0; // Compute the root count check; var Q = (.25f * b * b) + ((1f / 27f) * a * a * a); // Test the multiplicity. if (float.Epsilon < Q) { return new Vector3(1f); // Only one root, which implies we have a multiple of the identity. } else if (Q < -float.Epsilon) { // Three distinct roots var theta = Math.Atan2(Math.Sqrt(Q), -.5f * b); var rho = Math.Sqrt((.25f * b * b) - Q); var rt = Math.Pow(rho, 1f / 3f); var ct = Math.Cos(theta / 3f); var st = Math.Sin(theta / 3f); var l1 = ((1f / 3f) * c2) + (2f * rt * ct); var l2 = ((1f / 3f) * c2) - (rt * (ct + (Math.Sqrt(3f) * st))); var l3 = ((1f / 3f) * c2) - (rt * (ct - (Math.Sqrt(3f) * st))); // Pick the larger. if (Math.Abs(l2) > Math.Abs(l1)) { l1 = l2; } if (Math.Abs(l3) > Math.Abs(l1)) { l1 = l3; } // Get the eigenvector return GetMultiplicity1Evector(matrix, (float)l1); } else { // Q very close to 0 // Two roots double rt; if (b < 0.0f) { rt = -Math.Pow(-.5f * b, 1f / 3f); } else { rt = Math.Pow(.5f * b, 1f / 3f); } var l1 = ((1f / 3f) * c2) + rt; var l2 = ((1f / 3f) * c2) - (2f * rt); // Get the eigenvector if (Math.Abs(l1) > Math.Abs(l2)) { return GetMultiplicity2Evector(matrix, (float)l1); } else { return GetMultiplicity1Evector(matrix, (float)l2); } } }
public RangeFit(ColourSet colours, SquishFlags flags, float?metric) : base(colours, flags) { // initialise the metric (old perceptual = 0.2126f, 0.7152f, 0.0722f) if (metric != null) { //m_metric = new Vector3( metric[0], metric[1], metric[2] ); } else { m_metric = new Vector3(1.0f); } // initialise the best error m_besterror = float.MaxValue; // cache some values int count = m_colours.Count; Vector3[] values = m_colours.Points; float[] weights = m_colours.Weights; // get the covariance matrix Sym3x3 covariance = Sym3x3.ComputeWeightedCovariance(count, values, weights); // compute the principle component Vector3 principle = Sym3x3.ComputePrincipleComponent(covariance); // get the min and max range as the codebook endpoints Vector3 start = new Vector3(0.0f); Vector3 end = new Vector3(0.0f); if (count > 0) { float min, max; // compute the range start = end = values[0]; min = max = Vector3.Dot(values[0], principle); for (int i = 1; i < count; ++i) { float val = Vector3.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] Vector3 one = new Vector3(1.0f); Vector3 zero = new Vector3(0.0f); start = Vector3.Min(one, Vector3.Max(zero, start)); end = Vector3.Min(one, Vector3.Max(zero, end)); // clamp to the grid and save Vector3 grid = new Vector3(31.0f, 63.0f, 31.0f); Vector3 gridrcp = new Vector3(1.0f / 31.0f, 1.0f / 63.0f, 1.0f / 31.0f); Vector3 half = new Vector3(0.5f); m_start = Helpers.Truncate(grid * start + half) * gridrcp; m_end = Helpers.Truncate(grid * end + half) * gridrcp; }
public static Vector3 ComputePrincipledComponent(Sym3x3 matrix) { // Compute the cubic coefficients var c0 = (matrix[0] * matrix[3] * matrix[5]) + (matrix[1] * matrix[2] * matrix[4] * 2f) - (matrix[0] * matrix[4] * matrix[4]) - (matrix[3] * matrix[2] * matrix[2]) - (matrix[5] * matrix[1] * matrix[1]); var c1 = (matrix[0] * matrix[3]) + (matrix[0] * matrix[5]) + (matrix[3] * matrix[5]) - (matrix[1] * matrix[1]) - (matrix[2] * matrix[2]) - (matrix[4] * matrix[4]); var c2 = matrix[0] + matrix[3] + matrix[5]; // Compute the quadratic coefficients var a = c1 - ((1f / 3f) * c2 * c2); var b = ((-2f / 27f) * c2 * c2 * c2) + ((1f / 3f) * c1 * c2) - c0; // Compute the root count check; var Q = (.25f * b * b) + ((1f / 27f) * a * a * a); // Test the multiplicity. if (float.Epsilon < Q) { return(new Vector3(1f)); // Only one root, which implies we have a multiple of the identity. } else if (Q < -float.Epsilon) { // Three distinct roots var theta = Math.Atan2(Math.Sqrt(Q), -.5f * b); var rho = Math.Sqrt((.25f * b * b) - Q); var rt = Math.Pow(rho, 1f / 3f); var ct = Math.Cos(theta / 3f); var st = Math.Sin(theta / 3f); var l1 = ((1f / 3f) * c2) + (2f * rt * ct); var l2 = ((1f / 3f) * c2) - (rt * (ct + (Math.Sqrt(3f) * st))); var l3 = ((1f / 3f) * c2) - (rt * (ct - (Math.Sqrt(3f) * st))); // Pick the larger. if (Math.Abs(l2) > Math.Abs(l1)) { l1 = l2; } if (Math.Abs(l3) > Math.Abs(l1)) { l1 = l3; } // Get the eigenvector return(GetMultiplicity1Evector(matrix, (float)l1)); } else // Q very close to 0 // Two roots { double rt; if (b < 0.0f) { rt = -Math.Pow(-.5f * b, 1f / 3f); } else { rt = Math.Pow(.5f * b, 1f / 3f); } var l1 = ((1f / 3f) * c2) + rt; var l2 = ((1f / 3f) * c2) - (2f * rt); // Get the eigenvector if (Math.Abs(l1) > Math.Abs(l2)) { return(GetMultiplicity2Evector(matrix, (float)l1)); } else { return(GetMultiplicity1Evector(matrix, (float)l2)); } } }