public static Image <Rgb24> GetLcnSpectrogram( SonogramConfig sonoConfig, AudioRecording recordingSegment, string sourceRecordingName, double neighbourhoodSeconds, double lcnContrastLevel) { BaseSonogram sonogram = new AmplitudeSonogram(sonoConfig, recordingSegment.WavReader); int neighbourhoodFrames = (int)(sonogram.FramesPerSecond * neighbourhoodSeconds); LoggedConsole.WriteLine("LCN: FramesPerSecond (Prior to LCN) = {0}", sonogram.FramesPerSecond); LoggedConsole.WriteLine("LCN: Neighbourhood of {0} seconds = {1} frames", neighbourhoodSeconds, neighbourhoodFrames); // subtract the lowest 20% of frames. This is first step in LCN noise removal. Sets the baseline. const int lowPercentile = 20; sonogram.Data = NoiseRemoval_Briggs.NoiseReduction_byLowestPercentileSubtraction(sonogram.Data, lowPercentile); sonogram.Data = NoiseRemoval_Briggs.NoiseReduction_byLCNDivision(sonogram.Data, neighbourhoodFrames, lcnContrastLevel); //Matrix normalisation //MatrixTools.PercentileCutoffs(sonogram.Data, 10.0, 90, out double minCut, out double maxCut); //NoiseRemoval_Briggs.NoiseReduction_byLowestPercentileSubtraction(sonogram.Data, lowPercentile); var image = sonogram.GetImageFullyAnnotated( "AMPLITUDE SPECTROGRAM with freq bin Local Contrast Normalization - " + sourceRecordingName, ImageTags[AmplitudeSpectrogramLocalContrastNormalization]); return(image); }
public static Image GetLcnSpectrogram(SonogramConfig sonoConfig, AudioRecording recordingSegment, string sourceRecordingName, double neighbourhoodSeconds, double lcnContrastLevel) { BaseSonogram sonogram = new AmplitudeSonogram(sonoConfig, recordingSegment.WavReader); int neighbourhoodFrames = (int)(sonogram.FramesPerSecond * neighbourhoodSeconds); 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); var image = sonogram.GetImageFullyAnnotated("AMPLITUDE SPECTROGRAM with freq bin Local Contrast Normalization - " + sourceRecordingName); 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); }
/// <summary> /// Generates the FREQUENCY x OSCILLATIONS Graphs and csv /// </summary> public static Tuple <Image, double[, ], double[]> GenerateOscillationDataAndImages(FileInfo audioSegment, Dictionary <string, string> configDict, bool drawImage = false) { // set two oscillation detection parameters double sensitivity = DefaultSensitivityThreshold; if (configDict.ContainsKey(AnalysisKeys.OscilDetection2014SensitivityThreshold)) { sensitivity = double.Parse(configDict[AnalysisKeys.OscilDetection2014SensitivityThreshold]); } // Sample length i.e. number of frames spanned to calculate oscillations per second int sampleLength = DefaultSampleLength; if (configDict.ContainsKey(AnalysisKeys.OscilDetection2014SampleLength)) { sampleLength = int.Parse(configDict[AnalysisKeys.OscilDetection2014SampleLength]); } SonogramConfig sonoConfig = new SonogramConfig(configDict); // default values config if (configDict.ContainsKey(AnalysisKeys.OscilDetection2014FrameSize)) { sonoConfig.WindowSize = int.Parse(configDict[AnalysisKeys.OscilDetection2014FrameSize]); } var recordingSegment = new AudioRecording(audioSegment.FullName); 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); } //LoggedConsole.WriteLine("Oscillation Detection: Sample rate = {0}", sonogram.SampleRate); //LoggedConsole.WriteLine("Oscillation Detection: FramesPerSecond = {0}", sonogram.FramesPerSecond); // Do LOCAL CONRAST Normalisation first. LCN over frequency bins is better and faster than standard noise removal. double neighbourhoodSeconds = 0.25; int neighbourhoodFrames = (int)(sonogram.FramesPerSecond * neighbourhoodSeconds); double lcnContrastLevel = 0.5; // was previously 0.1 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_byLCNDivision(sonogram.Data, neighbourhoodFrames, lcnContrastLevel); string algorithmName1 = "autocorr-svd-fft"; double[,] freqOscilMatrix1 = GetFrequencyByOscillationsMatrix(sonogram.Data, sensitivity, sampleLength, algorithmName1); //get the max spectral index - this reduces the matrix to an array double[] spectralIndex1 = ConvertMatrix2SpectralIndexBySummingFreqColumns(freqOscilMatrix1, 0); Image compositeImage = null; if (drawImage) { string algorithmName2 = "autocorr-fft"; double[,] freqOscilMatrix2 = GetFrequencyByOscillationsMatrix(sonogram.Data, sensitivity, sampleLength, algorithmName2); var image1 = GetFreqVsOscillationsImage(freqOscilMatrix1, sonogram.FramesPerSecond, sonogram.FBinWidth, sampleLength, algorithmName1); var image2 = GetFreqVsOscillationsImage(freqOscilMatrix2, sonogram.FramesPerSecond, sonogram.FBinWidth, sampleLength, algorithmName2); compositeImage = ImageTools.CombineImagesInLine(new[] { image1, image2 }); } // Return (1) composite image of oscillations, (2) data matrix from only one algorithm, // and (3) spectrum of oscillation values for accumulation into data from a multi-hour recording. return(Tuple.Create(compositeImage, freqOscilMatrix1, spectralIndex1)); }
public static void Execute(Arguments arguments) { const string Title = "# DETERMINING SIGNAL TO NOISE RATIO IN RECORDING"; string date = "# DATE AND TIME: " + DateTime.Now; Log.WriteLine(Title); Log.WriteLine(date); Log.Verbosity = 1; var input = arguments.Source; var sourceFileName = input.Name; var outputDir = arguments.Output; var fileNameWithoutExtension = Path.GetFileNameWithoutExtension(input.FullName); var outputTxtPath = Path.Combine(outputDir.FullName, fileNameWithoutExtension + ".txt").ToFileInfo(); Log.WriteIfVerbose("# Recording file: " + input.FullName); Log.WriteIfVerbose("# Config file: " + arguments.Config); Log.WriteIfVerbose("# Output folder =" + outputDir.FullName); FileTools.WriteTextFile(outputTxtPath.FullName, date + "\n# Recording file: " + input.FullName); //READ PARAMETER VALUES FROM INI FILE // load YAML configuration Config configuration = ConfigFile.Deserialize(arguments.Config); //ii: SET SONOGRAM CONFIGURATION SonogramConfig sonoConfig = new SonogramConfig(); //default values config sonoConfig.SourceFName = input.FullName; sonoConfig.WindowSize = configuration.GetIntOrNull(AnalysisKeys.KeyFrameSize) ?? 512; sonoConfig.WindowOverlap = configuration.GetDoubleOrNull(AnalysisKeys.FrameOverlap) ?? 0.5; sonoConfig.WindowFunction = configuration[AnalysisKeys.KeyWindowFunction]; sonoConfig.NPointSmoothFFT = configuration.GetIntOrNull(AnalysisKeys.KeyNPointSmoothFft) ?? 256; sonoConfig.NoiseReductionType = SNR.KeyToNoiseReductionType(configuration[AnalysisKeys.NoiseReductionType]); int minHz = configuration.GetIntOrNull("MIN_HZ") ?? 0; int maxHz = configuration.GetIntOrNull("MAX_HZ") ?? 11050; double segK1 = configuration.GetDoubleOrNull("SEGMENTATION_THRESHOLD_K1") ?? 0; double segK2 = configuration.GetDoubleOrNull("SEGMENTATION_THRESHOLD_K2") ?? 0; double latency = configuration.GetDoubleOrNull("K1_K2_LATENCY") ?? 0; double vocalGap = configuration.GetDoubleOrNull("VOCAL_GAP") ?? 0; double minVocalLength = configuration.GetDoubleOrNull("MIN_VOCAL_DURATION") ?? 0; //bool DRAW_SONOGRAMS = (bool?)configuration.DrawSonograms ?? true; //options to draw sonogram //double intensityThreshold = Acoustics.AED.Default.intensityThreshold; //if (dict.ContainsKey(key_AED_INTENSITY_THRESHOLD)) intensityThreshold = Double.Parse(dict[key_AED_INTENSITY_THRESHOLD]); //int smallAreaThreshold = Acoustics.AED.Default.smallAreaThreshold; //if( dict.ContainsKey(key_AED_SMALL_AREA_THRESHOLD)) smallAreaThreshold = Int32.Parse(dict[key_AED_SMALL_AREA_THRESHOLD]); // COnvert input recording into wav var convertParameters = new AudioUtilityRequest { TargetSampleRate = 17640 }; var fileToAnalyse = new FileInfo(Path.Combine(outputDir.FullName, "temp.wav")); if (File.Exists(fileToAnalyse.FullName)) { File.Delete(fileToAnalyse.FullName); } var convertedFileInfo = AudioFilePreparer.PrepareFile( input, fileToAnalyse, convertParameters, outputDir); // (A) ########################################################################################################################## AudioRecording recording = new AudioRecording(fileToAnalyse.FullName); int signalLength = recording.WavReader.Samples.Length; TimeSpan wavDuration = TimeSpan.FromSeconds(recording.WavReader.Time.TotalSeconds); double frameDurationInSeconds = sonoConfig.WindowSize / (double)recording.SampleRate; TimeSpan frameDuration = TimeSpan.FromTicks((long)(frameDurationInSeconds * TimeSpan.TicksPerSecond)); int stepSize = (int)Math.Floor(sonoConfig.WindowSize * (1 - sonoConfig.WindowOverlap)); double stepDurationInSeconds = sonoConfig.WindowSize * (1 - sonoConfig.WindowOverlap) / recording.SampleRate; TimeSpan stepDuration = TimeSpan.FromTicks((long)(stepDurationInSeconds * TimeSpan.TicksPerSecond)); double framesPerSecond = 1 / stepDuration.TotalSeconds; int frameCount = signalLength / stepSize; // (B) ################################## EXTRACT ENVELOPE and SPECTROGRAM ################################## var dspOutput = DSP_Frames.ExtractEnvelopeAndFfts( recording, sonoConfig.WindowSize, sonoConfig.WindowOverlap); //double[] avAbsolute = dspOutput.Average; //average absolute value over the minute recording // (C) ################################## GET SIGNAL WAVEFORM ################################## double[] signalEnvelope = dspOutput.Envelope; double avSignalEnvelope = signalEnvelope.Average(); // (D) ################################## GET Amplitude Spectrogram ################################## double[,] amplitudeSpectrogram = dspOutput.AmplitudeSpectrogram; // get amplitude spectrogram. // (E) ################################## Generate deciBel spectrogram from amplitude spectrogram double epsilon = Math.Pow(0.5, recording.BitsPerSample - 1); double[,] deciBelSpectrogram = MFCCStuff.DecibelSpectra( dspOutput.AmplitudeSpectrogram, dspOutput.WindowPower, recording.SampleRate, epsilon); LoggedConsole.WriteLine("# Finished calculating decibel spectrogram."); StringBuilder sb = new StringBuilder(); sb.AppendLine("\nSIGNAL PARAMETERS"); sb.AppendLine("Signal Duration =" + wavDuration); sb.AppendLine("Sample Rate =" + recording.SampleRate); sb.AppendLine("Min Signal Value =" + dspOutput.MinSignalValue); sb.AppendLine("Max Signal Value =" + dspOutput.MaxSignalValue); sb.AppendLine("Max Absolute Ampl =" + signalEnvelope.Max().ToString("F3") + " (See Note 1)"); sb.AppendLine("Epsilon Ampl (1 bit)=" + epsilon); sb.AppendLine("\nFRAME PARAMETERS"); sb.AppendLine("Window Size =" + sonoConfig.WindowSize); sb.AppendLine("Frame Count =" + frameCount); sb.AppendLine("Envelope length=" + signalEnvelope.Length); sb.AppendLine("Frame Duration =" + frameDuration.TotalMilliseconds.ToString("F3") + " ms"); sb.AppendLine("Frame overlap =" + sonoConfig.WindowOverlap); sb.AppendLine("Step Size =" + stepSize); sb.AppendLine("Step duration =" + stepDuration.TotalMilliseconds.ToString("F3") + " ms"); sb.AppendLine("Frames Per Sec =" + framesPerSecond.ToString("F1")); sb.AppendLine("\nFREQUENCY PARAMETERS"); sb.AppendLine("Nyquist Freq =" + dspOutput.NyquistFreq + " Hz"); sb.AppendLine("Freq Bin Width =" + dspOutput.FreqBinWidth.ToString("F2") + " Hz"); sb.AppendLine("Nyquist Bin =" + dspOutput.NyquistBin); sb.AppendLine("\nENERGY PARAMETERS"); double val = dspOutput.FrameEnergy.Min(); sb.AppendLine( "Minimum dB / frame =" + (10 * Math.Log10(val)).ToString("F2") + " (See Notes 2, 3 & 4)"); val = dspOutput.FrameEnergy.Max(); sb.AppendLine("Maximum dB / frame =" + (10 * Math.Log10(val)).ToString("F2")); sb.AppendLine("\ndB NOISE SUBTRACTION"); double noiseRange = 2.0; //sb.AppendLine("Noise (estimate of mode) =" + sonogram.SnrData.NoiseSubtracted.ToString("F3") + " dB (See Note 5)"); //double noiseSpan = sonogram.SnrData.NoiseRange; //sb.AppendLine("Noise range =" + noiseSpan.ToString("F2") + " to +" + (noiseSpan * -1).ToString("F2") + " dB (See Note 6)"); //sb.AppendLine("SNR (max frame-noise) =" + sonogram.SnrData.Snr.ToString("F2") + " dB (See Note 7)"); //sb.Append("\nSEGMENTATION PARAMETERS"); //sb.Append("Segment Thresholds K1: {0:f2}. K2: {1:f2} (See Note 8)", segK1, segK2); //sb.Append("# Event Count = " + predictedEvents.Count()); FileTools.Append2TextFile(outputTxtPath.FullName, sb.ToString()); FileTools.Append2TextFile(outputTxtPath.FullName, GetSNRNotes(noiseRange).ToString()); // (F) ################################## DRAW IMAGE 1: original spectorgram Log.WriteLine("# Start drawing noise reduced sonograms."); TimeSpan X_AxisInterval = TimeSpan.FromSeconds(1); //int Y_AxisInterval = (int)Math.Round(1000 / dspOutput.FreqBinWidth); int nyquist = recording.SampleRate / 2; int hzInterval = 1000; var image1 = DrawSonogram(deciBelSpectrogram, wavDuration, X_AxisInterval, stepDuration, nyquist, hzInterval); // (G) ################################## Calculate modal background noise spectrum in decibels //double SD_COUNT = -0.5; // number of SDs above the mean for noise removal //NoiseReductionType nrt = NoiseReductionType.MODAL; //System.Tuple<double[,], double[]> tuple = SNR.NoiseReduce(deciBelSpectrogram, nrt, SD_COUNT); //double upperPercentileBound = 0.2; // lowest percentile for noise removal //NoiseReductionType nrt = NoiseReductionType.LOWEST_PERCENTILE; //System.Tuple<double[,], double[]> tuple = SNR.NoiseReduce(deciBelSpectrogram, nrt, upperPercentileBound); // (H) ################################## Calculate BRIGGS noise removal from amplitude spectrum int percentileBound = 20; // low energy percentile for noise removal //double binaryThreshold = 0.6; //works for higher SNR recordings double binaryThreshold = 0.4; //works for lower SNR recordings //double binaryThreshold = 0.3; //works for lower SNR recordings double[,] m = NoiseRemoval_Briggs.BriggsNoiseFilterAndGetMask( amplitudeSpectrogram, percentileBound, binaryThreshold); string title = "TITLE"; var image2 = NoiseRemoval_Briggs.DrawSonogram( m, wavDuration, X_AxisInterval, stepDuration, nyquist, hzInterval, title); //Image image2 = NoiseRemoval_Briggs.BriggsNoiseFilterAndGetSonograms(amplitudeSpectrogram, upperPercentileBound, binaryThreshold, // wavDuration, X_AxisInterval, stepDuration, Y_AxisInterval); // (I) ################################## Calculate MEDIAN noise removal from amplitude spectrum //double upperPercentileBound = 0.8; // lowest percentile for noise removal //NoiseReductionType nrt = NoiseReductionType.MEDIAN; //System.Tuple<double[,], double[]> tuple = SNR.NoiseReduce(deciBelSpectrogram, nrt, upperPercentileBound); //double[,] noiseReducedSpectrogram1 = tuple.Item1; // //double[] noiseProfile = tuple.Item2; // smoothed modal profile //SNR.NoiseProfile dBProfile = SNR.CalculateNoiseProfile(deciBelSpectrogram, SD_COUNT); // calculate noise value for each freq bin. //double[] noiseProfile = DataTools.filterMovingAverage(dBProfile.noiseThresholds, 7); // smooth modal profile //double[,] noiseReducedSpectrogram1 = SNR.TruncateBgNoiseFromSpectrogram(deciBelSpectrogram, dBProfile.noiseThresholds); //Image image2 = DrawSonogram(noiseReducedSpectrogram1, wavDuration, X_AxisInterval, stepDuration, Y_AxisInterval); var combinedImage = ImageTools.CombineImagesVertically(image1, image2); string imagePath = Path.Combine(outputDir.FullName, fileNameWithoutExtension + ".png"); combinedImage.Save(imagePath); // (G) ################################## Calculate modal background noise spectrum in decibels Log.WriteLine("# Finished recording:- " + input.Name); }
public static void Main(Arguments arguments) { // 1. set up the necessary files FileInfo sourceRecording = arguments.Source; FileInfo configFile = arguments.Config.ToFileInfo(); DirectoryInfo opDir = arguments.Output; opDir.Create(); if (arguments.StartOffset.HasValue ^ arguments.EndOffset.HasValue) { throw new InvalidStartOrEndException("If StartOffset or EndOffset is specified, then both must be specified"); } var offsetsProvided = arguments.StartOffset.HasValue && arguments.EndOffset.HasValue; // set default offsets - only use defaults if not provided in argments list TimeSpan?startOffset = null; TimeSpan?endOffset = null; if (offsetsProvided) { startOffset = TimeSpan.FromSeconds(arguments.StartOffset.Value); endOffset = TimeSpan.FromSeconds(arguments.EndOffset.Value); } const string Title = "# MAKE A SONOGRAM FROM AUDIO RECORDING and do OscillationsGeneric activity."; string date = "# DATE AND TIME: " + DateTime.Now; LoggedConsole.WriteLine(Title); LoggedConsole.WriteLine(date); LoggedConsole.WriteLine("# Input audio file: " + sourceRecording.Name); string sourceName = Path.GetFileNameWithoutExtension(sourceRecording.FullName); // 2. get the config dictionary Config configuration = ConfigFile.Deserialize(configFile); // below three lines are examples of retrieving info from Config config // string analysisIdentifier = configuration[AnalysisKeys.AnalysisName]; // bool saveIntermediateWavFiles = (bool?)configuration[AnalysisKeys.SaveIntermediateWavFiles] ?? false; // scoreThreshold = (double?)configuration[AnalysisKeys.EventThreshold] ?? scoreThreshold; // Resample rate must be 2 X the desired Nyquist. Default is that of recording. var resampleRate = configuration.GetIntOrNull(AnalysisKeys.ResampleRate) ?? AppConfigHelper.DefaultTargetSampleRate; var configDict = new Dictionary <string, string>(configuration.ToDictionary()); // #NOISE REDUCTION PARAMETERS //string noisereduce = configDict[ConfigKeys.Mfcc.Key_NoiseReductionType]; configDict[AnalysisKeys.NoiseDoReduction] = "false"; configDict[AnalysisKeys.NoiseReductionType] = "NONE"; configDict[AnalysisKeys.AddAxes] = configuration[AnalysisKeys.AddAxes] ?? "true"; configDict[AnalysisKeys.AddSegmentationTrack] = configuration[AnalysisKeys.AddSegmentationTrack] ?? "true"; configDict[ConfigKeys.Recording.Key_RecordingCallName] = sourceRecording.FullName; configDict[ConfigKeys.Recording.Key_RecordingFileName] = sourceRecording.Name; configDict[AnalysisKeys.AddTimeScale] = configuration[AnalysisKeys.AddTimeScale] ?? "true"; configDict[AnalysisKeys.AddAxes] = configuration[AnalysisKeys.AddAxes] ?? "true"; configDict[AnalysisKeys.AddSegmentationTrack] = configuration[AnalysisKeys.AddSegmentationTrack] ?? "true"; // #################################################################### // print out the sonogram parameters LoggedConsole.WriteLine("\nPARAMETERS"); foreach (KeyValuePair <string, string> kvp in configDict) { LoggedConsole.WriteLine("{0} = {1}", kvp.Key, kvp.Value); } LoggedConsole.WriteLine("Sample Length for detecting oscillations = {0}", SampleLength); // 3: GET RECORDING FileInfo tempAudioSegment = new FileInfo(Path.Combine(opDir.FullName, "tempWavFile.wav")); // delete the temp audio file if it already exists. if (File.Exists(tempAudioSegment.FullName)) { File.Delete(tempAudioSegment.FullName); } // This line creates a temporary version of the source file downsampled as per entry in the config file MasterAudioUtility.SegmentToWav(sourceRecording, tempAudioSegment, new AudioUtilityRequest() { TargetSampleRate = resampleRate }); // 1) get amplitude spectrogram AudioRecording recordingSegment = new AudioRecording(tempAudioSegment.FullName); SonogramConfig sonoConfig = new SonogramConfig(configDict); // default values config BaseSonogram sonogram = new AmplitudeSonogram(sonoConfig, recordingSegment.WavReader); Console.WriteLine("FramesPerSecond = {0}", sonogram.FramesPerSecond); // remove the DC bin sonogram.Data = MatrixTools.Submatrix(sonogram.Data, 0, 1, sonogram.FrameCount - 1, sonogram.Configuration.FreqBinCount); // ############################################################### // DO LocalContrastNormalisation //int fieldSize = 9; //sonogram.Data = LocalContrastNormalisation.ComputeLCN(sonogram.Data, fieldSize); // LocalContrastNormalisation over frequency bins is better and faster. int neighbourhood = 15; double contrastLevel = 0.5; sonogram.Data = NoiseRemoval_Briggs.NoiseReduction_byLCNDivision(sonogram.Data, neighbourhood, contrastLevel); // ############################################################### // lowering the sensitivity threshold increases the number of hits. if (configDict.ContainsKey(AnalysisKeys.OscilDetection2014SensitivityThreshold)) { Oscillations2014.DefaultSensitivityThreshold = double.Parse(configDict[AnalysisKeys.OscilDetection2014SensitivityThreshold]); } if (configDict.ContainsKey(AnalysisKeys.OscilDetection2014SampleLength)) { Oscillations2014.DefaultSampleLength = int.Parse(configDict[AnalysisKeys.OscilDetection2014SensitivityThreshold]); } var list1 = new List <Image>(); //var result = Oscillations2014.GetFreqVsOscillationsDataAndImage(sonogram, 64, "Autocorr-FFT"); //list1.Add(result.FreqOscillationImage); var result = Oscillations2014.GetFreqVsOscillationsDataAndImage(sonogram, "Autocorr-FFT"); list1.Add(result.FreqOscillationImage); result = Oscillations2014.GetFreqVsOscillationsDataAndImage(sonogram, "Autocorr-SVD-FFT"); list1.Add(result.FreqOscillationImage); result = Oscillations2014.GetFreqVsOscillationsDataAndImage(sonogram, "Autocorr-WPD"); list1.Add(result.FreqOscillationImage); Image compositeOscImage1 = ImageTools.CombineImagesInLine(list1.ToArray()); // ############################################################### // init the sonogram image stack var sonogramList = new List <Image>(); var image = sonogram.GetImageFullyAnnotated("AMPLITUDE SPECTROGRAM"); sonogramList.Add(image); //string testPath = @"C:\SensorNetworks\Output\Sonograms\amplitudeSonogram.png"; //image.Save(testPath, ImageFormat.Png); Image envelopeImage = ImageTrack.DrawWaveEnvelopeTrack(recordingSegment, image.Width); sonogramList.Add(envelopeImage); // 2) now draw the standard decibel spectrogram sonogram = new SpectrogramStandard(sonoConfig, recordingSegment.WavReader); // ############################################################### list1 = new List <Image>(); //result = Oscillations2014.GetFreqVsOscillationsDataAndImage(sonogram, 64, "Autocorr-FFT"); //list1.Add(result.FreqOscillationImage); result = Oscillations2014.GetFreqVsOscillationsDataAndImage(sonogram, "Autocorr-FFT"); list1.Add(result.FreqOscillationImage); result = Oscillations2014.GetFreqVsOscillationsDataAndImage(sonogram, "Autocorr-SVD-FFT"); list1.Add(result.FreqOscillationImage); result = Oscillations2014.GetFreqVsOscillationsDataAndImage(sonogram, "Autocorr-WPD"); list1.Add(result.FreqOscillationImage); Image compositeOscImage2 = ImageTools.CombineImagesInLine(list1.ToArray()); // ############################################################### //image = sonogram.GetImageFullyAnnotated("DECIBEL SPECTROGRAM"); //list.Add(image); // combine eight images list1 = new List <Image>(); list1.Add(compositeOscImage1); list1.Add(compositeOscImage2); Image compositeOscImage3 = ImageTools.CombineImagesVertically(list1.ToArray()); string imagePath3 = Path.Combine(opDir.FullName, sourceName + "_freqOscilMatrix.png"); compositeOscImage3.Save(imagePath3, ImageFormat.Png); Image segmentationImage = ImageTrack.DrawSegmentationTrack( sonogram, EndpointDetectionConfiguration.K1Threshold, EndpointDetectionConfiguration.K2Threshold, image.Width); sonogramList.Add(segmentationImage); // 3) now draw the noise reduced decibel spectrogram sonoConfig.NoiseReductionType = NoiseReductionType.Standard; sonoConfig.NoiseReductionParameter = configuration.GetDoubleOrNull(AnalysisKeys.NoiseBgThreshold) ?? 3.0; sonogram = new SpectrogramStandard(sonoConfig, recordingSegment.WavReader); image = sonogram.GetImageFullyAnnotated("NOISE-REDUCED DECIBEL SPECTROGRAM"); sonogramList.Add(image); // ############################################################### // deriving osscilation graph from this noise reduced spectrogram did not work well //Oscillations2014.SaveFreqVsOscillationsDataAndImage(sonogram, sampleLength, algorithmName, opDir); // ############################################################### Image compositeSonogram = ImageTools.CombineImagesVertically(sonogramList); string imagePath2 = Path.Combine(opDir.FullName, sourceName + ".png"); compositeSonogram.Save(imagePath2, ImageFormat.Png); LoggedConsole.WriteLine("\n##### FINISHED FILE ###################################################\n"); }