C# 用渐变色绘制矩阵“;光谱图;

C# 用渐变色绘制矩阵“;光谱图;,c#,audio,drawing,fft,spectrogram,C#,Audio,Drawing,Fft,Spectrogram,使用STFT(短时傅里叶变换)后,输出是一个表示3d绘图的矩阵,就好像(a[X,Y]=M)a是输出矩阵,X是时间,Y是频率,三维M是由像素颜色的强度表示的振幅,如下图所示: 如何绘制具有渐变颜色的输出矩阵A,如C#中的图片是否有包含C#的光谱图控件的库 更新: 在对给定的算法进行一些修改后,我可以绘制光谱图,除了第一种颜色变为黑色之外,我没有改变调色板,但我不知道为什么它会变得非常褪色 这句话代表了一种合理的说法 再见 这是一个纯正弦波,所以它的频率几乎一直是相同的 输出是可以接受

使用STFT(短时傅里叶变换)后,输出是一个表示3d绘图的矩阵,就好像
(a[X,Y]=M)
a是输出矩阵,X是时间,Y是频率,三维M是由像素颜色的强度表示的振幅,如下图所示:

如何绘制具有渐变颜色的输出矩阵A,如C#中的图片
是否有包含C#的光谱图控件的库



更新:
在对给定的算法进行一些修改后,我可以绘制光谱图,除了第一种颜色变为黑色之外,我没有改变调色板,但我不知道为什么它会变得非常褪色

这句话代表了一种合理的说法

再见

这是一个纯正弦波,所以它的频率几乎一直是相同的



输出是可以接受的,它代表了预期的输入信号的频率,但我认为有一种方法可以使频谱图与示例中的频谱图一样清晰,您能看看我的代码并提出修改建议吗


这是事件处理程序:

private void SpectrogramButton_Click(object sender, EventArgs e)
{
    Complex[][] SpectrogramData = Fourier_Transform.STFT(/*signal:*/ samples,  /*windowSize:*/ 512, /*hopSize:*/ 512);
    SpectrogramBox.Image = Spectrogram.DrawSpectrogram(SpectrogramData, /*Interpolation Factor:*/ 1000, /*Height:*/ 256);
}

这是我修改后的绘图功能:

public static Bitmap DrawSpectrogram(Complex[][] Data, int InterpolationFactor, int Height)
{
    // target size:
    Size sz = new Size(Data.GetLength(0), Height);
    Bitmap bmp = new Bitmap(sz.Width, sz.Height);

    // the data array:
    //double[,] data = new double[222, 222];

    // step sizes:
    float stepX = 1f * sz.Width / Data.GetLength(0);
    float stepY = 1f * sz.Height / Data[0].GetLength(0);

    // create a few stop colors:
    List<Color> baseColors = new List<Color>();  // create a color list
    baseColors.Add(Color.Black);
    baseColors.Add(Color.LightSkyBlue);
    baseColors.Add(Color.LightGreen);
    baseColors.Add(Color.Yellow);
    baseColors.Add(Color.Orange);
    baseColors.Add(Color.Red);


    // and the interpolate a larger number of grdient colors:
    List<Color> colors = interpolateColors(baseColors, InterpolationFactor);

    // a few boring test data
    //Random rnd = new Random(1);
    //for (int x = 0; x < data.GetLength(0); x++)
    //    for (int y = 0; y < data.GetLength(1); y++)
    //    {
    //        //data[x, y] = rnd.Next((int)(300 + Math.Sin(x * y / 999) * 200)) +
    //        //                rnd.Next(x + y + 111);
    //        data[x, y] = 0;
    //    }

    // now draw the data:
    float Max = Complex.Max(Data);
    using (Graphics G = Graphics.FromImage(bmp))
        for (int x = 0; x < Data.GetLength(0); x++)
            for (int y = 0; y < Data[0].GetLength(0); y++)
            {
                int Val = (int)Math.Ceiling((Data[x][y].Magnitude / Max) * (InterpolationFactor - 1));
                using (SolidBrush brush = new SolidBrush(colors[(int)Val]))
                    G.FillRectangle(brush, x * stepX, (Data[0].GetLength(0) - y) * stepY, stepX, stepY);
            }

    // and display the result
    return bmp;
}
公共静态位图绘制光谱图(复数[][]数据,整数插值因子,整数高度)
{
//目标尺寸:
尺寸sz=新尺寸(Data.GetLength(0),高度);
位图bmp=新位图(sz.Width,sz.Height);
//数据阵列:
//double[,]数据=新的double[222222];
//步长:
浮点步长x=1f*sz.Width/Data.GetLength(0);
float stepY=1f*sz.Height/Data[0].GetLength(0);
//创建一些停止颜色:
List baseColors=new List();//创建颜色列表
基本颜色。添加(颜色。黑色);
baseColors.Add(Color.LightSkyBlue);
基本颜色。添加(颜色。浅绿色);
基本颜色。添加(颜色。黄色);
基本颜色。添加(颜色。橙色);
基本颜色。添加(颜色。红色);
//并且插值更多的渐变颜色:
列表颜色=插值颜色(基色、插值因子);
//一些无聊的测试数据
//随机rnd=新随机(1);
//for(int x=0;x
我真的不明白你在回答中所说的
日志
的内容,很抱歉我的知识太少



更新:
这是将取数
log10
添加到震级后的输出(忽略负值):


  • 我认为这个输出是可以接受的,它与我在开始时介绍的示例不同,但我认为它更好。

    不,我知道没有现成的控件。当然,你可以在图书馆外买到图书馆,但是嘘,你不能问这么多关于图书馆的事

    理论上你可以使用,或者我想我更应该说滥用
    图表
    控件。但由于
    数据点
    是相当昂贵的对象,或者至少比它们看起来更昂贵,因此这似乎是不可取的

    相反,您可以自己将图形绘制到
    位图中

    • 第一步是决定颜色的渐变。有关此示例,请参见

    • 然后,您只需对步长和像素大小使用
      floats
      对数据进行双循环,然后在那里执行
      Graphics.FillRectangle

    下面是一个使用
    GDI+
    创建
    Bitmap
    Winforms PictureBox
    进行显示的简单示例。它不会向图形添加任何轴,而是完全填充图形

    它首先创建一些样本数据和带有
    1000
    颜色的渐变。然后将其绘制到
    位图中
    ,并显示结果:

    private void按钮6\u单击(对象发送者,事件参数e)
    {
    //目标尺寸:
    大小sz=pictureBox1.ClientSize;
    位图bmp=新位图(sz.Width,sz.Height);
    //数据阵列:
    double[,]数据=新的double[222222];
    //步长:
    浮点步长x=1f*sz.Width/data.GetLength(0);
    float stepY=1f*sz.Height/data.GetLength(1);
    //创建一些停止颜色:
    List baseColors=new List();//创建颜色列表
    baseColors.Add(Color.RoyalBlue);
    baseColors.Add(Color.LightSkyBlue);
    基本颜色。添加(颜色。浅绿色);
    基本颜色。添加(颜色。黄色);
    基本颜色。添加(颜色。橙色);
    基本颜色。添加(颜色。红色);
    //并且插值更多的渐变颜色:
    列表颜色=插值颜色(基色,1000);
    //一些无聊的测试数据
    随机rnd=新随机(1);
    for(int x=0;xprivate void button6_Click(object sender, EventArgs e)
    {
        // target size:
        Size sz = pictureBox1.ClientSize;
        Bitmap bmp = new Bitmap(sz.Width, sz.Height);
    
        // the data array:
        double[,] data = new double[222, 222];
    
        // step sizes:
        float stepX = 1f * sz.Width / data.GetLength(0);
        float stepY = 1f * sz.Height / data.GetLength(1);
    
        // create a few stop colors:
        List<Color> baseColors = new List<Color>();  // create a color list
        baseColors.Add(Color.RoyalBlue);
        baseColors.Add(Color.LightSkyBlue);
        baseColors.Add(Color.LightGreen);
        baseColors.Add(Color.Yellow);
        baseColors.Add(Color.Orange);
        baseColors.Add(Color.Red);
        // and the interpolate a larger number of grdient colors:
        List<Color> colors = interpolateColors(baseColors, 1000);
    
        // a few boring test data
        Random rnd = new Random(1);
        for (int x = 0; x < data.GetLength(0); x++)
        for (int y = 0; y < data.GetLength(1); y++)
        {
            data[x, y] = rnd.Next( (int) (300 + Math.Sin(x * y / 999) * 200 )) +
                            rnd.Next(  x +  y + 111);
        }
    
        // now draw the data:
        using (Graphics G = Graphics.FromImage(bmp))
        for (int x = 0; x < data.GetLength(0); x++)
            for (int y = 0; y < data.GetLength(1); y++)
            {
                using (SolidBrush brush = new SolidBrush(colors[(int)data[x, y]]))
                    G.FillRectangle(brush, x * stepX, y * stepY, stepX, stepY);
            }
    
        // and display the result
        pictureBox1.Image = bmp;
    }
    
    List<Color> interpolateColors(List<Color> stopColors, int count)
    {
        SortedDictionary<float, Color> gradient = new SortedDictionary<float, Color>();
        for (int i = 0; i < stopColors.Count; i++)
            gradient.Add(1f * i / (stopColors.Count - 1), stopColors[i]);
        List<Color> ColorList = new List<Color>();
    
        using (Bitmap bmp = new Bitmap(count, 1))
        using (Graphics G = Graphics.FromImage(bmp))
        {
            Rectangle bmpCRect = new Rectangle(Point.Empty, bmp.Size);
            LinearGradientBrush br = new LinearGradientBrush
                                    (bmpCRect, Color.Empty, Color.Empty, 0, false);
            ColorBlend cb = new ColorBlend();
            cb.Positions = new float[gradient.Count];
            for (int i = 0; i < gradient.Count; i++)
                cb.Positions[i] = gradient.ElementAt(i).Key;
            cb.Colors = gradient.Values.ToArray();
            br.InterpolationColors = cb;
            G.FillRectangle(br, bmpCRect);
            for (int i = 0; i < count; i++) ColorList.Add(bmp.GetPixel(i, 0));
            br.Dispose();
        }
        return ColorList;
    }