Java springBoot项目整合海康威视摄像头抓拍车辆功能

Java springBoot项目整合海康威视摄像头抓拍获取车辆信息功能

目前对海康摄像头的使用以及java的对接还是很多的,最近做了两个项目,
一个是安全帽报警人脸抓拍(单个摄像头)。一个是获取车辆信息并抓拍车牌图片(30个摄像头)。
写一篇文章记录一下开发过程,也可供大家学习借鉴,不懂也可留言。

下载海康威视sdk

海康sdk官网下载 —按照提示下载解压。

整合到springboot项目中

将sdk整合到springboot项目中,以下是以4个摄像头抓拍为例子写的。
我的结构目录
因为要同时启动多个摄像头进行抓拍车辆,所以使用了多线程,具体效果是实现了,但是可能还有优化的余地。
如果有懂多线程的大佬还请指导一二。
Java springBoot项目整合海康威视摄像头抓拍车辆功能_第1张图片
这里再导入jar包的时候需要再pom文件中配置,不然可能启动会检测不到

 
            com
            jna
            1.0.0
            system
            ${project.basedir}/src/main/resources/lib/jna.jar
        
        
            com
            examples
            1.0.0
            system
            ${project.basedir}/src/main/resources/lib/examples.jar
        

创建摄像头信息类,将所有摄像头信息存入

package com.danger.utils;

/**
 * @Author: SONGtiank
 * @Description: 摄像头信息
 * @Date: 2020/11/3 9:34
 * @Version: 1.0
 */
public class CameraInfo {
     

    public static final  String[][] cameraInfo =new String[31][];
	//在这只展示几个,数组用于存放摄像头信息:ip username password port
	//因为这里所有的摄像头用户名密码一致,所以我只存了ip和端口
	//如果不一致的话可以将用户名密码存入
    static {
     
        cameraInfo[0] = new String[]{
     "172.172.2.9","8000"};
        cameraInfo[1] = new String[]{
     "172.172.2.10","8000"};
        cameraInfo[2] = new String[]{
     "172.172.2.11","8000"};
        cameraInfo[3] = new String[]{
     "172.172.2.12","8000"};
        ....
    }


}

创建线程池

package com.danger.vehicle.controller;
import org.springframework.aop.interceptor.AsyncUncaughtExceptionHandler;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.scheduling.annotation.AsyncConfigurer;
import org.springframework.scheduling.annotation.EnableAsync;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
import java.util.concurrent.Executor;

/**
 * @Description: 配置类实现AsyncConfigurer接口,并重写getAsyncExecutor方法,并返回一个ThreadPoolTaskExecutor,
 * 这样我们就获得一个基于线程池TaskExecutor
 * @author SONGtiank
 * @Date: 2020/11/2 16:55
 * @Version: 1.0
 */
@Configuration
@ComponentScan("com.danger.vehicle")
@EnableAsync//利用@EnableAsync注解开启异步任务支持
public class CustomMultiThreadingConfig implements AsyncConfigurer{
     

    @Override
    public Executor getAsyncExecutor() {
     
        ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
        //核心线程数15:线程池创建时候初始化的线程数
        executor.setCorePoolSize(15);
        //最大线程数31:线程池最大的线程数,只有在缓冲队列满了之后才会申请超过核心线程数的线程
        executor.setMaxPoolSize(31);
        //缓冲队列500:用来缓冲执行任务的队列
        executor.setQueueCapacity(500);
        //允许线程的空闲时间60秒:当超过了核心线程出之外的线程在空闲时间到达之后会被销毁
        executor.setKeepAliveSeconds(60);
        //线程池名的前缀:设置好了之后可以方便我们定位处理任务所在的线程池
        executor.setThreadNamePrefix("DailyAsync-");
        executor.initialize();
        return executor;
    }

    @Override
    public AsyncUncaughtExceptionHandler getAsyncUncaughtExceptionHandler() {
     
        return AsyncConfigurer.super.getAsyncUncaughtExceptionHandler();
    }

}

创建海康sdk服务类

package com.danger.hktv.basics;
import com.danger.hktv.ClientDemo.HCNetSDK;
import com.danger.utils.*;
import com.sun.jna.NativeLong;
import com.sun.jna.Pointer;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.io.*;
import java.nio.ByteBuffer;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.*;
/**
 * @Author: SONGtiank
 * @Description: 海康sdk服务类
 * @Date: 2020/11/3 9:50
 * @Version: 1.0
 */
public class HikVisionService {
     
    private static Logger logger = LoggerFactory.getLogger(HikVisionService.class);
    static HCNetSDK hCNetSDK = HCNetSDK.INSTANCE;
    static String m_sUsername = "admin";//设备用户名
    static String m_sPassword = "*******";//设备密码
    static short m_sPort = 8000;//端口号,这是默认的
    public NativeLong lUserID;//用户句柄
    public NativeLong lAlarmHandle;//报警布防句柄
    public int lListenHandle;//报警监听句柄
    public NativeLong RemoteConfig;
    public static int code = 5;
    //撤防
    public void CloseAlarmChan() {
     
        //报警撤防
        if (lAlarmHandle.intValue() > -1) {
     
            if (hCNetSDK.NET_DVR_CloseAlarmChan_V30(lAlarmHandle)) {
     
                System.out.println("撤防成功");
                lAlarmHandle = new NativeLong(-1);
            }
        }
    }

    public  void initMemberFlowUpload(String m_sDeviceIP, int remainMinuteTime) throws InterruptedException {
     
        // 初始化
        Boolean flag = hCNetSDK.NET_DVR_Init();
        if (flag){
     
            System.out.println("初始化成功");
        }else{
     
            System.out.println("初始化失败");
        }
        //设置连接时间与重连时间
        hCNetSDK.NET_DVR_SetConnectTime(2000, 1);
        hCNetSDK.NET_DVR_SetReconnect(100000, true);
        //设备信息, 输出参数
        HCNetSDK.NET_DVR_DEVICEINFO_V40 m_strDeviceInfo = new HCNetSDK.NET_DVR_DEVICEINFO_V40();
        HCNetSDK.NET_DVR_USER_LOGIN_INFO m_strLoginInfo = new HCNetSDK.NET_DVR_USER_LOGIN_INFO();
        // 注册设备-登录参数,包括设备地址、登录用户、密码等
        m_strLoginInfo.sDeviceAddress = new byte[hCNetSDK.NET_DVR_DEV_ADDRESS_MAX_LEN];
        System.arraycopy(m_sDeviceIP.getBytes(), 0, m_strLoginInfo.sDeviceAddress, 0, m_sDeviceIP.length());
        m_strLoginInfo.sUserName = new byte[hCNetSDK.NET_DVR_LOGIN_USERNAME_MAX_LEN];
        System.arraycopy(m_sUsername.getBytes(), 0, m_strLoginInfo.sUserName, 0, m_sUsername.length());
        m_strLoginInfo.sPassword = new byte[hCNetSDK.NET_DVR_LOGIN_PASSWD_MAX_LEN];
        System.arraycopy(m_sPassword.getBytes(), 0, m_strLoginInfo.sPassword, 0, m_sPassword.length());
        m_strLoginInfo.wPort = m_sPort;
        m_strLoginInfo.bUseAsynLogin = false; //是否异步登录:0- 否,1- 是
        m_strLoginInfo.write();

        //设备信息, 输出参数
        int lUserID = hCNetSDK.NET_DVR_Login_V40(m_strLoginInfo,m_strDeviceInfo);
        if(lUserID< 0){
     
            System.out.println("hCNetSDK.NET_DVR_Login_V30()"+"\n" +hCNetSDK.NET_DVR_GetErrorMsg(null));
            hCNetSDK.NET_DVR_Cleanup();
            return;
        }
        //设置报警回调函数
        if (!hCNetSDK.NET_DVR_SetDVRMessageCallBack_V31(this::MsesGCallBack,null )){
     
            System.out.println("设置回调函数失败"+hCNetSDK.NET_DVR_GetLastError());
            return;
        }else {
     
            System.out.println("设置回调函数成功");
        }
        //启用布防
        HCNetSDK.NET_DVR_SETUPALARM_PARAM lpSetupParam = new HCNetSDK.NET_DVR_SETUPALARM_PARAM();
        lpSetupParam.dwSize = 0;
        lpSetupParam.byLevel = 1;//布防优先级:0- 一等级(高),1- 二等级(中)
        lpSetupParam.byAlarmInfoType = 1;//上传报警信息类型: 0- 老报警信息(NET_DVR_PLATE_RESULT), 1- 新报警信息(NET_ITS_PLATE_RESULT)
        int lAlarmHandle = hCNetSDK.NET_DVR_SetupAlarmChan_V41(lUserID,lpSetupParam);
        if (lAlarmHandle< 0)
        {
     
            System.out.println("NET_DVR_SetupAlarmChan_V41 error, %d\n"+hCNetSDK.NET_DVR_GetLastError());
            hCNetSDK.NET_DVR_Logout(lUserID);
            hCNetSDK.NET_DVR_Cleanup();
            return;
        }
        System.out.println("布防成功,开始监测车辆");

        //启动监听----------------------------------------------
        int iListenPort = 8000;
        String m_sListenIP = "127.0.0.1";

        lListenHandle = hCNetSDK.NET_DVR_StartListen_V30(m_sListenIP, (short) iListenPort, this::MsesGCallBack, null);
        if(lListenHandle < 0) {
     
//            JOptionPane.showMessageDialog(null, "启动监听失败,错误号:" +  hCNetSDK.NET_DVR_GetLastError());
        }
        else {
     
            System.out.println("启动监听成功");
        }
        

    }
    public boolean MsesGCallBack(int lCommand, HCNetSDK.NET_DVR_ALARMER pAlarmer, Pointer pAlarmInfo, int dwBufLen, Pointer pUser) {
     
        System.out.println("〈--进入回调,开始识别车牌--〉");
        try {
     
            String sAlarmType = new String();
            String[] newRow = new String[3];
            DateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd hh:mm:ss");
            SimpleDateFormat sf = new SimpleDateFormat("yyyyMMddHHmmss");
            String imgName =sf.format(new Date())+".jpg";
            String clImgName ="cl"+sf.format(new Date())+".jpg";
            String[] sIP = new String[2];
            switch (lCommand) {
     
                case 0x2800:	//交通抓拍结果上传
                    HCNetSDK.NET_DVR_PLATE_RESULT strPlateResult = new HCNetSDK.NET_DVR_PLATE_RESULT();
                    strPlateResult.write();
                    Pointer pPlateInfo = strPlateResult.getPointer();
                    pPlateInfo.write(0, pAlarmInfo.getByteArray(0, strPlateResult.size()), 0, strPlateResult.size());
                    strPlateResult.read();
                    try {
     
                        String srt3=new String(strPlateResult.struPlateInfo.sLicense,"GBK");
                        sAlarmType = sAlarmType + ":抓拍上传,车牌:"+ srt3;
                    }
                    catch (UnsupportedEncodingException e1) {
     
                        // TODO Auto-generated catch block
                        e1.printStackTrace();
                    } catch (IOException e) {
     
                        // TODO Auto-generated catch block
                        e.printStackTrace();
                    }
                    newRow[0] = dateFormat.format(new Date());
                    //报警类型
                    newRow[1] = sAlarmType;
                    //报警设备IP地址
                    sIP = new String(pAlarmer.sDeviceIP).split("\0", 2);
                    newRow[2] = sIP[0];
                    break;
                case 0x3050:	//交通抓拍的终端图片上传
                    HCNetSDK.NET_ITS_PLATE_RESULT strItsPlateResult = new HCNetSDK.NET_ITS_PLATE_RESULT();
                    strItsPlateResult.write();
                    Pointer pItsPlateInfo = strItsPlateResult.getPointer();
                    pItsPlateInfo.write(0, pAlarmInfo.getByteArray(0, strItsPlateResult.size()), 0, strItsPlateResult.size());
                    strItsPlateResult.read();
                    try {
     
                        byte byDangerousVehicles = strItsPlateResult.byDangerousVehicles;
                        String srt3=new String(strItsPlateResult.struPlateInfo.sLicense,"GBK");
                        sAlarmType ="是否危化品:"+byDangerousVehicles+"-->"+ sAlarmType + ",车辆类型:"+ CarType.getCarType(strItsPlateResult.byVehicleType+"".trim()) + ",交通抓拍上传,车牌:"+ srt3;
                        Map<String,String> paramMap = new HashMap<String,String>();
                        paramMap.put("type", CarType.getCarType(strItsPlateResult.byVehicleType+"".trim()));车辆类型
                        String filename = "D:\\imgUpload\\"+new String(pAlarmer.sDeviceIP).trim()+"\\";
                        String carFileName = "D:\\carImg\\"+new String(pAlarmer.sDeviceIP).trim()+"\\";
                        if("黄".equals(srt3.substring(0, 1).trim())){
     
                            paramMap.put("plateNumber", srt3.substring(1, srt3.length()).trim());//车牌号
                            paramMap.put("byCountry",srt3.substring(1, 2).trim());//省份
                            paramMap.put("byColor",srt3.substring(0, 1).trim());//车牌颜色
                            paramMap.put("cameraIp",new String(pAlarmer.sDeviceIP).trim());//ip地址
                            paramMap.put("picTime",dateFormat.format(new Date()));//当前时间
                            paramMap.put("wSpeed",String.valueOf(new Random().nextInt(55-5)+5));//速度 这是假的
                            paramMap.put("byIllegalType", BreakRulesType.getBreakRulesType(strItsPlateResult.wIllegalType));
                            for(int i=0;i<strItsPlateResult.dwPicNum;i++) {
     
                                if(strItsPlateResult.struPicInfo[i].dwDataLen>0) {
     
                                    FileOutputStream fout;
                                    if(strItsPlateResult.struPicInfo[i].byType==0){
      //车牌图片
                                        File file = new File(filename+imgName);
                                        if (!file.getParentFile().exists()) {
     
                                            file.getParentFile().mkdirs();
                                        }
                                        fout = new FileOutputStream(filename+imgName);
                                        logger.info("文件路径"+filename+imgName);
                                        //将字节写入文件
                                        long offset = 0;
                                        ByteBuffer buffers = strItsPlateResult.struPicInfo[i].pBuffer.getByteBuffer(offset, strItsPlateResult.struPicInfo[i].dwDataLen);
                                        byte [] bytes = new byte[strItsPlateResult.struPicInfo[i].dwDataLen];
                                        buffers.rewind();
                                        buffers.get(bytes);
                                        fout.write(bytes);
                                        fout.close();
                                    }
                                    if(strItsPlateResult.struPicInfo[i].byType==1){
     //车辆场景图片
                                        File file = new File(carFileName+clImgName);
                                        if (!file.getParentFile().exists()) {
     
                                            file.getParentFile().mkdirs();
                                        }
                                        fout = new FileOutputStream(carFileName+clImgName);
                                        logger.info("文件路径"+carFileName+clImgName);
                                        //将字节写入文件
                                        long offset = 0;
                                        ByteBuffer buffers = strItsPlateResult.struPicInfo[i].pBuffer.getByteBuffer(offset, strItsPlateResult.struPicInfo[i].dwDataLen);
                                        byte [] bytes = new byte[strItsPlateResult.struPicInfo[i].dwDataLen];
                                        buffers.rewind();
                                        buffers.get(bytes);
                                        fout.write(bytes);
                                        fout.close();
                                    }

                                }
                            }
                        }
                    }
                    catch (UnsupportedEncodingException e1) {
     
                        // TODO Auto-generated catch block
                        e1.printStackTrace();
                    } catch (IOException e) {
     
                        // TODO Auto-generated catch block
                        e.printStackTrace();
                    }
                    break;
            }
            logger.info("识别信息:---》" +sAlarmType +" ip:"+new String(pAlarmer.sDeviceIP).trim()+"时间:"+dateFormat.format(new Date()));
            return true;
        }catch (Exception e){
     
            e.printStackTrace();
            return false;
        }
    }
}

创建线程任务服务类

package com.danger.vehicle.service;

import com.danger.hktv.basics.HikVisionService;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Service;

/**
 * @Description: 创建线程任务服务
 * @Author SONGtiank
 * @Date: 2020/11/3 16:55
 * @Version: 1.0
 */
@Service
public class CustomMultiThreadingService {
     
    private Logger logger = LoggerFactory.getLogger(CustomMultiThreadingService.class);
    /**
     * @Description:通过@Async注解表明该方法是一个异步方法,
     * 如果注解在类级别上,则表明该类所有的方法都是异步方法,而这里的方法自动被注入使用ThreadPoolTaskExecutor作为TaskExecutor
     * @Author SONGtiank
     * @Date: 2020/11/2 16:55
     * @Version: 1.0
     * @Throws
     * @param m_ip
     */
    @Async
    public  void executeAysncTask1(String m_ip) throws InterruptedException{
     
        HikVisionService hikVisionService = new HikVisionService();
        hikVisionService.initMemberFlowUpload(m_ip, 100);

    }
    @Async
    public void executeAsyncTask2(String m_ip)throws InterruptedException{
     
        HikVisionService hikVisionService = new HikVisionService();
        hikVisionService.initMemberFlowUpload(m_ip, 100);
    }
    @Async
    public void executeAsyncTask3(String m_ip)throws InterruptedException{
     
        HikVisionService hikVisionService = new HikVisionService();
        hikVisionService.initMemberFlowUpload(m_ip, 100);
    }
    @Async
    public void executeAsyncTask4(String m_ip)throws InterruptedException{
     
        HikVisionService hikVisionService = new HikVisionService();
        hikVisionService.initMemberFlowUpload(m_ip, 100);
    }
  }

摄像头启动控制类

package com.danger.vehicle.controller;
import com.danger.utils.CameraInfo;
import com.danger.vehicle.service.CustomMultiThreadingService;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
import java.util.Timer;
import java.util.TimerTask;

/**
 * @description 摄像头控制类
 * @author SONGtiank
 * @Date: 2020/11/4 9:11
 * @Version: 1.0
 */
@Controller
public class CameraController {
     

    private org.slf4j.Logger logger = LoggerFactory.getLogger(CameraController.class);

    @Autowired
    private CustomMultiThreadingService customMultiThreadingService;

    @RequestMapping("/healthy")
    @ResponseBody
    public String healthy() throws InterruptedException {
     
        return "启动成功";

    }

    @ResponseBody
    @RequestMapping(value="/dotask")
    public String doTask() throws InterruptedException{
     
        Timer timer = new Timer();// 实例化Timer类
        timer.schedule(new TimerTask() {
     
            public void run() {
     
                //撤销布防上传通道
                try {
     
                    customMultiThreadingService.executeAysncTask1(CameraInfo.cameraInfo[0][0]);
                    customMultiThreadingService.executeAsyncTask2(CameraInfo.cameraInfo[1][0]);
                    customMultiThreadingService.executeAsyncTask3(CameraInfo.cameraInfo[2][0]);
                    customMultiThreadingService.executeAsyncTask4(CameraInfo.cameraInfo[3][0]);
                } catch (InterruptedException e) {
     
                    e.printStackTrace();
                }
            }
        }, 1000*60*5,1000*60*5);// 这里毫秒
        customMultiThreadingService.executeAysncTask1(CameraInfo.cameraInfo[0][0]);
        customMultiThreadingService.executeAsyncTask2(CameraInfo.cameraInfo[1][0]);
        customMultiThreadingService.executeAsyncTask3(CameraInfo.cameraInfo[2][0]);
        customMultiThreadingService.executeAsyncTask4(CameraInfo.cameraInfo[3][0]);
        return "success";
    }


}

违章类型(根据海康设备网络sdk开发手册编写,用于分辨车辆违章类型)

package com.danger.utils;

/**
 * @Author: SONGtiank
 * @Description: 违章类型
 * @Date: 2020/11/5 8:50
 * @Version: 1.0
 */
public class BreakRulesType {
     

    public static String getBreakRulesType( short rulesType ) {
     


        if(1349 <= rulesType && rulesType <=1728 && rulesType !=1357){
     
            return "超速行驶";
        }else
        if(1018<= rulesType && rulesType <=1625){
     

            switch (rulesType){
     
                case 1018:
                    return "占用非机动车道";
                case 1019:
                    return "占用专用车道";
                case 1039:
                    return "城市违停";
                case 1208:
                    return "不按导向车道行驶";
                case 1211:
                    return "路口停车";
                case 1228:
                    return "路口滞留";
                case 1240:
                    return "未系安全带";
                case 1301:
                    return "逆行";
                case 1344:
                    return "违反禁令标志";
                case 1357:
                    return "未礼让行人";
                case 1625:
                    return "违反信号灯";
            }
        }else {
     

            switch (rulesType){
     
                case 4613:
                    return "高速路违停";
                case 4615:
                    return "不按规定行驶";
                case 13451:
                    return "压线";
                case 13453:
                    return "违法变道";
                case 16251:
                    return "绿灯停车";
                case 4016:
                    return "低速行驶";
                case  4306:
                    return "低速行驶";
                case 6046:
                    return "超速行驶";
                case 6047:
                    return "超速行驶";
                case 6048:
                    return "超速行驶";
                case  6050:
                    return "超速行驶";
            }
        }
        return "未检测到违章";
    }

}

车辆类型(根据海康设备网络sdk开发手册编写,用于分辨车辆类型)

package com.danger.utils;

/**
 * @Description:车辆类型
 * @Date: 2020/11/4 15:29
 * @Version: 1.0
 */
public class CarType {
     

    public static String getCarType( String carType ) {
     
        switch (carType) {
     
            case "0":
                return "未知";
            case "1":
                return "客车";
            case "2":
                return "货车";
            case "3":
                return "轿车";
            case "4":
                return "面包车";
            case "5":
                return "小货车";
            case "6":
                return "行人";
            case "7":
                return "二轮车";
            case "8":
                return "三轮车";
            case "9":
                return "SUV";
            case "10":
                return "中型课车";
            case "11":
                return "机动车";
            case "12":
                return "非机动车";
            case "13":
                return "小型轿车";
            case "14":
                return "微型轿车";
            case "15":
                return "皮卡车";
            case "16":
                return "集装箱卡车";
            case "17":
                return "微卡";
            case "18":
                return "渣土车";
            case "19":
                return "吊车,工程车";
            case "20":
                return "油罐车";
            case "21":
                return "混凝土搅拌车";
            case "22":
                return "平板拖车";
            case "23":
                return "两厢轿车";
            case "24":
                return "三厢轿车";
            case "25":
                return "轿跑";
            case "26":
                return "小型客车";
            default:
                return null;
        }
    }

}

启动项目访问 /dotask 即可

这是我抓拍到的车辆图片,只是黄色牌照。文件夹名是所在摄像头的ip地址

Java springBoot项目整合海康威视摄像头抓拍车辆功能_第2张图片
Java springBoot项目整合海康威视摄像头抓拍车辆功能_第3张图片

车辆场景图

Java springBoot项目整合海康威视摄像头抓拍车辆功能_第4张图片

你可能感兴趣的:(海康sdk开发,java,spring,boot,spring)