Пример #1
0
        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;
        }
Пример #3
0
        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);
        }
Пример #4
0
        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);
        }
Пример #5
0
        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);
        }
Пример #6
0
        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]));
            }
        }
Пример #7
0
        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();
        }
Пример #9
0
        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());
        }
Пример #10
0
        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]);
            }
        }
Пример #11
0
        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]);
            }
        }
Пример #12
0
        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;
        }
Пример #13
0
        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;
        }
Пример #15
0
        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));
                }
            }
        }