一、前文
前文可以参考我的前一篇博文:C# .Net实现简易灰度图和酷炫HeatMap热力图winform
但是,先前的热力图效果,我并不满意。不满意的地方主要有三点:
- 热力图的颜色是通过一个调色板图片来实现,如果想要其他颜色,改起来比较麻烦
- 热力图的扩散效果不好看,不够渐进
- 热力图的每个点大小都一致,应该是大小不一才对
因此,我做了改进,上一个图是之前的效果,下一个图是改进后的效果
二、渐进颜色调色板
public Bitmap Colorize(Bitmap mask)
{
//创建新的位图,为上色做准备
Bitmap output = new Bitmap(mask.Width, mask.Height, System.Drawing.Imaging.PixelFormat.Format32bppArgb);
//同理,从Bitmap获得Graphics GDI+ 绘图图面
Graphics graphics = Graphics.FromImage(output);
//清除整个绘图面并以透明填充
graphics.Clear(System.Drawing.Color.Transparent);
// 构建一组颜色映射以将我们的灰度蒙版重新映射为全色
ColorMap[] colorMaps = CreatePalette();
// 创建新的图像属性类来处理颜色重新映射
// 注入我们的颜色映射数组来指示图像属性类如何进行着色
ImageAttributes Remapper = new ImageAttributes();
Remapper.SetRemapTable(colorMaps);
// 使用新的颜色映射方案将我们的蒙版绘制到我们的内存位图工作表面上
graphics.DrawImage(mask, new System.Drawing.Rectangle(0, 0, mask.Width, mask.Height), 0, 0, mask.Width, mask.Height, GraphicsUnit.Pixel, Remapper);
return output;
}
//创建调色板,颜色映射
private ColorMap[] CreatePalette()
{
ColorMap[] colorMaps = new ColorMap[256];
List<Color> newColors = new List<Color>();
//颜色集合
newColors.AddRange(GetGradientColorList(Color.Red, Color.Yellow, 64));
newColors.AddRange(GetGradientColorList(Color.Yellow, Color.Green, 64));
newColors.AddRange(GetGradientColorList(Color.Green, Color.Blue, 64));
newColors.AddRange(GetGradientColorList(Color.Blue, Color.Navy, 64));
//颜色调色板展示
Bitmap colorBitmap = new Bitmap(colorPanel.Width, colorPanel.Height);
Graphics graphic = Graphics.FromImage(colorBitmap);
for (int i = 0; i < 256; i++)
{
SolidBrush solidBrush = new SolidBrush(newColors[i]);
Rectangle rectangle = new Rectangle((int)(i * 2), 0, (int)2, colorPanel.Height);
graphic.FillRectangle(solidBrush, rectangle);
graphic.Save();
solidBrush.Dispose();
}
colorPanel.BackgroundImage = colorBitmap;
// 遍历每个像素并创建一个新的颜色映射
for (int X = 0; X <= 255; X++)
{
colorMaps[X] = new ColorMap();
colorMaps[X].OldColor = System.Drawing.Color.FromArgb(X, X, X);
colorMaps[X].NewColor = System.Drawing.Color.FromArgb(255, newColors[X]);
}
return colorMaps;
}
/// <summary>
/// 获得两个颜色之间渐进颜色的集合
/// </summary>
/// <param name="sourceColor">起始颜色</param>
/// <param name="destColor">终止颜色</param>
/// <param name="count">渐进颜色的个数</param>
/// <returns>返回颜色集合</returns>
public static List<Color> GetGradientColorList(Color srcColor, Color desColor, int count)
{
List<Color> colorFactorList = new List<Color>();
int redSpan = desColor.R - srcColor.R;
int greenSpan = desColor.G - srcColor.G;
int blueSpan = desColor.B - srcColor.B;
for (int i = 0; i < count; i++)
{
Color color = Color.FromArgb(
srcColor.R + (int)((double)i / count * redSpan),
srcColor.G + (int)((double)i / count * greenSpan),
srcColor.B + (int)((double)i / count * blueSpan)
);
colorFactorList.Add(color);
}
return colorFactorList;
}
三、热力点大小和扩展大小
private void DrawHeatPoint2(Graphics graphics, HeatPoint heatPoint)
{
Console.WriteLine("heatPoint.Intensity = " + heatPoint.Intensity);
int radius = 40 * (heatPoint.Intensity+6) / 240;
List<System.Drawing.Point> pointsList = new List<System.Drawing.Point>();
for (double degrees = 0; degrees <= 360; degrees += 10)
{
// 在定义半径的圆的圆周上绘制新点
// 使用点坐标、半径和角度
// 计算这个迭代点在圆上的位置
System.Drawing.Point point = new System.Drawing.Point();
point.X = Convert.ToInt32(heatPoint.X + radius * Math.Cos((Math.PI / 180) * degrees));
point.Y = Convert.ToInt32(heatPoint.Y + radius * Math.Sin((Math.PI / 180) * degrees));
pointsList.Add(point);
}
// 创建新的颜色混合来告诉 PathGradientBrush 使用什么颜色以及放置它们的位置
ColorBlend colorBlend = new ColorBlend(3);
colorBlend.Positions = new float[3] { 0, 0.8f, 1 };
colorBlend.Colors = new System.Drawing.Color[3]
{
System.Drawing.Color.FromArgb(0, System.Drawing.Color.White),
System.Drawing.Color.FromArgb(heatPoint.Intensity, System.Drawing.Color.Black),
System.Drawing.Color.FromArgb(heatPoint.Intensity, System.Drawing.Color.Black)
};
// 创建新的 PathGradientBrush 以使用圆周点创建径向渐变
PathGradientBrush brush = new PathGradientBrush(pointsList.ToArray());
// 将颜色混合传递给 PathGradientBrush 以指示它如何生成渐变
brush.InterpolationColors = colorBlend;
graphics.FillPolygon(brush, pointsList.ToArray());
//brush.Dispose();
}
四、更新视图
private void UpdateView()
{
//灰度
Bitmap bitmap1 = CreateIntensityMask(new Bitmap((int)panel1.Width, (int)panel1.Height, System.Drawing.Imaging.PixelFormat.Format32bppArgb), heatPoints, 1);
panel1.BackgroundImage = bitmap1;
//上色
panel3.BackgroundImage = Colorize(bitmap1);
}
private Bitmap CreateIntensityMask(Bitmap bitmap, List<HeatPoint> aHeatPoints)
{
//从Bitmap获得Graphics GDI+ 绘图图面
Graphics graphics = Graphics.FromImage(bitmap);
//清除整个绘图面并以白色填充
graphics.Clear(System.Drawing.Color.White);
foreach (HeatPoint point in aHeatPoints)
{
DrawHeatPoint2(graphics, point);
}
return bitmap;
}
觉得好,就一键三连呗(点赞+收藏+关注)