8.实时识别并标记算法
1.调试演示所用传感器为8×8像素(IR64)
本次红外传感器比较小只有64个像素,无法准备描绘出物体轮廓,所以才需要插值提升像素。
2.mqtt实时将数据转发给移动端
传感器数据直接通过mqtt发送给移动端或者服务器通过mqtt中转给移动端,都可以做到无刷新实时显示热成像画面。
本次测试使用的是5Hz,传感器每秒发送5次数据,移动端每秒渲染5次热成像画面。实时度高的场景可以增加次数。
3.温度数组转为温度矩阵算法
由于红外传感器上报给服务器的数据是一维数组,要想显示图像就需要将数据转为二维数组矩阵
//传感器横轴像素
int sourcePixelRowCount = 8;
int len = temperatureList.length;
//传感器纵轴像素
int lineNum = len % sourcePixelRowCount == 0
? (len ~/ sourcePixelRowCount).toInt()
: ((len / sourcePixelRowCount) + 1).floor();
for (var i = 0; i < lineNum; i++) {
int startIndex = i * sourcePixelRowCount;
//截取数组指定长度后生成新数组
Iterable<double> range = temperatureList.getRange(startIndex ,startIndex + sourcePixelRowCount);
temperature.add(range.toList());
}
4.画面镜像翻转,二维数组重新排序
如果不进行镜像翻转,显示的画面将和实际的画面是相反的,左右相反
5.双三次多项式插值提升像素算法
插值提升像素,锐化边缘后,提升后像素为32×32,看下图片基本可以看到物体轮廓了。
//计算权重
static dynamic getCubicWeight(double v) {
double a = -0.5;
// 取整
int nv = v.floor();
// 坐标差值集合
List<double> xList = new List(4);
// 坐标集合
List<int> xs = new List(4);
// 最近的4个坐标差值
xList[0] = nv - v - 1;
xList[1] = nv - v;
xList[2] = nv - v + 1;
xList[3] = nv - v + 2;
//
xs[0] = nv - 1;
xs[1] = nv;
xs[2] = nv + 1;
xs[3] = nv + 2;
// 计算权重
List<double> ws = List(4);
for (int i = 0; i < 4; i++) {
double val = xList[i].abs();
double w = 0;
// 基于BiCubic基函数的双三次插值
if (val <= 1) {
w = (a + 2) * val * val * val - (a + 3) * val * val + 1;
} else if (val < 2) {
w = a * val * val * val - 5 * a * val * val + 8 * a * val - 4 * a;
}
ws[i] = w;
}
return {'weight': ws, 'coordinate': xs};
}
6.温度数值转为RGB色彩编码算法,想要色阶越多可以用255/色阶数,我用的4
//将温度转为RGB,用64将颜色分为4个区间,可以分为更多区间比如51
RGB grayToPseColor(int grayValue) {
if (grayValue > 255) {
return RGB(255, 0, 0);
}
if (grayValue < 0) {
return RGB(0, 0, 0);
}
if ((grayValue >= 0) && (grayValue <= 63)) {
return RGB(0, 0, (grayValue / 64 * 255).round());
} else if ((grayValue >= 64) && (grayValue <= 127)) {
return RGB(0, ((grayValue - 64) / 64 * 255).round(),((127 - grayValue) / 64 * 255).round());
} else if ((grayValue >= 128) && (grayValue <= 191)) {
return RGB(((grayValue - 128) / 64 * 255).round(), 255, 0);
} else if ((grayValue >= 192) && (grayValue <= 255)) {
return RGB(255, ((255 - grayValue) / 64 * 255).round(), 0);
}
return RGB(0, 0, 0);
}
7.屏幕实时显示热成像画面算法,优化像素增大后渲染卡顿算法流畅丝滑
//二维温度数组
List<List<double>> temperatureScale;
//每个像素点大小
final static double pixel;
//最低温度
static double temperatureMin = 10;
//最高温度
static double temperatureMax = 38;
//计算最大温度差
double difference = temperatureMax - temperatureMin;
@override
void paint(Canvas canvas, Size size) {
//创建画笔,默认颜色就是填充模式
Paint paint = Paint();
//画笔x轴位置,默认坐标为容器的左上角
double top = 0;
//画笔y轴位置
double left = 0;
//循环二维数组
for (var i = 0; i < temperatureScale.length; i++) {
for (var j = 0; j < temperatureScale[0].length; j++) {
double value = temperatureScale[i][j];
//计算温度系数
double scale = (value - temperatureMin) / difference;
//将温度转为rgb颜色值
RGB rbg = grayToPseColor((255 * scale).round());
//调整画笔的颜色
paint.color = Color.fromARGB(255, rbg.R, rbg.G, rbg.B);
//创建一个矩形
Rect rrect = Rect.fromLTWH(left, top, pixel, pixel);
//画一个矩形到屏幕
canvas.drawRect(rrect, paint);
//画笔向右移动一个像素
left = left + pixel;
}
left = 0;
//画笔向下移动一个像素
top = top + pixel;
}
}
9.移动端效果8×8图示例(优化前画面像素->优化中项画面像素->优化后画面像素)