我们要做什么呢?就是输入一个二维数组,

TestData = new double[9, 6] {{ 26,28,29,32,28,27},{ 27,30,32,35,30,28},{ 24,27,30,27,25,24},{ 22,20,25,28,26,23},{ 19,15,20,26,25,24},{ 17,18,23,27,26,22},{ 18,22,28,26,23,22},{ 18,18,23,22,22,19},{ 19,25,24,21,20,18}
};

然后输出类似下面的一个图:

其实云图跟等高线图有类似的地方,如果我们把图中的色彩减少,就会比较明显地看到线的轮廓:

绘制云图,其实最重要的就是插值问题。我们可以看到,原始的二维数组是9*6的,但我们显示的图片像素大致是600*500,甚至我们可能需要显示更大的图片。那除了9*6=54个点,其他的30万个点都是什么值呢?

为了简化问题,我们看下图:

我们假设全部格子就是图片的全部像素,而二维数组均匀地填在了某些位置。我们现在要做的,就是在空白区域填值。我们看格子A,它应该填什么值呢?有的人说,A直接根据10和12就能算出来。那我们不用考虑20和23对它的影响吗?假如二维数组代表了一些发热管的温度,那20和23肯定对A有影响。甚至,18、15这些点,对A都有影响。那么,我们现在就来看三种填值的算法。

算法一、点距离反比插值

这种算法比较适合绘制点源产生影响的云图。第一步,我们先把二维数组均匀地放到表格里面,正如上面的表格所示。我们把目前已经填上的数据称为定值。

然后我们看其他空白格子。平面上的任何一个点都受到了定值的影响,但肯定不是所有定值的影响都一样。我们很容易看出,距离越近,影响越大,距离越远,影响越小。一般我们认为,定值对点的影响,跟距离的平方成反比。那么,我们可以用下面的公式,求出每一个空白格子的值:

其中,Dij是点到每一个定值的距离平方的倒数,Vij是每一个定值。假设现在要求的点的坐标为(x,y),我们的二维数组是data(M,N),那么,上面的公式用代码写就是:

double SumD = 0;
double SumDV = 0;
for (int i = 0; i < M; i++)
{for (int j = 0; j < N; j++){double D = 1 / (Math.Pow(i - x, 2) + Math.Pow(j - y, 2));SumD += D;SumDV += D * data[i, j];}
}
double value = SumDV / SumD;

上面的代码求出了一个点的值,我们可以看到,如果是9*6的二维数组,它一共循环了54次。然后总共是30万个点,那么总共要循环1620万次,而且每一次循环都有三个乘法和一个除法。

如果写到这里就运行程序的话,你必定会发现,这个算法很慢!

于是,我做了几个方面的优化:

(1)其实我们没必要计算所有定值对点的影响,远一些的定值,其影响微乎其微,可以忽略。所以,我先求出跟点最近的定值,然后计算周围3*3=9个定值对它的影响。

(2)我们可以减少循环里面的乘法次数。我们知道,第1个点到第3个点,和第3个点到第5个点,它们的距离是一样的。也就是说,计算它们距离的时候,必定会重复计算2的平方。其实我们可以用查表法代替乘法。假设我们的图形是600*500,我们可以建一个长600的数组,然后把0-599的平方都放进去。那么array[i]就代表了i的平方。寻址比乘法要快得多。

经过上面两个方法的优化,程序运行时间勉强可以接受。

下面是算法一的结果图:

使用算法一,比较明显的特点是原数组点比较突出。所以在目标源是点的场合,比较适用。另外,由于采用了优化方法一,我们可以看到图中有一些边界。暂时还没有很好的解决办法。

算法二、双线性插值

双线性插值是一种比较常见的图片放大算法。读者可以直接到百度搜索,查看它的详细原理,本文就不介绍了。

在应用上,我们每一步跟算法一是一致的,就是把二维数组均匀地放到表格里面。然后其他空白值,使用定值去插值。

如图所示:

V1、V2、V3、V4都是定值,而P是空白格子,根据上面的信息,我们在纸上面演算一下,很快就能得出公式,具体的代码是:

private double DoubleLinear(int m, int n, int X, int Y, double V1, double V2, double V3, double V4)
{return (m * n * (V3 - V4 - V2 + V1) + X * n * (V4 - V1) + m * Y * (V2 - V1)) / (X * Y) + V1;
}

这就是P点的值。可以看到,每一个点,并不需要循环得出,所以我们只要30万次循环就能求出所有点的值(看上去好像挺多,但跟1620万比,已是两个数量级),时间上来说还是比较快的。

我们来看看算法二得出的结果:

可以看到,形状跟算法一基本一致,但很明显有一些十字交叉的图形。这一般来说并不是我们希望看到的。而且,算法二只考虑了一个点跟它周围四个定值的关系,完全忽略了其他定值的影响。

算法三、面距离反比+双线性插值

这是最复杂的一个算法,也是个人觉得效果最好的一个算法。可以看到,上面两种算法,都是把二维数组的数据作为点来看待的。但其实有的时候,二维数组的数据代表了一个区域的平均值。也就是说,原始的数据,看起来应该是这样的:

然后我们需要做的,就是对这个图进行平滑处理。

首先,我们用到算法一的方法。只是对于每一个点,我们不再借助54个定值求值了,我们用的,是整个图的数据。那么,你不用写代码,就应该意识到,每一个点的值,都要循环30万次求出来,然后,总共有30万个点要求,30万*30万……这个数我都不打算写出来了,打开程序算个几天都算不出来。

那怎么办!

我想到的办法是,原始数组不要扩大到600*500,而是先扩大几倍,例如说4倍,也就是说扩大到一个36*24的尺寸。但这样的尺寸实在太小,我们没办法实用啊!

(这是扩大6倍的图,4倍实在看不清)

但我们可以发现,上面的图除了比较小,基本轮廓是很不错的。我们再对这个图进行双线性插值不就行了吗!

我们根据需要展示的图尺寸确定XY各要增大的倍数,然后使用双线性插值,得到的结果如下:

使用此算法有一点需要注意,就是做面距离反比之后,表格里面可能一个原来数组的数都没有,而且范围变了。例如原来数组是15-35的数,做完面距离反比之后,可能表格里数据的范围是18-31。必须对数组进行扩展,然后再进行双线性插值。

三种算法的性能比较

三种算法使用的时间如下表所示:

算法一、点距离反比插值 1864ms
算法二、双线性插值 18ms
算法三、面距离反比+双线性插值 35ms

可以看到,即使经过优化,算法一还是最耗时间。虽然算法二最快,但实用性不大。

数据渲染方法

我们可以看到,经过上面三种算法的插值计算之后,得到的无非是一个跟图形相同尺寸的二维数组,怎么把这个二维数组用颜色表示出来,变成云图呢?

其实方法很简单。我们先确定一个颜色列表,例如是#FA1207,#FAAD07,#ECFA07,#07FAA7,#07C4FA,#072FFA。这里六种颜色肯定不够用的,我们需要插值。对,颜色也要插值。可以按RGB分别计算。例如第一个颜色的G是0x12,第二个颜色G是0xAD,如果中间要插5个值,那每个值的增量就是(0xAD-0x12)/(5+1)了。

经过插值,我们可能得到一个有上百种颜色的列表。然后数组里的值需要跟这些颜色对应起来。我们可以求出数组的最小最大值,然后划分为跟颜色列表相同的数量,就能得到一个数据增量。借助此增量,可以算出每个值对应的颜色。

好,绘制云图的方法介绍到这里。源码下载

绘制云图的三种算法(附C#代码)相关推荐

  1. 三位数最大公约数c语言,C语言求最小公倍数和最大公约数三种算法(经典)(示例代码)...

    把以前写的一些经验总结汇个总,方便给未来的学弟学妹们做个参考! --------------------------永远爱你们的:Sakura 最小公倍数:数论中的一种概念,两个整数公有的倍数成为他们 ...

  2. LCA 朴素算法+树差分倍增+Tarjan算法 三种算法实现c++代码实现

    哔哩哔哩up视频:https://www.bilibili.com/video/BV1nE411L7rz?t=379 转载:http 文章目录 树差分 & 倍增LCA Tarjan 朴素算法 ...

  3. 【雷达】基于RD、RMA、CS三种算法实现雷达成像附matlab代码

    1 简介 基于RD.RMA.CS三种算法实现雷达成像matlab代码​ 2 完整代码 %Chirp Scaling二维成像仿真. %抛物面聚焦,条带测绘,正侧视工作方式. 匹配滤波.%目标为3个散射点 ...

  4. 最短路小结(三种算法+各种常见变种)

    额,博主只是做了几(约数)道题而已,写这篇小结纯粹想留作纪念(勿喷,但是可以交流)(那啥,转载的话注明一下来源..打字不容易..) 最短路呢,包括三种算法,但是各有各的变种,其中变化有很多. 简单记录 ...

  5. 爱因斯坦谜题解答(三种算法比较)

    爱因斯坦谜题:     在一条街上有颜色互不相同的五栋房子,不同国籍的人分别住在这五栋房子力,每人抽不同品牌的香烟,喝不同的饮料,养不同的宠物.已知如下情况: 1.  英国人住红色房子里. 2.  瑞 ...

  6. EL之DTRFGBT:基于三种算法(DT、RF、GBT)对泰坦尼克号乘客数据集进行二分类(是否获救)预测并对比各自性能

    EL之DT&RF&GBT:基于三种算法(DT.RF.GBT)对泰坦尼克号乘客数据集进行二分类(是否获救)预测并对比各自性能 目录 输出结果 ​设计思路 核心代码 输出结果 设计思路 核 ...

  7. pyecharts学习(part1)--绘制图表的三种方式

    学习笔记,仅供参考,有错必究 文章目录 pyecharts学习 绘制图表的三种方式 绘制的图表生成HTML jupyter notebook 内嵌展示 pyecharts生成图片 pyecharts学 ...

  8. java 求最大公因数_求最大公约数的三种算法(java实现)

    三种算法: //欧几里得算法(辗转相除): public static int gcd(int m,int n) { if(m int k=m; m=n; n=k; } //if(m%n!=0) { ...

  9. SQL Server 索引基础知识(10)----Join 时的三种算法简介

    我们书写查询语句的时候,Join 参数之前可以是下面三个 { LOOP | MERGE | HASH } JOIN  . 如果不使用,则系统自己分析那种方式快,使用那种方式. 这其实是SQL Serv ...

最新文章

  1. Ubuntu 14.04安装搜狗拼音linux版应该注意的问题
  2. 2020图灵年度好书大赏 | 15周年视频纪念版
  3. Redis:常见的面试题
  4. [转]FFT倒序算法—雷德算法
  5. linux下运行hadoop,Linux环境下hadoop运行平台的搭建
  6. 【BUG记录】Matisse显示的图片乱序或者在全部项不显示
  7. c语言构造数据类型有,《c语言程序设计基础7构造数据类型.ppt
  8. this和static
  9. 手持移动扫描终端 PDA移动开单系统-批发零售管理
  10. php 返回script,从PHP脚本返回JSON
  11. JAVA中的isMirror函数_Swift中的反射Mirror
  12. 计算电磁学及其在复杂电磁环境数值模拟中的应用和发展趋势
  13. MSDN中文版 - MSDN中文版 - 微软官方MSDN原版资源下载平台
  14. iOS App 性能优化总结
  15. 2017阿里巴巴校招在线笔试——货架格子编号
  16. 广告roi怎么计算公式_【图】- 什么是ROI?ROI计算公式?ROI的影响因素 - 杭州江干九堡广告媒体 - 杭州百姓网...
  17. Cobble Web 页面操作记录
  18. 物联网产业前景看涨然5大挑战在眼前
  19. 巴厘岛7天6晚实用型游记
  20. 天才小毒妃 第912章 坑了一大笔

热门文章

  1. MFC中的Resource.h文件理解
  2. Parallel Platform (Stewart Platform) 类型机械臂的正逆解 01
  3. Vue3 高级语法以及自定义组件
  4. 绝对连续的一个等价定义
  5. java安卓字体_Android开发之字体设置
  6. 软考中级考试数据库工程师需要备考多久?
  7. iPhone锁屏字体
  8. 春节档低迷,中国影视的好内容饥渴症如何解?
  9. 谷歌新大招UDG|直接生成训练数据送给你
  10. linux 文件夹修改名字,linux命令修改文件名_修改文件夹名字怎么操作