灰度 FFT 与彩色 FFT

3
以下代码将彩色图像转换为灰度图像,然后计算其FFT:
    private void button1_Click(object sender, EventArgs e)
    {
        Bitmap source = pictureBox1.Image as Bitmap;

        Bitmap gray = Grayscale.ToGrayscale(source);

        Complex[,] cpxImage = ImageDataConverter.ToComplex(gray);

        Complex[,] fftCpxImage = FourierTransform.ForwardFFT(cpxImage);

        Complex[,] shiftedFftCpxImage = FourierShifter.ShiftFft(fftCpxImage);

        Bitmap mag = FourierPlot.FftMagnitudePlot(shiftedFftCpxImage, PixelFormat.Format8bppIndexed);
        Bitmap phase = FourierPlot.FftPhasePlot(shiftedFftCpxImage, PixelFormat.Format8bppIndexed);

        pictureBox2.Image = gray;

        pictureBox3.Image =  mag;

        pictureBox4.Image = phase;
    }

以下代码将彩色图像分成三个通道,计算它们的FFT并将它们合并在一起,形成FFT的RGB图像。
    private void button2_Click(object sender, EventArgs e)
    {
        Bitmap source = pictureBox1.Image as Bitmap;

        int [,,] array3d = ImageDataConverter.ToInteger3d(source);

        int[,] red = ArrayTools<int>.Split(array3d, 0);
        int[,] green = ArrayTools<int>.Split(array3d, 1);
        int[,] blue = ArrayTools<int>.Split(array3d, 2);

        Complex [,] cpxRed = ImageDataConverter.ToComplex(red);
        Complex [,] cpxGreen = ImageDataConverter.ToComplex(green);
        Complex [,] cpxBlue = ImageDataConverter.ToComplex(blue);

        Complex[,] fftCpxRed = FourierTransform.ForwardFFT(cpxRed);
        Complex[,] fftCpxGreen = FourierTransform.ForwardFFT(cpxGreen);
        Complex[,] fftCpxBlue = FourierTransform.ForwardFFT(cpxBlue);

        Complex[,] shiftedFftCpxRed = FourierShifter.ShiftFft(fftCpxRed);
        Complex[,] shiftedFftCpxGreen = FourierShifter.ShiftFft(fftCpxGreen);
        Complex[,] shiftedFftCpxBlue = FourierShifter.ShiftFft(fftCpxBlue);

        int[,] fftRed = ImageDataConverter.ToIntegerMagnitude(shiftedFftCpxRed);
        int[,] fftGreen = ImageDataConverter.ToIntegerMagnitude(shiftedFftCpxGreen);
        int[,] fftBlue = ImageDataConverter.ToIntegerMagnitude(shiftedFftCpxBlue);

        int [,,] dest = ArrayTools<int>.Merge(fftRed, fftGreen, fftBlue);

        Bitmap mag = ImageDataConverter.ToBitmap3d(dest, PixelFormat.Format8bppIndexed);
        Grayscale.SetPalette(mag);

        pictureBox3.Image = mag;
    }

输出

enter image description hereenter image description here

在第一个案例中,结果非常好,符合预期。 在第二个案例中,输出完全是黑色的。

再做一个测试:如果我只选择一个通道,那么输出也很好:

        ... ... ...

        Complex[,] shiftedFftCpxRed = FourierShifter.ShiftFft(fftCpxRed);
        Complex[,] shiftedFftCpxGreen = FourierShifter.ShiftFft(fftCpxGreen);
        Complex[,] shiftedFftCpxBlue = FourierShifter.ShiftFft(fftCpxBlue);

        Bitmap mag = FourierPlot.FftMagnitudePlot(shiftedFftCpxRed, PixelFormat.Format8bppIndexed);
        Bitmap phase = FourierPlot.FftPhasePlot(shiftedFftCpxRed, PixelFormat.Format8bppIndexed);

        pictureBox2.Image = ImageDataConverter.ToBitmap2d(red, PixelFormat.Format8bppIndexed);
        pictureBox3.Image = mag;
        pictureBox4.Image = phase;

        ... ... ...

我认为存在问题的地方是

enter image description here

    public static int[,] ToIntegerMagnitude(Complex[,] image)
    {
        int Width = image.GetLength(0);
        int Height = image.GetLength(1);

        int[,] integer = new int[Width, Height];


        for (int j = 0; j <= Height - 1; j++)
        {
            for (int i = 0; i <= Width - 1; i++)
            {
                integer[i, j] = ((int)image[i, j].Magnitude);
            }
        }

        return integer;
    }

这只提取了幅度部分,因此在此过程中丢失了数据。
有什么建议吗?

相关源代码
public static class FourierPlot
{
    public static Bitmap FftMagnitudePlot(Complex[,] fftImage, PixelFormat pixelFormat)
    {
        int[,] FourierMagnitudeNormalizedInteger = FourierNormalizer.Normalize(fftImage, NormalizeType.Magnitude);

        Bitmap color = ImageDataConverter.ToBitmap2d(FourierMagnitudeNormalizedInteger, pixelFormat);

        Grayscale.SetPalette(color);

        return color;
    }

    public static Bitmap FftPhasePlot(Complex[,] fftImage, PixelFormat pixelFormat)
    {
        int[,] FourierPhaseNormalizedInteger = FourierNormalizer.Normalize(fftImage, NormalizeType.Phase);

        Bitmap color = ImageDataConverter.ToBitmap2d(FourierPhaseNormalizedInteger, pixelFormat);

        Grayscale.SetPalette(color);

        return color;
    }
}

public partial class FourierNormalizer
{
    public static int[,] Normalize(Complex[,] Output, NormalizeType normalizeType)
    {
        int Width = Output.GetLength(0);
        int Height = Output.GetLength(1);

        double[,] FourierDouble = new double[Width, Height];
        double[,] FourierLogDouble = new double[Width, Height];
        int[,] FourierNormalizedInteger = new int[Width, Height];

        double max = 0;

        if (normalizeType == NormalizeType.Magnitude)
        {
            for (int i = 0; i <= Width - 1; i++)
            {
                for (int j = 0; j <= Height - 1; j++)
                {
                    FourierDouble[i, j] = Output[i, j].Magnitude;
                    FourierLogDouble[i, j] = (double)Math.Log(1 + FourierDouble[i, j]);
                }
            }

            max = FourierLogDouble[0, 0];
        }
        else
        {
            for (int i = 0; i <= Width - 1; i++)
            {
                for (int j = 0; j <= Height - 1; j++)
                {
                    FourierDouble[i, j] = Output[i, j].Phase;
                    FourierLogDouble[i, j] = (double)Math.Log(1 + Math.Abs(FourierDouble[i, j]));
                }
            }

            FourierLogDouble[0, 0] = 0;
            max = FourierLogDouble[1, 1];
        }

        for (int i = 0; i <= Width - 1; i++)
        {
            for (int j = 0; j <= Height - 1; j++)
            {
                if (FourierLogDouble[i, j] > max)
                {
                    max = FourierLogDouble[i, j];
                }
            }
        }

        for (int i = 0; i <= Width - 1; i++)
        {
            for (int j = 0; j <= Height - 1; j++)
            {
                FourierLogDouble[i, j] = FourierLogDouble[i, j] / max;
            }
        }

        if (normalizeType == NormalizeType.Magnitude)
        {
            for (int i = 0; i <= Width - 1; i++)
            {
                for (int j = 0; j <= Height - 1; j++)
                {
                    FourierNormalizedInteger[i, j] = (int)(2000 * FourierLogDouble[i, j]);
                }
            }
        }
        else
        {
            for (int i = 0; i <= Width - 1; i++)
            {
                for (int j = 0; j <= Height - 1; j++)
                {
                    FourierNormalizedInteger[i, j] = (int)(255 * FourierLogDouble[i, j]);
                }
            }
        }

        return FourierNormalizedInteger;
    }
}

    public static Bitmap ToBitmap3d(int[, ,] image, PixelFormat pixelFormat)
    {
        int Width = image.GetLength(1);
        int Height = image.GetLength(2);

        Bitmap bmp = new Bitmap(Width, Height, pixelFormat);

        BitmapLocker locker = new BitmapLocker(bmp);
        locker.Lock();

        int [,] red = ArrayTools<int>.Split(image, 0);
        int [,] green = ArrayTools<int>.Split(image, 1);
        int [,] blue = ArrayTools<int>.Split(image, 2);

        for (int y = 0; y < Height; y++)
        {
            for (int x = 0; x < Width; x++)
            {
                int r = red[x,y];
                int g = green[x,y];
                int b = blue[x,y];

                Color clr = Color.FromArgb(r,g,b);

                locker.SetPixel(x, y, clr);
            }
        }

        locker.Unlock();

        return bmp;
    } 

你可能不想像那样将幅度转换为整数。你需要先进行缩放。你能否使用FourierPlot.FftMagnitudePlot()将每个通道的结果转换为整数位图,然后将这些位图组合起来? - Cris Luengo
@CrisLuengo,可以的。但是,为什么这段特定的代码不起作用?我该如何让它工作? - user366312
1
FourierPlot.FftMagnitudePlot 似乎对输入值应用了对数拉伸。在将其转换为整数时,您没有这样做,很可能所有值的亮度都太低而无法看到。 - Cris Luengo
1
的确。我会将三个通道通过“FourierNormalizer.Normalize”传递,然后将它们结合成一个彩色位图。 - Cris Luengo
你能发布 ImageDataConverter.ToBitmap3d 的代码吗? - mnistic
显示剩余5条评论
1个回答

1

enter image description here

这个评论解决了我的问题。

    private void button2_Click(object sender, EventArgs e)
    {
        Bitmap source = (Bitmap)(pictureBox1.Image as Bitmap).Clone();

        int[, ,] array3d = ImageDataConverter.ToInteger3d(source);

        int[,] red = ArrayTools<int>.Split(array3d, 0);
        int[,] green = ArrayTools<int>.Split(array3d, 1);
        int[,] blue = ArrayTools<int>.Split(array3d, 2);

        Complex[,] cpxRed = ImageDataConverter.ToComplex(red);
        Complex[,] cpxGreen = ImageDataConverter.ToComplex(green);
        Complex[,] cpxBlue = ImageDataConverter.ToComplex(blue);

        Complex[,] fftCpxRed = FourierTransform.ForwardFFT(cpxRed);
        Complex[,] fftCpxGreen = FourierTransform.ForwardFFT(cpxGreen);
        Complex[,] fftCpxBlue = FourierTransform.ForwardFFT(cpxBlue);

        Complex[,] shiftedFftCpxRed = FourierShifter.ShiftFft(fftCpxRed);
        Complex[,] shiftedFftCpxGreen = FourierShifter.ShiftFft(fftCpxGreen);
        Complex[,] shiftedFftCpxBlue = FourierShifter.ShiftFft(fftCpxBlue);

        int[,] normRed = FourierNormalizer.Normalize(shiftedFftCpxRed, NormalizeType.Magnitude);
        int[,] normGreen = FourierNormalizer.Normalize(shiftedFftCpxGreen, NormalizeType.Magnitude);
        int[,] normBlue = FourierNormalizer.Normalize(shiftedFftCpxBlue, NormalizeType.Magnitude);

        Bitmap mag = ImageDataConverter.ToBitmap3d(normRed, normGreen, normBlue, PixelFormat.Format8bppIndexed);
        //Grayscale.SetPalette(mag);
        //Bitmap mag = FourierPlot.FftMagnitudePlot(shiftedFftCpxRed, PixelFormat.Format8bppIndexed);
        Bitmap phase = FourierPlot.FftPhasePlot(shiftedFftCpxRed, PixelFormat.Format8bppIndexed);

        pictureBox2.Image = mag;
        pictureBox3.Image = mag;
        pictureBox4.Image = phase;
    }

很高兴能帮忙! :) - Cris Luengo

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接