/// <summary> /// Generate non-overlapping random patches from a matrix /// </summary> private static List <double[]> GetRandomPatches(double[,] matrix, int patchWidth, int patchHeight, int numberOfPatches) { int seed = 100; Random randomNumber = new Random(seed); List <double[]> patches = new List <double[]>(); int rows = matrix.GetLength(0); int columns = matrix.GetLength(1); for (int i = 0; i < numberOfPatches; i++) { // selecting a random number from the height of the matrix int rowRandomNumber = randomNumber.Next(0, rows - patchHeight); // selecting a random number from the width of the matrix int columnRandomNumber = randomNumber.Next(0, columns - patchWidth); double[,] submatrix = MatrixTools.Submatrix(matrix, rowRandomNumber, columnRandomNumber, rowRandomNumber + patchHeight - 1, columnRandomNumber + patchWidth - 1); // convert a matrix to a vector by concatenating columns and // store it to the array of vectors patches.Add(MatrixTools.Matrix2Array(submatrix)); } return(patches); }
/// <summary> /// WARNING!!: This method implements a convolution and like all convolutions is very slow (unless it can be fully parellised); /// Consider using another noise normalisation method such as in the class NoiseRemoval_Briggs. /// /// This method does local contrast normalisation. Typically LCN normalises by division only and is motivated by what is known /// to happen in the visual cortext. /// Every matrix element or pixel value is divided by the (scaled) standard deviation of pixel values /// in a local field centred on the pixel. Scaling affects the severity of the normalisation. /// There are several ways of doing LCN. That is can divide by the local sum of squares. Or can calculate the local z-score /// which effectively normalises by both subtraction and division. /// This method is based on formula given by LeCun. Python code at the bottom of this class is the actual /// code used by LeCun which appears to do something different. /// Wish I knew Python! /// /// </summary> /// <param name="inputM"></param> /// <param name="fieldSize"></param> /// <returns></returns> public static double[,] ComputeLCN(double[,] inputM, int fieldSize) { /* * // FOLLOWING LINES ARE FOR DEBUGGING AND TESTING * var inputM2 = MatrixTools.MatrixRotate90Anticlockwise(inputM); * ImageTools.DrawReversedMatrix(inputM2, @"C:\SensorNetworks\Output\Sonograms\TESTMATRIX0.png"); * double fractionalStretching = 0.05; * inputM2 = ImageTools.ContrastStretching(inputM2, fractionalStretching); * ImageTools.DrawReversedMatrix(inputM2, @"C:\SensorNetworks\Output\Sonograms\TESTMATRIX1.png"); * */ int rowCount = inputM.GetLength(0); int colCount = inputM.GetLength(1); int frameWidth = fieldSize / 2; /// add frame around matrix to compensate for edge effects. double[,] framedM = MatrixTools.FrameMatrixWithZeros(inputM, frameWidth); // output matrix is same size as input. double[,] outputM = new double[rowCount, colCount]; double[,] subMatrix; double NSquared = fieldSize * fieldSize; // alpha is a scaling factor. LeCun set it = 0.00001. Here set much higher to have a noticeable effect! double alpha = 1.0; // convolve gaussian with the matrix for (int r1 = 0; r1 < rowCount; r1++) { for (int c1 = 0; c1 < colCount; c1++) { // get field int r2 = r1 + fieldSize - 1; int c2 = c1 + fieldSize - 1; subMatrix = MatrixTools.Submatrix(framedM, r1, c1, r2, c2); double[] V = MatrixTools.Matrix2Array(subMatrix); double av, variance; NormalDist.AverageAndVariance(V, out av, out variance); double numerator = inputM[r1, c1]; //double numerator = (inputM[r1, c1] - av); double denominator = Math.Sqrt(1 + (alpha * variance)); outputM[r1, c1] = numerator / denominator; } } // FOLLOWING LINES ARE FOR DEBUGGING AND TESTING /* * outputM = MatrixTools.MatrixRotate90Anticlockwise(outputM); * ImageTools.DrawReversedMatrix(outputM, @"C:\SensorNetworks\Output\Sonograms\TESTMATRIX2.png"); * double fractionalStretching = 0.05; * outputM = ImageTools.ContrastStretching(outputM, fractionalStretching); * ImageTools.DrawReversedMatrix(outputM, @"C:\SensorNetworks\Output\Sonograms\TESTMATRIX3.png"); */ return(outputM); }
/// <summary> /// METHOD to TEST the FFT2D. /// </summary> public static void TestFFT2D() { string imageFilePath = @"C:\SensorNetworks\Output\FFT2D\test5.png"; bool reversed = false; double[,] matrix = GetImageDataAsGrayIntensity(imageFilePath, reversed); //matrix = MatrixTools.NormaliseMatrixValues(matrix); double[,] output = FFT2Dimensional(matrix); Console.WriteLine("Sum={0}", MatrixTools.Matrix2Array(output).Sum()); //draws matrix after normalisation with white=low and black=high ImageTools.DrawReversedMatrix(output, @"C:\SensorNetworks\Output\FFT2D\test5_2DFFT.png"); }
/// <summary> /// Generate overlapped random patches from a matrix /// </summary> private static List <double[]> GetOverlappedRandomPatches(double[,] matrix, int patchWidth, int patchHeight, int numberOfPatches) { int seed = 100; Random randomNumber = new Random(seed); List <double[]> patches = new List <double[]>(); int rows = matrix.GetLength(0); int columns = matrix.GetLength(1); int no = 0; while (no < numberOfPatches) { // First select a random patch // selecting a random number from the height of the matrix int rowRandomNumber = randomNumber.Next(0, rows - patchHeight); // selecting a random number from the width of the matrix int columnRandomNumber = randomNumber.Next(0, columns - patchWidth); double[,] submatrix = MatrixTools.Submatrix(matrix, rowRandomNumber, columnRandomNumber, rowRandomNumber + patchHeight - 1, columnRandomNumber + patchWidth - 1); // convert a matrix to a vector by concatenating columns and // store it to the array of vectors patches.Add(MatrixTools.Matrix2Array(submatrix)); no++; // shifting the row by one // note that if we select full band patches, then we don't need to shift the column. rowRandomNumber = rowRandomNumber + 1; // Second, slide the patch window (rowRandomNumber + 1) to select the next patch double[,] submatrix2 = MatrixTools.Submatrix(matrix, rowRandomNumber, columnRandomNumber, rowRandomNumber + patchHeight - 1, columnRandomNumber + patchWidth - 1); patches.Add(MatrixTools.Matrix2Array(submatrix2)); no++; // The below commented code can be used when shifting the row by three /* * rInt = rInt + 2; * // Second, slide the patch window (rowRandomNumber+1) to select the next patch * double[,] submatrix3 = MatrixTools.Submatrix(spectrogram, rowRandomNumber, columnRandomNumber, * rowRandomNumber + patchHeight - 1, columnRandomNumber + patchWidth - 1); * patches.Add(MatrixTools.MatrixToArray(submatrix3)); * no++; */ } return(patches); }
/// <summary> /// Generate non-overlapping sequential patches from a <paramref name="matrix"/> /// </summary> private static List <double[]> GetSequentialPatches(double[,] matrix, int patchWidth, int patchHeight) { List <double[]> patches = new List <double[]>(); int rows = matrix.GetLength(0); int columns = matrix.GetLength(1); for (int r = 0; r < rows / patchHeight; r++) { for (int c = 0; c < columns / patchWidth; c++) { double[,] submatrix = MatrixTools.Submatrix(matrix, r * patchHeight, c * patchWidth, (r * patchHeight) + patchHeight - 1, (c * patchWidth) + patchWidth - 1); // convert a matrix to a vector by concatenating columns and // store it to the array of vectors patches.Add(MatrixTools.Matrix2Array(submatrix)); } } return(patches); }
/// <summary> /// Generate non-overlapping random patches from a matrix /// </summary> private static List <double[]> GetRandomPatches(double[,] matrix, int patchWidth, int patchHeight, int numberOfPatches) { // Note: to make the method more flexible in terms of selecting a random patch with any height and width, // first a random number generator is defined for both patchHeight and patchWidth. // However, the possibility of selecting duplicates especially when selecting too many random numbers from // a range (e.g., 1000 out of 1440) is high with a a random generator. // Since, we are mostly interested in full-band patches, i.e., patchWidth = (maxFreqBin - minFreqBin + 1) / numFreqBand, // it is important to select non-duplicate patchHeights. Hence, instead of a random generator for patchHeight, // a better solution is to make a sequence of numbers to be selected, shuffle them, and // finally, a first n (number of required patches) numbers could be selected. int rows = matrix.GetLength(0); int columns = matrix.GetLength(1); int seed = 100; Random randomNumber = new Random(seed); // not sure whether it is better to use new Guid() instead of randomNumber.Next() var randomRowNumbers = Enumerable.Range(0, rows - patchHeight).OrderBy(x => randomNumber.Next()).Take(numberOfPatches).ToList(); List <double[]> patches = new List <double[]>(); for (int i = 0; i < randomRowNumbers.Count; i++) { // selecting a random number from the height of the matrix //int rowRandomNumber = randomNumber.Next(0, rows - patchHeight); // selecting a random number from the width of the matrix int columnRandomNumber = randomNumber.Next(0, columns - patchWidth); double[,] submatrix = MatrixTools.Submatrix(matrix, randomRowNumbers[i], columnRandomNumber, randomRowNumbers[i] + patchHeight - 1, columnRandomNumber + patchWidth - 1); // convert a matrix to a vector by concatenating columns and // store it to the array of vectors patches.Add(MatrixTools.Matrix2Array(submatrix)); } return(patches); }