视频AI分析定时任务思路解析

序言:

     最近项目中用到视频ai分析,由于sdk涉及保密,不便透露,仅对定时任务分析的思路作出分享,仅供参考。

1、定时任务

     由于ai服务器的性能上限,只能同时对64个rtsp流分析一种算法,或者对8个rtsp流分析8种算法。因此定时任务,做如下设计。   

    AiHandlerTask.java 



import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.ewaycloud.jw.ai.service.AiService;
import com.ewaycloud.jw.camera.entity.Camera;
import com.ewaycloud.jw.camera.mapper.CameraMapper;
import com.ewaycloud.jw.camera.service.CameraService;
import com.ewaycloud.jw.cases.dto.CaseDTO;
import com.ewaycloud.jw.cases.service.CaseService;
import com.ewaycloud.jw.channel.service.HikService;
import com.ewaycloud.jw.task.entity.Task;
import com.ewaycloud.jw.task.mapper.TaskMapper;
import org.springframework.scheduling.annotation.EnableScheduling;
import org.springframework.stereotype.Component;

import javax.annotation.Resource;
import java.util.Date;
import java.util.List;

/**
 * AI分析 定时任务 处理类
 *
 * @author gwh
 * @date 2024-04-14 13:59:17
 */
@Component
@EnableScheduling
public class AiHandlerTask {

    @Resource
    AiService aiService;
    @Resource
    TaskService taskService;
    @Resource
    CameraService cameraService;
    @Resource
    private TaskMapper taskMapper;

    @Resource
    private CameraMapper cameraMapper;
    @Resource
    private HikService hkService;

    @Resource
    private CaseService caseService;

    /**
     *	注解中的Cron表达式: {秒数} {分钟} {小时} {日期} {月份} {星期} {年份(可为空)}
     *	注意:日和周其中的一个必须为"?"
     *	10/5 20 10 * * ? 每天10点20分第10秒以后,每3秒执行一次,到10点21分就不会执行了
     *
     * AI算法分析任务: 每5秒执行一次
     */
//   @Scheduled(cron = "0/5 * * * * ?")
    public void startTask(){
      // System.out.println("AI分析定时任务执行 每隔5秒执行一次:" + new Date());
       //查询要执行的任务
        List<Task> aiTasks = taskMapper.findAiTasks(null);
        if (null != aiTasks) {
            for(Task vo:aiTasks){
                if (null != vo.getDeptId()) {
                    //查询某谈话室下边的摄像头列表(flag是1 谈话人特写 和2 被谈话人特写 的)
                    List<Camera> cameraList = cameraMapper.findCamersByDeptId(vo.getDeptId());
                    if (null != cameraList && cameraList.size()>0) {
                        for(Camera camera:cameraList) {
                            //根据摄像头编码cameraCode,调用海康接口拉流
                            String cameraCode = camera.getCameraCode();
                            try {
                                //根据cameraCode、开始时间、结束时间 调用海康接口 拉回放流
                                //查询时间(IOS8601格式yyyy-MM-dd'T'HH:mm:ss.SSSzzz,和结束时间相差不超过三天
                                JSONObject data = hkService.playbackURLs( cameraCode, vo.getStartTime(),  vo.getEndTime());
                                //谈话人特写AI分析
                                if (null != data && null != data.getString("url")) {
                                    String rtspUrl = data.getString("url");
                                    //疑似肢体冲突
                                  //  startAiTask(rtspUrl, 1L, vo.getStartTime(), vo.getEndTime(), vo);
                                    //玩手机分析
                                  //  startAiTask(rtspUrl, 2L, vo.getStartTime(), vo.getEndTime(), vo);
                                    //倒地分析
                                  //  startAiTask(rtspUrl, 3L, vo.getStartTime(), vo.getEndTime(), vo);
                                    //人数异常
                                    startAiTask(rtspUrl, 5L, vo.getStartTime(), vo.getEndTime(), vo);
                                }
                            } catch (Exception e) {
                                e.printStackTrace();
                            }
                        }
                    }
                }
            }
        }
      //  System.out.println("AI分析定时任务执行 每隔10秒执行一次:: " + new Date());
    }

    //执行拉流调用AI分析的方法
    public void startAiTask(String rtspUrl, Long aiId, String startTime, String endTime, Task vo) {
        //调用AI分析接口
        if (null != rtspUrl) {
            //调用海康AI算法分析
            String aiResponse = "";
            if (aiId == 1) {//疑似肢体冲突
                aiResponse = aiService.indoorPhysicalConfront(rtspUrl, startTime, endTime);
                vo.setBreakName("疑似肢体冲突");
                vo.setAiId(1L);
            } else if (aiId == 2) {//玩手机
                aiResponse = aiService.playCellphone(rtspUrl, startTime, endTime);
                vo.setBreakName("玩手机");
                vo.setAiId(2L);
            } else if (aiId == 3) {//倒地
                aiResponse = aiService.failDown(rtspUrl, startTime, endTime);
                vo.setBreakName("倒地");
                vo.setAiId(3L);
            } else if (aiId == 4) {//人员站立
                aiResponse = aiService.Standup(rtspUrl,startTime, endTime);
                vo.setBreakName("人员站立");
                vo.setAiId(4L);
            } else if (aiId == 5) {//人数异常
                aiResponse = aiService.PeopleNumChange(rtspUrl, startTime, endTime);
                vo.setBreakName("人数异常");
                vo.setAiId(5L);
            } else if (aiId == 6) {//声强突变
                aiResponse = aiService.audioAbnormal(rtspUrl, startTime, endTime);
                vo.setBreakName("声强突变");
                vo.setAiId(6L);
            } else if (aiId == 7) {//超时滞留
                aiResponse = aiService.overtimeTarry(rtspUrl, startTime, endTime);
                vo.setBreakName("超时滞留");
                vo.setAiId(7L);
            } else if (aiId == 8) {//攀高
                aiResponse = aiService.reachHeight(rtspUrl, startTime, endTime);
                vo.setBreakName("攀高");
                vo.setAiId(8L);
            }
            JSONObject aiResponseJSONObject = JSON.parseObject(aiResponse);
//            System.out.println("AI分析定时任务返回aiResponseJSONObject:" + aiResponseJSONObject);
            String taskId = "";
            String taskStatus = "";
            if (null != aiResponseJSONObject && null != aiResponseJSONObject.getString("taskID") ){
                taskId = aiResponseJSONObject.getString("taskID");
                //调用海康查询任务状态接口获取AI分析任务状态
                String result = aiService.queryTaskVideoStatus(taskId);
                JSONObject resultJSONObject = JSON.parseObject(result);
                JSONArray statusJSONArray = resultJSONObject.getJSONArray("status");
                JSONObject statusJSONObject = (JSONObject) statusJSONArray.get(0);
                 taskStatus = statusJSONObject.getString("taskStatus");
                //将AI分析结果taskStatus插入task表中,更新任务表,状态:1 未执行, 2等待, 3 正在执行 , 4 已完成
                vo.setTaskState(Integer.parseInt(taskStatus));
                vo.setTaskId(taskId); //保存 海康返回的 taskID
                //如果任务完成,关闭rtsp流
                if ("4".equals(taskStatus)) {
                    //根据caseId更新案件表的 task_state =1 , ai任务状态(0:未执行  1:已执行)
                    Long caseId = vo.getCaseId();
                    CaseDTO caseDTO = new CaseDTO();
                    caseDTO.setCaseId(caseId);
                    caseDTO.setCaseState(1);
                    caseService.updCaseInfo(caseDTO);
                    //关闭rtsp流
                    try {
                    hkService.clearPlayUrls(rtspUrl);
                    } catch (Exception e) {
                        e.printStackTrace();
                    }
                }
            }
            System.out.println("AI分析定时任务返回 taskId:" + taskId +" breakName: "+ vo.getBreakName() +" taskStatus: "+ taskStatus);
            //更新任务表, 根据caseId 和taskId查询任务,如果有更新,没有插入
            Task dto = new Task();
               dto.setCaseId(vo.getCaseId());
               dto.setTaskId(vo.getTaskId());
            List<Task> tasks = taskMapper.findTasks(dto);
            if(null != tasks && tasks.size()>0){
                for(Task po : tasks){
                    vo.setId(po.getId());
                    vo.setUpdateTime(new Date());
                    taskService.updateById(po);
                }
            }else {
                vo.setCreateTime(new Date());
                vo.setUpdateTime(new Date());
                taskMapper.insert(vo);
            }
        }
    }

}

2、算法实现,由于涉密,只贴出接口

AiService.java



import com.baomidou.mybatisplus.extension.service.IService;
import com.ewaycloud.jw.ai.entity.Ai;
import com.ewaycloud.jw.task.entity.Task;

import java.util.List;

/**
 * AI对接
 *
 * @author gwh
 * @date 2024-03-13 13:49:09
 */
public interface AiService extends IService<Ai> {

    String getAiDeviceInfo();

    /**
     * 创建--疑似肢体冲突事件--分析视频分析任务
     *
     */
    String indoorPhysicalConfront(String streamUrl, String startTime, String endTime);

    /**
     * 创建--玩手机--分析视频分析任务
     *
     */
    String playCellphone(String streamUrl, String startTime, String endTime);

    /**
     * 创建--倒地检测--分析视频分析任务
     *
     */
    String failDown(String streamUrl, String startTime, String endTime);

    /**
     * 创建--人员站立--分析视频分析任务
     *
     */
    String Standup(String streamUrl, String startTime, String endTime);

    /**
     * 创建--人数异常--分析视频分析任务
     *
     */
    String PeopleNumChange(String streamUrl, String startTime, String endTime);


    /**
     * 创建--声强突变--分析视频分析任务
     *
     */
    String audioAbnormal(String streamUrl, String startTime, String endTime);


    /**
     * 创建--超时滞留--分析视频分析任务
     *
     */
     String overtimeTarry(String streamUrl, String startTime, String endTime);

    /**
     * 创建--攀高--分析视频分析任务
     *
     */
    String reachHeight(String streamUrl, String startTime, String endTime);


    /**
     * 查询分析视频分析任务状态
     *
     */
    String queryTaskVideoStatus(String taskId);



}

3、启动一个线程,Socket监听10006端口,接收ai服务器返回的结果

ListenThread.java



import com.ewaycloud.jw.ai.entity.AiResolveResult;
import com.ewaycloud.jw.ai.mapper.AiResolveResultMapper;
import com.ewaycloud.jw.task.entity.ContentTypeEnum;
import com.ewaycloud.jw.task.entity.Task;
import com.ewaycloud.jw.task.mapper.TaskMapper;
import com.mysql.cj.util.StringUtils;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.io.ByteArrayOutputStream;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.Date;
import java.util.List;

/**
 * @author gwhui
 * @date 2024/1/18 17:38
 * @desc 监听处理线程
 */
@Slf4j
@Service
public class ListenThread implements Runnable {
    private final AlarmDataParser alarmDataParser = new AlarmDataParser();

    private static TaskMapper taskMapper;
    @Resource
    public void setVerificDao(TaskMapper taskMapper) {
        ListenThread.taskMapper = taskMapper;
    }
    private static AiResolveResultMapper aiResolveResultMapper;
    @Resource
    public void setVerificDao(AiResolveResultMapper aiResolveResultMapper) {
        ListenThread.aiResolveResultMapper = aiResolveResultMapper;
    }

    @Override
    public void run() {
//        int listenPort = propertiesUtil.getIntegerProperty("custom.isapi.listen.port", 9999);
        int listenPort =10006;
        try {
            ServerSocket serverSocket = new ServerSocket(listenPort);
            System.out.println("启动监听, 监听端口:" + listenPort);
            while (!Thread.currentThread().isInterrupted()) {
                Socket accept = serverSocket.accept();
                accept.setKeepAlive(true);
               System.out.println("设备(客户端)信息:" + accept.getInetAddress().getHostAddress());
                if (accept.isConnected()) {
                    handleData(accept);
                }
                accept.close();
            }
            serverSocket.close();
            System.out.println("停止监听完成");
        } catch (InterruptedException e) {
            // 线程被中断的处理逻辑
            System.out.println("停止监听完成: " + e.getMessage());
        } catch (Exception e) {
            System.out.println("监听创建异常: " + e.getMessage());
        }
    }

    @Transactional(rollbackFor = Exception.class)
    public synchronized  void handleData(Socket accept) throws Exception {
        InputStream inputData = accept.getInputStream();
        OutputStream outputData = accept.getOutputStream();

        // 输出数据
        ByteArrayOutputStream byOutputData = new ByteArrayOutputStream();

        byte[] buffer = new byte[2 * 1024 * 1024];
        int length = 0;

        // 持续接收处理数据直到接收完毕
        String recvAlarmData = "";
        while ((length = inputData.read(buffer)) > 0) {
            byOutputData.write(buffer, 0, length);

            String recvData = byOutputData.toString();
            recvAlarmData = recvAlarmData + recvData;

            // 获取boundary
            String strBoundary = "boundary=";
            int beginIndex = recvData.indexOf(strBoundary);
            beginIndex += strBoundary.length();
            int lenIndex = recvData.indexOf("\r\n", beginIndex);
            String strBoundaryMark = recvData.substring(beginIndex, lenIndex);

            if (recvAlarmData.contains("--" + strBoundaryMark.trim() + "--")) {
                //表单结束符判断接收结束
                break;
            }
        }
//        System.out.println("==============recvAlarmData========>>  "+recvAlarmData);
        if(null != recvAlarmData){
            String taskId = null;
            int index = recvAlarmData.indexOf("<taskID>");
            if(index != -1){
                taskId = recvAlarmData.substring(index + 8, index + 40);
            }
            //获取服务器返回的图片
            String bkgUrl = null;
            int indexStartBkgUrl = recvAlarmData.indexOf("<bkgUrl>");
            int indexEndBkgUrl = recvAlarmData.indexOf("</bkgUrl>");
            if(indexStartBkgUrl != -1){
                bkgUrl = recvAlarmData.substring(indexStartBkgUrl+8, indexEndBkgUrl);
                bkgUrl =bkgUrl.replaceAll("&amp;","&");
            }
            System.out.println("===AIrecieveData===>>taskId:  "+taskId +" bkgUrl: "+ bkgUrl);
            //根据taskId查询 任务信息
            if(!StringUtils.isNullOrEmpty(taskId)){
                Task task = taskMapper.finTaskByTaskId(taskId);
                if(null != task){
                        AiResolveResult vo = new AiResolveResult();
                        vo.setCreateTime(new Date());
                        vo.setUpdateTime(new Date());
                        vo.setTaskId(taskId); //保存海康返回的 taskId
                        vo.setBreakName(task.getBreakName());
                        vo.setAiId(task.getAiId());
                        vo.setDeptId(task.getDeptId());
                        vo.setCameraId(task.getCameraId());
                        vo.setBreakTypeId(task.getAiId());
                        vo.setRiskTime(task.getTalkTime());
                        vo.setTalkAddress(task.getTalkAddress());
                        vo.setTalkAddressName(task.getTalkAddressName());
                        vo.setTalkUnit(task.getTalkUnit());
                        vo.setTalkUnitName(task.getTalkUnitName());
                        vo.setPhoto(bkgUrl); //保存海康返回的图片
                        vo.setCaseId(task.getCaseId());
                        vo.setCaseName(task.getCaseName());
                        vo.setInterviewerName(task.getInterviewerName());
                        //根据taskId查询任务结果表,如果有做更新操作,没有做插入操作
                        List<AiResolveResult>  aiResolveResults  =  aiResolveResultMapper.findAiResults(vo);
                        if(null != aiResolveResults && aiResolveResults.size()>0){
                            for(AiResolveResult aiResolveResult:aiResolveResults){
                                if(null != aiResolveResult){
                                    aiResolveResult.setPhoto(vo.getPhoto());
                                    aiResolveResultMapper.updateById(aiResolveResult);
                                }
                            }
                        }else {
                            aiResolveResultMapper.insert(vo);
                        }
                }

            }
        }
        String response = "HTTP/1.1 200 OK" +
                "\r\n" +
                "Connection: close" +
                "\r\n\r\n";
        outputData.write(response.getBytes());
        outputData.flush();
        outputData.close();
        inputData.close();
        //解析数据
        response = parseAlarmInfoByte(byOutputData);
        System.out.println("==============response========>>  "+response);
    }

    private String parseAlarmInfoByte(ByteArrayOutputStream byOutputData) throws Exception {
        // 事件报文字节
        byte[] byAlarmDataInfo = byOutputData.toByteArray();
        int iDataLen = byAlarmDataInfo.length;

        String szBoundaryMark = "boundary=";
        String szContentTypeMark = "Content-Type: ";
        int iTypeMarkLen = szContentTypeMark.getBytes("UTF-8").length;
        String szContentLenMark = "Content-Length: ";
        int iLenMarkLen = szContentLenMark.getBytes("UTF-8").length;
        String szContentLenMark2 = "content-length: ";
        int iLenMarkLen2 = szContentLenMark2.getBytes("UTF-8").length;
        int iContentLen = 0;
        String szEndMark = "\r\n";
        int iMarkLen = szEndMark.getBytes("UTF-8").length;
        String szEndMark2 = "\r\n\r\n";
        int iMarkLen2 = szEndMark2.getBytes("UTF-8").length;
        String szJson = "text/json";
        String szJpg = "image/jpeg";

        int iStartBoundary = doDataSearch(byAlarmDataInfo, szBoundaryMark.getBytes("UTF-8"), 0, byAlarmDataInfo.length);
        iStartBoundary += szBoundaryMark.getBytes("UTF-8").length;
        int iEndBoundary = doDataSearch(byAlarmDataInfo, szEndMark.getBytes("UTF-8"), iStartBoundary, byAlarmDataInfo.length);
        byte[] byBoundary = new byte[iEndBoundary - iStartBoundary];
        System.arraycopy(byAlarmDataInfo, iStartBoundary, byBoundary, 0, iEndBoundary - iStartBoundary);

        String szBoundaryEndMark = "--" + new String(byBoundary).trim() + "--";
        int iDateEnd = doDataSearch(byAlarmDataInfo, szBoundaryEndMark.getBytes("UTF-8"), 0, byAlarmDataInfo.length);

        String szBoundaryMidMark = "--" + new String(byBoundary).trim();
        int iBoundaryMidLen = szBoundaryMidMark.getBytes("UTF-8").length;
        int startIndex = iEndBoundary;

        String szContentType = "";

        int[] iBoundaryPos = new int[11]; //boundary个数,这里最大解析10个
        int iBoundaryNum = 0;
        for (iBoundaryNum = 0; iBoundaryNum < 10; iBoundaryNum++) {
            startIndex = doDataSearch(byAlarmDataInfo, szBoundaryMidMark.getBytes("UTF-8"), startIndex, iDateEnd);
            if (startIndex < 0) {
                break;
            }
            startIndex += iBoundaryMidLen;
            iBoundaryPos[iBoundaryNum] = startIndex;
        }
        iBoundaryPos[iBoundaryNum] = iDateEnd;//最后一个是结束符

        for (int i = 0; i < iBoundaryNum; i++) {
            // Content-Type
            int iStartType = doDataSearch(byAlarmDataInfo, szContentTypeMark.getBytes("UTF-8"), iBoundaryPos[i], iBoundaryPos[i + 1]);
            if (iStartType > 0) {
                iStartType += iTypeMarkLen;
                int iEndType = doDataSearch(byAlarmDataInfo, szEndMark.getBytes("UTF-8"), iStartType, iBoundaryPos[i + 1]);
                if (iEndType > 0) {
                    byte[] byType = new byte[iEndType - iStartType];
                    System.arraycopy(byAlarmDataInfo, iStartType, byType, 0, iEndType - iStartType);
                    szContentType = new String(byType).trim();
                }
            }

            // Content-Length
            int iStartLength = doDataSearch(byAlarmDataInfo, szContentLenMark.getBytes("UTF-8"), iBoundaryPos[i], iBoundaryPos[i + 1]);
            if (iStartLength > 0) {
                iStartLength += iLenMarkLen;
                int iEndLength = doDataSearch(byAlarmDataInfo, szEndMark.getBytes("UTF-8"), iStartLength, iBoundaryPos[i + 1]);
                if (iEndLength > 0) {
                    byte[] byLength = new byte[iEndLength - iStartLength];
                    System.arraycopy(byAlarmDataInfo, iStartLength, byLength, 0, iEndLength - iStartLength);
                    iContentLen = Integer.parseInt(new String(byLength).trim());
                }
            }

            // Content-Length(兼容错误大小写)
            int iStartLength2 = doDataSearch(byAlarmDataInfo, szContentLenMark2.getBytes("UTF-8"), iBoundaryPos[i], iBoundaryPos[i + 1]);
            if (iStartLength2 > 0) {
                iStartLength2 += iLenMarkLen2;
                int iEndLength2 = doDataSearch(byAlarmDataInfo, szEndMark.getBytes("UTF-8"), iStartLength2, iBoundaryPos[i + 1]);
                if (iEndLength2 > 0) {
                    byte[] byLength2 = new byte[iEndLength2 - iStartLength2];
                    System.arraycopy(byAlarmDataInfo, iStartLength2, byLength2, 0, iEndLength2 - iStartLength2);
                    iContentLen = Integer.parseInt(new String(byLength2).trim());
                }
            }

            // 通过\r\n\r\n判断报文数据起始位置
            int iStartData = doDataSearch(byAlarmDataInfo, szEndMark2.getBytes("UTF-8"), iBoundaryPos[i], iBoundaryPos[i + 1]);
            if (iStartData > 0) {
                iStartData += iMarkLen2;

                // 有的报文可能没有Content-Length
                if (iContentLen <= 0) {
                    iContentLen = iBoundaryPos[i + 1] - iStartData;
                }

                // 截取数据内容
                byte[] byData = new byte[iContentLen];
                System.arraycopy(byAlarmDataInfo, iStartData, byData, 0, iContentLen);

                // 根据类型处理数据
                int contentType = ContentTypeEnum.getEventType(szContentType);
                String storeFolder = System.getProperty("user.dir") + "\\output\\listen\\event\\";
                switch (contentType) {
                    case ContentTypeEnum.APPLICATION_JSON:
                    case ContentTypeEnum.APPLICATION_XML: {
                        String rawContent = new String(byData).trim();
                        alarmDataParser.parseAlarmInfo(contentType, storeFolder, rawContent, null);
                        break;
                    }
                    case ContentTypeEnum.IMAGE_JPEG:
                    case ContentTypeEnum.IMAGE_PNG:
                    case ContentTypeEnum.VIDEO_MPG:
                    case ContentTypeEnum.VIDEO_MPEG4:
                    case ContentTypeEnum.APPLICATION_ZIP: {
                        alarmDataParser.parseAlarmInfo(contentType, storeFolder, null, byData);
                        break;
                    }
                    default: {
                        System.out.println("未匹配到可以解析的content-type, 请自行补全处理!");
                    }
                }
            }
        }
        // 响应报文
        String response = "";

        // 消费交易事件 (实际如果没有消费机设备可以不需要消费机的处理代码)
        String eventType = "";
        String eventConfirm = "";
        if (eventType.equals("ConsumptionEvent") || eventType.equals("TransactionRecordEvent") || eventType.equals("HealthInfoSyncQuery")) {
            response = "HTTP/1.1 200 OK" +
                    "\r\n" +
                    "Content-Type: application/json; charset=\"UTF-8\"" +
                    "\r\n" +
                    "Content-Length: " + eventConfirm.length() +
                    "\r\n\r\n" + eventConfirm +
                    "\r\n";
        } else {
            response = "HTTP/1.1 200 OK" +
                    "\r\n" +
                    "Connection: close" +
                    "\r\n\r\n";
        }

        return response;
    }

    private int doDataSearch(byte[] bySrcData, byte[] keyData, int startIndex, int endIndex) {
        if (bySrcData == null || keyData == null || bySrcData.length <= startIndex || bySrcData.length < keyData.length) {
            return -1;
        }

        if (endIndex > bySrcData.length) {
            endIndex = bySrcData.length;
        }

        int iPos, jIndex;
        for (iPos = startIndex; iPos < endIndex; iPos++) {
            if (bySrcData.length < keyData.length + iPos) {
                break;
            }

            for (jIndex = 0; jIndex < keyData.length; jIndex++) {
                if (bySrcData[iPos + jIndex] != keyData[jIndex]) {
                    break;
                }
            }
            if (jIndex == keyData.length) {
                return iPos;
            }
        }
        return -1;
    }


}

4、数据库设计

瀚高国产数据库

        

5、前端页面设计

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/735965.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

累了就坐下来喝杯茶 然后继续前行

前言&#xff1a; 今天是情人节就不发技术文章了 先祝愿各位有情人总成眷属。也包括我&#xff0c;哈哈哈 今天要分享的是一个diy制作的教程 因为我女朋友不在这边&#xff0c;心中那份思念难耐 所以有感而发 写了这篇diy 教程的文章 效果图&#xff1a; 需要的材料 502胶水…

动手学自然语言处理:解读大模型背后的核心技术

自从 ChatGPT 横空出世以来&#xff0c;自然语言处理&#xff08;Natural Language Processing&#xff0c;NLP&#xff09; 研究领域就出现了一种消极的声音&#xff0c;认为大模型技术导致 NLP “死了”。在某乎上就有一条热门问答&#xff0c;大家热烈地讨论了这个问题。 有…

▶《强化学习的数学原理》(2024春)_西湖大学赵世钰 Ch5 蒙特卡洛方法【model-based ——> model-free】

PPT 截取必要信息。 课程网站做习题。总体 MOOC 过一遍 1、视频 学堂在线 习题 2、 过 电子书 是否遗漏 【下载&#xff1a;本章 PDF GitHub 页面链接 】 【第二轮 才整理的&#xff0c;忘光了。。。又看了一遍视频】 3、 过 MOOC 习题 看 PDF 迷迷糊糊&#xff0c; 恍恍惚惚。…

STM32 温湿度采集与OLED显示

目录 一、I2C总线通信协议 1、I2C介绍 2、软件I2C和硬件I2C &#xff08;1&#xff09;硬件I2C &#xff08;2&#xff09;软件I2C 差异 二、AHT20温湿度传感器 接口原理介绍 1. 温度测量原理 2. 湿度测量原理 实物引脚 传感器性能 电气特性 三、任务实现 具…

工程师 - Total Phase公司介绍

Total Phase 是一家领先的嵌入式系统工具供应商&#xff0c;可简化各种通信协议的开发和调试。公司提供一系列产品&#xff0c;旨在帮助工程师和开发人员更高效地使用 I2C、SPI、USB 和 CAN 等协议。 关于Total Phase的关键信息&#xff1a; 产品&#xff1a; 协议分析仪&…

day1-web安全基础(米斯特web渗透测试)

day1-web安全基础&#xff08;米斯特web渗透测试&#xff09; 一、搭建网站二、专业术语1.域名2.木马&#xff08;1&#xff09;软件木马&#xff1a;&#xff08;2&#xff09;脚本木马&#xff1a; 3.社工4.IP5.后门6.Poc&#xff08;验证&#xff09;&#xff0c;exp&#x…

2024.06.23 刷题日记

〇、前言 今天重点刷了回溯&#xff0c;以及常见的题目。 46. 全排列 给定一个不含重复数字的数组 nums &#xff0c;返回其 所有可能的全排列 。你可以 按任意顺序 返回答案。 示例 1&#xff1a; 输入&#xff1a;nums [1,2,3] 输出&#xff1a;[[1,2,3],[1,3,2],[2,1,3…

提示缺少Microsoft Visual C++ 2019 Redistributable Package (x64)(下载)

下载地址&#xff1a;这个是官网下载地址&#xff1a;Microsoft Visual C 2019 Redistributable Package (x64) 步骤&#xff1a; 第一步&#xff1a;点开链接&#xff0c;找到下图所示的东西 第二步&#xff1a;点击保存下载 第三步&#xff1a;双击运行安装 第四步&#xf…

【漏洞复现】AJ-Report开源数据大屏 verification;swagger-ui RCE漏洞

0x01 产品简介 AJ-Report是一个完全开源的B平台&#xff0c;酷炫大屏展示&#xff0c;能随时随地掌控业务动态&#xff0c;让每个决策都有数据支撑。多数据源支持&#xff0c;内置mysql、elasticsearch、kudu等多种驱动&#xff0c;支持自定义数据集省去数据接口开发&#xff…

three.js 基础02 ---光源

1.光源【基础材质不受光照影响】 注&#xff1a; 除MeshBasicMaterial&#xff08;网格基础材质&#xff09;外&#xff0c;设置材质时必须同时设置光源&#xff0c;否则图形出不来 1.1 材质 漫反射 MeshBasicMaterial 高光 MeshLambertMaterial 物理 MeshStandardMa…

【数据结构】链表的大概认识及单链表的实现

目录 一、链表的概念及结构 二、链表的分类 三、单链表的实现 建立链表的节点&#xff1a; 尾插——尾删&#xff1a; 头插——头删&#xff1a; 查找&#xff1a; 指定位置之后删除——插入&#xff1a; 指定位置之前插入——删除指定位置&#xff1a; 销毁链表&am…

浏览器插件利器-allWebPluginV2.0.0.14-bata版发布

allWebPlugin简介 allWebPlugin中间件是一款为用户提供安全、可靠、便捷的浏览器插件服务的中间件产品&#xff0c;致力于将浏览器插件重新应用到所有浏览器。它将现有ActiveX插件直接嵌入浏览器&#xff0c;实现插件加载、界面显示、接口调用、事件回调等。支持谷歌、火狐等浏…

C语言中的字符输入/输出和验证输入

在C语言中&#xff0c;字符输入/输出功能允许程序与用户进行交互&#xff0c;读取用户的输入信息并展示输出结果。同时&#xff0c;验证输入的作用在于确保用户输入的数据符合预期&#xff0c;以提高程序的稳定性和可靠性&#xff0c;防止无效输入引发的错误或异常行为&#xf…

外排序(C语言实现)

前言 本篇博客讲解一下外排序&#xff0c;看这篇排序你的先去看一下&#xff1a;八大经典排序算法-CSDN博客 &#x1f493; 个人主页&#xff1a;普通young man-CSDN博客 ⏩ 文章专栏&#xff1a;排序_普通young man的博客-CSDN博客 若有问题 评论区见&#x1f4dd; &#x1f3…

二叉树的基础讲解

二叉树在遍历&#xff0c;查找&#xff0c;增删的效率上面都很高&#xff0c;是数据结构中很重要的&#xff0c;下面我们来基础的认识一下。(高级的本人还没学&#xff0c;下面的代码用伪代码或C语言写的)我会从树&#xff0c;树的一些专有名词&#xff0c;树的遍历&#xff0c…

【博客719】时序数据库基石:LSM Tree的增删查改

时序数据库基石&#xff1a;LSM Tree的增删查改 LSM结构 LSM树将任何的对数据操作都转化为对内存中的Memtable的一次插入。Memtable可以使用任意内存数据结构&#xff0c;如HashTable&#xff0c;BTree&#xff0c;SkipList等。对于有事务控制需要的存储系统&#xff0c;需要在…

web安全渗透测试十大常规项(一):web渗透测试之JAVA反序列化

渗透测试之PHP反序列化 1. Java反序列化1.1 Java安全-反序列化-原生序列化类函数1.1.1 原生序列化类函数:1.2 Java安全-SpringBoot框架-泄漏&CVE1. Java反序列化 1、序列化与反序列化 序列化:将内存中的对象压缩成字节流 反序列化:将字节流转化成内存中的对象2、为什么…

huggingface官网下载并处理ImageNet2012数据集

文章目录 一、下载imagenet2012数据集二、转换imagenet数据集格式 ImageNet数据集可以直接从ImageNet官方网站获取数据&#xff0c;但通常需要注册并遵守使用协议。另外&#xff0c;由于数据集较大&#xff0c;往往下载需要花费大量的时间空间&#xff0c;而通过huggingface下载…

达梦8 通过SF_INJECT_HINT解决新排序机制下失控语句影响其他SQL执行的问题

达梦数据库有两种排序机制。当SORT_FLAG设置0时&#xff0c;采用旧排序机制&#xff1b;当SORT_FLAG1时&#xff0c;采用新排序机制。详见《达梦新老排序机制的对比》 两种排序机制各有优缺点。 新排序机制引入了全局排序区概念&#xff0c;虽然避免了内存溢出导致系统OOM&am…

[数据概念|方案实操]清华数据大讲堂5-数据要素化治理的理论方法与工程实践

“ 数据要素化是资产化的重要前提和实现路径” 鼹鼠哥公众号链接在 [数据概念|方案实操]清华数据大讲堂5-数据要素化治理的理论方法与工程实践 (qq.com) 2024年6月5日&#xff0c;清华数据大讲堂第五讲开讲。 中国电子信息产业集团副总 陆志鹏 以《数据要素化治理的理论方法与…