【发布时间】:2015-12-27 14:03:40
【问题描述】:
使用 STFT(短时傅里叶变换)后,输出是一个矩阵,表示 3d 图,好像(A[X, Y] = M) A 是输出矩阵,X 是时间,Y 是频率,第三维 M 是由像素颜色的强度表示的幅度如下图:
如何使用 C# 中的图片中的颜色渐变绘制输出矩阵 A?
是否有包含 C# 频谱图控件的库?
更新:
在对给定的算法进行一些修改后,我可以绘制频谱图,除了第一种颜色变为黑色之外,我没有更改调色板,但我不知道为什么它非常褪色!
这个代表一个声音说
再见
这是一个pure sine wave,所以它几乎一直是相同的频率
Pure sine wave Spectrogram
输出被接受,它代表了预期的输入信号的频率,但我认为有一种方法可以使频谱图与示例中的频谱图一样好,您能否看看我的代码并提出修改建议?
这是事件处理程序:
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;
}
我不太明白你在回答中所说的log 的东西,对不起,我的知识很少。
更新:
这是将 log10 添加到幅度后的输出(忽略负值):
我认为这个输出是可以接受的,它与我一开始带来的例子不同,但我认为它更好。
【问题讨论】:
-
我有点纠结 atm 但稍后会在我的答案中添加一些内容以演示使用对数刻度,因为它通常是声波数据所必需的。但第一张图片看起来不错 imo,所以你在那里没有问题。但是,如果您将第一种颜色更改为黑色,您可能应该在其后插入深色和中等蓝色停止颜色。玩弄颜色来感受它们!您可以使用它们中的任意数量。另外:您需要知道您的值的范围!这是声波的正常范围(16-16k)吗?如果是这样..
-
..直接映射到线性颜色列表将无法正常工作。该列表是线性的,只有 1000 种颜色,即使您将其放大到 16k 或 20k,它仍然是不正确的。相反,您需要对它们进行对数查找..
-
我没有直接使用
Magnitude,而是直接使用Val = 20d * Math.Log10(Data[x][y].Magnitude),我不知道这是否是您的意思,但我不得不忽略出现在Magnitude values < 1的所有负值成为原始图像中非常暗的区域,所以我想将log之后的整个值范围映射到我拥有的颜色范围,所以我确保显示所有值。 -
听起来和我推荐的差不多。您是否在黑色停止色之后添加了一些颜色?随意发布当前结果!
-
是的,这是现在的颜色列表:
baseColors.Add(Color.Black); baseColors.Add(Color.DarkBlue); baseColors.Add(Color.MediumBlue); baseColors.Add(Color.LightSkyBlue); baseColors.Add(Color.LightGreen); baseColors.Add(Color.Yellow); baseColors.Add(Color.Orange); baseColors.Add(Color.Red);
标签: c# audio drawing fft spectrogram