예제 #1
0
        // -------------- Average and Maximum --------------

        // This method that takes YData instead of YDataFloat is by far the fastest method.
        public static void CalculateAverageAndMaximumCPU(YData imageData, out float average, out float maximum)
        {
            const float LOW_ACCURACY_THRESHOLD = 64.0f;
            const int   LOW_ACCURACY_DIVISOR   = 8;

            int width  = imageData.Width;
            int height = imageData.Height;

            // Calculate average and maximum
            average = 0.0f;
            maximum = 0.0f;

            var averageSlices = new int[height];
            var averageCounts = new int[height];
            var maximumSlices = new byte[height];

            int loopCount = height / LOW_ACCURACY_DIVISOR;

            Parallel.For(0, loopCount, (loop, state) =>
            {
                for (int y = loop * LOW_ACCURACY_DIVISOR; y < (loop + 1) * LOW_ACCURACY_DIVISOR && (y < height); y++)
                {
                    unsafe
                    {
                        fixed(byte *pDataByte = imageData.Data)
                        {
                            var pData = (int *)pDataByte; // Tried long* instead of int* and it made little difference

                            int ySrcOffset = (y * imageData.Stride) / sizeof(int);
                            int xMax       = width / sizeof(int);

                            int avg   = 0;
                            int count = 0;
                            byte max  = 0;
                            for (int x = 0; x < xMax; x++)
                            {
                                var color = pData[ySrcOffset++];

                                byte value;

                                value = (byte)(color & 0xFF);
                                avg  += value;
                                if (max < value)
                                {
                                    max = value;
                                }

                                value = (byte)((color >> 8) & 0xFF);
                                avg  += value;
                                if (max < value)
                                {
                                    max = value;
                                }

                                value = (byte)((color >> 16) & 0xFF);
                                avg  += value;
                                if (max < value)
                                {
                                    max = value;
                                }

                                value = (byte)((color >> 24) & 0xFF);
                                avg  += value;
                                if (max < value)
                                {
                                    max = value;
                                }

                                count += 4;

                                if (max > LOW_ACCURACY_THRESHOLD)
                                {
                                    x          += 7;
                                    ySrcOffset += 7;
                                }
                            }

                            averageSlices[y] = avg;
                            averageCounts[y] = count;
                            maximumSlices[y] = max;

                            if (max > LOW_ACCURACY_THRESHOLD)
                            {
                                break;
                            }
                        }
                    }
                }
            });

            average = averageSlices.AsParallel().Sum();
            var totalCount = averageCounts.AsParallel().Sum();

            average /= (float)totalCount;

            maximum = maximumSlices.AsParallel().Max();
        }
예제 #2
0
        // -------------- Standard Deviation --------------

        public static void CalculateStandardDeviationCPU(YData imageData, float average, out float stdDev)
        {
            const float LOW_ACCURACY_THRESHOLD = 48.0f;
            const int   LOW_ACCURACY_DIVISOR   = 16;

            int width  = imageData.Width;
            int height = imageData.Height;

            // Calculate standard deviation
            stdDev = 0.0f;

            float[] totalSlices = new float[height];
            int[]   countSlices = new int[height];

            int loopCount = height;

            if (average > LOW_ACCURACY_THRESHOLD)
            {
                loopCount = height / LOW_ACCURACY_DIVISOR;
            }

            //for (int y = 0; y < height; y++)
            Parallel.For(0, loopCount, (y) =>
            {
                if (average > LOW_ACCURACY_THRESHOLD)
                {
                    y *= LOW_ACCURACY_DIVISOR;
                }

                unsafe
                {
                    fixed(byte *pDataByte = imageData.Data)
                    {
                        var pData = (int *)pDataByte; // Tried long* instead of int* and it was far worse performance

                        int ySrcOffset = (y * imageData.Stride) / sizeof(int);
                        int xMax       = width / sizeof(int);

                        float total = 0.0f;
                        int count   = 0;

                        for (int x = 0; x < xMax; x++)
                        {
                            var color = pData[ySrcOffset++];
                            float value;

                            value  = (float)(color & 0xFF);
                            value  = (value - average) * (value - average);
                            total += value;

                            value  = (float)((color >> 8) & 0xFF);
                            value  = (value - average) * (value - average);
                            total += value;

                            value  = (float)((color >> 16) & 0xFF);
                            value  = (value - average) * (value - average);
                            total += value;

                            value  = (float)((color >> 24) & 0xFF);
                            value  = (value - average) * (value - average);
                            total += value;

                            count += 4;

                            if (average > LOW_ACCURACY_THRESHOLD)
                            {
                                x          += (LOW_ACCURACY_DIVISOR - 1);
                                ySrcOffset += (LOW_ACCURACY_DIVISOR - 1);
                            }
                        }
                        totalSlices[y] = total;
                        countSlices[y] = count;
                    }
                }
            });

            stdDev = totalSlices.AsParallel().Sum();
            var totalCount = countSlices.AsParallel().Sum();

            stdDev /= (float)totalCount;
            stdDev  = (float)Math.Sqrt(stdDev);
        }