/// <summary> /// Перевод оператора искажения из пространственной в частотную область. Размерность не меняется. /// </summary> /// <param name="filter">Оператор искажения PSF (Point Spread Function)</param> /// <returns>OTF (Optical Transfer Function)</returns> public static Complex[,] Psf2otf(ConvolutionFilter filter) { double[,] filterMatrix = filter.normalizedFilterMatrix; int FilterSize = filterMatrix.GetLength(0); int halfSize = (FilterSize - 1) / 2; int ost = FilterSize - halfSize; double[,] newFilter = new double[FilterSize, FilterSize]; //+ + - //+ + - //- - - for (int i = 0; i < ost; i++) { for (int j = 0; j < ost; j++) { newFilter[i, j] = filterMatrix[i + halfSize, j + halfSize]; } } //- - + //- - + //- - - for (int i = 0; i < ost; i++) { for (int j = ost; j < FilterSize; j++) { newFilter[i, j] = filterMatrix[i + halfSize, j - ost]; } } //- - - //- - - //+ + - for (int i = ost; i < FilterSize; i++) { for (int j = 0; j < ost; j++) { newFilter[i, j] = filterMatrix[i - ost, j + halfSize]; } } //- - - //- - - //- - + for (int i = ost; i < FilterSize; i++) { for (int j = ost; j < FilterSize; j++) { newFilter[i, j] = filterMatrix[i - ost, j - ost]; } } return(Fourier.Transform(Converter.ToComplexMatrix(newFilter))); }
/// <summary> /// Двумерное прямое преобразование фурье /// </summary> /// <param name="source">входная матрица</param> /// <returns>Выходной ряд</returns> public static Complex[,] Transform(Complex[,] source) { int M = source.GetLength(0); //строк int N = source.GetLength(1); //столбцов Complex[,] outC = new Complex[M, N]; //преобразуем строки for (int i = 0; i < M; i++) //проходим по строкам { Complex[] str = new Complex[N]; for (int j = 0; j < N; j++) //проходим внутри строки, собирая её { str[j] = source[i, j]; } str = Fourier.Transform(str); //получаем фурье образ строки for (int j = 0; j < N; j++) //записываем его в массив { outC[i, j] = str[j]; } } //преобразуем столбцы for (int i = 0; i < N; i++) //проходим по столбцам { Complex[] raw = new Complex[M]; for (int j = 0; j < M; j++) //проходим внутри столбца, собирая его { raw[j] = outC[j, i]; } raw = Fourier.Transform(raw); //получаем фурье образ столбца for (int j = 0; j < M; j++) //записываем его в массив { outC[j, i] = raw[j]; } } return(outC); }
/// <summary> /// Двумерное прямое быстрое преобразование фурье /// </summary> /// <param name="source">входная матрица</param> /// <returns>Выходной ряд</returns> public static Complex[,] FastTransform(Complex[,] source) { int m = source.GetLength(0); //строк int n = source.GetLength(1); //столбцов int size = n; if (m > n) { size = m; } double log = Math.Log(size, 2); Complex[,] x; if (log - Math.Round(log) != 0) { size = (int)Math.Pow(2, (int)log + 1); } x = new Complex[size, size]; for (int i = 0; i < m; i++) { for (int j = 0; j < n; j++) { x[i, j] = source[i, j]; } } Complex[,] outC = new Complex[size, size]; //преобразуем строки for (int i = 0; i < size; i++) //проходим по строкам { Complex[] str = new Complex[size]; for (int j = 0; j < size; j++) //проходим внутри строки, собирая её { str[j] = x[i, j]; } str = Fourier.UnsafeFastTransform(str); //получаем фурье образ строки for (int j = 0; j < size; j++) //записываем его в массив { outC[i, j] = str[j]; } } //преобразуем столбцы for (int i = 0; i < size; i++) //проходим по столбцам { Complex[] raw = new Complex[size]; for (int j = 0; j < size; j++) //проходим внутри столбца, собирая его { raw[j] = outC[j, i]; } raw = Fourier.UnsafeFastTransform(raw); //получаем фурье образ столбца for (int j = 0; j < size; j++) //записываем его в массив { outC[j, i] = raw[j]; } } return(outC); }
/// <summary> /// Конволюция (свёртка) в частотной области /// </summary> /// <param name="sourceImage">исходное изображение</param> /// <returns>искаженное изображение</returns> public Image FastConvolution(Image sourceImage) { int height = sourceImage.Height; int width = sourceImage.Width; int filterSize = this.filterMatrix.GetLength(0); //размер PSF int filterHalfSize = (filterSize - 1) / 2 + 1; //центр PSF Image expandedImage = sourceImage.Expand(filterHalfSize); int expHeight = expandedImage.Height; int expWidth = expandedImage.Width; double[] image = Converter.ToDoubleArray(expandedImage); double[,] red = new double[expHeight, expWidth]; double[,] green = new double[expHeight, expWidth]; double[,] blue = new double[expHeight, expWidth]; int index = 0; for (int i = 0; i < expHeight; i++) { for (int j = 0; j < expWidth; j++) { blue[i, j] = image[index]; green[i, j] = image[index + 1]; red[i, j] = image[index + 2]; index += 4; } } Complex[,] redFourier = Fourier.FastTransform(Converter.ToComplexMatrix(red)); Complex[,] greenFourier = Fourier.FastTransform(Converter.ToComplexMatrix(green)); Complex[,] blueFourier = Fourier.FastTransform(Converter.ToComplexMatrix(blue)); int newSize = redFourier.GetLength(0); double[,] kernel = this.ExpendedByZero(newSize); Complex[,] kernelFourier = Fourier.FastTransform(Converter.ToComplexMatrix(kernel)); for (int u = 0; u < newSize; u++) { for (int v = 0; v < newSize; v++) { redFourier[u, v] *= kernelFourier[u, v]; greenFourier[u, v] *= kernelFourier[u, v]; blueFourier[u, v] *= kernelFourier[u, v]; } } Complex[,] newRed = Fourier.IFastTransform(redFourier, expHeight, expWidth); Complex[,] newGreen = Fourier.IFastTransform(greenFourier, expHeight, expWidth); Complex[,] newBlue = Fourier.IFastTransform(blueFourier, expHeight, expWidth); Complex[,] resRed = new Complex[height, width]; Complex[,] resGreen = new Complex[height, width]; Complex[,] resBlue = new Complex[height, width]; for (int i = 0; i < height; i++) { for (int j = 0; j < width; j++) { resRed[i, j] = Math.Round(newRed[i + filterHalfSize + 1, j + filterHalfSize + 1].Real); resGreen[i, j] = Math.Round(newGreen[i + filterHalfSize + 1, j + filterHalfSize + 1].Real); resBlue[i, j] = Math.Round(newBlue[i + filterHalfSize + 1, j + filterHalfSize + 1].Real); } } Image result = Converter.ToImage(resRed, resGreen, resBlue); return(result); }
/// <summary> /// Перевод оператора искажения из пространственной в частотную область с новой (бОльшей) размерностью. /// </summary> /// <param name="filter">оператор искажения исходного размера</param> /// <param name="newSize">новая размерность</param> /// <returns></returns> public static Complex[,] Psf2otf(ConvolutionFilter filter, int newSize) { double[,] filterMatrix = filter.normalizedFilterMatrix; int sourceFilterSize = filterMatrix.GetLength(0); int halfSize = (filter.filterMatrix.GetLength(0) - 1) / 2; if (newSize < sourceFilterSize) { return(null); } double[,] extendedFilter = new double[newSize, newSize]; //0 0 0 //0 0 0 //0 0 0 for (int i = 0; i < newSize; i++) { for (int j = 0; j < newSize; j++) { extendedFilter[i, j] = 0; } } //- - - //- + + //- + + for (int i = 0; i < halfSize + 1; i++) { for (int j = 0; j < halfSize + 1; j++) { extendedFilter[i, j] = filterMatrix[i + halfSize, j + halfSize]; } } //- - - //+ - - //+ - - for (int i = 0; i < halfSize + 1; i++) { for (int j = newSize - halfSize; j < newSize; j++) { extendedFilter[i, j] = filterMatrix[i + halfSize, j - (newSize - halfSize)]; } } //- + + //- - - //- - - for (int i = newSize - halfSize; i < newSize; i++) { for (int j = 0; j < halfSize + 1; j++) { extendedFilter[i, j] = filterMatrix[i - (newSize - halfSize), j + halfSize]; } } //+ - - //- - - //- - - for (int i = newSize - halfSize; i < newSize; i++) { for (int j = newSize - halfSize; j < newSize; j++) { extendedFilter[i, j] = filterMatrix[i - (newSize - halfSize), j - (newSize - halfSize)]; } } return(Fourier.Transform(Converter.ToComplexMatrix(extendedFilter))); }