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; }
}
}