Après avoir utilisé STFT (transformée de Fourier à court terme), la sortie est une masortingce représentant un tracé 3D comme si (A[X, Y] = M)
A était la masortingce de sortie, X le temps, Y la fréquence et la troisième dimension M est l’amplitude illustrée par l’intensité de la couleur du pixel comme dans les images suivantes:
Spectrogramme 2
Comment dessiner la masortingce de sortie A avec un dégradé de couleurs comme dans les images en C #?
Existe-t-il une bibliothèque contenant un contrôle spectrogramme pour C #?
Mettre à jour:
Après quelques modifications sur l’algorithme donné, je pouvais dessiner le spectrogramme, je n’ai pas changé la palette de couleurs sauf la première couleur changée en noir mais je ne sais pas pourquoi elle est très fanée!
Celui-ci représente un dicton sonore
Bye Bye
Au revoir spectrogramme
Et celui-ci d’une pure sine wave
donc c’est presque la même fréquence tout le temps
Spectrogramme d’onde sinusoïdale pure
La sortie est acceptée, elle représente les fréquences du signal d’entrée comme prévu, mais je pense qu’il existe un moyen de rendre le spectrogramme aussi bien illustré que ceux des exemples. Pourriez-vous s’il vous plaît jeter un coup d’œil à mon code et suggérer des modifications?
C’est le gestionnaire d’événement:
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); }
Et celle-ci est la fonction de dessin après mes modifications:
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 baseColors = new List(); // 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 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; }
Je ne comprends pas vraiment le truc du log
dont vous parlez dans vos réponses, je suis désolé pour ma petite connaissance.
Mettre à jour:
Voici le résultat après l’ajout de la prise de log10
aux grandeurs (valeurs négatives négligées):
Je pense que cette sortie est acceptable, elle est différente des exemples que j’ai apportés au début mais je pense que c’est mieux.
Non, il n’y a pas de contrôle prêt à l’emploi à ma connaissance. Il y a peut-être des bibliothèques extérieures que vous pouvez acheter, bien sûr, mais chut, vous ne pouvez pas vous renseigner sur elles.
En théorie, vous pouvez utiliser, ou plutôt deviner, utiliser un contrôle Chart
pour cela. Mais comme les DataPoints
sont des objects plutôt chers, ou du moins plus chers qu’ils ne le paraissent, cela ne semble pas souhaitable.
Au lieu de cela, vous pouvez simplement dessiner vous-même le graphique dans une image Bitmap
.
La première étape consiste à choisir un dégradé de couleurs. Voir la fonction interpolateColors ici pour un exemple!
Ensuite, vous feriez simplement une double boucle sur les données en utilisant des floats
pour les tailles de pas et de pixels et feriez un Graphics.FillRectangle
ici.
Voici un exemple simple d’utilisation de GDI+
pour créer une image Bitmap
et un Winforms PictureBox
fins d’affichage. Il n’ajoute aucun axe au graphique et le remplit complètement.
Il crée d’abord quelques échantillons de données et un dégradé de 1000
couleurs. Ensuite, il dessine dans un Bitmap
et affiche le résultat:
private 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 baseColors = new List (); // 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 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; }
Voici la fonction du lien:
List interpolateColors(List stopColors, int count) { SortedDictionary gradient = new SortedDictionary(); for (int i = 0; i < stopColors.Count; i++) gradient.Add(1f * i / (stopColors.Count - 1), stopColors[i]); List ColorList = new List (); 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; }
Vous voudrez probablement dessiner des axes avec des étiquettes, etc. Vous pouvez utiliser Graphics.DrawSsortingng
ou TextRenderer.DrawText
pour le faire. Laissez juste assez d’espace autour de la zone de dessin!
J'ai utilisé les valeurs de données transtypées sur int
comme pointeurs directs dans la table des couleurs.
En fonction de vos données, vous devrez les réduire ou même utiliser une conversion de journal. La première de vos images montre une échelle logarithmique allant de 100 à 20k, la seconde semble linéaire allant de 0 à 100.
Si vous nous montrez votre structure de données, nous pourrons vous donner d'autres indications sur la manière d'adapter le code pour l'utiliser.
Vous pouvez créer un bitmap conformément à l’autre réponse. Il est également courant d’utiliser une table de correspondance des couleurs pour convertir l’amplitude du journal FFT en couleur à utiliser pour chaque pixel ou petit rectangle.