/// <summary> /// AN EXPERIMENTAL SPECTROGRAM - A FALSE-COLOR VERSION OF A standard scale SPECTROGRAM. /// </summary> /// <param name="dbSpectrogramData">The original data for decibel spectrogram.</param> /// <param name="nrSpectrogram">The noise-reduced spectrogram.</param> /// <param name="sourceRecordingName">Name of the source file. Required only to add label to spectrogram.</param> /// <returns>Image of spectrogram.</returns> public static Image <Rgb24> GetDecibelSpectrogram_Ridges( double[,] dbSpectrogramData, SpectrogramStandard nrSpectrogram, string sourceRecordingName) { // ########################### SOBEL ridge detection var ridgeThreshold = 3.5; var matrix = ImageTools.WienerFilter(dbSpectrogramData, 3); var 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 var frameStep = nrSpectrogram.Configuration.WindowStep; var sampleRate = nrSpectrogram.SampleRate; var image = SpectrogramTools.CreateFalseColourDecibelSpectrogram(dbSpectrogramData, nrSpectrogram.Data, hits); image = BaseSonogram.GetImageAnnotatedWithLinearHertzScale( image, sampleRate, frameStep, $"AN EXPERIMENTAL DECIBEL SPECTROGRAM with ridges ({sourceRecordingName})", ImageTags[Experimental]); //var image = decibelSpectrogram.GetImageFullyAnnotated("DECIBEL SPECTROGRAM - with ridges"); return(image); }
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); }
public static AudioToSonogramResult GenerateSpectrogramImages(FileInfo sourceRecording, Dictionary <string, string> configDict, DirectoryInfo outputDirectory) { // the source name was set up in the Analyse() method. But it could also be obtained directly from recording. string sourceName = configDict[ConfigKeys.Recording.Key_RecordingFileName]; sourceName = Path.GetFileNameWithoutExtension(sourceName); var result = new AudioToSonogramResult(); // init the image stack var list = new List <Image>(); // 1) draw amplitude spectrogram var recordingSegment = new AudioRecording(sourceRecording.FullName); // default values config except disable noise removal for first two spectrograms SonogramConfig sonoConfig = new SonogramConfig(configDict) { NoiseReductionType = NoiseReductionType.None }; BaseSonogram sonogram = new AmplitudeSonogram(sonoConfig, recordingSegment.WavReader); // remove the DC bin sonogram.Data = MatrixTools.Submatrix(sonogram.Data, 0, 1, sonogram.FrameCount - 1, sonogram.Configuration.FreqBinCount); // save spectrogram data at this point - prior to noise reduction double[,] spectrogramDataBeforeNoiseReduction = sonogram.Data; const int lowPercentile = 20; const double neighbourhoodSeconds = 0.25; int neighbourhoodFrames = (int)(sonogram.FramesPerSecond * neighbourhoodSeconds); const double lcnContrastLevel = 0.25; ////LoggedConsole.WriteLine("LCN: FramesPerSecond (Prior to LCN) = {0}", sonogram.FramesPerSecond); ////LoggedConsole.WriteLine("LCN: Neighbourhood of {0} seconds = {1} frames", neighbourhoodSeconds, neighbourhoodFrames); sonogram.Data = NoiseRemoval_Briggs.NoiseReduction_ShortRecordings_SubtractAndLCN(sonogram.Data, lowPercentile, neighbourhoodFrames, lcnContrastLevel); // draw amplitude spectrogram unannotated FileInfo outputImage1 = new FileInfo(Path.Combine(outputDirectory.FullName, sourceName + ".amplitd.bmp")); ImageTools.DrawReversedMatrix(MatrixTools.MatrixRotate90Anticlockwise(sonogram.Data), outputImage1.FullName); // draw amplitude spectrogram annotated 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); // 2) A FALSE-COLOUR VERSION OF AMPLITUDE SPECTROGRAM double ridgeThreshold = 0.20; double[,] matrix = ImageTools.WienerFilter(sonogram.Data, 3); 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); // 3) now draw the standard decibel spectrogram sonogram = new SpectrogramStandard(sonoConfig, recordingSegment.WavReader); // remove the DC bin sonogram.Data = MatrixTools.Submatrix(sonogram.Data, 0, 1, sonogram.FrameCount - 1, sonogram.Configuration.FreqBinCount); // draw decibel spectrogram unannotated FileInfo outputImage2 = new FileInfo(Path.Combine(outputDirectory.FullName, sourceName + ".deciBel.bmp")); ImageTools.DrawReversedMatrix(MatrixTools.MatrixRotate90Anticlockwise(sonogram.Data), outputImage2.FullName); 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 (NOT noise reduced) for later use double[,] dbSpectrogramData = (double[, ])sonogram.Data.Clone(); // 4) now draw the noise reduced decibel spectrogram sonoConfig.NoiseReductionType = NoiseReductionType.Standard; sonoConfig.NoiseReductionParameter = 3; ////sonoConfig.NoiseReductionType = NoiseReductionType.SHORT_RECORDING; ////sonoConfig.NoiseReductionParameter = 50; sonogram = new SpectrogramStandard(sonoConfig, recordingSegment.WavReader); // draw decibel spectrogram unannotated FileInfo outputImage3 = new FileInfo(Path.Combine(outputDirectory.FullName, sourceName + ".noNoise_dB.bmp")); ImageTools.DrawReversedMatrix(MatrixTools.MatrixRotate90Anticlockwise(sonogram.Data), outputImage3.FullName); image = sonogram.GetImageFullyAnnotated("DECIBEL SPECTROGRAM + Lamel noise subtraction"); list.Add(image); // keep the sonogram data for later use double[,] nrSpectrogramData = sonogram.Data; // 5) A FALSE-COLOUR VERSION OF DECIBEL SPECTROGRAM ridgeThreshold = 2.5; matrix = ImageTools.WienerFilter(dbSpectrogramData, 3); hits = RidgeDetection.Sobel5X5RidgeDetectionExperiment(matrix, ridgeThreshold); image = SpectrogramTools.CreateFalseColourDecibelSpectrogram(dbSpectrogramData, nrSpectrogramData, hits); image = sonogram.GetImageAnnotatedWithLinearHerzScale(image, "DECIBEL SPECTROGRAM - Colour annotated"); list.Add(image); // 6) COMBINE THE SPECTROGRAM IMAGES Image compositeImage = ImageTools.CombineImagesVertically(list); FileInfo outputImage = new FileInfo(Path.Combine(outputDirectory.FullName, sourceName + ".5spectro.png")); compositeImage.Save(outputImage.FullName, ImageFormat.Png); result.SpectrogramFile = outputImage; // 7) Generate the FREQUENCY x OSCILLATIONS Graphs and csv data ////bool saveData = true; ////bool saveImage = true; ////double[] oscillationsSpectrum = Oscillations2014.GenerateOscillationDataAndImages(sourceRecording, configDict, saveData, saveImage); return(result); }