public void GetRidgeSpectraVersion1(double[,] dbSpectrogramData, double ridgeThreshold)
        {
            int rowCount  = dbSpectrogramData.GetLength(0);
            int colCount  = dbSpectrogramData.GetLength(1);
            int spanCount = rowCount - 4; // 4 because 5x5 grid means buffer of 2 on either side

            double[,] matrix = dbSpectrogramData;

            //double[,] matrix = ImageTools.WienerFilter(dbSpectrogramData, 3);
            // returns a byte matrix of ridge directions
            // 0 = no ridge detected or below magnitude threshold.
            // 1 = ridge direction = horizontal or slope = 0;
            // 2 = ridge is positive slope or pi/4
            // 3 = ridge is vertical or pi/2
            // 4 = ridge is negative slope or 3pi/4.
            //byte[,] hits = RidgeDetection.Sobel5X5RidgeDetectionExperiment(matrix, ridgeThreshold);
            byte[,] hits = RidgeDetection.Sobel5X5RidgeDetectionVersion1(matrix, ridgeThreshold);

            //image for debugging
            //ImageTools.DrawMatrix(hits, @"C:\SensorNetworks\Output\BIRD50\temp\hitsSpectrogram.png");

            double[] spectrum = new double[colCount];
            byte[]   freqBin;

            //Now aggregate hits to get ridge info
            //note that the Spectrograms were passed in flat-rotated orientation.
            //Therefore need to assign ridge number to re-oriented values.
            // Accumulate info for the horizontal ridges
            for (int col = 0; col < colCount; col++)
            {
                // i.e. for each frequency bin
                freqBin = MatrixTools.GetColumn(hits, col);
                int count = freqBin.Count(x => x == 3);
                if (count < 2)
                {
                    continue; // i.e. not a track.
                }

                spectrum[col] = count / (double)spanCount;
            }

            this.RhzSpectrum = spectrum;

            // accumulate info for the vertical ridges
            spectrum = new double[colCount];
            for (int col = 0; col < colCount; col++)
            {
                // i.e. for each frequency bin
                freqBin = MatrixTools.GetColumn(hits, col);
                int count = freqBin.Count(x => x == 1);
                if (count < 2)
                {
                    continue; // i.e. not a track.
                }

                spectrum[col] = count / (double)spanCount;
            }

            this.RvtSpectrum = spectrum;

            // accumulate info for the up slope ridges
            spectrum = new double[colCount];
            for (int col = 0; col < colCount; col++)
            {
                // i.e. for each frequency bin
                freqBin = MatrixTools.GetColumn(hits, col);
                int count = freqBin.Count(x => x == 4);
                spectrum[col] = count / (double)spanCount;
            }

            this.RpsSpectrum = spectrum;

            // accumulate info for the down slope ridges
            spectrum = new double[colCount];
            for (int col = 0; col < colCount; col++)
            {
                // i.e. for each frequency bin
                freqBin = MatrixTools.GetColumn(hits, col);
                int count = freqBin.Count(x => x == 2);
                spectrum[col] = count / (double)spanCount;
            }

            this.RngSpectrum = spectrum;
        }
        public void GetRidgeSpectraVersion2(double[,] dbSpectrogramData)
        {
            int rowCount = dbSpectrogramData.GetLength(0);
            int colCount = dbSpectrogramData.GetLength(1);

            // calculate span = number of cells over which will take average of a feature.
            // -4 because 5x5 grid means buffer of 2 on either side
            int spanCount = rowCount - 4;

            double[,] matrix = dbSpectrogramData;

            //ImageTools.DrawMatrix(matrix, @"C:\SensorNetworks\Output\BIRD50\temp\SpectrogramBeforeWeinerFilter.png");

            // DO NOT USE WIENER FILTERING because smooths the ridges and lose definition
            //matrix = ImageTools.WienerFilter(dbSpectrogramData, 3);
            //ImageTools.DrawMatrix(matrix, @"C:\SensorNetworks\Output\BIRD50\temp\hitsSpectrogramAfterWeinerFilter.png");

            // returns a byte matrix of ridge directions
            // 0 = ridge direction = horizontal or slope = 0;
            // 1 = ridge is positive slope or pi/4
            // 2 = ridge is vertical or pi/2
            // 3 = ridge is negative slope or 3pi/4.
            List <double[, ]> hits = RidgeDetection.Sobel5X5RidgeDetection_Version2(matrix);

            //image for debugging
            //ImageTools.DrawMatrix(hits[0], 0, 10.0, @"C:\SensorNetworks\Output\BIRD50\temp\hitsSpectrogram0.png");
            //ImageTools.DrawMatrix(hits[1], 0, 10.0, @"C:\SensorNetworks\Output\BIRD50\temp\hitsSpectrogram1.png");
            //ImageTools.DrawMatrix(hits[2], 0, 10.0, @"C:\SensorNetworks\Output\BIRD50\temp\hitsSpectrogram2.png");
            //ImageTools.DrawMatrix(hits[3], 0, 10.0, @"C:\SensorNetworks\Output\BIRD50\temp\hitsSpectrogram3.png");

            double[] spectrum = new double[colCount];
            double   sum;

            //Now aggregate hits to get ridge info
            //note that the Spectrograms were passed in flat-rotated orientation.
            //Therefore need to assign ridge number to re-oriented values.

            // Accumulate info for the horizontal ridges
            var hitsMatrix = hits[2];

            // for each frequency bin
            for (int col = 0; col < colCount; col++)
            {
                sum = 0;
                for (int row = 2; row < rowCount - 2; row++)
                {
                    sum += hitsMatrix[row, col];
                }

                spectrum[col] = sum / spanCount;
            }

            this.RhzSpectrum = spectrum;

            // accumulate info for the vertical ridges
            hitsMatrix = hits[0];
            spectrum   = new double[colCount];
            for (int col = 0; col < colCount; col++)
            {
                // i.e. for each frequency bin
                sum = 0;
                for (int row = 2; row < rowCount - 2; row++)
                {
                    sum += hitsMatrix[row, col];
                }

                spectrum[col] = sum / spanCount;
            }

            this.RvtSpectrum = spectrum;

            // accumulate info for the positive/up-slope ridges
            hitsMatrix = hits[3];
            spectrum   = new double[colCount];

            // for each frequency bin
            for (int col = 0; col < colCount; col++)
            {
                sum = 0;
                for (int row = 2; row < rowCount - 2; row++)
                {
                    sum += hitsMatrix[row, col];
                }

                spectrum[col] = sum / spanCount;
            }

            this.RpsSpectrum = spectrum;

            // accumulate info for the negative/down slope ridges
            hitsMatrix = hits[1];
            spectrum   = new double[colCount];

            // for each frequency bin
            for (int col = 0; col < colCount; col++)
            {
                sum = 0;
                for (int row = 2; row < rowCount - 2; row++)
                {
                    sum += hitsMatrix[row, col];
                }

                spectrum[col] = sum / spanCount;
            }

            this.RngSpectrum = spectrum;
        }