예제 #1
0
        private void SetSegmentProbas()
        {
            int[] p = new int[NumMbSegments];
            int   n;

            for (n = 0; n < this.Mbw * this.Mbh; ++n)
            {
                Vp8MacroBlockInfo mb = this.MbInfo[n];
                ++p[mb.Segment];
            }

            if (this.SegmentHeader.NumSegments > 1)
            {
                byte[] probas = this.Proba.Segments;
                probas[0] = (byte)GetProba(p[0] + p[1], p[2] + p[3]);
                probas[1] = (byte)GetProba(p[0], p[1]);
                probas[2] = (byte)GetProba(p[2], p[3]);

                this.SegmentHeader.UpdateMap = probas[0] != 255 || probas[1] != 255 || probas[2] != 255;
                if (!this.SegmentHeader.UpdateMap)
                {
                    this.ResetSegments();
                }

                this.SegmentHeader.Size = (p[0] * (LossyUtils.Vp8BitCost(0, probas[0]) + LossyUtils.Vp8BitCost(0, probas[1]))) +
                                          (p[1] * (LossyUtils.Vp8BitCost(0, probas[0]) + LossyUtils.Vp8BitCost(1, probas[1]))) +
                                          (p[2] * (LossyUtils.Vp8BitCost(1, probas[0]) + LossyUtils.Vp8BitCost(0, probas[2]))) +
                                          (p[3] * (LossyUtils.Vp8BitCost(1, probas[0]) + LossyUtils.Vp8BitCost(1, probas[2])));
            }
            else
            {
                this.SegmentHeader.UpdateMap = false;
                this.SegmentHeader.Size      = 0;
            }
        }
예제 #2
0
        // Simplified k-Means, to assign Nb segments based on alpha-histogram.
        private void AssignSegments(int[] alphas)
        {
            int nb = this.SegmentHeader.NumSegments < NumMbSegments ? this.SegmentHeader.NumSegments : NumMbSegments;

            int[] centers         = new int[NumMbSegments];
            int   weightedAverage = 0;

            int[] map = new int[WebpConstants.MaxAlpha + 1];
            int   n, k;

            int[] accum     = new int[NumMbSegments];
            int[] distAccum = new int[NumMbSegments];

            // Bracket the input.
            for (n = 0; n <= WebpConstants.MaxAlpha && alphas[n] == 0; ++n)
            {
            }

            int minA = n;

            for (n = WebpConstants.MaxAlpha; n > minA && alphas[n] == 0; --n)
            {
            }

            int maxA   = n;
            int rangeA = maxA - minA;

            // Spread initial centers evenly.
            for (k = 0, n = 1; k < nb; ++k, n += 2)
            {
                centers[k] = minA + (n * rangeA / (2 * nb));
            }

            for (k = 0; k < MaxItersKMeans; ++k)
            {
                // Reset stats.
                for (n = 0; n < nb; ++n)
                {
                    accum[n]     = 0;
                    distAccum[n] = 0;
                }

                // Assign nearest center for each 'a'
                n = 0;    // track the nearest center for current 'a'
                int a;
                for (a = minA; a <= maxA; ++a)
                {
                    if (alphas[a] != 0)
                    {
                        while (n + 1 < nb && Math.Abs(a - centers[n + 1]) < Math.Abs(a - centers[n]))
                        {
                            n++;
                        }

                        map[a] = n;

                        // Accumulate contribution into best centroid.
                        distAccum[n] += a * alphas[a];
                        accum[n]     += alphas[a];
                    }
                }

                // All point are classified. Move the centroids to the center of their respective cloud.
                int displaced = 0;
                weightedAverage = 0;
                int totalWeight = 0;
                for (n = 0; n < nb; ++n)
                {
                    if (accum[n] != 0)
                    {
                        int newCenter = (distAccum[n] + (accum[n] / 2)) / accum[n];
                        displaced       += Math.Abs(centers[n] - newCenter);
                        centers[n]       = newCenter;
                        weightedAverage += newCenter * accum[n];
                        totalWeight     += accum[n];
                    }
                }

                weightedAverage = (weightedAverage + (totalWeight / 2)) / totalWeight;
                if (displaced < 5)
                {
                    break;   // no need to keep on looping...
                }
            }

            // Map each original value to the closest centroid
            for (n = 0; n < this.Mbw * this.Mbh; ++n)
            {
                Vp8MacroBlockInfo mb = this.MbInfo[n];
                int alpha            = mb.Alpha;
                mb.Segment = map[alpha];
                mb.Alpha   = centers[map[alpha]];
            }

            // TODO: add possibility for SmoothSegmentMap
            this.SetSegmentAlphas(centers, weightedAverage);
        }