package com.netsdk.demo.customize.heatmap; import java.awt.image.BufferedImage; import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; import java.io.File; import java.io.IOException; import javax.imageio.ImageIO; import javax.swing.JOptionPane; import com.netsdk.demo.util.CaseMenu; import com.netsdk.lib.HeatMapLib; import com.netsdk.lib.NetSDKLib; import com.netsdk.lib.ToolKits; import com.netsdk.lib.HeatMapLib.*; import com.netsdk.lib.NetSDKLib.*; import com.sun.jna.Memory; import com.sun.jna.Pointer; import com.sun.jna.ptr.IntByReference; /** * 生成热度图Demo,没有界面的,通过调用转换库 */ public class HeatMapEx2 { static NetSDKLib NetSdk = NetSDKLib.NETSDK_INSTANCE; static NetSDKLib ConfigSdk = NetSDKLib.CONFIG_INSTANCE; static HeatMapLib HeatMapSdk = HeatMapLib.HEATMAP_INSTANCE; //登陆参数 private String m_strIp = "172.29.4.55"; private Integer m_nPort = new Integer("37777"); private String m_strUser = "admin"; private String m_strPassword = "admin123"; //设备信息 private NetSDKLib.NET_DEVICEINFO_Ex m_stDeviceInfo = new NetSDKLib.NET_DEVICEINFO_Ex(); private static LLong m_hLoginHandle = new LLong(0); //登陆句柄 private DisConnect disConnect = new DisConnect(); //设备断线通知回调 private HaveReConnect haveReConnect = new HaveReConnect(); //网络连接恢复 public static GRAY_MAP grayData = null; //设备断线回调: 通过 CLIENT_Init 设置该回调函数,当设备出现断线时,SDK会调用该函数 public class DisConnect implements NetSDKLib.fDisConnect { public void invoke(LLong m_hLoginHandle, String pchDVRIP, int nDVRPort, Pointer dwUser) { System.out.printf("Device[%s] Port[%d] DisConnect!\n", pchDVRIP, nDVRPort); } } //网络连接恢复,设备重连成功回调 // 通过 CLIENT_SetAutoReconnect 设置该回调函数,当已断线的设备重连成功时,SDK会调用该函数 public class HaveReConnect implements NetSDKLib.fHaveReConnect { public void invoke(LLong m_hLoginHandle, String pchDVRIP, int nDVRPort, Pointer dwUser) { System.out.printf("ReConnect Device[%s] Port[%d]\n", pchDVRIP, nDVRPort); } } public void EndTest() { System.out.println("End Test"); if( m_hLoginHandle.longValue() != 0) { NetSdk.CLIENT_Logout(m_hLoginHandle); } System.out.println("See You..."); NetSdk.CLIENT_Cleanup(); System.exit(0); } public void InitTest() { //初始化SDK库 NetSdk.CLIENT_Init(disConnect, null); // 设置断线重连回调接口,设置过断线重连成功回调函数后,当设备出现断线情况,SDK内部会自动进行重连操作 // 此操作为可选操作,但建议用户进行设置 NetSdk.CLIENT_SetAutoReconnect(haveReConnect, null); //设置登录超时时间和尝试次数,可选 int waitTime = 5000; //登录请求响应超时时间设置为5S int tryTimes = 3; //登录时尝试建立链接3次 NetSdk.CLIENT_SetConnectTime(waitTime, tryTimes); // 设置更多网络参数,NET_PARAM的nWaittime,nConnectTryNum成员与CLIENT_SetConnectTime // 接口设置的登录设备超时时间和尝试次数意义相同,可选 NetSDKLib.NET_PARAM netParam = new NetSDKLib.NET_PARAM(); netParam.nConnectTime = 10000; //登录时尝试建立链接的超时时间 NetSdk.CLIENT_SetNetworkParam(netParam); // 打开日志,可选 NetSDKLib.LOG_SET_PRINT_INFO setLog = new NetSDKLib.LOG_SET_PRINT_INFO(); File path = new File("."); String logPath = path.getAbsoluteFile().getParent() + File.separator + "sdklog"; File file = new File(logPath); if (!file.exists()) { file.mkdir(); } logPath = file + File.separator + "123456789.log"; System.out.println(logPath); setLog.bSetFilePath = 1; System.arraycopy(logPath.getBytes(), 0, setLog.szLogFilePath, 0, logPath.getBytes().length); for (int i = 0; i < setLog.szLogFilePath.length; i++) { System.out.print((char)setLog.szLogFilePath[i] + " "); } System.out.println(); setLog.bSetPrintStrategy = 1; setLog.nPrintStrategy = 0; boolean bLogopen = NetSdk.CLIENT_LogOpen(setLog); if (!bLogopen) { System.err.println("Failed to open NetSDK log !!!"); } // 向设备登入 int nSpecCap = 0; Pointer pCapParam = null; IntByReference nError = new IntByReference(0); m_hLoginHandle = NetSdk.CLIENT_LoginEx2(m_strIp, m_nPort, m_strUser , m_strPassword ,nSpecCap,pCapParam, m_stDeviceInfo,nError); if(m_hLoginHandle.longValue() != 0) { System.out.printf("Login Device[%s] Port[%d]Success!\n" , m_strIp , m_nPort); } else { System.out.printf("Login Device[%s] Port[%d]Fail.Last Error[0x%x]\n" , m_strIp , m_nPort , NetSdk.CLIENT_GetLastError()); // EndTest(); } } // 远程抓图 public void snapPicture(int chn) { //设置抓图回调函数, 图片主要在m_SnapReceiveCB中返回 NetSdk.CLIENT_SetSnapRevCallBack(fSnapReceiveCB.getInstance(), null); // 发送抓图命令给前端设备,抓图的信息 NetSDKLib.SNAP_PARAMS stuSnapParams = new NetSDKLib.SNAP_PARAMS() ; stuSnapParams.Channel = chn; //抓图通道 stuSnapParams.mode = 0; //表示请求一帧 stuSnapParams.Quality = 3; stuSnapParams.InterSnap = 5; stuSnapParams.CmdSerial = 100; // 请求序列号,有效值范围 0~65535,超过范围会被截断为 IntByReference reserved = new IntByReference(0); if (false == NetSdk.CLIENT_SnapPictureEx(m_hLoginHandle, stuSnapParams, reserved)) { System.err.println("CLIENT_SnapPictureEx Failed!" + ToolKits.getErrorCode()); return; } else { System.out.println("CLIENT_SnapPictureEx success"); } } public static class fSnapReceiveCB implements NetSDKLib.fSnapRev{ private fSnapReceiveCB() {} private static class fSnapReceiveCBHolder { private static fSnapReceiveCB instance = new fSnapReceiveCB(); } private static fSnapReceiveCB getInstance() { return fSnapReceiveCBHolder.instance; } public void invoke( LLong lLoginID, Pointer pBuf, int RevLen, int EncodeType, int CmdSerial, Pointer dwUser) { ////////////////////// 读取抓图的数据(格式JPG) /////////////////////////// System.out.println("正在获取背景图数据..."); // jpg格式的Buf byte[] buf = pBuf.getByteArray(0, RevLen); ByteArrayInputStream byteArrInput = new ByteArrayInputStream(buf); try { BufferedImage bufferedImage = ImageIO.read(byteArrInput); if(bufferedImage == null) { return; } ByteArrayOutputStream byteArrOutput = new ByteArrayOutputStream(); try { // 此方式转换出来的位深度为 24 ImageIO.write(bufferedImage, "bmp", byteArrOutput); } catch (IOException e1) { e1.printStackTrace(); } ////////////////// 获取背景图的缓存、宽高 ///////////// byte[] buffer = byteArrOutput.toByteArray(); // bmp格式的Buf int width = bufferedImage.getWidth(); int height = bufferedImage.getHeight(); new MyThread(buffer, width, height).start(); } catch (IOException e) { e.printStackTrace(); } } } private static class MyThread extends Thread { byte[] bBackBuf;; int nBackWidth; int nBackHeight; public MyThread(byte[] buffer, int width, int height) { this.bBackBuf = buffer; this.nBackWidth = width; this.nBackHeight = height; } @Override public void run() { System.out.println("正在查询灰度图数据..."); ////////////////// 查询灰度图数据 ////////////////////////// if(queryHeatMap(0, "2022-05-06 14:00:0", "2022-05-06 17:00:00")) { System.out.println("正在生成热度图..."); /** * 入参 */ HEATMAP_IMAGE_IN stIn = new HEATMAP_IMAGE_IN(); /////////////////////// 灰度图, 不带头 //////////////////////// // 获取到的灰度数据的位深度是8, 位深度为8时,需要加 1024 // 灰度图大小,不带头 int nGrayLen = 0; // 位深度 int nBit = grayData.getGrayBufLen() / ( grayData.getGrayWidth() * grayData.getGrayHeight() ) * 8; if(nBit == 8) { nGrayLen = grayData.getGrayBufLen() * 8/8; } else { nGrayLen = grayData.getGrayWidth() * grayData.getGrayHeight() * nBit / 8; } // 申请内存 stIn.stuGrayBmpInfo.pBuffer = new Memory(nGrayLen); stIn.stuGrayBmpInfo.pBuffer.clear(nGrayLen); // 灰度图赋值 stIn.stuGrayBmpInfo.pBuffer = grayData.getGratBufData(); stIn.stuGrayBmpInfo.nWidth = grayData.getGrayWidth(); stIn.stuGrayBmpInfo.nHeight = grayData.getGrayHeight(); stIn.stuGrayBmpInfo.nBitCount = nBit; stIn.stuGrayBmpInfo.nDirection = 0; ////////////////////////// 背景图, 带头 ////////////////////////////// // 转换出来的背景图位深度是24 // 54是头 int nBackPicLen = nBackWidth * nBackHeight * 24/8 + 54; stIn.stuBkBmpInfo.pBuffer = new Memory(nBackPicLen); stIn.stuBkBmpInfo.pBuffer.clear(nBackPicLen); stIn.stuBkBmpInfo.pBuffer.write(0, bBackBuf, 0, nBackPicLen); stIn.stuBkBmpInfo.nWidth = nBackWidth; stIn.stuBkBmpInfo.nHeight = nBackHeight; stIn.stuBkBmpInfo.nBitCount = 24; stIn.stuBkBmpInfo.nDirection = 1; /** * 出参 */ //////////////////////// 热度图, 带头 ////////////////////////// HEATMAP_IMAGE_Out stOut = new HEATMAP_IMAGE_Out(); stOut.pBuffer = new Memory(nBackPicLen); stOut.pBuffer.clear(nBackPicLen); stOut.nPicSize = nBackPicLen; // 热度图的大小与背景图相同 stOut.fOpacity = 0.2F; // 透明度 // 生成热度图 if(HeatMapSdk.CreateHeatMap(stIn, stOut)) { File currentPath = new File("."); String strFileSnapPic = currentPath.getAbsoluteFile().getParent() + "\\" + "HeatMap.jpg"; byte[] buf = stOut.pBuffer.getByteArray(0, nBackPicLen); ByteArrayInputStream bInputStream = new ByteArrayInputStream(buf); try { BufferedImage bufferedImage = ImageIO.read(bInputStream); if(bufferedImage == null) { System.err.println("bufferedImage == null"); return; } // 写文件,生成图片 ImageIO.write(bufferedImage, "jpg", new File(strFileSnapPic)); } catch (IOException e) { e.printStackTrace(); } System.out.println("已生成热度图..."); } else { System.err.println("失败!!!"); } } } } // 查询热度图 public static boolean queryHeatMap(int chn, String startTime, String endTime) { // 开始时间 String[] startStr = startTime.split(" "); String[] startTimeStr1 = startStr[0].split("-"); String[] startTimeStr2 = startStr[1].split(":"); // 结束时间 String[] endStr = endTime.split(" "); String[] endTimeStr1 = endStr[0].split("-"); String[] endTimeStr2 = endStr[1].split(":"); NET_QUERY_HEAT_MAP heatMap = new NET_QUERY_HEAT_MAP(); heatMap.stuIn.nChannel = chn; // 通道 // 开始时间 heatMap.stuIn.stuBegin.dwYear = Integer.parseInt(startTimeStr1[0]); heatMap.stuIn.stuBegin.dwMonth = Integer.parseInt(startTimeStr1[1]); heatMap.stuIn.stuBegin.dwDay = Integer.parseInt(startTimeStr1[2]); heatMap.stuIn.stuBegin.dwHour = Integer.parseInt(startTimeStr2[0]); heatMap.stuIn.stuBegin.dwMinute = Integer.parseInt(startTimeStr2[1]); heatMap.stuIn.stuBegin.dwSecond = Integer.parseInt(startTimeStr2[2]); // 结束时间 heatMap.stuIn.stuEnd.dwYear = Integer.parseInt(endTimeStr1[0]); heatMap.stuIn.stuEnd.dwMonth = Integer.parseInt(endTimeStr1[1]); heatMap.stuIn.stuEnd.dwDay = Integer.parseInt(endTimeStr1[2]); heatMap.stuIn.stuEnd.dwHour = Integer.parseInt(endTimeStr2[0]); heatMap.stuIn.stuEnd.dwMinute = Integer.parseInt(endTimeStr2[1]); heatMap.stuIn.stuEnd.dwSecond = Integer.parseInt(endTimeStr2[2]); // 指针申请内存 int size = 4000 * 4000; heatMap.stuOut.pBufData = new Memory(size); heatMap.stuOut.pBufData.clear(size); heatMap.stuOut.nBufLen = size; heatMap.stuOut.emDataType = 1; // 1-灰度数据 2-原始数据 IntByReference pRetLen = new IntByReference(0); heatMap.write(); boolean bRet = NetSdk.CLIENT_QueryDevState(m_hLoginHandle, NetSDKLib.NET_DEVSTATE_GET_HEAT_MAP, heatMap.getPointer(), heatMap.size(), pRetLen, 5000); heatMap.read(); if(bRet) { grayData = new GRAY_MAP(); grayData.setGratBufData(heatMap.stuOut.pBufData); grayData.setGrayBufLen(heatMap.stuOut.nBufRet); grayData.setGrayWidth(heatMap.stuOut.nWidth); grayData.setGrayHeight(heatMap.stuOut.nHeight); } else { JOptionPane.showMessageDialog(null, "查到热度图失败, 错误码 :" + ToolKits.getErrorCode()); System.err.println("Query HeatMap Failed!" + ToolKits.getErrorCode()); return false; } return true; } // 灰度图数据 static class GRAY_MAP { public Pointer pGratBufData; public int nGrayBufLen; public int nGrayWidth; public int nGrayHeight; public Pointer getGratBufData() { return pGratBufData; } public void setGratBufData(Pointer pGratBufData) { this.pGratBufData = pGratBufData; } public int getGrayBufLen() { return nGrayBufLen; } public void setGrayBufLen(int nGrayBufLen) { this.nGrayBufLen = nGrayBufLen; } public int getGrayWidth() { return nGrayWidth; } public void setGrayWidth(int nGrayWidth) { this.nGrayWidth = nGrayWidth; } public int getGrayHeight() { return nGrayHeight; } public void setGrayHeight(int nGrayHeight) { this.nGrayHeight = nGrayHeight; } } public void CreateHeatMap() { snapPicture(0); } public void RunTest() { System.out.println("Run Test"); CaseMenu menu = new CaseMenu(); menu.addItem(new CaseMenu.Item(this , "获取热度图" , "CreateHeatMap")); menu.run(); } public static void main(String[]args) { HeatMapEx2 demo = new HeatMapEx2(); demo.InitTest(); demo.RunTest(); demo.EndTest(); } }