Dessiner une masortingce avec un dégradé de couleurs «Spectrogramme»

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 1

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):

  1. Celui de “Bye bye” d’avant:

entrez la description de l'image ici

  1. Un coup de fusil de chasse:

entrez la description de l'image ici

  1. Une boîte à musique:

entrez la description de l'image ici

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:

entrez la description de l'image ici

 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.