スペクトログラム2 - peace098beat/windows_applicaciton GitHub Wiki
Fitibtコンターに使った用
using System;
using System.Collections.Generic;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
namespace FitBitvsMouseLogApp
{
public class Spectrogram : Panel
{
// スペクトログラムのBitmapばっふぁ
Bitmap bitmap_buffer = null;
// フォント
Font Font_s = new Font("Arial", 7);
Font Font_m = new Font("Arial", 9);
Font Font_l = new Font("Arial", 11);
TextFormatFlags FontAlignMid = TextFormatFlags.HorizontalCenter | TextFormatFlags.VerticalCenter; // センター寄オプション
TextFormatFlags FontAlignLeft = TextFormatFlags.Left | TextFormatFlags.VerticalCenter; // センター寄オプション
TextFormatFlags FontAlignRight = TextFormatFlags.Right | TextFormatFlags.VerticalCenter; // センター寄オプション
public Spectrogram()
{
this.SetStyle(ControlStyles.ResizeRedraw, true);
this.DoubleBuffered = true; // ダブルバッファリング: ちらつき防止
}
public List<double[]> ValueMatrix = null;
public double vMax = double.MinValue;
public double vMin = double.MaxValue;
/// <summary>
/// 描画するデータのセット
/// </summary>
/// <param name="ValueMatrix">描画する2テンソルデータ</param>
/// <param name="BmpHeight">描画するビットマップの高さ</param>
public void Plot(List<double[]> ValueMatrix, int BmpHeight = 512)
{
this.ValueMatrix = ValueMatrix;
this.ValueMatrix.Reverse();
int boxpix = 8;
int xWidth = 512; // 画像の高さを設定
int yWidth = ValueMatrix.Count;
int bmpWidth = xWidth;
int bmpHeight = yWidth * boxpix;
bitmap_buffer = new Bitmap(bmpWidth, bmpHeight);
// カラーマップ
var cmap = ColorMap.GenerateColorMapColors();
// 最大,最小
vMax = double.MinValue;
vMin = double.MaxValue;
double _vMin = double.MaxValue;
for (int i = 0; i < ValueMatrix.Count; i++)
{
for (int j = 0; j < ValueMatrix[i].Length; j++)
{
//ValueMatrix[i][j] = Math.Log(ValueMatrix[i][j]+1);
}
vMax = Math.Max(vMax, ValueMatrix[i].Max());
vMin = Math.Min(vMin, ValueMatrix[i].Min());
}
for (int yi = 0; yi < yWidth; yi++) //縦トレース
{
for (int xi = 0; xi < xWidth; xi++) // 横トレース
{
//色を決める
int xindex = (int)Math.Floor(ValueMatrix[yi].Length * ((double)xi / xWidth));
var value = ValueMatrix[yi][xindex];
//正規化
value = (value - vMin) / (vMax - vMin);
if (value > 1.0) value = 1.0;
if (value < 0.0) value = 0.0;
int cindex = (int)(255 * value);
Color c = cmap[cindex];
////1つのピクセルの色を変える
for (int i = 0; i < boxpix; i++)
{
bitmap_buffer.SetPixel(xi, (bmpHeight - 1) - (yi * boxpix + i), c);
}
bitmap_buffer.SetPixel(xi, (bmpHeight - 1) - (yi * boxpix + 0), Color.FromArgb(100, 100, 100, 100));
}
}
//補間方法を指定して画像を縮小して描画する
this.Refresh();
}
public List<DateTime> YDatetimeList = null;
public void SetYDateTime(List<DateTime> dList)
{
this.YDatetimeList = new List<DateTime>(dList);
this.YDatetimeList.Reverse();
this.Refresh();
}
protected override void OnResize(EventArgs eventargs)
{
base.OnResize(eventargs);
}
protected override void OnPaint(PaintEventArgs e)
{
base.OnPaint(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.InterpolationMode = System.Drawing.Drawing2D.InterpolationMode.Default;
//画像を縮小して描画する
g.DrawImage(bitmap_buffer, 0, 0, this.Width, this.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));
double x, y, xDiv, yDiv;
/*
* Y軸罫線
*/
if (YDatetimeList != null)
{
int yMaxCount = YDatetimeList.Count;
int Yskip = 10;
if (yMaxCount < 100) Yskip = 1;
else Yskip = 7;
for (int yi = 0; yi < yMaxCount; yi += Yskip) //縦トレース
{
//Rectangle RC_DateText = new Rectangle((int)(Width * 0.5), (int)((Height-1) - (double)(yi / yMaxCount) * Height), 200, 20);
yDiv = (double)Height / yMaxCount;
y = Height - (yi * yDiv) - yDiv;
Rectangle RC_DateText = new Rectangle((int)(Width * 0.0), (int)y, 200, 20);
string text = $"{YDatetimeList[yi].ToLongDateString()}:{YDatetimeList[yi].DayOfWeek.ToString()}";
TextRenderer.DrawText(g, text, Font_l, RC_DateText, Color.Black, FontAlignLeft);
}
}
/*
* X軸文字
*/
if (YDatetimeList != null)
{
int xMaxCout = 9;
for (int xi = 0; xi < xMaxCout; xi++)
{
xDiv = (double)Width / (xMaxCout - 1);
x = xi * xDiv;
y = (1 - 0.05) * Height;
Rectangle RC_DateText2 = new Rectangle((int)x, (int)y, 200, 20);
TextRenderer.DrawText(g, $"{3 * xi}時", Font_l, RC_DateText2, Color.Black, FontAlignLeft);
g.DrawLine(Pens.Gray, new Point((int)x, 0), new Point((int)x, Height));
}
}
/*
* 最大値vMax, 最小値vMin
*/
x = 0.8 * Width;
y = (1 - 0.05) * Height;
Rectangle RC_DateText3 = new Rectangle((int)x, (int)y, 200, 20);
TextRenderer.DrawText(g, $"Max:{(int)vMax}, Min:{(int)vMin}", Font_l, RC_DateText3, Color.Black, FontAlignLeft);
// END
}
}
}
using System;
using System.Collections.Generic;
using System.Drawing;
namespace FitBitvsMouseLogApp
{
public class ColorMap
{
/// <summary>
/// 100分率から256階調のカラーマップを生成
/// </summary>
/// <param name="in_value"></param>
/// <returns></returns>
public static int[] ColorScaleFloat2RGB3i(double in_value)
{
// 0.0~1.0 の範囲の値をサーモグラフィみたいな色にする
// 0.0 1.0
// 青 水 緑 黄 赤
// 最小値以下 = 青
// 最大値以上 = 赤
int[] ret;
int a = 255; // alpha値
int r, g, b; // RGB値
double value = in_value;
double tmp_val = Math.Cos(4 * Math.PI * value);
int col_val = (int)((-tmp_val / 2 + 0.5) * 255);
if (value >= (4.0 / 4.0)) { r = 255; g = 0; b = 0; } // 赤
else if (value >= (3.0 / 4.0)) { r = 255; g = col_val; b = 0; } // 黄~赤
else if (value >= (2.0 / 4.0)) { r = col_val; g = 255; b = 0; } // 緑~黄
else if (value >= (1.0 / 4.0)) { r = 0; g = 255; b = col_val; } // 水~緑
else if (value >= (0.0 / 4.0)) { r = 0; g = col_val; b = 255; } // 青~水
else { r = 0; g = 0; b = 255; } // 青
// int
ret = new int[3] { r, g, b };
return ret;
}
/// <summary>
/// 100分率から256階調のカラーマップを生成
/// </summary>
/// <param name="in_value"></param>
/// <returns></returns>
public static float[] ColorScaleFloat2RGB3f(double in_value)
{
// int
int[] RGB = ColorScaleFloat2RGB3i(in_value);
// int -> float
return new float[3] { (float)RGB[0] / 255.0f, (float)RGB[1] / 255.0f, (float)RGB[2] / 255.0f };
}
/// <summary>
/// 256階調のカラーマップを生成
/// </summary>
/// <returns></returns>
public static List<float[]> GenerateColorMap3f()
{
List<float[]> ColorMapf = new List<float[]>();
int N = 255;
double value;
for (int n = 0; n <= N; n++)
{
value = (double)n / N;
float[] Colorf = ColorMap.ColorScaleFloat2RGB3f(value);
ColorMapf.Add(Colorf);
}
if (ColorMapf.Count != 256) throw new ArgumentOutOfRangeException($"ColorMapf.Count:{ColorMapf.Count} != 256");
return ColorMapf;
}
/// <summary>
/// 256階調のカラーマップを生成
/// </summary>
/// <returns></returns>
public static List<int[]> GenerateColorMap3i()
{
List<int[]> ColorMapf = new List<int[]>();
int N = 255;
double value;
for (int n = 0; n <= N; n++)
{
value = (double)n / N;
int[] Color3i = ColorMap.ColorScaleFloat2RGB3i(value);
ColorMapf.Add(Color3i);
}
if (ColorMapf.Count != 256) throw new ArgumentOutOfRangeException($"ColorMapf.Count:{ColorMapf.Count} != 256");
return ColorMapf;
}
/// <summary>
/// 256階調のカラーマップを生成
/// </summary>
/// <returns></returns>
public static Color[] GenerateColorMapColors()
{
int N = 255;
Color[] ColorMapf = new Color[256];
double value;
for (int n = 0; n <= N; n++)
{
value = (double)n / N;
int[] Color3i = ColorMap.ColorScaleFloat2RGB3i(value);
ColorMapf[n] = Color.FromArgb(Color3i[0], Color3i[1], Color3i[2]);
}
if (ColorMapf.Length != 256) throw new ArgumentOutOfRangeException($"ColorMapf.Count:{ColorMapf.Length} != 256");
return ColorMapf;
}
}
}