Java调用海康sdk操作热成像设备获取对应点温度

Java调用海康sdk操作热成像设备获取对应点温度, 海康官方提供有Java版的sdk,遗憾的是里面提供的api比较旧了新版的api需要根据c++版的开发文档自己写对应的java接口和类。这对于不熟悉c++的开发人员比较吃力。下面的代码示例了通过海康的SDK获取热成像画面上某一点的具体温度。目前已经使用Python实现了相应的效果,有需要Python版本的可以留言。
maven依赖

        <dependency>
            <groupId>com.sun.jna</groupId>
            <artifactId>jna</artifactId>
            <version>3.0.9</version>
        </dependency>
import com.sun.jna.Native;
import com.sun.jna.NativeLong;
import lombok.extern.slf4j.Slf4j;

import java.nio.ByteBuffer;

/**
 * 调用demo
 *
 * @author JW
 * @version 1.0
 * @date 2021/3/25 14:47
 */
@Slf4j
public class HKNetApp {

    private NativeLong lUserID = new NativeLong(-1);//用户句柄
    private HCNetSDK.NET_DVR_DEVICEINFO_V30 m_strDeviceInfo;//设备信息

    static HCNetSDK hCNetSDK = null;//sdk

    public static synchronized void loadLibrary(String libraryPath){
        if(null == hCNetSDK){
            hCNetSDK = (HCNetSDK) Native.loadLibrary(libraryPath, HCNetSDK.class);
        }
    }

    public static void main(String[] args) {
        loadLibrary("你的sdk地址");

        HKNetApp hkNetApp = new HKNetApp();

        if (hkNetApp.init() && hkNetApp.login()) {
            Float temperature = hkNetApp.getTemperature(new HKPoint(1,1), 126, 100);
            log.info("1,1点的温度是,{}", temperature);
        }

        hkNetApp.logout();
        hCNetSDK.NET_DVR_Cleanup();
    }

    /**
     * SDK初始化
     * @return
     */
    public Boolean init() {
        if (!hCNetSDK.NET_DVR_Init()) {
            log.error("初始化失败");
            return false;
        }
        return true;
    }


    /*************************************************
     函数:      "注册"  按钮单击响应函数
     函数描述:  注册登录设备
     *************************************************/
    public Boolean login() {//GEN-FIRST:event_jButtonLoginActionPerformed
        //注册之前先注销已注册的用户,预览情况下不可注销
        if (lUserID.longValue() > -1) {
            //先注销
            hCNetSDK.NET_DVR_Logout_V30(lUserID);
        }
        //注册
        m_strDeviceInfo = new HCNetSDK.NET_DVR_DEVICEINFO_V30();

        lUserID = hCNetSDK.NET_DVR_Login_V30("192.168.8.14", (short) 8000, "admin", "a1234567", m_strDeviceInfo);

        long userID = lUserID.longValue();
        boolean initSuc = hCNetSDK.NET_DVR_SetLogToFile(3, "f:\\sdklog\\", false);

        if (userID == -1) {
            log.error("登录失败,{}", userID);
            return false;
        }
        return true;
    }

    public void logout() {
        hCNetSDK.NET_DVR_Logout_V30(lUserID);
    }

    public Float getTemperature(HKPoint hkPoint, int sourceWidth, int sourceHeight) {
        boolean bRet = false;
        int nErr = 0;
        int erro;
        HCNetSDK.NET_DVR_THERMOMETRY_PRESETINFO m_struThermometryInfo = new HCNetSDK.NET_DVR_THERMOMETRY_PRESETINFO();
        m_struThermometryInfo.dwSize = m_struThermometryInfo.size();

        HCNetSDK.NET_DVR_THERMOMETRY_COND m_struThermometryCond = new HCNetSDK.NET_DVR_THERMOMETRY_COND();
        m_struThermometryCond.dwSize = m_struThermometryCond.size();
        m_struThermometryCond.dwChannel = 1;
        m_struThermometryCond.wPresetNo = 1;
        m_struThermometryCond.write();

        HCNetSDK.NET_DVR_STD_CONFIG struCfg = new HCNetSDK.NET_DVR_STD_CONFIG();
        struCfg.lpCondBuffer = m_struThermometryCond.getPointer();
        struCfg.dwCondSize = m_struThermometryCond.size();
        struCfg.lpOutBuffer = m_struThermometryInfo.getPointer();
        struCfg.dwOutSize = m_struThermometryInfo.size();

        HCNetSDK.BYTE_ARRAY m_szStatusBuf = new HCNetSDK.BYTE_ARRAY(4096 * 4);
        struCfg.lpStatusBuffer = m_szStatusBuf.getPointer();
        struCfg.dwStatusSize = 4096 * 4;
        struCfg.byDataType = 0;

        bRet = hCNetSDK.NET_DVR_GetSTDConfig(lUserID, 3624, struCfg);
        if (!bRet) {
            nErr = hCNetSDK.NET_DVR_GetLastError();
            log.error("NET_DVR_GetSTDConfig失败,{}", nErr);
            return 0f;
        }

        m_struThermometryInfo.dwSize = m_struThermometryInfo.size();
        m_struThermometryInfo.wPresetNo = 1;
        m_struThermometryInfo.struPresetInfo[0] = new HCNetSDK.NET_DVR_THERMOMETRY_PRESETINFO_PARAM();
        m_struThermometryInfo.struPresetInfo[0].byEnabled = 1;
        m_struThermometryInfo.struPresetInfo[0].byRuleID = 1;
        m_struThermometryInfo.struPresetInfo[0].wDistance = 10;
        m_struThermometryInfo.struPresetInfo[0].fEmissivity = (float) 0.9599;
        m_struThermometryInfo.struPresetInfo[0].byReflectiveEnabled = 0;
        m_struThermometryInfo.struPresetInfo[0].fReflectiveTemperature = 20;
        m_struThermometryInfo.struPresetInfo[0].byRuleCalibType = 2;
        //m_struThermometryInfo.struPresetInfo[0].szRuleName ="1";
        m_struThermometryInfo.struPresetInfo[0].byDistanceUnit = 0;
        //m_struThermometryInfo.struPresetInfo[0].byemissivityMode = 0;
        m_struThermometryInfo.struPresetInfo[0].struPoint = new HCNetSDK.NET_VCA_POINT();
        m_struThermometryInfo.struPresetInfo[0].struPoint.fX = 0;
        m_struThermometryInfo.struPresetInfo[0].struPoint.fY = 0;
        m_struThermometryInfo.struPresetInfo[0].struPoint.write();
        m_struThermometryInfo.struPresetInfo[0].struRegion = new HCNetSDK.NET_VCA_POLYGON();
        m_struThermometryInfo.struPresetInfo[0].struRegion.dwPointNum = 2;
        m_struThermometryInfo.struPresetInfo[0].struRegion.struPos[0] = new HCNetSDK.NET_VCA_POINT();
        m_struThermometryInfo.struPresetInfo[0].struRegion.struPos[0].fX = (float) 0.187;
        m_struThermometryInfo.struPresetInfo[0].struRegion.struPos[0].fY = (float) 0.6119;
        m_struThermometryInfo.struPresetInfo[0].struRegion.struPos[0].write();
        m_struThermometryInfo.struPresetInfo[0].struRegion.struPos[1] = new HCNetSDK.NET_VCA_POINT();
        m_struThermometryInfo.struPresetInfo[0].struRegion.struPos[1].fX = (float) 0.876;
        m_struThermometryInfo.struPresetInfo[0].struRegion.struPos[1].fY = (float) 0.569;
        m_struThermometryInfo.struPresetInfo[0].struRegion.struPos[1].write();
        m_struThermometryInfo.struPresetInfo[0].struRegion.write();
        m_struThermometryInfo.write();
        struCfg.lpInBuffer = m_struThermometryInfo.getPointer();
        struCfg.dwInSize = m_struThermometryInfo.size();

        boolean setSTDConfig = hCNetSDK.NET_DVR_SetSTDConfig(lUserID, 3625, struCfg);
        log.info("NET_DVR_SetSTDConfig,{}", setSTDConfig);

        HCNetSDK.NET_DVR_JPEGPICTURE_WITH_APPENDDATA m_strJpegWithAppenData = new HCNetSDK.NET_DVR_JPEGPICTURE_WITH_APPENDDATA();
        m_strJpegWithAppenData.dwSize = m_strJpegWithAppenData.size();
        m_strJpegWithAppenData.dwChannel = 1;
        HCNetSDK.BYTE_ARRAY ptrJpegByte = new HCNetSDK.BYTE_ARRAY(2 * 1024 * 1024);
        HCNetSDK.BYTE_ARRAY ptrP2PDataByte = new HCNetSDK.BYTE_ARRAY(2 * 1024 * 1024);
        m_strJpegWithAppenData.pJpegPicBuff = ptrJpegByte.getPointer();
        m_strJpegWithAppenData.pP2PDataBuff = ptrP2PDataByte.getPointer();


        bRet = hCNetSDK.NET_DVR_CaptureJPEGPicture_WithAppendData(lUserID, 2, m_strJpegWithAppenData);
        if (bRet) {
            //测温数据
            if (m_strJpegWithAppenData.dwP2PDataLen > 0) {
                HKPoint point = point2point(hkPoint, sourceWidth, sourceHeight, m_strJpegWithAppenData.dwJpegPicWidth, m_strJpegWithAppenData.dwJpegPicHeight);
                return getTemperature0(m_strJpegWithAppenData.pP2PDataBuff.getByteBuffer( (m_strJpegWithAppenData.dwJpegPicWidth * point.y  + point.x) * 4, 4));
            }
        }

        return 0f;
    }

    private Float getTemperature0(ByteBuffer byteBuffer) {
        byte[] byTempData = new byte[4];
        byteBuffer.get(byTempData);

        int l = byTempData[0];
        l &= 0xff;
        l |= ((long) byTempData[1] << 8);
        l &= 0xffff;
        l |= ((long) byTempData[2] << 16);
        l &= 0xffffff;
        l |= ((long) byTempData[3] << 24);

        return Float.intBitsToFloat(l);
    }

    private HKPoint point2point(HKPoint points, int sourceWidth, int sourceHeight, int targetWidth, int targetHeight) {
        points.x = points.x * sourceWidth / targetWidth;
        points.y = points.y * sourceHeight / targetHeight;

        points.x = points.x >= targetWidth ? targetWidth : points.x;
        points.x = points.x < 0 ? 0 : points.x;

        points.y = points.y >= targetHeight ? targetHeight : points.y;
        points.y = points.y < 0 ? 0 : points.y;

        return points;
    }
}

sdk接口类,因为官方demo代码较多这里只提取了需要使用的部分。

import com.sun.jna.Native;
import com.sun.jna.NativeLong;
import com.sun.jna.Pointer;
import com.sun.jna.Structure;
import com.sun.jna.win32.StdCallLibrary;

import java.util.Arrays;
import java.util.List;

/**
 * 海康sdk调用接口
 */
public interface HCNetSDK extends StdCallLibrary {

    /**
     * 常量
     */
    int SERIALNO_LEN = 48;   //序列号长度
    int NAME_LEN = 32;    //用户名长度

    //method
    boolean NET_DVR_Init();

    boolean NET_DVR_Cleanup();

    NativeLong NET_DVR_Login_V30(String sDVRIP, short wDVRPort, String sUserName, String sPassword, NET_DVR_DEVICEINFO_V30 lpDeviceInfo);

    boolean NET_DVR_Logout_V30(NativeLong lUserID);

    boolean NET_DVR_SetSTDConfig(NativeLong lUserID, int dwCommand, NET_DVR_STD_CONFIG lpInConfigParam);

    boolean NET_DVR_GetSTDConfig(NativeLong lUserID, int dwCommand, NET_DVR_STD_CONFIG lpOutConfigParam);

    boolean NET_DVR_CaptureJPEGPicture_WithAppendData(NativeLong lUserID, int lChannel, NET_DVR_JPEGPICTURE_WITH_APPENDDATA lpJpegWithAppend);

    int NET_DVR_GetLastError();

    //启用日志文件写入接口
    boolean NET_DVR_SetLogToFile(int bLogEnable, String strLogDir, boolean bAutoDel);

    //NET_DVR_Login_V30()参数结构
    class NET_DVR_DEVICEINFO_V30 extends Structure {
        public byte[] sSerialNumber = new byte[SERIALNO_LEN];  //序列号
        public byte byAlarmInPortNum;                //报警输入个数
        public byte byAlarmOutPortNum;                //报警输出个数
        public byte byDiskNum;                    //硬盘个数
        public byte byDVRType;                    //设备类型, 1:DVR 2:ATM DVR 3:DVS ......
        public byte byChanNum;                    //模拟通道个数
        public byte byStartChan;                    //起始通道号,例如DVS-1,DVR - 1
        public byte byAudioChanNum;                //语音通道数
        public byte byIPChanNum;                    //最大数字通道个数
        public byte[] byRes1 = new byte[24];                    //保留
    }

    class NET_DVR_THERMOMETRY_PRESETINFO extends Structure {
        public int dwSize;//结构体大小
        public short wPresetNo;//0-保留
        public byte[] byRes = new byte[2];
        public NET_DVR_THERMOMETRY_PRESETINFO_PARAM[] struPresetInfo = new NET_DVR_THERMOMETRY_PRESETINFO_PARAM[40];
    }

    class NET_DVR_THERMOMETRY_PRESETINFO_PARAM extends Structure {
        public byte byEnabled;  //是否使能:0- 否,1- 是
        public byte byRuleID;//规则ID 0-表示无效,从1开始 (list内部判断数据有效性)
        public short wDistance;//距离(m)[0, 10000]
        public float fEmissivity;//发射率(发射率 精确到小数点后两位)[0.01, 1.00](即:物体向外辐射能量的本领)
        public byte byDistanceUnit;//距离单位: 0-米(m),1-英尺(feet),2-厘米(centimeter)
        public byte[] byRes = new byte[2];
        public byte byReflectiveEnabled;//反射温度使能:0- 否,1- 是
        public float fReflectiveTemperature;//反射温度 精确到小数后2位
        public byte[] szRuleName = new byte[NAME_LEN/*32*/];//规则名称
        public byte[] byRes1 = new byte[63];
        public byte byRuleCalibType;//规则标定类型 0-点,1-框,2-线
        public NET_VCA_POINT struPoint;//点测温坐标(当规则标定类型为"点"的时候生效)
        public NET_VCA_POLYGON struRegion;//区域、线(当规则标定类型为"框"或者"线"的时候生效)
    }

    class NET_VCA_POINT extends Structure {
        public float fX;                                // X轴坐标, 0.001~1
        public float fY;                                //Y轴坐标, 0.001~1
    }

    class NET_VCA_POLYGON extends Structure {
        public int dwPointNum;                                  //有效点 大于等于3,若是3点在一条线上认为是无效区域,线交叉认为是无效区域
        public NET_VCA_POINT[] struPos = new NET_VCA_POINT[10]; //多边形边界点,最多十个
    }

    class NET_DVR_THERMOMETRY_COND extends Structure {
        public int dwSize;//结构体大小
        public int dwChannel;
        public short wPresetNo;//0-保留
        public byte[] byRes = new byte[62];
    }

    class NET_DVR_STD_CONFIG extends Structure {
        public Pointer lpCondBuffer;        //[in]条件参数(结构体格式),例如通道号等.可以为NULL
        public int dwCondSize;            //[in] lpCondBuffer指向的内存大小
        public Pointer lpInBuffer;            //[in]输入参数(结构体格式),设置时不为NULL,获取时为NULL
        public int dwInSize;            //[in] lpInBuffer指向的内存大小
        public Pointer lpOutBuffer;        //[out]输出参数(结构体格式),获取时不为NULL,设置时为NULL
        public int dwOutSize;            //[in] lpOutBuffer指向的内存大小
        public Pointer lpStatusBuffer;        //[out]返回的状态参数(XML格式),获取成功时不会赋值,如果不需要,可以置NULL
        public int dwStatusSize;        //[in] lpStatusBuffer指向的内存大小
        public Pointer lpXmlBuffer;    //[in/out]byDataType = 1时有效,xml格式数据
        public int dwXmlSize;      //[in/out]lpXmlBuffer指向的内存大小,获取时同时作为输入和输出参数,获取成功后会修改会实际长度,设置时表示实际长度,而不是整个内存大小
        public byte byDataType;     //[in]输入/输出参数类型,0-使用结构体类型lpInBuffer/lpOutBuffer有效,1-使用XML类型lpXmlBuffer有效
        public byte[] byRes = new byte[23];
    }

    class BYTE_ARRAY extends Structure {
        public byte[] byValue;

        public BYTE_ARRAY(int iLen) {
            byValue = new byte[iLen];
        }

        @Override
        protected List<String> getFieldOrder() {
            return Arrays.asList("byValue");
        }
    }

    //设备抓图附加全屏测温数据结构体
    class NET_DVR_JPEGPICTURE_WITH_APPENDDATA extends Structure {
        public int dwSize;
        public int dwChannel;//通道号
        public int dwJpegPicLen;//Jpeg图片长度
        public Pointer pJpegPicBuff;//Jpeg图片指针
        public int dwJpegPicWidth;  // 图像宽度
        public int dwJpegPicHeight;  //图像高度
        public int dwP2PDataLen;//全屏测温数据长度
        public Pointer pP2PDataBuff; //全屏测温数据指针
        public byte byIsFreezedata;//是否数据冻结 0-否 1-是
        public byte[] byRes = new byte[255];
    }
}

下面是运行结果:


image.png
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 214,922评论 6 497
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 91,591评论 3 389
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 160,546评论 0 350
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 57,467评论 1 288
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 66,553评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,580评论 1 293
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,588评论 3 414
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,334评论 0 270
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,780评论 1 307
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,092评论 2 330
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,270评论 1 344
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,925评论 5 338
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,573评论 3 322
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,194评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,437评论 1 268
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,154评论 2 366
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,127评论 2 352

推荐阅读更多精彩内容