Esempio n. 1
0
        public static AudioToSonogramResult GenerateFourSpectrogramImages(
            FileInfo sourceRecording,
            FileInfo path2SoxSpectrogram,
            Dictionary <string, string> configDict,
            bool dataOnly        = false,
            bool makeSoxSonogram = false)
        {
            var result = new AudioToSonogramResult();

            if (dataOnly && makeSoxSonogram)
            {
                throw new ArgumentException("Can't produce data only for a SoX sonogram");
            }

            if (makeSoxSonogram)
            {
                SpectrogramTools.MakeSonogramWithSox(sourceRecording, configDict, path2SoxSpectrogram);
                result.Path2SoxImage = path2SoxSpectrogram;
            }
            else if (dataOnly)
            {
                var recordingSegment = new AudioRecording(sourceRecording.FullName);
                var sonoConfig       = new SonogramConfig(configDict); // default values config

                // disable noise removal
                sonoConfig.NoiseReductionType = NoiseReductionType.None;
                Log.Warn("Noise removal disabled!");

                var sonogram = new SpectrogramStandard(sonoConfig, recordingSegment.WavReader);
                result.DecibelSpectrogram = sonogram;
            }
            else
            {
                // init the image stack
                var list = new List <Image>();

                // IMAGE 1) draw amplitude spectrogram
                var recordingSegment = new AudioRecording(sourceRecording.FullName);
                var sonoConfig       = new SonogramConfig(configDict); // default values config

                // disable noise removal for first two spectrograms
                var disabledNoiseReductionType = sonoConfig.NoiseReductionType;
                sonoConfig.NoiseReductionType = NoiseReductionType.None;

                BaseSonogram sonogram = new AmplitudeSonogram(sonoConfig, recordingSegment.WavReader);

                // remove the DC bin if it has not already been removed.
                // Assume test of divisible by 2 is good enough.
                int binCount = sonogram.Data.GetLength(1);
                if (!binCount.IsEven())
                {
                    sonogram.Data = MatrixTools.Submatrix(sonogram.Data, 0, 1, sonogram.FrameCount - 1, binCount - 1);
                }

                //save spectrogram data at this point - prior to noise reduction
                var spectrogramDataBeforeNoiseReduction = sonogram.Data;

                const double neighbourhoodSeconds = 0.25;
                int          neighbourhoodFrames  = (int)(sonogram.FramesPerSecond * neighbourhoodSeconds);
                const double lcnContrastLevel     = 0.001;
                LoggedConsole.WriteLine("LCN: FramesPerSecond (Prior to LCN) = {0}", sonogram.FramesPerSecond);
                LoggedConsole.WriteLine("LCN: Neighbourhood of {0} seconds = {1} frames", neighbourhoodSeconds, neighbourhoodFrames);
                const int lowPercentile = 20;
                sonogram.Data = NoiseRemoval_Briggs.NoiseReduction_byLowestPercentileSubtraction(sonogram.Data, lowPercentile);
                sonogram.Data = NoiseRemoval_Briggs.NoiseReduction_byLCNDivision(sonogram.Data, neighbourhoodFrames, lcnContrastLevel);

                //sonogram.Data = NoiseRemoval_Briggs.NoiseReduction_byLowestPercentileSubtraction(sonogram.Data, lowPercentile);

                var image = sonogram.GetImageFullyAnnotated("AMPLITUDE SPECTROGRAM + Bin LCN (Local Contrast Normalisation)");
                list.Add(image);

                //string path2 = @"C:\SensorNetworks\Output\Sonograms\dataInput2.png";
                //Histogram.DrawDistributionsAndSaveImage(sonogram.Data, path2);

                // double[,] matrix = sonogram.Data;
                double[,] matrix = ImageTools.WienerFilter(sonogram.Data, 3);
                double ridgeThreshold = 0.25;
                byte[,] hits = RidgeDetection.Sobel5X5RidgeDetectionExperiment(matrix, ridgeThreshold);
                hits         = RidgeDetection.JoinDisconnectedRidgesInMatrix(hits, matrix, ridgeThreshold);
                image        = SpectrogramTools.CreateFalseColourAmplitudeSpectrogram(spectrogramDataBeforeNoiseReduction, null, hits);
                image        = sonogram.GetImageAnnotatedWithLinearHerzScale(image, "AMPLITUDE SPECTROGRAM + LCN + ridge detection");
                list.Add(image);

                Image envelopeImage = ImageTrack.DrawWaveEnvelopeTrack(recordingSegment, image.Width);
                list.Add(envelopeImage);

                // IMAGE 2) now draw the standard decibel spectrogram
                sonogram = new SpectrogramStandard(sonoConfig, recordingSegment.WavReader);
                result.DecibelSpectrogram = (SpectrogramStandard)sonogram;
                image = sonogram.GetImageFullyAnnotated("DECIBEL SPECTROGRAM");
                list.Add(image);

                Image segmentationImage = ImageTrack.DrawSegmentationTrack(
                    sonogram,
                    EndpointDetectionConfiguration.K1Threshold,
                    EndpointDetectionConfiguration.K2Threshold,
                    image.Width);
                list.Add(segmentationImage);

                // keep the sonogram data for later use
                double[,] dbSpectrogramData = (double[, ])sonogram.Data.Clone();

                // 3) now draw the noise reduced decibel spectrogram
                // #NOISE REDUCTION PARAMETERS - restore noise reduction ##################################################################
                sonoConfig.NoiseReductionType      = disabledNoiseReductionType;
                sonoConfig.NoiseReductionParameter = double.Parse(configDict[AnalysisKeys.NoiseBgThreshold] ?? "2.0");

                // #NOISE REDUCTION PARAMETERS - MARINE HACK ##################################################################
                //sonoConfig.NoiseReductionType = NoiseReductionType.FIXED_DYNAMIC_RANGE;
                //sonoConfig.NoiseReductionParameter = 80.0;

                sonogram = new SpectrogramStandard(sonoConfig, recordingSegment.WavReader);
                image    = sonogram.GetImageFullyAnnotated("DECIBEL SPECTROGRAM + Lamel noise subtraction");
                list.Add(image);

                // keep the sonogram data for later use
                double[,] nrSpectrogramData = sonogram.Data;

                // 4) A FALSE-COLOUR VERSION OF SPECTROGRAM
                // ########################### SOBEL ridge detection
                ridgeThreshold = 3.5;
                matrix         = ImageTools.WienerFilter(dbSpectrogramData, 3);
                hits           = RidgeDetection.Sobel5X5RidgeDetectionExperiment(matrix, ridgeThreshold);

                // ########################### EIGEN ridge detection
                //double ridgeThreshold = 6.0;
                //double dominanceThreshold = 0.7;
                //var rotatedData = MatrixTools.MatrixRotate90Anticlockwise(dbSpectrogramData);
                //byte[,] hits = RidgeDetection.StructureTensorRidgeDetection(rotatedData, ridgeThreshold, dominanceThreshold);
                //hits = MatrixTools.MatrixRotate90Clockwise(hits);
                // ########################### EIGEN ridge detection

                image = SpectrogramTools.CreateFalseColourDecibelSpectrogram(dbSpectrogramData, nrSpectrogramData, hits);
                image = sonogram.GetImageAnnotatedWithLinearHerzScale(image, "DECIBEL SPECTROGRAM - Colour annotated");

                list.Add(image);

                // 5) TODO: ONE OF THESE YEARS FIX UP THE CEPTRAL SONOGRAM
                ////SpectrogramCepstral cepgram = new SpectrogramCepstral((AmplitudeSonogram)amplitudeSpg);
                ////var mti3 = SpectrogramTools.Sonogram2MultiTrackImage(sonogram, configDict);
                ////var image3 = mti3.GetImage();
                ////image3.Save(fiImage.FullName + "3", ImageFormat.Png);

                // 6) COMBINE THE SPECTROGRAM IMAGES
                result.CompositeImage = ImageTools.CombineImagesVertically(list);
            }

            return(result);
        }