🎬 江城开朗的豌豆:个人主页
** 🔥 个人专栏**:《 VUE 》 《 javaScript 》
📝** 个人网站 **:《 江城开朗的豌豆🫛 》
⛺️生活的理想,就是为了理想的生活!
📘 前言
热成像技术在工业、医学和科学研究中发挥了重要作用,它能够通过捕捉不同物体的温度分布图像来提供宝贵的信息。然而,要有效地展示和分析这些热成像数据,我们需要使用适当的工具和算法。本文将介绍如何使用Excel展示热成像数据,并实现插值算法以增强数据分析的准确性和可视化效果。
** 原始图**
转换成功的效果图
📘一、热成像数据的导入与展示
热成像设备通常生成的是包含温度信息的二维数组数据。在Excel中展示这些数据,可以通过以下步骤
📟 1.数据导入:
将热成像数据以CSV或XLSX格式导入Excel。通常,这些数据以矩阵的形式存储,每个单元格代表一个温度值。
📟 2.创建热图:
在Excel中,可以使用条件格式来创建热图。选择包含温度数据的单元格区域,应用“条件格式”中的“色阶”功能,以不同的颜色表示不同的温度范围。这种可视化方法能帮助快速识别热图中的热点区域。
📟3.数据可视化
利用Excel的图表工具,将数据以图表形式展示。例如,可以创建散点图或折线图,帮助分析温度随时间或位置的变化
📘二、插值算法的应用
在热成像数据中,可能存在一些缺失值或数据点稀疏的情况。插值算法可以帮助我们估算这些缺失值,并提高数据的连续性。以下是一些常见的插值算法及其在Excel中的实现方法:
📟 1.线性插值:
线性插值是最简单的插值方法,通过连接已知数据点的直线来估算未知点的值。在Excel中,可以通过线性回归或在两个已知数据点之间插入一个新的数据点来实现。
📟 2.双线性插值:
双线性插值适用于二维数据,使用已知点形成的矩阵进行插值。你可以在Excel中创建一个新的数据表,通过公式计算每个数据点的插值值。双线性插值公式如下:
📟 3.样条插值:
样条插值是一种更复杂的插值方法,通过多项式拟合数据点,实现平滑的曲线插值。在Excel中,这种方法可以通过插件或VBA代码实现,虽然设置相对复杂,但可以生成更平滑的数据图。
📘三、实例操作
假设我们有一个包含热成像数据的Excel表格,我们可以通过以下步骤进行插值和数据展示:
- 创建数据表: 将热成像数据输入Excel,并使用条件格式创建热图。
- 应用插值算法: 使用Excel的插值公式填补缺失数据,或通过VBA实现更复杂的插值算法。
- 数据分析与优化: 根据插值后的数据,生成更精确的热图和图表。利用Excel的数据分析工具,评估数据的准确性和可靠性。
📘 完整代码展示
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Excel Heatmap with Canvas</title>
<script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/xlsx.full.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/xlsx/0.18.5/xlsx.full.min.js"></script>
<style>
#heatmapCanvas {
/* border: 1px solid black; */
}
</style>
</head>
<body>
<button onclick="chuNenFx()">储能分析</button>
<input type="file" id="fileInput" />
<input type="number" id="reLiNum" placeholder="输入数字" />
<button onclick="getValue()">获取值</button>
<button onclick="showMaxTemperature()">显示最高温度</button>
<button onclick="showMinTemperature()">显示最低温度</button>
<br />
<button onclick="highlightMaxTemperature()">标记最高温度</button>
<button onclick="highlightMinTemperature()">标记最低温度</button>
<canvas id="heatmapCanvas"></canvas>
<script>
document
.getElementById("fileInput")
.addEventListener("change", handleFileSelect, false);
// 双线性插值算法
var newData = [];
function processFile() {
const fileInput = document.getElementById("fileInput");
const file = fileInput.files[0];
const reader = new FileReader();
reader.onload = function (event) {
const data = new Uint8Array(event.target.result);
const workbook = XLSX.read(data, { type: "array" });
const sheetName = workbook.SheetNames[0];
const worksheet = workbook.Sheets[sheetName];
const csv = XLSX.utils.sheet_to_csv(worksheet);
const arrayData = csvToArray(csv);
const interpolatedData = interpolate22(arrayData, 480, 640); // 增加到 240, 320 的分辨率 1440, 1920 -- 384, 512
// console.log("Interpolated", interpolatedData);
const szNew = interpolatedData
.map((row) => row.map((cell) => Math.round(cell)))
.map(
(row) => row.filter((cell) => cell !== 0) // 过滤掉值为 0 的元素
);
console.log(szNew);
newData = szNew;
};
reader.readAsArrayBuffer(file);
}
function interpolate22(data, newRows, newCols) {
const rows = data.length;
const cols = data[0].length;
const interpolatedData = Array.from({ length: newRows }, () =>
Array(newCols).fill(0)
);
for (let i = 0; i < newRows; i++) {
for (let j = 0; j < newCols; j++) {
const xRatio = (j / (newCols - 1)) * (cols - 1);
const yRatio = (i / (newRows - 1)) * (rows - 1);
const x0 = Math.floor(xRatio);
const x1 = Math.min(x0 + 1, cols - 1);
const y0 = Math.floor(yRatio);
const y1 = Math.min(y0 + 1, rows - 1);
const q11 = data[y0][x0];
const q21 = data[y0][x1];
const q12 = data[y1][x0];
const q22 = data[y1][x1];
const r1 = (x1 - xRatio) * q11 + (xRatio - x0) * q21;
const r2 = (x1 - xRatio) * q12 + (xRatio - x0) * q22;
interpolatedData[i][j] = (y1 - yRatio) * r1 + (yRatio - y0) * r2;
}
}
return interpolatedData;
}
// 最大值
function getMaxTemperature(data) {
let maxTemp = -Infinity;
for (const row of data) {
for (const temp of row) {
if (temp > maxTemp) {
maxTemp = temp;
}
}
}
return maxTemp;
}
// 插值算法封装
function interpolate(data, newRows, newCols) {
const rows = data.length;
const cols = data[0].length;
const x = Array.from({ length: cols }, (_, i) => i);
const y = Array.from({ length: rows }, (_, i) => i);
const interpolatedData = Array.from({ length: newRows }, (_, i) => {
return Array.from({ length: newCols }, (_, j) => {
const xRatio = (j / (newCols - 1)) * (cols - 1);
const yRatio = (i / (newRows - 1)) * (rows - 1);
const x0 = Math.floor(xRatio);
const x1 = Math.min(x0 + 1, cols - 1);
const y0 = Math.floor(yRatio);
const y1 = Math.min(y0 + 1, rows - 1);
const q11 = data[y0][x0];
const q21 = data[y0][x1];
const q12 = data[y1][x0];
const q22 = data[y1][x1];
const r1 = (x1 - xRatio) * q11 + (xRatio - x0) * q21;
const r2 = (x1 - xRatio) * q12 + (xRatio - x0) * q22;
return (y1 - yRatio) * r1 + (yRatio - y0) * r2;
});
});
return interpolatedData;
}
function csvToArray(text) {
return text.split("\n").map((row) => row.split(",").map(Number));
}
var maxTemperature = [];
// 最小值
function getMinTemperature(data) {
let minTemp = Infinity;
for (const row of data) {
for (const temp of row) {
if (temp < minTemp) {
minTemp = temp;
}
}
}
return minTemp;
}
// 显示最低温度
function showMinTemperature() {
const minTemperature = getMinTemperature(maxTemperature);
alert(`最低温度是: ${minTemperature / 100}°C`);
}
function showMaxTemperature() {
if (maxTemperature.length > 0) {
const maxTempe = getMaxTemperature(maxTemperature);
alert(`最高温度是: ${maxTempe / 100}°C`);
} else {
alert(`最高温度是: 请先上传数据`);
}
}
// 封装双线性插值算法
function bilinearInterpolate(x, y, values) {
const x1 = Math.floor(x);
const y1 = Math.floor(y);
const x2 = Math.ceil(x);
const y2 = Math.ceil(y);
const Q11 = values[y1] ? values[y1][x1] : 0;
const Q12 = values[y1] ? values[y1][x2] : 0;
const Q21 = values[y2] ? values[y2][x1] : 0;
const Q22 = values[y2] ? values[y2][x2] : 0;
const xFraction = x - x1;
const yFraction = y - y1;
const R1 = Q11 * (1 - xFraction) + Q12 * xFraction;
const R2 = Q21 * (1 - xFraction) + Q22 * xFraction;
return R1 * (1 - yFraction) + R2 * yFraction;
}
// 获取excel数据
async function handleFileSelect(event, json) {
await processFile();
const file = event.target.files[0];
// console.log("=====>>>", file);
if (!file) return;
const reader = new FileReader();
reader.onload = function (e) {
const data = new Uint8Array(e.target.result);
const workbook = XLSX.read(data, { type: "array" });
// Assuming you want to process the first sheet
const sheetName = workbook.SheetNames[0];
const worksheet = workbook.Sheets[sheetName];
// const json = XLSX.utils.sheet_to_json(worksheet, {
// header: 1,
// defval: 0,
// });
// Default values for empty cells
// Convert data to 2D array
// console.log("===========json=====================", json);
const dataArray = newData.map((row) =>
row.map((cell) => parseFloat(cell) || 0)
);
// console.log("Data Array:", dataArray);
maxTemperature = dataArray;
// console.log("=workbook===" + maxTemperature);
drawHeatmap(dataArray);
};
reader.readAsArrayBuffer(file);
}
// 插值算法
const canvas = document.getElementById("heatmapCanvas");
// const cellSize = 10; // 原始单元格大小
let newCellSize = 1; // 插值后的单元格大小
function getValue() {
const inputElement = document.getElementById("reLiNum");
const value = inputElement.value; // 获取输入的值
newCellSize = value;
drawHeatmap(maxTemperature); // 重新绘制热力图
}
// 页面跳转
function chuNenFx() {
window.location.replace("./boxEchars.html");
}
// 绘制热力图
function drawHeatmap(dataArray) {
const width = dataArray[0].length;
const height = dataArray.length;
// 计算新画布的宽度和高度
const canvasWidth = width * newCellSize;
const canvasHeight = height * newCellSize;
// Adjust canvas size
canvas.width = canvasWidth; // Scale width
canvas.height = canvasHeight; // Scale height
const ctx = canvas.getContext("2d");
const imageData = ctx.createImageData(canvasWidth, canvasHeight);
// 查找归一化的最小值和最大值
let min = Infinity;
let max = -Infinity;
dataArray.flat().forEach((value) => {
if (value < min) min = value;
if (value > max) max = value;
});
// 生成热力图
for (let y = 0; y < canvasHeight; y++) {
for (let x = 0; x < canvasWidth; x++) {
const dataX = x / newCellSize;
const dataY = y / newCellSize;
const value = bilinearInterpolate(dataX, dataY, dataArray);
// const value = dataArray[y][x];
const normalizedValue = (value - min) / (max - min);
// for (let dy = 0; dy < cellSize; dy++) {
// for (let dx = 0; dx < cellSize; dx++) {
// const index = ((y * cellSize + dy) * canvas.width + (x * cellSize + dx)) * 4;
// const color = getHeatmapColor(normalizedValue);
// imageData.data[index] = color[0];
// imageData.data[index + 1] = color[1];
// imageData.data[index + 2] = color[2];
// imageData.data[index + 3] = 255;
// }
// }
// // 获取颜色值
const color = getHeatmapColor(normalizedValue);
// 设置画布上的像素颜色
const index = (y * canvasWidth + x) * 4;
imageData.data[index] = color[0]; // Red
imageData.data[index + 1] = color[1]; // Green
imageData.data[index + 2] = color[2]; // Blue
imageData.data[index + 3] = 255; // Alpha
}
}
// console.log("imageDat", imageData);
ctx.putImageData(imageData, 0, 0);
}
// 找到最高温度及其位置
function getMaxTemperatureInfo(isMax) {
let extremeTemp = isMax ? -Infinity : Infinity;
let position = { row: 0, col: 0 };
maxTemperature.forEach((row, rowIndex) => {
row.forEach((temp, colIndex) => {
if (
(isMax && temp > extremeTemp) ||
(!isMax && temp < extremeTemp)
) {
extremeTemp = temp;
position = { row: rowIndex, col: colIndex };
}
});
});
return { extremeTemp, position };
}
// 找到最高温度及其位置
// function getMaxTemperatureInfo() {
// let maxTemp = -Infinity;
// let position = { row: 0, col: 0 };
// maxTemperature.forEach((row, rowIndex) => {
// row.forEach((temp, colIndex) => {
// if (temp > maxTemp) {
// maxTemp = temp;
// position = { row: rowIndex, col: colIndex };
// }
// });
// });
// return { maxTemp, position };
// }
// 标记最高温度
function highlightMaxTemperature() {
const { extremeTemp, position } = getMaxTemperatureInfo(true);
drawHeatmap(maxTemperature); // 重新绘制热力图
const ctx = canvas.getContext("2d");
// 绘制标记
ctx.strokeStyle = "yellow";
ctx.lineWidth = 30;
ctx.beginPath();
const x = position.col * newCellSize + newCellSize / 2;
const y = position.row * newCellSize + newCellSize / 2;
ctx.arc(x, y, newCellSize / 4, 0, 2 * Math.PI);
ctx.stroke();
ctx.fillStyle = "yellow";
ctx.fill();
// alert(`最高温度是: ${extremeTemp/100}°C`);
// 显示温度值
ctx.fillStyle = "black";
ctx.font = "12px Arial";
ctx.textAlign = "center";
ctx.textBaseline = "middle";
ctx.fillText(`${extremeTemp / 100}°C`, x, y);
}
// 标记最低温度
function highlightMinTemperature() {
const { extremeTemp, position } = getMaxTemperatureInfo(false);
drawHeatmap(maxTemperature); // 重新绘制热力图
const ctx = canvas.getContext("2d");
// 绘制标记
ctx.strokeStyle = "green";
ctx.lineWidth = 30;
ctx.beginPath();
const x = position.col * newCellSize + newCellSize / 2;
const y = position.row * newCellSize + newCellSize / 2;
ctx.arc(x, y, newCellSize / 4, 0, 2 * Math.PI);
ctx.stroke();
ctx.fillStyle = "green";
ctx.fill();
// alert(`最低温度是: ${extremeTemp/100}°C`);
// 显示温度值
ctx.fillStyle = "white";
ctx.font = "12px Arial";
ctx.textAlign = "center";
ctx.textBaseline = "middle";
ctx.fillText(`${extremeTemp / 100}°C`, x, y);
}
function getHeatmapColor(value) {
// 从蓝色到红色的简单热图颜色渐变
const r = Math.min(255, Math.max(0, Math.floor(255 * value)));
const g = Math.min(255, Math.max(0, Math.floor(255 * (1 - value))));
const b = 0;
return [r, g, b];
}
</script>
</body>
</html>
📘 写在最后
Excel作为一种强大的数据处理工具,可以有效地展示和分析热成像数据。通过合理使用插值算法,可以提升数据的连续性和可视化效果。希望本文能帮助你更好地利用Excel进行热成像数据的展示和分析。如果你有更复杂的数据需求,也可以考虑结合使用专业的数据分析工具和编程语言。
通过掌握这些基本技巧,你将能够更好地理解和利用热成像数据,为你的工作和研究提供有力支持。
感谢大家一如既往对我的点赞与支持,不是我的作品有多好,而是你们的不嫌弃。这世界上有一种爱叫“关注”,感恩遇见、感恩有你~
版权归原作者 江城开朗的豌豆 所有, 如有侵权,请联系我们删除。