スペクトログラム - peace098beat/windows_applicaciton GitHub Wiki

スペクトログラム

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Drawing;
using System.Data;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;

namespace golfApp1
{
    public partial class Spectrogram : UserControl
    {
        // スペクトログラムのBitmapばっふぁ 
        Bitmap bitmap_buffer = null;

        // ヘアーライン用のイベント
        public event EventHandler CursorMoved;

        // ヘアーライン
        int mouse_x = 0;
        int mouse_y = 0;

        public Spectrogram()
        {
            InitializeComponent();
        }

        private void Spectrogram_Load(object _s, EventArgs _e)
        {
            pictureBox1.Capture = true;
            pictureBox1.MouseDown += (sender, e) => this.OnMouseDown(e);
            pictureBox1.MouseMove += (sender, e) => this.OnMouseMove(e);

        }

        /// <summary>
        /// プロットデータをセット
        /// </summary>
        public void  plot(List<double[]> listBuffer)
        {
            int height = 512;                                                   // 画像の高さを設定
            bitmap_buffer = new Bitmap(listBuffer.Count, height);

            var cmap = ColorMapMaker.Create(ColorMapMaker.FocusType.High);

            for (int k = 0; k < height; k++)
            {
                for (int j = 0; j < listBuffer.Count; j++)
                {
                    //色を決める
                    int index = listBuffer[j].Length * k / height;
                    //double pram = 2.0;                                         // 表示幅を決定する。3.0だと、中央値の1000倍~0.001倍までを表示させる。2.0だと100~0.01倍の範囲。
                    //var value = (Math.Log10(listBuffer[j][index] / max) + pram) / (pram * 2.0);
                    var value = listBuffer[j][index];

                    value = 10 * Math.Log10(value);
                    value += 120;
                    value /= 60;

                    if (value > 1.0) value = 1.0;
                    if (value < 0.0) value = 0.0;

                    //Console.WriteLine(value);
                    int cindex = (int)(255 * value);
                    Color c = cmap[cindex];

                    //Color c = cmap.GetColor(value);
                    //1つのピクセルの色を変える
                    bitmap_buffer.SetPixel(j, height - k - 1, c);
                }
            }

            //補間方法を指定して画像を縮小して描画する

            this.Refresh();
        }

        private void Spectrogram_Paint(object sender, PaintEventArgs e)
        {

        }

        private void Spectrogram_Resize(object sender, EventArgs e)
        {

        }


        private void pictureBox1_Paint(object sender, PaintEventArgs e)
        {

            if (bitmap_buffer == null) return;


            // Graphicsオブジェクトを作成する
            var g = e.Graphics;

            //補間方法として最近傍補間を指定する
            g.InterpolationMode = System.Drawing.Drawing2D.InterpolationMode.NearestNeighbor;
            ////補間方法として高品質双三次補間を指定する
            g.InterpolationMode = System.Drawing.Drawing2D.InterpolationMode.HighQualityBicubic;

            //画像を縮小して描画する
            g.DrawImage(bitmap_buffer, 0, 0, pictureBox1.Width, pictureBox1.Height);

            g.DrawLine(new Pen(Color.White), new Point(mouse_x, 0), new Point(mouse_x, pictureBox1.Height));
            g.DrawLine(new Pen(Color.White), new Point(0, mouse_y), new Point(pictureBox1.Width, mouse_y));
        }

        private void pictureBox1_MouseMove(object sender, MouseEventArgs e)
        {

            mouse_x = e.X;
            mouse_y = e.Y;
            this.Refresh();
        }

        private void pictureBox1_Click(object sender, EventArgs e)
        {

        }
    }
}

カラーマップ

using System;
using System.Collections.Generic;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace golfApp1
{
    class ColorPallete
    {
    }

    /// <summary>
    /// カラーマップを生成するクラス
    /// var cmap = ColorMapMaker.Create(ColorMapMaker.FocusType.High);
    /// i   nt cindex = (int)(255 * value);
    //// Color c = cmap[cindex];
    /// 
    /// </summary>
    public class ColorMapMaker
    {
        private const int MAX = 255;
        private const int LENGTH = 256;
        /// <summary>
        /// カラーマップ種別
        /// </summary>
        public enum FocusType
        {
            /// <summary>
            /// 通常
            /// </summary>
            None,
            /// <summary>
            /// 低温域強調
            /// </summary>
            Low,
            /// <summary>
            /// 中温域強調
            /// </summary>
            Mid,
            /// <summary>
            /// 高温域強調
            /// </summary>
            High
        }
        /// <summary>
        /// 256階調のカラーマップを1つ生成する
        /// </summary>
        /// <param name="focusType">種別</param>
        /// <returns></returns>
        public static Color[] Create(FocusType focusType)
        {
            var ret = new Color[LENGTH];
            var pts = IPoints(focusType);
            int i1 = pts[1];
            int i2 = pts[2];
            int i3 = pts[3];
            int i4 = pts[4];
            int i5 = pts[5];
            for (int i = 0; i < LENGTH; i++)
            {
                // 6段階に分けて計算する
                int r = 0;
                int g = 0;
                int b = 0;
                if (i < i1)
                {
                    b = Increase(i, 0, i1);
                }
                else if (i < i2)
                {
                    b = MAX;
                    g = Increase(i, i1, i2);
                }
                else if (i < i3)
                {
                    r = Increase(i, i2, i4);
                    b = Decrease(i, i2, i4);
                    g = MAX;
                }
                else if (i < i4)
                {
                    g = MAX;
                    r = Increase(i, i2, i4);
                    b = Decrease(i, i2, i4);
                }
                else if (i < i5)
                {
                    r = MAX;
                    g = Decrease(i, i4, i5);
                }
                else
                {
                    r = MAX;
                    g = Increase(i, i5, LENGTH);
                    b = Increase(i, i5, LENGTH);
                }
                // Debug.WriteLine("r=" + r + "/g=" + g + "/b=" + b);
                ret[i] = Color.FromArgb(r, g, b);
            }
            return ret;
        }
        /// <summary>
        /// i1~i5を返す
        /// </summary>
        /// <param name="focusType"></param>
        /// <returns></returns>
        private static int[] IPoints(FocusType focusType)
        {
            var ret = new int[6];
            ret[0] = 0;
            if (focusType == FocusType.None)
            {
                // まんべんなく
                var i1 = LENGTH / 6;
                ret[1] = i1;
                ret[2] = i1 * 2;
                ret[3] = i1 * 3;
                ret[4] = i1 * 4;
                ret[5] = i1 * 5;
            }
            else if (focusType == FocusType.Low)
            {
                // 低い方を強調
                var i1 = LENGTH / 12;
                ret[1] = i1 * 2;
                ret[2] = i1 * 3;
                ret[3] = i1 * 4;
                ret[4] = i1 * 6;
                ret[5] = i1 * 9;
            }
            else if (focusType == FocusType.Mid)
            {
                // 真ん中を強調
                var i1 = LENGTH / 12;
                ret[1] = i1 * 3;
                ret[2] = i1 * 5;
                ret[3] = i1 * 6;
                ret[4] = i1 * 7;
                ret[5] = i1 * 9;
            }
            else if (focusType == FocusType.High)
            {
                var i1 = LENGTH / 12;
                ret[1] = i1 * 4;
                ret[2] = i1 * 7;
                ret[3] = i1 * 8;
                ret[4] = i1 * 9;
                ret[5] = i1 * 10;
            }
            return ret;
        }


        /// <summary>
        /// 上り
        /// </summary>
        /// <param name="x"></param>
        /// <param name="x1"></param>
        /// <param name="x2"></param>
        /// <returns></returns>
        private static int Increase(int x, int x1, int x2)
        {
            double y = (Math.Cos(Math.PI / (x2 - x1) * (x - x2)) + 1) * MAX / 2;
            if (y > MAX)
            {
                return MAX;
            }
            else if (y < 0)
            {
                return 0;
            }
            else
            {
                return (int)Math.Round(y);
            }
        }
        /// <summary>
        /// 下り
        /// </summary>
        /// <param name="x"></param>
        /// <param name="x1"></param>
        /// <param name="x2"></param>
        /// <returns></returns>
        private static int Decrease(int x, int x1, int x2)
        {
            double y = (Math.Cos(Math.PI / (x2 - x1) * (x - x1)) + 1) * MAX / 2;
            if (y > MAX)
            {
                return MAX;
            }
            else if (y < 0)
            {
                return 0;
            }
            else
            {
                return (int)Math.Round(y);
            }
        }
    }// ColorMapMaker
}

スペクトラム

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Drawing;
using System.Data;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;

namespace golfApp1
{
    public partial class Spectrum : UserControl
    {

        List<PlotData> plotdatas = new List<PlotData>(20);
        List<Color> m_Colors = new List<Color>(20);

        // 設定
        double XMIN { set; get; }
        double XMAX { set; get; }
        double YMIN { set; get; }
        double YMAX { set; get; }

        int divx = 12;
        int divy = 12;

        int tick_x = 6;
        int tick_y = 6;

        string title { set; get; }
        string xlabel { set; get; }
        string ylabel { set; get; }

        int mouse_x = 0;
        int mouse_y = 0;


        public Spectrum()
        {
            InitializeComponent();

            pictureBox1.Capture = true;
        }

        private void Spectrum_Load(object sender, EventArgs e)
        {
            XMIN = 0;
            XMAX = 10000;
            YMIN = -120;
            YMAX = 0;
            xlabel = "Frequency[Hz]";
            ylabel = "PSD[-]";
            title = "Spectrum";

            BackColor = Color.FromArgb(255, 25, 25, 25); // 背景

            pictureBox1.BackColor = Color.FromArgb(255, 0, 0, 0);

            m_Colors.Clear();
            for (int i = 0; i < 5; i++)
            {
                m_Colors.Add(Color.FromArgb(0x7Fd6c200));
                m_Colors.Add(Color.FromArgb(0x7F48c704));
                m_Colors.Add(Color.FromArgb(0x7F2b6fd0));
                m_Colors.Add(Color.FromArgb(0x7Fe60000));
                m_Colors.Add(Color.FromArgb(0x7Fece7e7));
                m_Colors.Add(Color.FromArgb(0x7F8307e8));
            }
        }


        /// <summary>
        /// プロットするデータを追加
        /// </summary>
        /// <param name="plotdata"></param>
        public void plot(double[] pX, double[] pY)
        {

            double[] _px = new double[pY.Length];
            double[] _py = new double[pY.Length];

            if (repainting == false)
            {
                plotdatas.Clear();

                // nullの場合は0から整数で生成
                if (pX == null)
                {
                    // X軸を適当に生成
                    for (int i = 0; i < _px.Length; i++)
                    {
                        _px[i] = (double)i;
                    }

                    for (int i = 0; i < _py.Length; i++)
                    {
                        _py[i] = pY[i];
                    }
                }

                plotdatas.Add(new PlotData(_px, _py));

                this.Refresh();
            }

        }

        bool repainting = false;


        private void pictureBox1_Paint(object sender, PaintEventArgs e)
        {

            if (plotdatas == null) return;
            if (plotdatas.Count < 1) return;


            double[] X = plotdatas[0].X;
            double[] Y = plotdatas[0].Y;

            if (X == null) return;
            if (Y == null) return;

            repainting = true;
            int width = pictureBox1.Width;
            int height = pictureBox1.Height;

            int total = X.Length;

            //スキップ数の計算
            int skip = 1; // 初期値
            while ((double)total / (double)skip > width) skip++;
            // ひとつ大きいぐらい
            skip = skip - 1;

            // 描画するデータの長さ
            int plotdata_length = (int)((double)total / (double)skip);

            int[] Xs = new int[plotdata_length];
            int[] Ys = new int[plotdata_length];

            var g = e.Graphics;

            // 座標変換
            int viewport(double x, double x0, double x1, int X0, int X1)
            {
                return (int)((double)(x - x0) / (double)(x1 - x0) * (double)(X1 - X0));
            }

            XMIN = X.Min();
            XMAX = X.Max();
            YMIN = Y.Min();
            YMAX = Y.Max();



            if (XMIN >= XMAX)
            {
                MessageBox.Show("XMIN > XMAX");
                Console.Write("XMIN{0} > XMAX{1} \r\n", XMIN, XMAX);
            }

            if (YMIN >= YMAX)
            {
                MessageBox.Show("YMIN > YMAX");

                Console.Write("YMIN{0} > YMAX{1} \r\n", YMIN, YMAX);

                YMIN = -120;
                YMAX = 0;
            }

            YMIN = -120;
            YMAX = 0;

            Console.Write("(YMIN,YMAX = {0},{1})", YMIN, YMAX);


            checked
            {
                // Y軸はMax値を描画
                for (int gi = 0; gi < plotdata_length; gi++)
                {

                    // 座標変換
                    Xs[gi] = viewport(X[gi * skip], XMIN, XMAX, 0, width);
                    Ys[gi] = height - viewport(Y[gi * skip], YMIN, YMAX, 0, height);

                    if (false)
                    {
                        // Max Pooling
                        double[] _ys = new double[skip];
                        for (int yi = 0; yi < skip; yi++)
                        {
                            if (gi * skip + yi < total) _ys[yi] = Y[(gi) * skip + yi];
                        }
                        double max = double.MinValue; //最大値検索
                        double fugou = 1;
                        for (int j = 0; j < skip; j++)
                        {
                            if (max < Math.Abs(_ys[j]))
                            {
                                max = Math.Abs(_ys[j]);
                                fugou = _ys[j] / Math.Abs(_ys[j]);
                            }
                        }
                        Ys[gi] = height - viewport(fugou * max, YMIN, YMAX, 0, height);
                    }

                }

            }


            Pen p = new Pen(m_Colors[0], 1.5f);

            for (int gi = 1; gi < plotdata_length; gi++)
            {
                g.DrawLine(p, (float)Xs[gi - 1], (float)Ys[gi - 1], (float)Xs[gi], (float)Ys[gi]); // 100ms
            }

            ////リソースを解放する
            p.Dispose();

            repainting = false;

        } // pictureBox1_Paint


    }


    // グラフプロット用のデータクラス
    public class PlotData
    {
        public PlotData(double[] X, double[] Y)
        {
            this.X = X;
            this.Y = Y;

            double XMIN = X.Min();
            double XMAX = X.Max();

            double XRANGE = XMAX - XMIN;

            double YMIN = Y.Min();
            double YMAX = Y.Max();

            double YRANGE = YMAX - YMIN;

            // 長さを判定して保管
            if (this.X.Length == this.Y.Length)
            {
                this.Length = X.Length;
            }
            else
            {
                MessageBox.Show("PlotData(X,Y) X" + X.Length.ToString() + "とY" + Y.Length.ToString() + "の長さが異なります.");
            }
        }

        public double[] X { set; get; }
        public double[] Y { set; get; }
        public int Length { set; get; }
    }
}
⚠️ **GitHub.com Fallback** ⚠️