目录

背景:

 1、问题

2、截图程序自动化和多通道实现

3、摄像头参数灵活化

至此已经全部结束,运行程序可以看到


背景:

目标识别需要对每一帧图像进行检测,因此我们需要将摄像头获取的视频流转换成单帧图像,海康威视官网提供的原本的sdk包实现了点击抓图按钮就截一张图,并且不支持多摄像头截图。海康威视的sdk下载链接为SDK下载

python海康监控预览截图 海康摄像头截图_System

Java版本实现单通道结果如图,在红框内输入摄像头的数据--单机注册--预览就可以看到右边摄像头实时画面了。

python海康监控预览截图 海康摄像头截图_System_02

 1、问题

对于我们的目标检测需求来说,需要解决以下几个问题:

  1. 截图程序自动化,例如每一秒截一张图,而不需要手动点击抓图
  2. 截图程序能够实现多通道截图,而不是只能使用单通道
  3. 摄像头配置灵活化,应该利用数据库存储每个摄像头参数,然后程序读取数据库的摄像头数据。

2、截图程序自动化和多通道实现

        解决自动化问题和多通道问题我的主要思路为通过多线程(Threads)来完成,利用线程的sleep(XXX)方法,根据设定的xxx来实现自动截图。下面解释一下我的代码

(1)实现runnable接口,重写run方法

public class MultiThreaded implements Runnable {
	private MonitorCameraInfo cameraInfo;
	//创建构造方法,在new的时候外界传递摄像头参数对象cameraInfo。
	public MultiThreaded(MonitorCameraInfo cameraInfo){
		this.cameraInfo=cameraInfo;
	}
	//默认的构造参数
	public  MultiThreaded() {
	}
	//重写接口的run方法;这部分后期摄像头多的情况下需要改成线程池的方法
	@Override
	public void run() {
		// TODO Auto-generated method stub
		
		MultiThreaded mt = new MultiThreaded();
		//while目的是实现自动截图,配合sleep函数
		while(true){
			//调用摄像头注册验证功能模块
			mt.getDVRConfig(cameraInfo);
			try {
				//主要作用是截图并存储
				mt.getDVRPic(cameraInfo);
			} catch (IOException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
		}
	}

(2)注册和验证摄像头 以及 抓图功能

/**
	 * 注册摄像头以及验证
	 * @param cameraInfo
	 */
	public  void getDVRConfig(MonitorCameraInfo cameraInfo) {  
        HCNetSDK sdk = HCNetSDK.INSTANCE;  
        //判断摄像头是否开启  
        if (!sdk.NET_DVR_Init()) {  
            System.out.println("SDK初始化失败");  
            return;  
        }  
        NET_DVR_DEVICEINFO_V30 devinfo = new NET_DVR_DEVICEINFO_V30();// 设备信息  
        //登录信息  
        NativeLong id = sdk.NET_DVR_Login_V30(cameraInfo.getCameraIp(), (short) cameraInfo.getCameraPort(),  
                cameraInfo.getUserName(), cameraInfo.getUserPwd(), devinfo);  
  
        cameraInfo.setUserId(id);// 返回一个用户编号,同时将设备信息写入devinfo  
        if (cameraInfo.getUserId().intValue() < 0) {  
            System.out.println("设备注册失败");  
            return;  
        }  
        //DVR工作状态  
        NET_DVR_WORKSTATE_V30 devwork = new NET_DVR_WORKSTATE_V30();  
        if (!sdk.NET_DVR_GetDVRWorkState_V30(cameraInfo.getUserId(), devwork)) {  
            // 返回Boolean值,判断是否获取设备能力  
            System.out.println("返回设备状态失败");  
        }  
  
        IntByReference ibrBytesReturned = new IntByReference(0);// 获取IP接入配置参数  
        NET_DVR_IPPARACFG ipcfg = new NET_DVR_IPPARACFG();//IP接入配置结构  
        ipcfg.write();  
        Pointer lpIpParaConfig = ipcfg.getPointer();  
        //获取相关参数配置  
        sdk.NET_DVR_GetDVRConfig(cameraInfo.getUserId(), HCNetSDK.NET_DVR_GET_IPPARACFG, new NativeLong(0),  
                lpIpParaConfig, ipcfg.size(), ibrBytesReturned);  
        ipcfg.read();  
        System.out.print("IP地址:" + cameraInfo.getCameraIp());  
        System.out.println("|设备状态:" + devwork.dwDeviceStatic);// 0正常,1CPU占用率过高,2硬件错误,3未知  
        //System.out.println("ChanNum"+devinfo.byChanNum);  
        // 显示模拟通道  
        for (int i = 0; i < devinfo.byChanNum; i++) {  
            System.out.print("Camera" + i + 1);// 模拟通道号名称  
            System.out.print("|是否录像:" + devwork.struChanStatic[i].byRecordStatic);// 0不录像,不录像  
            System.out.print("|信号状态:" + devwork.struChanStatic[i].bySignalStatic);// 0正常,1信号丢失  
            System.out.println("|硬件状态:" + devwork.struChanStatic[i].byHardwareStatic);// 0正常,1异常  
        }  
        //注销用户  
        sdk.NET_DVR_Logout(cameraInfo.getUserId());//释放SDK资源  
        sdk.NET_DVR_Cleanup();  
    }  
	/**
	 * 抓拍图片  
	 * @param cameraInfo
	 * @throws IOException
	 */
    public void getDVRPic(MonitorCameraInfo cameraInfo) throws IOException {           
        //设置通道号,其中1正常,-1不正常  
        NativeLong chanLong = new NativeLong(1);  
        cameraInfo.setChannel(chanLong);  
        //System.out.println("Channel:"+chanLong);  
        long startTime = System.currentTimeMillis();  
        HCNetSDK sdk = HCNetSDK.INSTANCE;  
        if (!sdk.NET_DVR_Init()) {  
            System.out.println("SDK初始化失败");  
            return;  
        }  
  
        NET_DVR_DEVICEINFO_V30 devinfo = new NET_DVR_DEVICEINFO_V30();// 设备信息  
          
        //注册设备  
        NativeLong id = sdk.NET_DVR_Login_V30(cameraInfo.getCameraIp(), (short) cameraInfo.getCameraPort(),  
                cameraInfo.getUserName(), cameraInfo.getUserPwd(), devinfo);  
        cameraInfo.setUserId(id);// 返回一个用户编号,同时将设备信息写入devinfo  
        if (cameraInfo.getUserId().intValue() < 0) {  
            System.out.println("设备注册失败"+sdk.NET_DVR_GetLastError());  
            return;  
        } else {  
            System.out.println("id:" + cameraInfo.getUserId().intValue());  
        }  
        NET_DVR_WORKSTATE_V30 devwork = new NET_DVR_WORKSTATE_V30();  
        if (!sdk.NET_DVR_GetDVRWorkState_V30(cameraInfo.getUserId(), devwork)) {  
            // 返回Boolean值,判断是否获取设备能力  
            System.out.println("返回设备状态失败");  
        }  
  
        //System.out.println("设备注册耗时:[" + (System.currentTimeMillis() - startTime) + "]");  
  
        startTime = System.currentTimeMillis();  
        //图片质量  
        NET_DVR_JPEGPARA jpeg = new NET_DVR_JPEGPARA();  
        // 设置图片的分辨率  
        jpeg.wPicSize = 2;  
        // 设置图片质量  
        jpeg.wPicQuality = 2;  
  
        IntByReference a = new IntByReference();  
        //设置图片大小  
        ByteBuffer jpegBuffer = ByteBuffer.allocate(1024 * 1024);  
        // 创建文件目录和文件  
        SimpleDateFormat sd = new SimpleDateFormat("yyyyMMdd");  
        SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMddHHmmss");  
        Date date = new Date();  
        //按照每天设置一个目录  
        String fileName = cameraInfo.getPath() +sd.format(date) ;   
        File files = new File(fileName);  
        if(!files.exists()){  
            files.mkdirs();  
        }  
          
        //按照日期文件夹放入图片  
        String fileNameString = fileName+"/"+ cameraInfo.getId()+sdf.format(date)+".jpg";  
        System.out.println(fileNameString);  
        File file = new File(fileNameString);  
  
        // 抓图到内存,单帧数据捕获并保存成JPEG存放在指定的内存空间中  
        //需要加入通道  
        boolean is = sdk.NET_DVR_CaptureJPEGPicture_NEW(cameraInfo.getUserId(), cameraInfo.getChannel(), jpeg,  
                jpegBuffer, 1024 * 1024, a);  
        //System.out.println("Channel:"+cameraInfo.getChannel());  
        System.out.println("抓图到内存耗时:[" + (System.currentTimeMillis() - startTime) + "ms]");  
  
        // 抓图到文件  
        //boolean is = sdk.NET_DVR_CaptureJPEGPicture(cameraInfo.UserId,cameraInfo.Channel,jpeg, fileNameString);  
        if (is) {  
            System.out.println("抓取成功,返回长度:" + a.getValue());  
        } else {  
            System.out.println("抓取失败:"+sdk.NET_DVR_GetLastError());  
        }  
  
        //startTime = System.currentTimeMillis();  
        // 存储本地,写入内容  
        BufferedOutputStream outputStream = null;  
        try {  
            outputStream = new BufferedOutputStream(new FileOutputStream(file));  
            outputStream.write(jpegBuffer.array(), 0, a.getValue());  
            outputStream.flush();  
        } catch (Exception e) {  
            e.printStackTrace();  
        } finally {  
            if (outputStream != null) {  
                try {  
                    outputStream.close();  
                } catch (IOException e) {  
                    e.printStackTrace();  
                }  
            }  
        }  
  
        System.out.println("存储本地耗时:[" + (System.currentTimeMillis() - startTime) + "ms]");  
  
        sdk.NET_DVR_Logout(cameraInfo.getUserId());  
        sdk.NET_DVR_Cleanup();  
    }  
}

(3)多线程通道开启,首先查询数据库获取摄像头总个数,然后根据摄像头个数创建对应的线程数,第二 遍历摄像头集合,创建对应的MultiThread对象,将摄像头作为构造参数赋值;第三开启线程,并配合sleep方法。

python海康监控预览截图 海康摄像头截图_bc_03

3、摄像头参数灵活化

(1)创建数据库,将数据存储到数据库中

python海康监控预览截图 海康摄像头截图_映射文件_04

 

(2)Java使用Mybaties作为数据库连接 

具体配置等信息可以参考我的博客SSM相关配置;下面大体写一下实现过程

  • 创建pojo对象(get set方法篇幅所限省略)

python海康监控预览截图 海康摄像头截图_python海康监控预览截图_05

  • 数据库连接数据 db.properties
jdbc.driver=com.mysql.jdbc.Driver
jdbc.url=jdbc:mysql://localhost:3306/object_detect?characterEncoding=utf-8
jdbc.username=root
jdbc.password=root
  • 创建SqlMapConfig.xml文件 功能主要为连接数据库和mapper扫描
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE configuration
PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-config.dtd">
<configuration>
	<properties resource="db.properties"></properties>
	
	<typeAliases> 
		<!-- 定义单个pojo类别名
		type:类的全路劲名称
		alias:别名
		 -->
<!-- 		<typeAlias type="cn.chuantao.pojo.User" alias="user"/> -->
		
		<!-- 使用包扫描的方式批量定义别名 
		定以后别名等于类名,不区分大小写,但是建议按照java命名规则来,首字母小写,以后每个单词的首字母大写
		-->
		<package name="pojo"/>
	</typeAliases>
 
	<!-- 和spring整合后 environments配置将废除-->
	<environments default="development">
		<environment id="development">
		<!-- 使用jdbc事务管理-->
		<transactionManager type="JDBC" />
		<!-- 数据库连接池-->
		<dataSource type="POOLED">
			<property name="driver" value="${jdbc.driver}" />
			<property name="url" value="${jdbc.url}" />
			<property name="username" value="${jdbc.username}" />
			<property name="password" value="${jdbc.password}" />
		</dataSource>
		</environment>
	</environments>
	
	<mappers>
		<!-- <mapper resource="mapper/FindCamera.xml"/> -->
		
		<!-- 
		使用class属性引入接口的全路径名称:
		使用规则:
			1. 接口的名称和映射文件名称除扩展名外要完全相同
			2. 接口和映射文件要放在同一个目录下
		 -->
<!-- 		<mapper class="cn.chuantao.mapper.UserMapper"/> -->
		
		<!-- 使用包扫描的方式批量引入Mapper接口 
				使用规则:
				1. 接口的名称和映射文件名称除扩展名外要完全相同
				2. 接口和映射文件要放在同一个目录下
		-->
		<package name="mapper"/>
	</mappers>
</configuration>
  • 创建mapper信息:xml和对应的接口映射

python海康监控预览截图 海康摄像头截图_System_06

python海康监控预览截图 海康摄像头截图_python海康监控预览截图_07

(3)程序:查询数据库得到摄像头配置信息

python海康监控预览截图 海康摄像头截图_映射文件_08

python海康监控预览截图 海康摄像头截图_多摄像头截图程序_09

至此已经全部结束,运行程序可以看到

python海康监控预览截图 海康摄像头截图_bc_10

python海康监控预览截图 海康摄像头截图_bc_11