想要的效果

如上是silverlight版本。原理是设定一个调色板,为256的渐变色(存在一个png文件中,宽度为256,高度为1),然后针对要处理的距离矩阵图形,取图片中每个像素的Alpha值作为索引,对应到调色板的颜色。每个像素处理之后,则形成上面的热度图。该图主要表达了一个数据分布的密度。

网络上有一个Gildor.HeatmapDemos工程,我主要参考了SL版本。要注意elipseRadius,如果过小,即每个圆彼此不相交,则看不到热度效果,所以代码设置初始值为100。(上图的数值初始化部分,对应代码如下)

private List<Point> plist = new List<Point>();
private void drawHeatMap ()
{
plist.Clear();
plist.Add(new Point(0.15*map.ActualWidth, 0.49*map.ActualHeight));
plist.Add(new Point(0.20 * map.ActualWidth, 0.25 * map.ActualHeight));
plist.Add(new Point(0.10 * map.ActualWidth, 0.15 * map.ActualHeight));
plist.Add(new Point(0.12 * map.ActualWidth, 0.05 * map.ActualHeight));
plist.Add(new Point(0.17 * map.ActualWidth, 0.34 * map.ActualHeight));
plist.Add(new Point(0.17 * map.ActualWidth, 0.33 * map.ActualHeight));
plist.Add(new Point(0.16 * map.ActualWidth, 0.33 * map.ActualHeight)); heatMap.Source = _heatMapGen.GenerateHeatMap (
plist,
new Size (map.ActualWidth, map.ActualHeight));
}

我需要在windows 8.1的RT版本中实现类似功能。

1、读取调色板文件

            Uri uri = new Uri("ms-appx:///assets/bookpage/Palette.bmp");
RandomAccessStreamReference streamRef = RandomAccessStreamReference.CreateFromUri(uri); using (IRandomAccessStreamWithContentType fileStream = await streamRef.OpenReadAsync())
{
BitmapDecoder decoder = await BitmapDecoder.CreateAsync(fileStream);
BitmapFrame frame = await decoder.GetFrameAsync(); PixelDataProvider pixelProvider = await frame.GetPixelDataAsync();
this.palette = pixelProvider.DetachPixelData();
}

2、把UIElement转换为图形

Windows 8.1之前,没有RenderTargetBitmap类。最开始我采用了codeplex上的WriteableBitmapExtensions类,后来发现8.1中已经增加了这个类。

            RenderTargetBitmap renderTargetBitmap = new RenderTargetBitmap();
await renderTargetBitmap.RenderAsync(canvasSpitList);//, (int)pdfBorder.Width, (int)pdfBorder.Height);

第二行就会把UIElement及所有子element写入到bitmap中。

关于RenderTargetBitmap有无数坑,msdn如下:

There are a few scenarios for XAML-composed visual content that you can't capture to a RenderTargetBitmap:

  • Video content in a MediaElement or CaptureElement can't be captured using RenderTargetBitmap. That includes capturing      frames from within video content.
  • Custom DirectX content (your      own swap chain) inside a SwapChainBackgroundPanel or SwapChainPanel can't be captured using RenderTargetBitmap.
  • Content that's in the tree but      with its Visibility set to Collapsed won't be captured.
  • Content that's not directly      connected to the XAML visual tree and the content of the main window won't      be captured. This includes Popup content, which is considered      to be like a sub-window.

Note  Windows Phone: The contents of a WebView control can't be rendered into a RenderTargetBitmap.

  • Content that can't be captured      will appear as blank in the captured image, but other content in the same      visual tree can still be captured and will render (the presence of content      that can't be captured won't invalidate the entire capture of that XAML composition).
  • Content that's in the XAML      visual tree but offscreen can be captured, so long as it's not Visibility=Collapsed or in the other restricted      cases.

From <https://msdn.microsoft.com/en-us/library/windows/apps/windows.ui.xaml.media.imaging.rendertargetbitmap.aspx>

3、RadialGradientBrush在Windows RT 8.1中没有!只有LinearGradientBrush。MSDN说法这里

GradientBrush is the parent class for LinearGradientBrush. The Windows Runtime XAML vocabulary doesn't support RadialGradientBrush.

From <https://msdn.microsoft.com/en-us/library/windows/apps/windows.ui.xaml.media.gradientbrush.aspx>

我在SL中用Linear模式画的图如下:

4、读取要处理图形的每个像素

int width = renderTargetBitmap.PixelWidth;
int height = renderTargetBitmap.PixelHeight; var buf = await renderTargetBitmap.GetPixelsAsync(); var stream = buf.AsStream();
byte[] srcPixels = new byte[stream.Length];
stream.Read(srcPixels, , (int)stream.Length);

舍弃R/G/B值,只保留A,然后读取对应的调色板颜色,进行替换。

var dstPixels = new byte[ * width * height];

            for (int i = ; i < srcPixels.Length; i += )
{
//int pixelIndex = ((srcPixels[i + 3] << 24) + (srcPixels[i + 2] << 16) + (srcPixels[i + 1] << 8) + (srcPixels[i + 0]));
byte pixelIndex = srcPixels[i + ];//只取Alpha通道的值 if ((srcPixels[i + ] == ) && (srcPixels[i + ] == ) && (srcPixels[i + ] == ) && (srcPixels[i + ] == )) continue; //winform中,pixelProvider.DetachPixelData,颜色顺序从低到高字节为:A,R,G,B,包括开始的palette取到的也是A,R,G,B
//metro中,renderTargetBitmap.GetPixelsAsync,颜色顺序从低到高字节为:B,G,R,A
dstPixels[i + ] = this.palette[(byte)(~( * pixelIndex + ))];//B<->A
dstPixels[i + ] = this.palette[(byte)(~( * pixelIndex + ))];//G<->R
dstPixels[i + ] = this.palette[(byte)(~( * pixelIndex + ))];//R<->G
dstPixels[i + ] = this.palette[(byte)(~( * pixelIndex + ))];//A<->B
} var bmp = new WriteableBitmap(width, height);//(container, null);
WriteableBitmapExtensions.FromByteArray(bmp, dstPixels);

5、悲催的地方
通过上面第二部分读到的像素值,是A/R/G/B顺序,用winform读取,也是一样的结果

private void button1_Click(object sender, EventArgs e)
{
StringBuilder sb = new StringBuilder(); using (Bitmap bmp = new Bitmap(@"c:\1.png"))
{
using (Graphics g = this.CreateGraphics())
{
for (int i = ; i < ; i++)
{
var col = bmp.GetPixel(i, );
sb.AppendFormat("{0:X8},", col.ToArgb()); using (SolidBrush brush = new System.Drawing.SolidBrush(col))
{
g.FillRectangle(brush, new Rectangle( * i, , , ));
}
}
}
} MessageBox.Show(sb.ToString());
}

得到的像素顺序:

比如第一个亮黄颜色,在这里与palette部分读到都是A/R/G/B顺序,但是在上面第4部分,读到的确是B/G/R/A部分。所以第4部分中,对像素颜色进行了对调。

但是,得到的是这么一个悲催的图像:

颜色不对!热度效果也没有!

求指点,请帮助!

-------------------------------------------------------

6、仔细检查了一下,第2部分的palette取到的是R/G/B/A顺序,所以第4部分的调色板代码修改如下:

                //winform中,颜色顺序从低到高字节为:A,R,G,B
//palette中,pixelProvider.DetachPixelData取到的却是R,G,B,A
//metro中,renderTargetBitmap.GetPixelsAsync,颜色顺序从低到高字节为:B,G,R,A
dstPixels[i + ] = this.palette[(byte)(( * pixelIndex + ))];//B<->A
dstPixels[i + ] = this.palette[(byte)(( * pixelIndex + ))];//G<->R
dstPixels[i + ] = this.palette[(byte)(( * pixelIndex + ))];//R<->G
dstPixels[i + ] = this.palette[(byte)(( * pixelIndex + ))];//A<->B

但是热度效果依然不对,难道是因为LinearGradientBrush缘故?

Windows8.1画热度图 - 坑的更多相关文章

  1. seaborn用heatmap画热度图

    原文链接 https://blog.csdn.net/m0_38103546/article/details/79935671

  2. 利用opencv作透明重叠人群密度热度图

    在作热度图的时候我们经常需要将热度图调整透明度后叠加在原图上达到更好的展示效果.比如检测人气密度的热度图: (来自sensetime) 一般作图的时候会第一时间想到matplotlib,因为可以很方便 ...

  3. 如何使用excel画甘特图

    甘特图小伙伴们都非常的熟悉,首先小编简单的向各位小伙伴介绍一下什么是甘特图,甘特图内在思想简单,即以图示的方式通过活动列表和时间刻度形象地表示出任何特定项目的活动顺序与持续时间.基本是一条线条图,横轴 ...

  4. 使用Mysql Workbench 画E-R图

    MySQL Workbench 是一款专为MySQL设计的ER/数据库建模工具.你可以用MySQL Workbench设计和创建新的数据库图示,建立数据库文档,以及进行复杂的MySQL 迁移.这里介绍 ...

  5. 用rose画UML图(用例图,活动图)

    用rose画UML图(用例图,活动图) 首先,安装rose2003,电脑从win8升到win10以后,发现win10并不支持rose2003的安装,换了rose2007以后,发现也不可以. 解决途径: ...

  6. python中matplotlib画折线图实例(坐标轴数字、字符串混搭及标题中文显示)

    最近在用python中的matplotlib画折线图,遇到了坐标轴 "数字+刻度" 混合显示.标题中文显示.批量处理等诸多问题.通过学习解决了,来记录下.如有错误或不足之处,望请指 ...

  7. 相机拍的图,电脑上画的图,word里的文字,电脑屏幕,手机屏幕,相机屏幕显示大小一切的一切都搞明白了!

    相机拍的图,电脑上画的图,word里的文字,电脑屏幕,手机屏幕,相机屏幕显示大小一切的一切都搞明白了! 先说图片X×dpi=点数dotX是图片实际尺寸,简单点,我们只算图片的高吧,比如说拍了张图片14 ...

  8. SAS 画折线图PROC GPLOT

    虽然最后做成PPT里的图表会被要求用EXCEL画,但当我们只是在分析的过程中,想看看数据的走势,直接在SAS里画会比EXCEL画便捷的多. 修改起来也会更加的简单,,不用不断的修改程序然后刷新EXCE ...

  9. 使用网站websequencediagrams在线画时序图

    在线画时序图的网站:https://www.websequencediagrams.com/ 该网站提供拖拉图形和编写脚本代码2个方式来制作时序图,同时提供多种显示风格. 实例: 1.脚本代码: ti ...

随机推荐

  1. SQL server基础知识(表操作、数据约束、多表链接查询)

    SQL server基础知识 一.基础知识 (1).存储结构:数据库->表->数据 (2).管理数据库 增加:create database 数据库名称 删除:drop database ...

  2. 说下查询动作 Pivot

    上一篇说了一下查询5步走~然后就几天_(:з」∠)_ ~今天继续说一下其中 表里面操作符里面的 Pivot ~ Pivot 在实现行转列的时候灰常有用.通常一个例子 ), ),LoginTime TI ...

  3. 如何在centos上安装epel源

    一.EPEL是什么? EPEL (Extra Packages for Enterprise Linux,企业版Linux的额外软件包) 是Fedora小组维护的一个软件仓库项目,为RHEL/Cent ...

  4. /usr/include/sys/types.h:62: error: conflicting types for ‘dev_t’

    /usr/include/sys/types.h:62: error: conflicting types for ‘dev_t’/usr/include/linux/types.h:13: erro ...

  5. HADOOP HDFS的设计

    Hadoop提供的对其HDFS上的数据的处理方式,有以下几种, 1 批处理,mapreduce 2 实时处理:apache storm, spark streaming , ibm streams 3 ...

  6. [转]ASP.NET 成员资格 Part.1(API)

    本文转自:http://www.cnblogs.com/SkySoot/archive/2013/04/08/3008418.html 表单验证解决了 ASP.NET 应用程序页面验证的问题,但另一方 ...

  7. 使用ajaxfileupload.js上传文件

    一直以来上传文件都是使用form表单上传文件,也看到过有人使用js上传文件,不过看起来蛮简单的也就没有怎么去理会.今天突然要使用这种方式上传文件,期间还遇到点问题.因此就记录下来,方便以后遇到这样的问 ...

  8. RCC BUCK变压器设计

    RCC电路工作于临界模式,不是固定工作频率,其设计遵从BUCK原理.Buck电路在最高输入电压时为电感最恶劣工作条件: 以下图为例: 1.首先设定如下参数:输入电压Vin,输出电压Iout,工作频率f ...

  9. POJ2230Watchcow[欧拉回路]

    Watchcow Time Limit: 3000MS   Memory Limit: 65536K Total Submissions: 7512   Accepted: 3290   Specia ...

  10. BZOJ1029: [JSOI2007]建筑抢修[模拟 贪心 优先队列]

    1029: [JSOI2007]建筑抢修 Time Limit: 4 Sec  Memory Limit: 162 MBSubmit: 3785  Solved: 1747[Submit][Statu ...