我已經在頻域中將高斯模糊應用於圖像。 由於未知的原因(可能我沒有錯)我收到有線圖像,而不是模糊的。在頻域中對圖像應用高斯模糊
有什麼我一步一步做:
- 加載圖像。
將圖像拆分爲單獨的通道。
private static Bitmap[] separateColorChannels(Bitmap source, int channelCount) { if (channelCount != 3 && channelCount != 4) { throw new NotSupportedException("Bitmap[] FFTServices.separateColorChannels(Bitmap, int): Only 3 and 4 channels are supported."); } Bitmap[] result = new Bitmap[channelCount]; LockBitmap[] locks = new LockBitmap[channelCount]; LockBitmap sourceLock = new LockBitmap(source); sourceLock.LockBits(); for (int i = 0; i < channelCount; ++i) { result[i] = new Bitmap(source.Width, source.Height, PixelFormat.Format8bppIndexed); locks[i] = new LockBitmap(result[i]); locks[i].LockBits(); } for (int x = 0; x < source.Width; x++) { for (int y = 0; y < source.Height; y++) { switch (channelCount) { case 3: locks[0].SetPixel(x, y, Color.FromArgb(sourceLock.GetPixel(x, y).R)); locks[1].SetPixel(x, y, Color.FromArgb(sourceLock.GetPixel(x, y).G)); locks[2].SetPixel(x, y, Color.FromArgb(sourceLock.GetPixel(x, y).B)); break; case 4: locks[0].SetPixel(x, y, Color.FromArgb(sourceLock.GetPixel(x, y).A)); locks[1].SetPixel(x, y, Color.FromArgb(sourceLock.GetPixel(x, y).R)); locks[2].SetPixel(x, y, Color.FromArgb(sourceLock.GetPixel(x, y).G)); locks[3].SetPixel(x, y, Color.FromArgb(sourceLock.GetPixel(x, y).B)); break; default: break; } } } for (int i = 0; i < channelCount; ++i) { locks[i].UnlockBits(); } sourceLock.UnlockBits(); }
將每個通道轉換爲複雜的圖像(使用AForge.NET)。
public static AForge.Imaging.ComplexImage[] convertColorChannelsToComplex(Emgu.CV.Image<Emgu.CV.Structure.Gray, Byte>[] channels) { AForge.Imaging.ComplexImage[] result = new AForge.Imaging.ComplexImage[channels.Length]; for (int i = 0; i < channels.Length; ++i) { result[i] = AForge.Imaging.ComplexImage.FromBitmap(channels[i].Bitmap); } return result; }
應用高斯模糊。
首先我創建內核(用於測試目的的內核大小等於圖像大小,壽它唯一的中心部分與高斯函數來計算,內核其餘等於重新= 1 IM = 0)。
private ComplexImage makeGaussKernel(int side, double min, double max, double step, double std) { // get value at top left corner double _0x0 = gauss2d(min, min, std); // top left corner should be 1, so making scaler for rest of the values double scaler = 1/_0x0; int pow2 = SizeServices.getNextNearestPowerOf2(side); Bitmap bitmap = new Bitmap(pow2, pow2, PixelFormat.Format8bppIndexed); var result = AForge.Imaging.ComplexImage.FromBitmap(bitmap); // For test purposes my kernel is size of image, so first, filling with 1 only. for (int i = 0; i < result.Data.GetLength(0); ++i) { for (int j = 0; j < result.Data.GetLength(0); ++j) { result.Data[i, j].Re = 1; result.Data[i, j].Im = 0; } } // The real kernel's size. int count = (int)((Math.Abs(max) + Math.Abs(min))/step); double h = min; // Calculating kernel's values and storing them somewhere in the center of kernel. for (int i = result.Data.GetLength(0)/2 - count/2; i < result.Data.GetLength(0)/2 + count/2; ++i) { double w = min; for (int j = result.Data.GetLength(1)/2 - count/2; j < result.Data.GetLength(1)/2 + count/2; ++j) { result.Data[i, j].Re = (scaler * gauss2d(w, h, std)) * 255; w += step; } h += step; } return result; } // The gauss function private double gauss2d(double x, double y, double std) { return ((1.0/(2 * Math.PI * std * std)) * Math.Exp(-((x * x + y * y)/(2 * std * std)))); }
將FFT應用於每個通道和內核。
按內核乘以每個通道的中心部分。
void applyFilter(/*shortened*/) { // Image's size is 512x512 that's why 512 is hardcoded here // min = -2.0; max = 2.0; step = 0.33; std = 11 ComplexImage filter = makeGaussKernel(512, min, max, step, std); // Applies FFT (with AForge.NET) to every channel and filter applyFFT(complexImage); applyFFT(filter); for (int i = 0; i < 3; ++i) { applyGauss(complexImage[i], filter, side); } // Applies IFFT to every channel applyIFFT(complexImage); } private void applyGauss(ComplexImage complexImage, ComplexImage filter, int side) { int width = complexImage.Data.GetLength(1); int height = complexImage.Data.GetLength(0); for(int i = 0; i < height; ++i) { for(int j = 0; j < width; ++j) { complexImage.Data[i, j] = AForge.Math.Complex.Multiply(complexImage.Data[i, j], filter.Data[i, j]); } } }
- 應用IFFT到每一個通道。
將每個通道轉換回位圖(使用AForge.NET)。
public static System.Drawing.Bitmap[] convertComplexColorChannelsToBitmap(AForge.Imaging.ComplexImage[] channels) { System.Drawing.Bitmap[] result = new System.Drawing.Bitmap[channels.Length]; for (int i = 0; i < channels.Length; ++i) { result[i] = channels[i].ToBitmap(); } return result; }
合併位圖轉換爲單個位圖
public static Bitmap mergeColorChannels(Bitmap[] channels) { Bitmap result = null; switch (channels.Length) { case 1: return channels[0]; case 3: result = new Bitmap(channels[0].Width, channels[0].Height, PixelFormat.Format24bppRgb); break; case 4: result = new Bitmap(channels[0].Width, channels[0].Height, PixelFormat.Format32bppArgb); break; default: throw new NotSupportedException("Bitmap FFTServices.mergeColorChannels(Bitmap[]): Only 1, 3 and 4 channels are supported."); } LockBitmap resultLock = new LockBitmap(result); resultLock.LockBits(); LockBitmap red = new LockBitmap(channels[0]); LockBitmap green = new LockBitmap(channels[1]); LockBitmap blue = new LockBitmap(channels[2]); red.LockBits(); green.LockBits(); blue.LockBits(); for (int y = 0; y < result.Height; y++) { for (int x = 0; x < result.Width; x++) { resultLock.SetPixel(x, y, Color.FromArgb((int)red.GetPixel(x, y).R, (int)green.GetPixel(x, y).G, (int)blue.GetPixel(x, y).B)); } } red.UnlockBits(); green.UnlockBits(); blue.UnlockBits(); resultLock.UnlockBits(); return result; }
結果我有位移的圖像中,紅色的模糊版本:link。
@edit - 通過對代碼進行了多處更改,更新了問題。
如果你使用全1的內核發生什麼呢? –
@MobyDisk結果是一樣的... – user2475983
結果是否與原始圖像相同,或者與奇怪的圖像相同?如果所有1的內核給出奇怪的圖像,那麼你知道錯誤不在你的模糊代碼中。所以它必須在FFT/IFFT中,或者在分離通道和重新組合它們的過程中,或者在使用aforge.net生成複雜圖像的過程中。另一方面,如果所有1的內核都返回原始圖像,那麼問題在於模糊/內核。這種思路似乎有幫助嗎? –