public ClusterFit(ColourSet colours, SquishFlags flags) : base(colours, flags) { // set the iteration count m_iterationCount = ((m_flags & SquishFlags.kColourIterativeClusterFit) != 0) ? kMaxIterations : 1; // initialise the best error m_besterror = Vector4.one * float.MaxValue; // initialise the metric bool perceptual = ((m_flags & SquishFlags.kColourMetricPerceptual) != 0); if (perceptual) { m_metric = new Vector4(0.2126f, 0.7152f, 0.0722f, 0.0f); } else { m_metric = Vector4.one; } // cache some values int count = m_colours.GetCount(); Vector3[] values = m_colours.GetPoints(); // get the covariance matrix Sym3x3 covariance = math.ComputeWeightedCovariance(count, values, m_colours.GetWeights()); // compute the principle component m_principle = math.ComputePrincipleComponent(covariance); }
public static Sym3x3 ComputeWeightedCovariance(int n, Vector3[] points, float[] weights) { // compute the centroid float total = 0.0f; Vector3 centroid = Vector3.zero; for (int i = 0; i < n; ++i) { total += weights[i]; centroid += weights[i] * points[i]; } centroid /= total; // accumulate the covariance matrix Sym3x3 covariance = new Sym3x3(); 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 Vector3 GetMultiplicity1Evector(Sym3x3 matrix, float evalue) { // compute M Sym3x3 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 Sym3x3 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 float mc = Mathf.Abs(u[0]); int mi = 0; for (int i = 1; i < 6; ++i) { float c = Mathf.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 Vector3 GetMultiplicity2Evector(Sym3x3 matrix, float evalue) { // compute M Sym3x3 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 float mc = Mathf.Abs(m[0]); int mi = 0; for (int i = 1; i < 6; ++i) { float c = Mathf.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 RangeFit(ColourSet colours, SquishFlags flags) : base(colours, flags) { // initialise the metric bool perceptual = ((m_flags & SquishFlags.kColourMetricPerceptual) != 0); if (perceptual) { m_metric = new Vector3(0.2126f, 0.7152f, 0.0722f); } else { m_metric = Vector3.one; } // initialise the best error m_besterror = float.MaxValue; // cache some values int count = m_colours.GetCount(); Vector3[] values = m_colours.GetPoints(); float[] weights = m_colours.GetWeights(); // get the covariance matrix Sym3x3 covariance = math.ComputeWeightedCovariance(count, values, weights); // compute the principle component Vector3 principle = math.ComputePrincipleComponent(covariance); // get the min and max range as the codebook endpoints Vector3 start = Vector3.zero; Vector3 end = Vector3.zero; 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] start = Vector3.Min(Vector3.one, Vector3.Max(Vector3.zero, start)); end = Vector3.Min(Vector3.one, Vector3.Max(Vector3.zero, end)); // clamp to the grid and save Vector3 half = Vector3.one * (0.5f); m_start = Vector3.Scale(math.Truncate(Vector3.Scale(grid, start) + half), gridrcp); m_end = Vector3.Scale(math.Truncate(Vector3.Scale(grid, end) + half), gridrcp); }
public static Vector3 ComputePrincipleComponent(Sym3x3 matrix) { // compute the cubic coefficients float c0 = matrix[0] * matrix[3] * matrix[5] + 2.0f * matrix[1] * matrix[2] * matrix[4] - matrix[0] * matrix[4] * matrix[4] - matrix[3] * matrix[2] * matrix[2] - matrix[5] * matrix[1] * matrix[1]; float 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]; float c2 = matrix[0] + matrix[3] + matrix[5]; // compute the quadratic coefficients float a = c1 - (1.0f / 3.0f) * c2 * c2; float b = (-2.0f / 27.0f) * c2 * c2 * c2 + (1.0f / 3.0f) * c1 * c2 - c0; // compute the root count check float Q = 0.25f * b * b + (1.0f / 27.0f) * a * a * a; // test the multiplicity if (float.Epsilon < Q) { // only one root, which implies we have a multiple of the identity return Vector3.one; } else if (Q < -float.Epsilon) { // three distinct roots float theta = Mathf.Atan2(Mathf.Sqrt(-Q), -0.5f * b); float rho = Mathf.Sqrt(0.25f * b * b - Q); float rt = Mathf.Pow(rho, 1.0f / 3.0f); float ct = Mathf.Cos(theta / 3.0f); float st = Mathf.Sin(theta / 3.0f); float l1 = (1.0f / 3.0f) * c2 + 2.0f * rt * ct; float l2 = (1.0f / 3.0f) * c2 - rt * (ct + (float)Mathf.Sqrt(3.0f) * st); float l3 = (1.0f / 3.0f) * c2 - rt * (ct - (float)Mathf.Sqrt(3.0f) * st); // pick the larger if (Mathf.Abs(l2) > Mathf.Abs(l1)) l1 = l2; if (Mathf.Abs(l3) > Mathf.Abs(l1)) l1 = l3; // get the eigenvector return GetMultiplicity1Evector(matrix, l1); } else // if( -FLT_EPSILON <= Q && Q <= FLT_EPSILON ) { // two roots float rt; if (b < 0.0f) rt = -Mathf.Pow(-0.5f * b, 1.0f / 3.0f); else rt = Mathf.Pow(0.5f * b, 1.0f / 3.0f); float l1 = (1.0f / 3.0f) * c2 + rt; // repeated float l2 = (1.0f / 3.0f) * c2 - 2.0f * rt; // get the eigenvector if (Mathf.Abs(l1) > Mathf.Abs(l2)) return GetMultiplicity2Evector(matrix, l1); else return GetMultiplicity1Evector(matrix, l2); } }
public static Vector3 GetMultiplicity2Evector(Sym3x3 matrix, float evalue) { // compute M Sym3x3 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 float mc = Mathf.Abs(m[0]); int mi = 0; for (int i = 1; i < 6; ++i) { float c = Mathf.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 GetMultiplicity1Evector(Sym3x3 matrix, float evalue) { // compute M Sym3x3 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 Sym3x3 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 float mc = Mathf.Abs(u[0]); int mi = 0; for (int i = 1; i < 6; ++i) { float c = Mathf.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 float total = 0.0f; Vector3 centroid = Vector3.zero; for (int i = 0; i < n; ++i) { total += weights[i]; centroid += weights[i] * points[i]; } centroid /= total; // accumulate the covariance matrix Sym3x3 covariance = new Sym3x3(); 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 Vector3 ComputePrincipleComponent(Sym3x3 matrix) { // compute the cubic coefficients float c0 = matrix[0] * matrix[3] * matrix[5] + 2.0f * matrix[1] * matrix[2] * matrix[4] - matrix[0] * matrix[4] * matrix[4] - matrix[3] * matrix[2] * matrix[2] - matrix[5] * matrix[1] * matrix[1]; float 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]; float c2 = matrix[0] + matrix[3] + matrix[5]; // compute the quadratic coefficients float a = c1 - (1.0f / 3.0f) * c2 * c2; float b = (-2.0f / 27.0f) * c2 * c2 * c2 + (1.0f / 3.0f) * c1 * c2 - c0; // compute the root count check float Q = 0.25f * b * b + (1.0f / 27.0f) * a * a * a; // test the multiplicity if (float.Epsilon < Q) { // only one root, which implies we have a multiple of the identity return(Vector3.one); } else if (Q < -float.Epsilon) { // three distinct roots float theta = Mathf.Atan2(Mathf.Sqrt(-Q), -0.5f * b); float rho = Mathf.Sqrt(0.25f * b * b - Q); float rt = Mathf.Pow(rho, 1.0f / 3.0f); float ct = Mathf.Cos(theta / 3.0f); float st = Mathf.Sin(theta / 3.0f); float l1 = (1.0f / 3.0f) * c2 + 2.0f * rt * ct; float l2 = (1.0f / 3.0f) * c2 - rt * (ct + (float)Mathf.Sqrt(3.0f) * st); float l3 = (1.0f / 3.0f) * c2 - rt * (ct - (float)Mathf.Sqrt(3.0f) * st); // pick the larger if (Mathf.Abs(l2) > Mathf.Abs(l1)) { l1 = l2; } if (Mathf.Abs(l3) > Mathf.Abs(l1)) { l1 = l3; } // get the eigenvector return(GetMultiplicity1Evector(matrix, l1)); } else // if( -FLT_EPSILON <= Q && Q <= FLT_EPSILON ) { // two roots float rt; if (b < 0.0f) { rt = -Mathf.Pow(-0.5f * b, 1.0f / 3.0f); } else { rt = Mathf.Pow(0.5f * b, 1.0f / 3.0f); } float l1 = (1.0f / 3.0f) * c2 + rt; // repeated float l2 = (1.0f / 3.0f) * c2 - 2.0f * rt; // get the eigenvector if (Mathf.Abs(l1) > Mathf.Abs(l2)) { return(GetMultiplicity2Evector(matrix, l1)); } else { return(GetMultiplicity1Evector(matrix, l2)); } } }