/// <summary> /// (1) MEAN SUBTRACTION /// Assumes the passed matrix is a spectrogram. i.e. rows=frames, cols=freq bins. /// Returns the noise profile over freq bins. i.e. one noise value per freq bin. /// Note that NoiseThresholds array is identical to NoiseMedian array. /// </summary> /// <param name="matrix">the spectrogram with origin top-left</param> public static NoiseProfile CalculateMeanNoiseProfile(double[,] matrix) { int colCount = matrix.GetLength(1); double[] noiseMean = new double[colCount]; double[] minsOfBins = new double[colCount]; double[] maxsOfBins = new double[colCount]; for (int col = 0; col < colCount; col++) { double[] freqBin = MatrixTools.GetColumn(matrix, col); noiseMean[col] = freqBin.Average(); minsOfBins[col] = freqBin.Min(); maxsOfBins[col] = freqBin.Max(); } var profile = new NoiseProfile() { NoiseMean = noiseMean, NoiseSd = null, NoiseThresholds = noiseMean, MinDb = minsOfBins, MaxDb = maxsOfBins, }; return(profile); }
public static NoiseProfile CalculatePercentileNoiseProfile(double[,] matrix, int percentile) { int rowCount = matrix.GetLength(0); int colCount = matrix.GetLength(1); double[] noiseMedian = new double[colCount]; double[] minsOfBins = new double[colCount]; double[] maxsOfBins = new double[colCount]; for (int col = 0; col < colCount; col++) { double[] freqBin = MatrixTools.GetColumn(matrix, col); Array.Sort(freqBin); noiseMedian[col] = freqBin[rowCount * percentile / 100]; minsOfBins[col] = freqBin.Min(); maxsOfBins[col] = freqBin.Max(); } var profile = new NoiseProfile() { NoiseMedian = noiseMedian, NoiseSd = null, NoiseThresholds = noiseMedian, MinDb = minsOfBins, MaxDb = maxsOfBins, }; return(profile); }
// ############################################################################################################################# // ################################# FOUR DIFFERENT METHODS TO CALCULATE THE BACKGROUND NOISE PROFILE // // (1) MODAL METHOD // (2) LOWEST PERCENTILE FRAMES METHOD // (3) BIN-WISE LOWEST PERCENTILE CELLS METHOD // (4) FIRST N FRAMES // ################## /// <summary> /// (1) MODAL METHOD /// Assumes the passed matrix is a spectrogram. i.e. rows=frames, cols=freq bins. /// Returns the noise profile over freq bins. i.e. one noise value per freq bin. /// </summary> /// <param name="matrix">the spectrogram with origin top-left</param> /// <param name="sdCount">number of standard deviations</param> public static NoiseProfile CalculateModalNoiseProfile(double[,] matrix, double sdCount) { int colCount = matrix.GetLength(1); double[] noiseMode = new double[colCount]; double[] noiseSd = new double[colCount]; double[] noiseThreshold = new double[colCount]; double[] minsOfBins = new double[colCount]; double[] maxsOfBins = new double[colCount]; for (int col = 0; col < colCount; col++) { double[] freqBin = MatrixTools.GetColumn(matrix, col); SNR.BackgroundNoise binNoise = SNR.CalculateModalBackgroundNoiseInSignal(freqBin, sdCount); noiseMode[col] = binNoise.NoiseMode; noiseSd[col] = binNoise.NoiseSd; noiseThreshold[col] = binNoise.NoiseThreshold; minsOfBins[col] = binNoise.MinDb; maxsOfBins[col] = binNoise.MaxDb; } var profile = new NoiseProfile() { NoiseMode = noiseMode, NoiseSd = noiseSd, NoiseThresholds = noiseThreshold, MinDb = minsOfBins, MaxDb = maxsOfBins, }; return(profile); }
/// <summary> /// Assumes the passed matrix is a spectrogram. i.e. rows=frames, cols=freq bins. /// WARNING: This method should NOT be used for short recordings (i.e LT approx 10-15 seconds long) /// because it obtains a background noise profile from the passed percentile of lowest energy frames. /// /// Same method as above except take square root of the cell energy divided by the noise. /// Taking the square root has the effect of reducing image contrast. /// </summary> public static double[,] NoiseReduction_byDivisionAndSqrRoot(double[,] matrix, int percentileThreshold) { double[] profile = NoiseProfile.GetNoiseProfile_fromLowestPercentileFrames(matrix, percentileThreshold); profile = DataTools.filterMovingAverage(profile, 3); // to prevent division by zero. double epsilon = 0.0001; int rowCount = matrix.GetLength(0); int colCount = matrix.GetLength(1); double[,] outM = new double[rowCount, colCount]; //to contain noise reduced matrix // for all cols i.e. freq bins for (int col = 0; col < colCount; col++) { double denominator = profile[col]; if (denominator < epsilon) { denominator = epsilon; } // for all rows for (int y = 0; y < rowCount; y++) { outM[y, col] = Math.Sqrt(matrix[y, col] / denominator); } //end for all rows } //end for all cols return(outM); }
/// <summary> /// Assumes the passed matrix is a spectrogram. i.e. rows=frames, cols=freq bins. /// First obtains background noise profile calculated from lowest 20% of cells for each freq bin independently. /// Loop over freq bins (columns) - subtract noise and divide by LCN (Local Contrast Normalisation. /// /// The LCN denominator = (contrastLevelConstant + Sqrt(localVariance[y]) /// Note that sqrt of variance = std dev. /// A low contrastLevel = 0.1 give more grey image. /// A high contrastLevel = 1.0 give mostly white high contrast image. /// </summary> public static double[,] NoiseReduction_ShortRecordings_SubtractAndLCN(double[,] matrix, int lowPercent, int neighbourhood, double contrastLevel) { double[] noiseProfile = NoiseProfile.GetNoiseProfile_BinWiseFromLowestPercentileCells(matrix, lowPercent); noiseProfile = DataTools.filterMovingAverage(noiseProfile, 5); int rowCount = matrix.GetLength(0); int colCount = matrix.GetLength(1); //to contain noise reduced matrix double[,] outM = new double[rowCount, colCount]; //for all cols i.e. freq bins for (int col = 0; col < colCount; col++) { double[] column = MatrixTools.GetColumn(matrix, col); double[] localVariance = NormalDist.CalculateLocalVariance(column, neighbourhood); // NormaliseMatrixValues with local column variance // for all rows for (int y = 0; y < rowCount; y++) { //outM[y, col] = matrix[y, col] / (contrastLevel + localVariance[y]); outM[y, col] = (matrix[y, col] - noiseProfile[col]) / (contrastLevel + Math.Sqrt(localVariance[y])); } //end for all rows } //end for all cols return(outM); }
/// <summary> /// 10-percentile Noise Reduction /// </summary> public static double[,] NoiseReduction(double[,] matrix) { double[,] nrm = matrix; // calculate 10-percentile noise profile NoiseProfile profile = NoiseProfile.CalculatePercentileNoiseProfile(matrix, 10); // smooth the noise profile double[] smoothedProfile = DataTools.filterMovingAverage(profile.NoiseThresholds, width: 7); nrm = SNR.TruncateBgNoiseFromSpectrogram(nrm, smoothedProfile); return(nrm); }
/// <summary> /// Median Noise Reduction /// </summary> public static double[,] NoiseReduction(double[,] matrix) { double[,] nrm = matrix; // calculate modal noise profile // NoiseProfile profile = NoiseProfile.CalculateModalNoiseProfile(matrix, sdCount: 0.0); NoiseProfile profile = NoiseProfile.CalculateMedianNoiseProfile(matrix); // smooth the noise profile double[] smoothedProfile = DataTools.filterMovingAverage(profile.NoiseThresholds, width: 7); nrm = SNR.TruncateBgNoiseFromSpectrogram(nrm, smoothedProfile); // nrm = SNR.NoiseReduce_Standard(nrm, smoothedProfile, nhBackgroundThreshold: 2.0); return(nrm); }
/// <summary> /// Assumes the passed matrix is a spectrogram. i.e. rows=frames, cols=freq bins. /// WARNING: This method should NOT be used for short recordings (i.e LT approx 10-15 seconds long) /// Obtains a background noise profile from the passed percentile of lowest energy frames, /// Then subtracts the noise profile value from every cell. /// This method was adapted from a paper by Briggs. /// </summary> /// <param name="matrix"></param> /// <param name="percentileThreshold"></param> /// <returns></returns> public static double[,] NoiseReduction_byLowestPercentileSubtraction(double[,] matrix, int percentileThreshold) { double[] profile = NoiseProfile.GetNoiseProfile_fromLowestPercentileFrames(matrix, percentileThreshold); profile = DataTools.filterMovingAverage(profile, 3); int rowCount = matrix.GetLength(0); int colCount = matrix.GetLength(1); double[,] outM = new double[rowCount, colCount]; //to contain noise reduced matrix for (int col = 0; col < colCount; col++) //for all cols i.e. freq bins { for (int y = 0; y < rowCount; y++) //for all rows { outM[y, col] = matrix[y, col] - profile[col]; } //end for all rows } //end for all cols return(outM); }