大疆热红外图片温度读取

news/2024/11/15 1:38:32/

适用于 大疆禅思 Zenmuse H20 系列拍摄的红外图片,依赖于大疆发布的TSDK(DJI Thermal SDK),可用于视频的动态测温。

其实对TSDK并未深入研究,只是某一个小项目要使用TSDK处理H20拍摄的红外照片,利用TSDK中的sample又进行了一些处理,能够实现将对应像素、指定区域的温度进行读取。

大疆社区对这个TSDK的使用描述较少,为了任务只好硬着头皮上。

首先,对TSDK中的sample进行编译,这里有一点,默认编译脚本使用vs2015,但是我这里只安装了vs2017,只需要找到build.bat,将"Visual Studio 14 2015"改为"Visual Studio 15 2017"保存即可。

编译生成的程序中,我只用到了“dji_irp.exe”这一个,使用的参数为

"dji_irp.exe" -s "image/file/path" -a measure -o "path/of/raw/output"

其他命令和参数可以使用-help查看,上边省略的参数是INT32,即使用16位数据保存一个温度*10的整数,对得到的数值*0.1即为0.1精度的真实温度。

它可以将红外图片生成为16位raw文件,原来没有很明白,后来才渐渐搞懂,也就是说,每16位(2字节)对应原始图片的一个像素。起初对jpg格式的保存方式也不太了解,只好一点一点尝试。

好在方向没有搞错,大致保存方式为从左上角0,0开始,一行一行的存储,所以raw文件中也是如此保存的了。

这里也要说明一下,我确认没有搞错方向的依据是与大疆发布的大疆红外热分析工具的像素温度、最高最低温度点保持一致。

我定义了一个类RawParser来解析生成的raw文件数据,主要功能有:

1、获取指定点坐标的温度

2、获取指定区域的平均温度

3、获取指定区域最高、最低温度及其坐标

先上代码。

RawParser.h

#pragma once
#include <string>
#define IN
#define OUTstruct RectArea
{int x;int y;int w;int h;
};struct PixPoint
{int x;int y;
};struct PixTemperature
{PixPoint point;int temperature;//tenfold
};class RawParser
{
public:RawParser(const char* filePath, int width, int height);~RawParser();//将raw文件内容加载到内存中再进行操作和计算bool preloadRaw();//将像素点的坐标转换为内存索引long pointToIndex(int x, int y);//通过像素的坐标xy获取对应的温度,temperature为10倍温度的整数(温度取1位有效位)bool getPointTemperature(int x IN, int y IN, int &temperature OUT);//tenfold//计算指定范围内像素点温度的平均值、最高值、最高值坐标、最低值、最低值坐标bool rangeCaculate(RectArea rect IN, float &temperature OUT, PixTemperature &maxPT OUT, PixTemperature &minPT OUT);//rect的宽高应大于0bool rangeCaculate(RectArea rect IN, float &temperature OUT);private:FILE *m_imageFP;int m_imageW;int m_imageH;size_t m_fileSize;bool m_bHasPreload;std::string m_rawData;
};

RawParser.cpp

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "RawParser.h"#define RAW_LENGTH 16typedef unsigned char BYTE;RawParser::RawParser(const char* filePath, int width, int height):m_imageW(width),m_imageH(height),m_bHasPreload(false)
{m_imageFP = nullptr;if ((m_imageFP = fopen(filePath, "rb")) == nullptr){m_fileSize = 0;printf("can not open the raw image");return;}else{//读取文件总大小fseek(m_imageFP, 0, SEEK_END);m_fileSize = ftell(m_imageFP);fseek(m_imageFP, 0, SEEK_SET);}
}RawParser::~RawParser()
{if (m_imageFP){fclose(m_imageFP);}
}bool RawParser::preloadRaw()
{char* _content = (char*)malloc(m_fileSize);if (!_content){return false;}size_t _cnt = fread(_content, 1, m_fileSize, m_imageFP);if (_cnt != m_fileSize){free(_content);return false;}m_rawData.assign(_content, _cnt);m_bHasPreload = true;return true;
}bool RawParser::getPointTemperature(int x, int y, int &temperature)
{if (m_bHasPreload){if (m_rawData.empty()){return false;}}else{if (!m_imageFP){return false;}}if (m_imageW <= x){return false;}if (m_imageH <= y){return false;}unsigned char tmpValue[2];long _offset = (m_imageW*y + x) * 2;//每个温度数据占用两个字节16位if (m_fileSize < _offset){return false;}if(m_bHasPreload){tmpValue[0] = m_rawData.at(_offset);tmpValue[1] = m_rawData.at(_offset + 1);}else{fseek(m_imageFP, _offset, 0);//从像素坐标对应的文件位置读出两个字节数据size_t _ret = fread(tmpValue, 1, 2, m_imageFP);if (_ret != 2){return false;}}temperature = tmpValue[1];//字节序转换temperature = temperature << 8;temperature = temperature + (tmpValue[0]);return true;
}bool RawParser::rangeCaculate(RectArea rect IN, float &temperature OUT, PixTemperature &maxPT OUT, PixTemperature &minPT OUT)
{if (m_bHasPreload){if (m_rawData.empty()){return false;}}else{if (!m_imageFP){return false;}}if (   rect.x < 0|| rect.y < 0|| rect.w < 0|| rect.h < 0|| rect.x > m_imageW|| rect.y > m_imageH|| (rect.x+rect.w) > m_imageW|| (rect.y+rect.h) > m_imageH){return false;}PixPoint maxTPP, minTPP,bottomRight;int maxTemp, minTemp;bool pointsReady = false;//最高最低温度初始化标记//fseek(m_imageFP, 0, 0);long pointCount = 0;unsigned char _temp[2];//所有点温度之和。使用__int64保存结果足够保证计算时不会溢出,//温度保存16位,范围是±32767,_int64表示范围是±9,223,372,036,854,775,808//按照最大值计算,可保存281,474,976,710,656个数据之和//一张1080*1080的图片只有1,166,400个像素__int64 _temperature = 0;int pointTemp;//点温度bottomRight.x = rect.x + rect.w;bottomRight.y = rect.y + rect.h;for (int x = rect.x; x < bottomRight.x;++x){for (int y = rect.y; y < bottomRight.y; ++y){long _index = pointToIndex(x, y);if (m_fileSize < _index){return false;}if (m_bHasPreload){_temp[0] = m_rawData.at(_index);_temp[1] = m_rawData.at(_index + 1);}else{fseek(m_imageFP, _index, 0);fread(_temp, 1, 2, m_imageFP);}pointTemp = ((_temp[1] << 8) & 0xFF00);pointTemp += _temp[0];//判断最高、最低温度并记录坐标if (pointsReady){if (pointTemp < minTemp){minTemp = pointTemp;minTPP.x = x;minTPP.y = y;}else if (pointTemp > maxTemp){maxTemp = pointTemp;maxTPP.x = x;maxTPP.y = y;}}else{//最高、最低温度初始化为第一个点的温度minTemp = pointTemp;minTPP.x = x;minTPP.y = y;maxTemp = pointTemp;maxTPP.x = x;maxTPP.y = y;pointsReady = true;}_temperature += pointTemp;++pointCount;}}if (pointCount == 0){return false;}temperature = _temperature / pointCount * 0.1;maxPT.point = maxTPP;maxPT.temperature = maxTemp;minPT.point = minTPP;minPT.temperature = minTemp;return true;
}bool RawParser::rangeCaculate(RectArea rect IN, float &temperature OUT)
{PixTemperature maxPT, minPT;return rangeCaculate(rect, temperature, maxPT, minPT);
}long RawParser::pointToIndex(int x, int y)
{if (m_imageW <= x){return false;}return ((m_imageW*y + x) * 2);//每个温度数据占用两个字节16位
}

起初摸索的时候采用了文件指针偏移的方法实时从文件读取,效率非常低,后来直接把文件全部读到内存中再计算,效率就提高很多,640*512大小的图片,一次全图计算大概只需要500ms。

其中关键的部分就是找对像素坐标对应的数据位置,其他就简单多了。

后边附上Qt写的调用Demo,感兴趣的可以参考一下。

===

补充一下,RawParser这个类中并未使用依赖平台的库或头文件,只是简单的数学和逻辑运算,基本上可以轻松移植。写这个东西本来就是研究使用方法,给其他同事参考的,他是用的java,没有遇到什么问题。


http://www.ppmy.cn/news/497380.html

相关文章

无人机自由飞行测试台 FFT GYRO 600

产品简介 无人机在研制过程中需要不断地进行飞行测试&#xff0c;而测试的过程不是万无一失的&#xff0c;飞行过程中发生任何错误都有可能会导致无人机的损毁或破坏&#xff0c;更严重地甚至会造成外界伤害。 基于此我们推出了无人机的三旋转自由度(3-DOF)飞行平台测试系统&…

序列化框架的选择- hession2、kyro、protostuff

序列化框架的选择 前言Hessian 2KryoProtostuff性能对比其他比较 前言 当涉及到序列化框架时&#xff0c;Hessian 2、Kryo 和 Protostuff 是三个常见的选择。它们在性能、跨语言支持、序列化大小和使用灵活性等方面存在一些差异。hession2、kyro、protostuff都是第三方开源的序…

Java NIO中Buffer方法详解(含代码示例)

目录 概念及方法 容量&#xff08;Capacity&#xff09;&#xff1a; 位置&#xff08;Position&#xff09;&#xff1a; 上界&#xff08;Limit&#xff09;&#xff1a; 标记&#xff08;Mark&#xff09;&#xff1a; 清空&#xff08;Clear&#xff09;&#xff1a;…

C# 特性(Attribute)总结

目录 特性是什么&#xff1f; 如何使用特性&#xff1f; &#xff08;1&#xff09;.Net 框架预定义特性 &#xff08;2&#xff09;自定义特性 为什么要使用特性&#xff1f; 特性的应用 特性实现枚举展示描述信息 特性是什么&#xff1f; 特性&#xff08;Attribute&…

超好看的UI云开发壁纸小程序源码

正文: 本壁纸表情包头像小程序采用&#xff08;dcloud云开发&#xff09;所以无需服务器与域名&#xff0c;本次版本集合了前两个版本所有的功能并有以下的更新。 更改界面UI样式&#xff0c;修复了路径控制BUG。新增任务中心、首页栏目增加动态壁纸搜索(支持关键词搜索全网动…

导向滤波 Guided Filter 的 CUDA GPU版本

Guided Filter Using CUDA GitHub Repo : Plumess/Guided-Filter-Using-CUDA: A GPU version implementation of Guided Filter, using CUDA C/C, calculates 1080P images in 10ms on 4090 (github.com) 这是导向滤波/引导滤波的一种GPU实现&#xff0c;经测试&#xff0c;在…

有没有关于python的壁纸_初学Python——01(想要好看的壁纸吗?)

#把win10锁屏页面的图片批量导出图片到E&#xff1a;\win10壁纸 import os import shutil pathrC:\Users\Administrator\AppData\Local\Packages\Microsoft.Windows.ContentDeliveryManager_cw5n1h2txyewy\LocalState\Assets to_pathrE:\Win10壁纸 #创建文件夹 isExistso…

vue 常见问题处理

当使用Vue.js开发应用程序时&#xff0c;可能会遇到一些常见问题。以下是一些常见的Vue.js问题及其解决方法的集锦&#xff1a; Vue组件无法正常显示或渲染&#xff1a; 确保Vue组件被正确导入和注册。 检查模板语法是否正确&#xff0c;包括HTML标记、属性和指令的使用。 使…