public static Image GetFreqVsOscillationsImage(double[,] freqOscilMatrix, double framesPerSecond, double freqBinWidth, int sampleLength, string algorithmName) { // remove the high cycles/sec end of the matrix because nothing really happens here. freqOscilMatrix = MatrixTools.Submatrix(freqOscilMatrix, 0, 0, 30, freqOscilMatrix.GetLength(1) - 1); // get the OSC spectral index // double[] spectralIndex = ConvertMatrix2SpectralIndexBySummingFreqColumns(freqOscilMatrix, skipNrows: 0); var spectralIndex = MatrixTools.GetMaximumColumnValues(freqOscilMatrix); // Convert spectrum index to oscillations per second double oscillationBinWidth = framesPerSecond / sampleLength; //draw an image freqOscilMatrix = MatrixTools.MatrixRotate90Anticlockwise(freqOscilMatrix); int xscale = 5; int yscale = 5; var image1 = ImageTools.DrawMatrixInColour(freqOscilMatrix, xPixelsPerCell: xscale, yPixelsPerCell: yscale); var image2 = ImageTools.DrawVectorInColour(DataTools.reverseArray(spectralIndex), cellWidth: xscale); var image = ImageTools.CombineImagesInLine(new[] { image1, image2 }); // a tic every 5cpsec. double cycleInterval = 5.0; double xTicInterval = cycleInterval / oscillationBinWidth * xscale; // a tic every 1000 Hz. int herzInterval = 1000; double yTicInterval = herzInterval / freqBinWidth * yscale; int xOffset = xscale / 2; int yOffset = yscale / 2; image = ImageTools.DrawXandYaxes(image, 18, cycleInterval, xTicInterval, xOffset, herzInterval, yTicInterval, yOffset); var titleBar = DrawTitleBarOfOscillationSpectrogram(algorithmName, image.Width); var imageList = new List <Image> { titleBar, image }; var compositeBmp = (Bitmap)ImageTools.CombineImagesVertically(imageList); return(compositeBmp); }
public static Dictionary <string, double[, ]> GetSpectralIndexFilesAndConcatenate( DirectoryInfo[] dirs, string analysisType, string[] keys, IndexGenerationData indexGenerationData, bool verbose = false) { TimeSpan indexCalcTimeSpan = indexGenerationData.IndexCalculationDuration; Dictionary <string, double[, ]> spectrogramMatrices = new Dictionary <string, double[, ]>(); foreach (string key in keys) { //DateTime now1 = DateTime.Now; string pattern = "*__" + analysisType + "." + key + ".csv"; var files = GetFilesInDirectories(dirs, pattern); if (files.Length == 0) { LoggedConsole.WriteWarnLine($"{key} WARNING: No csv files found for KEY=" + key); continue; } List <double[, ]> matrices = ConcatenateSpectralIndexFilesWithTimeCheck(files, indexCalcTimeSpan, key); double[,] m = MatrixTools.ConcatenateMatrixRows(matrices); //Dictionary<string, double[,]> dict = spectralIndexValues.ToTwoDimensionalArray(SpectralIndexValues.CachedSelectors, TwoDimensionalArray.Rotate90ClockWise); m = MatrixTools.MatrixRotate90Anticlockwise(m); spectrogramMatrices.Add(key, m); //var now2 = DateTime.Now; //var et = now2 - now1; //if (verbose) //{ // LoggedConsole.WriteLine($"\t\tTime to read <{key}> spectral index files = {et.TotalSeconds:f2} seconds"); //} } return(spectrogramMatrices); }
public override AnalysisResult2 Analyze <T>(AnalysisSettings analysisSettings, SegmentSettings <T> segmentSettings) { var configuration = (StandardizedFeatureExtractionConfig)analysisSettings.Configuration; var audioFile = segmentSettings.SegmentAudioFile; var recording = new AudioRecording(audioFile.FullName); // Configurations non-specific for bands TimeSpan indexCalculationDuration = configuration.IndexCalculationDurationTimeSpan; TimeSpan bgNoiseNeighbourhood = configuration.BgNoiseBuffer; // Bands List <StandardizedFeatureExtractionConfig.BandsProperties> bandsList = configuration.Bands; // Check if there are identical bands CheckForIdenticalBands(bandsList); // Estimate total number of subsegments double segmentDurationSeconds = segmentSettings.AnalysisIdealSegmentDuration.TotalSeconds; double subsegmentDuration = indexCalculationDuration.TotalSeconds; int subsegmentCount = (int)Math.Round(segmentDurationSeconds / subsegmentDuration); int totalSubsegmentCount = subsegmentCount * bandsList.Count; // Store results of all subsegments var analysisResults = new AnalysisResult2(analysisSettings, segmentSettings, recording.Duration); analysisResults.AnalysisIdentifier = this.Identifier; var trackScores = new List <Plot>(totalSubsegmentCount); var tracks = new List <SpectralTrack>(totalSubsegmentCount); analysisResults.SummaryIndices = new SummaryIndexBase[totalSubsegmentCount]; analysisResults.SpectralIndices = new SpectralIndexBase[totalSubsegmentCount]; // Create list to store images, one for each band. They are later combined into one image. var list = new List <Image <Rgb24> >(); string imagePath = segmentSettings.SegmentImageFile.FullName; int maxImageWidth = 0; int bandCount = 0; foreach (var band in bandsList) { Log.DebugFormat("Starting band {0}/{1}", bandCount + 1, bandsList.Count); // Calculate spectral indices // get a fresh copy of the ICC config var config = (IndexCalculateConfig)((ICloneable)configuration).Clone(); // Add values specific for band from custom configuration file to config config.MinBandWidth = band.Bandwidth.Min; config.MaxBandWidth = band.Bandwidth.Max; config.FrameLength = band.FftWindow; if (band.MelScale != 0) { config.FrequencyScale = FreqScaleType.Mel; config.MelScale = band.MelScale; } else { config.FrequencyScale = FreqScaleType.Linear; } // Calculate indices for each subsegment and for each band IndexCalculateResult[] subsegmentResults = AcousticIndices.CalculateIndicesInSubsegments( recording, segmentSettings.SegmentStartOffset, segmentSettings.AnalysisIdealSegmentDuration, indexCalculationDuration, config.IndexProperties, segmentSettings.Segment.SourceMetadata.SampleRate, config); int columnsAmplitudeSpectrogram = subsegmentResults[0].AmplitudeSpectrogram.GetLength(1); double[,] amplitudeSpectrogramSegment = new double[0, columnsAmplitudeSpectrogram]; for (int i = 0; i < subsegmentResults.Length; i++) { var indexCalculateResult = subsegmentResults[i]; indexCalculateResult.SummaryIndexValues.FileName = segmentSettings.Segment.SourceMetadata.Identifier; indexCalculateResult.SpectralIndexValues.FileName = segmentSettings.Segment.SourceMetadata.Identifier; analysisResults.SummaryIndices[bandCount + (i * bandsList.Count)] = indexCalculateResult.SummaryIndexValues; analysisResults.SpectralIndices[bandCount + (i * bandsList.Count)] = indexCalculateResult.SpectralIndexValues; trackScores.AddRange(indexCalculateResult.TrackScores); if (indexCalculateResult.Tracks != null) { tracks.AddRange(indexCalculateResult.Tracks); } if (analysisSettings.AnalysisImageSaveBehavior.ShouldSave()) { // Add amplitude spectrograms of each subsegment together to get amplitude spectrogram of one segment double[,] amplitudeSpectrogramSubsegment = indexCalculateResult.AmplitudeSpectrogram; amplitudeSpectrogramSegment = MatrixTools.ConcatenateMatrixRows( amplitudeSpectrogramSegment, amplitudeSpectrogramSubsegment); } } if (analysisSettings.AnalysisImageSaveBehavior.ShouldSave()) { // Create image of amplitude spectrogram var image = ImageTools.DrawReversedMatrix(MatrixTools.MatrixRotate90Anticlockwise(amplitudeSpectrogramSegment)); // Label information string minBandWidth = band.Bandwidth.Min.ToString(); string maxBandWidth = band.Bandwidth.Max.ToString(); string fftWindow = band.FftWindow.ToString(); string mel; string melScale; if (band.MelScale != 0) { mel = "Mel"; melScale = band.MelScale.ToString(); } else { mel = "Standard"; melScale = 0.ToString(); } // Create label string segmentSeparator = "_"; string[] segments = { minBandWidth, maxBandWidth, fftWindow, mel, melScale }; string labelText = segments.Aggregate(string.Empty, (aggregate, item) => aggregate + segmentSeparator + item); var stringFont = Drawing.Arial14; int width = 250; int height = image.Height; var label = new Image <Rgb24>(width, height); label.Mutate(g1 => { g1.Clear(Color.Gray); g1.DrawText(labelText, stringFont, Color.Black, new PointF(4, 30)); g1.DrawLine(new Pen(Color.Black, 1), 0, 0, width, 0); //draw upper boundary g1.DrawLine(new Pen(Color.Black, 1), 0, 1, width, 1); //draw upper boundary }); var labelledImage = ImageTools.CombineImagesInLine(label, image); // Add labeled image to list list.Add(labelledImage); // Update maximal width of image if (image.Width > maxImageWidth) { maxImageWidth = image.Width; } } bandCount += 1; Log.InfoFormat("Completed band {0}/{1}", bandCount, bandsList.Count); } if (analysisSettings.AnalysisDataSaveBehavior) { this.WriteSummaryIndicesFile(segmentSettings.SegmentSummaryIndicesFile, analysisResults.SummaryIndices); analysisResults.SummaryIndicesFile = segmentSettings.SegmentSummaryIndicesFile; analysisResults.SpectraIndicesFiles = this.WriteSpectrumIndicesFiles( segmentSettings.SegmentSpectrumIndicesDirectory, Path.GetFileNameWithoutExtension(segmentSettings.SegmentAudioFile.Name), analysisResults.SpectralIndices); } if (analysisSettings.AnalysisImageSaveBehavior.ShouldSave()) { var finalImage = ImageTools.CombineImagesVertically(list, maxImageWidth); finalImage.Save(imagePath); analysisResults.ImageFile = new FileInfo(imagePath); LoggedConsole.WriteLine("See {0} for spectrogram pictures", imagePath); } return(analysisResults); }
public static void Main(Arguments arguments) { //1. set up the necessary files //DirectoryInfo diSource = arguments.Source.Directory; FileInfo fiSourceRecording = arguments.Source; FileInfo fiConfig = arguments.Config.ToFileInfo(); FileInfo fiImage = arguments.Output.ToFileInfo(); fiImage.CreateParentDirectories(); string title = "# CREATE FOUR (4) SONOGRAMS FROM AUDIO RECORDING"; string date = "# DATE AND TIME: " + DateTime.Now; LoggedConsole.WriteLine(title); LoggedConsole.WriteLine(date); LoggedConsole.WriteLine("# Input audio file: " + fiSourceRecording.Name); LoggedConsole.WriteLine("# Output image file: " + fiImage); //2. get the config dictionary Config configuration = ConfigFile.Deserialize(fiConfig); //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; //3 transfer conogram parameters to a dictionary to be passed around var configDict = new Dictionary <string, string>(); // #Resample rate must be 2 X the desired Nyquist. Default is that of recording. configDict["ResampleRate"] = (configuration.GetIntOrNull(AnalysisKeys.ResampleRate) ?? 17640).ToString(); configDict["FrameLength"] = configuration[AnalysisKeys.FrameLength] ?? "512"; int frameSize = configuration.GetIntOrNull(AnalysisKeys.FrameLength) ?? 512; // #Frame Overlap as fraction: default=0.0 configDict["FrameOverlap"] = configuration[AnalysisKeys.FrameOverlap] ?? "0.0"; double windowOverlap = configuration.GetDoubleOrNull(AnalysisKeys.FrameOverlap) ?? 0.0; // #MinHz: 500 // #MaxHz: 3500 // #NOISE REDUCTION PARAMETERS configDict["DoNoiseReduction"] = configuration["DoNoiseReduction"] ?? "true"; configDict["BgNoiseThreshold"] = configuration["BgNoiseThreshold"] ?? "3.0"; configDict["ADD_AXES"] = configuration["ADD_AXES"] ?? "true"; configDict["AddSegmentationTrack"] = configuration["AddSegmentationTrack"] ?? "true"; // 3: GET RECORDING var startOffsetMins = TimeSpan.Zero; var endOffsetMins = TimeSpan.Zero; FileInfo fiOutputSegment = fiSourceRecording; if (!(startOffsetMins == TimeSpan.Zero && endOffsetMins == TimeSpan.Zero)) { var buffer = new TimeSpan(0, 0, 0); fiOutputSegment = new FileInfo(Path.Combine(fiImage.DirectoryName, "tempWavFile.wav")); //This method extracts segment and saves to disk at the location fiOutputSegment. var resampleRate = configuration.GetIntOrNull(AnalysisKeys.ResampleRate) ?? AppConfigHelper.DefaultTargetSampleRate; AudioRecording.ExtractSegment(fiSourceRecording, startOffsetMins, endOffsetMins, buffer, resampleRate, fiOutputSegment); } var recording = new AudioRecording(fiOutputSegment.FullName); // EXTRACT ENVELOPE and SPECTROGRAM var dspOutput = DSP_Frames.ExtractEnvelopeAndFfts(recording, frameSize, windowOverlap); // average absolute value over the minute recording ////double[] avAbsolute = dspOutput.Average; // (A) ################################## EXTRACT INDICES FROM THE SIGNAL WAVEFORM ################################## // var wavDuration = TimeSpan.FromSeconds(recording.WavReader.Time.TotalSeconds); // double totalSeconds = wavDuration.TotalSeconds; // double[] signalEnvelope = dspOutput.Envelope; // double avSignalEnvelope = signalEnvelope.Average(); // double[] frameEnergy = dspOutput.FrameEnergy; // double highAmplIndex = dspOutput.HighAmplitudeCount / totalSeconds; // double binWidth = dspOutput.BinWidth; // int nyquistBin = dspOutput.NyquistBin; // dspOutput.WindowPower, // dspOutput.FreqBinWidth int nyquistFreq = dspOutput.NyquistFreq; double epsilon = recording.Epsilon; // i: prepare amplitude spectrogram double[,] amplitudeSpectrogramData = dspOutput.AmplitudeSpectrogram; // get amplitude spectrogram. var image1 = ImageTools.DrawReversedMatrix(MatrixTools.MatrixRotate90Anticlockwise(amplitudeSpectrogramData)); // ii: prepare decibel spectrogram prior to noise removal double[,] decibelSpectrogramdata = MFCCStuff.DecibelSpectra(dspOutput.AmplitudeSpectrogram, dspOutput.WindowPower, recording.SampleRate, epsilon); decibelSpectrogramdata = MatrixTools.NormaliseMatrixValues(decibelSpectrogramdata); var image2 = ImageTools.DrawReversedMatrix(MatrixTools.MatrixRotate90Anticlockwise(decibelSpectrogramdata)); // iii: Calculate background noise spectrum in decibels // Calculate noise value for each freq bin. double sdCount = 0.0; // number of SDs above the mean for noise removal var decibelProfile = NoiseProfile.CalculateModalNoiseProfile(decibelSpectrogramdata, sdCount); // DataTools.writeBarGraph(dBProfile.NoiseMode); // iv: Prepare noise reduced spectrogram decibelSpectrogramdata = SNR.TruncateBgNoiseFromSpectrogram(decibelSpectrogramdata, decibelProfile.NoiseThresholds); //double dBThreshold = 1.0; // SPECTRAL dB THRESHOLD for smoothing background //decibelSpectrogramdata = SNR.RemoveNeighbourhoodBackgroundNoise(decibelSpectrogramdata, dBThreshold); var image3 = ImageTools.DrawReversedMatrix(MatrixTools.MatrixRotate90Anticlockwise(decibelSpectrogramdata)); // prepare new sonogram config and draw second image going down different code pathway var config = new SonogramConfig { MinFreqBand = 0, MaxFreqBand = 10000, NoiseReductionType = SNR.KeyToNoiseReductionType("Standard"), NoiseReductionParameter = 1.0, WindowSize = frameSize, WindowOverlap = windowOverlap, }; //var mfccConfig = new MfccConfiguration(config); int bandCount = config.mfccConfig.FilterbankCount; bool doMelScale = config.mfccConfig.DoMelScale; int ccCount = config.mfccConfig.CcCount; int fftBins = config.FreqBinCount; //number of Hz bands = 2^N +1 because includes the DC band int minHz = config.MinFreqBand ?? 0; int maxHz = config.MaxFreqBand ?? nyquistFreq; var standardSonogram = new SpectrogramStandard(config, recording.WavReader); var image4 = standardSonogram.GetImage(); // TODO next line crashes - does not produce cepstral sonogram. //SpectrogramCepstral cepSng = new SpectrogramCepstral(config, recording.WavReader); //Image image5 = cepSng.GetImage(); //var mti = SpectrogramTools.Sonogram2MultiTrackImage(sonogram, configDict); //var image = mti.GetImage(); //Image image = SpectrogramTools.Matrix2SonogramImage(deciBelSpectrogram, config); //Image image = SpectrogramTools.Audio2SonogramImage(FileInfo fiAudio, Dictionary<string, string> configDict); //prepare sonogram images var protoImage6 = new Image_MultiTrack(standardSonogram.GetImage(doHighlightSubband: false, add1KHzLines: true, doMelScale: false)); protoImage6.AddTrack(ImageTrack.GetTimeTrack(standardSonogram.Duration, standardSonogram.FramesPerSecond)); protoImage6.AddTrack(ImageTrack.GetWavEnvelopeTrack(recording, protoImage6.SonogramImage.Width)); protoImage6.AddTrack(ImageTrack.GetSegmentationTrack(standardSonogram)); var image6 = protoImage6.GetImage(); var list = new List <Image <Rgb24> >(); list.Add(image1); // amplitude spectrogram list.Add(image2); // decibel spectrogram before noise removal list.Add(image3); // decibel spectrogram after noise removal list.Add(image4); // second version of noise reduced spectrogram //list.Add(image5); // ceptral sonogram list.Add(image6.CloneAs <Rgb24>()); // multitrack image Image finalImage = ImageTools.CombineImagesVertically(list); finalImage.Save(fiImage.FullName); ////2: NOISE REMOVAL //double[,] originalSg = sonogram.Data; //double[,] mnr = sonogram.Data; //mnr = ImageTools.WienerFilter(mnr, 3); //double backgroundThreshold = 4.0; //SETS MIN DECIBEL BOUND //var output = SNR.NoiseReduce(mnr, NoiseReductionType.STANDARD, backgroundThreshold); //double ConfigRange = 70; //sets the the max dB //mnr = SNR.SetConfigRange(output.Item1, 0.0, ConfigRange); ////3: Spectral tracks sonogram //byte[,] binary = MatrixTools.IdentifySpectralRidges(mnr); //binary = MatrixTools.ThresholdBinarySpectrum(binary, mnr, 10); //binary = MatrixTools.RemoveOrphanOnesInBinaryMatrix(binary); ////binary = MatrixTools.PickOutLines(binary); //syntactic approach //sonogram.SetBinarySpectrum(binary); ////sonogram.Data = SNR.SpectralRidges2Intensity(binary, originalSg); //image = new Image_MultiTrack(sonogram.GetImage(doHighlightSubband, false)); //image.AddTrack(ImageTrack.GetTimeTrack(sonogram.Duration, sonogram.FramesPerSecond)); //image.AddTrack(ImageTrack.GetWavEnvelopeTrack(recording, image.sonogramImage.Width)); //image.AddTrack(ImageTrack.GetSegmentationTrack(sonogram)); //fn = outputFolder + wavFileName + "_tracks.png"; //image.Save(fn); //LoggedConsole.WriteLine("Spectral tracks sonogram to file: " + fn); //3: prepare image of spectral peaks sonogram //sonogram.Data = SNR.NoiseReduce_Peaks(originalSg, dynamicRange); //image = new Image_MultiTrack(sonogram.GetImage(doHighlightSubband, add1kHzLines)); //image.AddTrack(ImageTrack.GetTimeTrack(sonogram.Duration)); //image.AddTrack(ImageTrack.GetWavEnvelopeTrack(recording, image.Image.Width)); //image.AddTrack(ImageTrack.GetSegmentationTrack(sonogram)); //fn = outputFolder + wavFileName + "_peaks.png"; //image.Save(fn); //LoggedConsole.WriteLine("Spectral peaks sonogram to file: " + fn); //4: Sobel approach //sonogram.Data = SNR.NoiseReduce_Sobel(originalSg, dynamicRange); //image = new Image_MultiTrack(sonogram.GetImage(doHighlightSubband, add1kHzLines)); //image.AddTrack(ImageTrack.GetTimeTrack(sonogram.Duration)); //image.AddTrack(ImageTrack.GetWavEnvelopeTrack(recording, image.Image.Width)); //image.AddTrack(ImageTrack.GetSegmentationTrack(sonogram)); //fn = outputFolder + wavFileName + "_sobel.png"; //image.Save(fn); //LoggedConsole.WriteLine("Sobel sonogram to file: " + fn); // I1.txt contains the sonogram matrix produced by matlab //string matlabFile = @"C:\SensorNetworks\Software\AudioAnalysis\AED\Test\matlab\GParrots_JB2_20090607-173000.wav_minute_3\I1.txt"; //double[,] matlabMatrix = Util.fileToMatrix(matlabFile, 256, 5166); //LoggedConsole.WriteLine(matrix[0, 2] + " vs " + matlabMatrix[254, 0]); //LoggedConsole.WriteLine(matrix[0, 3] + " vs " + matlabMatrix[253, 0]); // TODO put this back once sonogram issues resolved /* * LoggedConsole.WriteLine("START: AED"); * IEnumerable<Oblong> oblongs = AcousticEventDetection.detectEvents(3.0, 100, matrix); * LoggedConsole.WriteLine("END: AED"); * * * //set up static variables for init Acoustic events * //AcousticEvent. doMelScale = config.DoMelScale; * AcousticEvent.FreqBinCount = config.FreqBinCount; * AcousticEvent.FreqBinWidth = config.FftConfig.NyquistFreq / (double)config.FreqBinCount; * // int minF = (int)config.MinFreqBand; * // int maxF = (int)config.MaxFreqBand; * AcousticEvent.FrameDuration = config.GetFrameOffset(); * * * var events = new List<EventPatternRecog.Rectangle>(); * foreach (Oblong o in oblongs) * { * var e = new AcousticEvent(o); * events.Add(new EventPatternRecog.Rectangle(e.StartTime, (double) e.MaxFreq, e.StartTime + e.Duration, (double)e.MinFreq)); * //LoggedConsole.WriteLine(e.StartTime + "," + e.Duration + "," + e.MinFreq + "," + e.MaxFreq); * } * * LoggedConsole.WriteLine("# AED events: " + events.Count); * * LoggedConsole.WriteLine("START: EPR"); * IEnumerable<EventPatternRecog.Rectangle> eprRects = EventPatternRecog.detectGroundParrots(events); * LoggedConsole.WriteLine("END: EPR"); * * var eprEvents = new List<AcousticEvent>(); * foreach (EventPatternRecog.Rectangle r in eprRects) * { * var ae = new AcousticEvent(r.Left, r.Right - r.Left, r.Bottom, r.Top, false); * LoggedConsole.WriteLine(ae.WriteProperties()); * eprEvents.Add(ae); * } * * string imagePath = Path.Combine(outputFolder, "RESULTS_" + Path.GetFileNameWithoutExtension(recording.BaseName) + ".png"); * * bool doHighlightSubband = false; bool add1kHzLines = true; * var image = new Image_MultiTrack(sonogram.GetImage(doHighlightSubband, add1kHzLines)); * //image.AddTrack(ImageTrack.GetTimeTrack(sonogram.Duration)); * //image.AddTrack(ImageTrack.GetWavEnvelopeTrack(recording, image.Image.Width)); * //image.AddTrack(ImageTrack.GetSegmentationTrack(sonogram)); * image.AddEvents(eprEvents); * image.Save(outputFolder + wavFileName + ".png"); */ LoggedConsole.WriteLine("\nFINISHED!"); }
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); }