zhanghua
2024-12-20 1f45c25ea725445d7e78e8d5da6e72150f35f2eb
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
package com.dahua.netsdk.module;
 
import com.dahua.netsdk.lib.HeatMapLib;
import com.dahua.netsdk.lib.NetSDKLib;
import com.dahua.netsdk.lib.ToolKits;
import com.dahua.netsdk.lib.callback.fVideoStatHeatMapCallBack;
import com.dahua.netsdk.lib.enumeration.EM_HEATMAP_TYPE;
import com.dahua.netsdk.lib.enumeration.ENUMERROR;
import com.dahua.netsdk.lib.structure.*;
import com.dahua.netsdk.module.entity.BmpInfo;
import com.sun.jna.Memory;
import com.sun.jna.Pointer;
import com.sun.jna.Structure;
 
import javax.imageio.ImageIO;
import java.awt.image.BufferedImage;
import java.io.*;
 
/**
 * @author 47081
 * @version 1.0
 * @description 二次封装的模块, 热度图相关
 * @date 2020/9/23
 */
public class HeatMapModule extends BaseModule {
  private HeatMapLib heatMap;
 
  public HeatMapModule() {
    this(NetSDKLib.NETSDK_INSTANCE, HeatMapLib.HEATMAP_INSTANCE);
  }
 
  public HeatMapModule(NetSDKLib netsdkApi) {
    this(netsdkApi, HeatMapLib.HEATMAP_INSTANCE);
  }
 
  public HeatMapModule(NetSDKLib netsdkApi, HeatMapLib heatMapLib) {
    super(netsdkApi);
    this.heatMap = heatMapLib;
  }
 
  /**
   * 订阅热度图数据
   *
   * @param loginHandler 登录句柄
   * @param channel 通道号
   * @param callBack 回调函数,回调函数建议使用单例模式
   * @param dwUser 用户数据,不需要可以传null,如果使用,请注意保持dwUser,别被JVM回收
   * @param nWaitTime 超时时间,单位毫秒
   * @return
   */
  public long attach(
      long loginHandler,
      int channel,
      fVideoStatHeatMapCallBack callBack,
      Structure dwUser,
      int nWaitTime) {
    NET_IN_ATTACH_VIDEOSTAT_HEATMAP inParam = new NET_IN_ATTACH_VIDEOSTAT_HEATMAP();
    inParam.nChannel = channel;
    inParam.cbVideoStatHeatMap = callBack;
    if (dwUser != null) {
      inParam.dwUser = dwUser.getPointer();
    }
    NET_OUT_ATTACH_VIDEOSTAT_HEATMAP outParam = new NET_OUT_ATTACH_VIDEOSTAT_HEATMAP();
    Pointer pointer = new Memory(inParam.size());
    ToolKits.SetStructDataToPointer(inParam, pointer, 0);
    NetSDKLib.LLong attachHandler =
        getNetsdkApi()
            .CLIENT_AttachVideoStatHeatMap(
                new NetSDKLib.LLong(loginHandler), pointer, outParam.getPointer(), nWaitTime);
    if (attachHandler.longValue() == 0) {
      System.err.println(
          "CLIENT_AttachVideoStatHeatMap failed.the error is "
              + ENUMERROR.getErrorMessage()
              + "\n"
              + ENUMERROR.getENUMError());
    }
    return attachHandler.longValue();
  }
 
  /**
   * 获取热度图数据
   *
   * @param attachHandler 订阅句柄
   * @param planId 计划(预置点,仅球机有效,范围1~MaxNumberStatPlan), 球机必填,范围1~MaxNumberStatPlan。
   *     IPC等没有PlanID概念,不填或者0表示不关注PlanID
   * @param startTime 开始时间 时间格式为(年/月/日/时/分/秒)
   * @param endTime 结束时间 时间格式为(年/月/日/时/分/秒)
   * @param type AI热图类型
   * @return
   */
  public int get(
      long attachHandler,
      int planId,
      String startTime,
      String endTime,
      EM_HEATMAP_TYPE type,
      int waitTime) {
    NET_IN_GET_VIDEOSTAT_HEATMAP inParam = new NET_IN_GET_VIDEOSTAT_HEATMAP();
    inParam.nPlanID = planId;
    inParam.stuStartTime = new NET_TIME(startTime);
    inParam.stuEndTime = new NET_TIME(endTime);
    inParam.emHeatMapType = type.getType();
    Pointer inPointer = new Memory(inParam.size());
    ToolKits.SetStructDataToPointer(inParam, inPointer, 0);
    NET_OUT_GET_VIDEOSTAT_HEATMAP outParam = new NET_OUT_GET_VIDEOSTAT_HEATMAP();
    Pointer pointer = new Memory(outParam.size());
    ToolKits.SetStructDataToPointer(outParam, pointer, 0);
    boolean result =
        getNetsdkApi()
            .CLIENT_GetVideoStatHeatMap(
                new NetSDKLib.LLong(attachHandler), inPointer, pointer, waitTime);
    if (!result) {
      System.out.println(
          "CLIENT_GetVideoStatHeatMap failed. the error is " + ENUMERROR.getErrorMessage());
      return 0;
    }
    ToolKits.GetPointerData(pointer, outParam);
    return outParam.nToken;
  }
 
  /**
   * 退订热度图数据
   *
   * @param attachHandler 订阅句柄
   * @return
   */
  public boolean detach(long attachHandler) {
    boolean result =
        getNetsdkApi().CLIENT_DetachVideoStatHeatMap(new NetSDKLib.LLong(attachHandler));
    if (!result) {
      System.out.println(
          "CLIENT_DetachVideoStatHeatMap failed. the error is " + ENUMERROR.getErrorMessage());
    }
    return result;
  }
 
  /**
   * 将网络数据转换成灰度数据
   *
   * @param data 热度图数据
   * @param width 宽
   * @param height 高
   * @return
   */
  public byte[] transferGray(byte[] data, int width, int height) {
    Pointer inParam = new Memory(data.length);
    inParam.write(0, data, 0, data.length);
    byte[] out = new byte[width * height];
    Pointer outParam = new Memory(width * height);
    heatMap.TransNetDataToGrayData(inParam, width, height, outParam);
    outParam.read(0, out, 0, out.length);
    return out;
  }
 
  public boolean createHeatMap(
      BmpInfo srcBmp, BufferedImage backBmp, String destFile, float opacity) throws IOException {
    ByteArrayOutputStream byteArrOutput = new ByteArrayOutputStream();
    // 此方式转换出来的位深度是24位
    ImageIO.write(backBmp, "bmp", byteArrOutput);
    ////////////////// 获取背景图的缓存、宽高 /////////////
    // bmp格式的Buf
    byte[] buffer = byteArrOutput.toByteArray();
    int width = backBmp.getWidth();
    int height = backBmp.getHeight();
    // 转换出来的背景图位深度是24
    // 54是头
    int nBackPicLen = width * height * 24 / 8 + 54;
    BmpInfo backInfo = new BmpInfo(buffer, width, height, 24, 1, nBackPicLen);
    return createHeatMap(srcBmp, backInfo, destFile, opacity);
  }
 
  /**
   * 生成热度图图片
   *
   * @return
   */
  public boolean createHeatMap(BmpInfo srcBmp, BmpInfo backBmp, String destFile, float opacity) {
    HeatMapLib.HEATMAP_IMAGE_IN inParam = new HeatMapLib.HEATMAP_IMAGE_IN();
 
    inParam.stuGrayBmpInfo.pBuffer = new Memory(srcBmp.getLength());
    inParam.stuGrayBmpInfo.pBuffer.write(0, srcBmp.getData(), 0, srcBmp.getLength());
    inParam.stuGrayBmpInfo.nWidth = srcBmp.getWidth();
    inParam.stuGrayBmpInfo.nHeight = srcBmp.getHeight();
    inParam.stuGrayBmpInfo.nDirection = srcBmp.getnDirection();
    inParam.stuGrayBmpInfo.nBitCount = srcBmp.getBitCount();
 
    inParam.stuBkBmpInfo.pBuffer = new Memory(backBmp.getLength());
    inParam.stuBkBmpInfo.pBuffer.write(0, backBmp.getData(), 0, backBmp.getLength());
    inParam.stuBkBmpInfo.nWidth = backBmp.getWidth();
    inParam.stuBkBmpInfo.nHeight = backBmp.getHeight();
    inParam.stuBkBmpInfo.nDirection = backBmp.getnDirection();
    inParam.stuBkBmpInfo.nBitCount = backBmp.getBitCount();
 
    HeatMapLib.HEATMAP_IMAGE_Out outParam = new HeatMapLib.HEATMAP_IMAGE_Out();
    outParam.pBuffer = new Memory(backBmp.getData().length);
    outParam.nPicSize = backBmp.getWidth() * backBmp.getHeight() * backBmp.getBitCount() / 8 + 54;
    // 热度图的大小与背景图相同
    outParam.fOpacity = opacity;
    boolean result = heatMap.CreateHeatMap(inParam, outParam);
    if (!result) {
      System.out.println("create heatMap failed. the error is " + ENUMERROR.getErrorMessage());
      return false;
    }
    // 如果成功,写入目标文件
    byte[] buf = outParam.pBuffer.getByteArray(0, outParam.nPicSize);
    ByteArrayInputStream bInputStream = new ByteArrayInputStream(buf);
 
    BufferedImage bufferedImage = null;
    try {
      bufferedImage = ImageIO.read(bInputStream);
      // 写文件,生成图片
      ImageIO.write(bufferedImage, "bmp", new File(destFile));
      System.out.println("bmp heatmap write to " + destFile);
    } catch (IOException e) {
      e.printStackTrace();
    }
    if (bufferedImage == null) {
      System.err.println("bufferedImage == null");
      return false;
    }
    return true;
  }
 
  /**
   * 读取bmp文件
   *
   * @param file bmp文件路径
   * @return
   */
  public int[][] readBmpPic(String file) throws IOException {
    FileInputStream fis = new FileInputStream(file);
    BufferedInputStream bis = new BufferedInputStream(fis);
 
    // 丢掉文件头信息
    bis.skip(18);
 
    // 获取长度与宽度
    byte[] b1 = new byte[4];
    bis.read(b1);
    byte[] b2 = new byte[4];
    bis.read(b2);
 
    int Width = byte2Int(b1);
    int Height = byte2Int(b2);
    System.out.println("Height:" + Height + " Width:" + Width);
 
    // 因为bmp位图的读取顺序为横向扫描,所以应把数组定义为int[Height][Width]
    int[][] data = new int[Height][Width];
    int skipnum = 0;
 
    // bmp图像区域的大小必须为4的倍数,而它以三个字节存一个像素,读的是偶应当跳过补上的0
    if (Width * 3 % 4 != 0) {
      skipnum = 4 - Width * 3 % 4;
    }
    System.out.println(skipnum);
 
    bis.skip(28);
 
    for (int i = 0; i < data.length; i++) {
      for (int j = 0; j < data[i].length; j++) {
        int red = bis.read();
        int green = bis.read();
        int blue = bis.read();
      }
      if (skipnum != 0) {
        bis.skip(skipnum);
      }
    }
 
    bis.close();
    return data;
  }
 
  /**
   * byte to int
   *
   * @param b bmp
   * @return
   * @throws IOException
   */
  private int byte2Int(byte[] b) throws IOException {
    int num = (b[3] & 0xff << 24) | (b[2] & 0xff) << 16 | (b[1] & 0xff) << 8 | (b[0] & 0xff);
    return num;
  }
}