大华相机接入web页面实现人脸识别

news2024/9/23 21:22:03

先看下效果,中间主视频流就是大华相机(视频编码H.264),海康相机(视屏编码H.265)

在这里插入图片描述

在这里插入图片描述
前端接入视屏流代码

  <!--视频流-->
            <div id="col2">
                <div class="cell" style="flex: 7; background: none">
                    <div class="cell-box" style="position: relative">
                        <video autoplay muted id="video" class="video" />

                        <div class="cell div-faces">
                            <div class="cell-box">
                                <!--人脸识别-->
                                <div class="faces-wrapper">
                                    <div v-for="i in 5" :key="i" class="face-wrapper">
                                        <div class="face-arrow"></div>
                                        <div
                                            class="face-image"
                                            :style="{
                                                background: faceImages[i - 1]
                                                    ? `url(data:image/jpeg;base64,${
                                                          faceImages[i - 1]
                                                      }) 0 0 / 100% 100% no-repeat`
                                                    : ''
                                            }"></div>
                                    </div>
                                </div>
                            </div>
                        </div>
                    </div>
                </div>
api.post('screen2/init').then((attach) => {
        const { streamerIp, streamerPort, cameraIp, cameraPort, cameraAdmin, cameraPsw } = attach
        webRtcServer = new WebRtcStreamer('video', `${location.protocol}//${streamerIp}:${streamerPort}`)
        webRtcServer.connect(`rtsp://${cameraAdmin}:${cameraPsw}@${cameraIp}:${cameraPort}`)
    })

后台部署需要启动:webrtc-streamer.exe 用来解码视屏流,这样就能实现web页面接入视屏流。

主视屏流下面的相机抓拍图片和预警数据接口是怎么实现的呢?
1、需要把大华相机的sdk加载到项目中sdk下载
在这里插入图片描述
在maven的pom.xml中添加依赖,将上面jar包 依赖到项目中

        <!--外部依赖-->
        <dependency>
            <!--groupId和artifactId不知道随便写-->
            <groupId>com.dahua.netsdk</groupId>
            <artifactId>netsdk-api-main</artifactId>
            <!--依赖范围,必须system-->
            <scope>system</scope>
            <version>1.0-SNAPSHOT</version>
            <!--依赖所在位置-->
            <systemPath>${project.basedir}/libs/netsdk-api-main-1.0.jar</systemPath>
        </dependency>
        <dependency>
            <!--groupId和artifactId不知道随便写-->
            <groupId>com.dahua.netsdk</groupId>
            <artifactId>netsdk-dynamic</artifactId>
            <!--依赖范围,必须system-->
            <scope>system</scope>
            <version>1.0-SNAPSHOT</version>
            <!--依赖所在位置-->
            <systemPath>${project.basedir}/libs/netsdk-dynamic-lib-main-1.0.jar</systemPath>
        </dependency>
        <dependency>
            <!--groupId和artifactId不知道随便写-->
            <groupId>com.dahua.netsdk</groupId>
            <artifactId>netsdk-jna</artifactId>
            <!--依赖范围,必须system-->
            <scope>system</scope>
            <version>1.0-SNAPSHOT</version>
            <!--依赖所在位置-->
            <systemPath>${project.basedir}/libs/jna.jar</systemPath>
        </dependency>

然后写一个大华初始化,登录,订阅类 InitDahua

package ahpu.aip.controller.dahua;

import com.netsdk.lib.NetSDKLib;
import com.netsdk.lib.ToolKits;
import com.sun.jna.Pointer;
import com.sun.jna.ptr.IntByReference;
import org.springframework.beans.factory.DisposableBean;
import org.springframework.boot.ApplicationArguments;
import org.springframework.boot.ApplicationRunner;
import org.springframework.stereotype.Component;

@Component
public class InitDahua implements ApplicationRunner {

    @Override
    public void run(ApplicationArguments args) throws Exception {
        //NetSDK 库初始化
          boolean bInit    = false;
         NetSDKLib netsdkApi = NetSDKLib.NETSDK_INSTANCE;
        // 智能订阅句柄
          NetSDKLib.LLong attachHandle = new NetSDKLib.LLong(0);


        //设备断线回调: 通过 CLIENT_Init 设置该回调函数,当设备出现断线时,SDK会调用该函数
          class DisConnect implements NetSDKLib.fDisConnect {
            public void invoke(NetSDKLib.LLong m_hLoginHandle, String pchDVRIP, int nDVRPort, Pointer dwUser) {
                System.out.printf("Device[%s] Port[%d] DisConnect!\n", pchDVRIP, nDVRPort);
            }
        }
        //网络连接恢复,设备重连成功回调
        // 通过 CLIENT_SetAutoReconnect 设置该回调函数,当已断线的设备重连成功时,SDK会调用该函数
          class HaveReConnect implements NetSDKLib.fHaveReConnect {
            public void invoke(NetSDKLib.LLong m_hLoginHandle, String pchDVRIP, int nDVRPort, Pointer dwUser) {
                System.out.printf("ReConnect Device[%s] Port[%d]\n", pchDVRIP, nDVRPort);
            }
        }


        //登陆参数
          String m_strIp         = "192.168.1.108";
          int m_nPort        	   = 37777;
          String m_strUser       = "admin";
          String m_strPassword   = "admin123456";
        //设备信息
          NetSDKLib.NET_DEVICEINFO_Ex m_stDeviceInfo = new NetSDKLib.NET_DEVICEINFO_Ex(); // 对应CLIENT_LoginEx2
          NetSDKLib.LLong m_hLoginHandle = new NetSDKLib.LLong(0);     // 登陆句柄
          NetSDKLib.LLong m_hAttachHandle = new NetSDKLib.LLong(0);    // 智能订阅句柄

//        初始化
        bInit = netsdkApi.CLIENT_Init(new DisConnect(), null);
        if(!bInit) {
            System.out.println("Initialize SDK failed");
        }else{
            System.out.println("Initialize SDK Success");
        }

        // 登录
        int nSpecCap = NetSDKLib.EM_LOGIN_SPAC_CAP_TYPE.EM_LOGIN_SPEC_CAP_TCP; //=0
        IntByReference nError = new IntByReference(0);
        m_hLoginHandle = netsdkApi.CLIENT_LoginEx2(m_strIp, m_nPort, m_strUser, m_strPassword, nSpecCap, null, m_stDeviceInfo, nError);
        if(m_hLoginHandle.longValue() == 0) {
            System.err.printf("Login Device[%s] Port[%d]Failed.\n", m_strIp, m_nPort, ToolKits.getErrorCode());
        } else {
            System.out.println("Login Success [ " + m_strIp + " ]");
        }


        // 订阅
        int bNeedPicture = 1; // 是否需要图片
        m_hAttachHandle =  netsdkApi.CLIENT_RealLoadPictureEx(m_hLoginHandle, 0, NetSDKLib.EVENT_IVS_ALL, bNeedPicture, new AnalyzerDataCB(), null, null);
        if(m_hAttachHandle.longValue() == 0) {
            System.err.println("CLIENT_RealLoadPictureEx Failed, Error:" + ToolKits.getErrorCode());
        }else {
            System.out.println("订阅成功~");
        }

    }


}

回调类,具体识别结果在回调中获取

package ahpu.aip.controller.dahua;

import ahpu.aip.AiPlatformServerApplication;
import ahpu.aip.util.RedisUtils;
import ahpu.aip.util.StringUtils;
import cn.hutool.core.codec.Base64;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.ObjUtil;
import cn.hutool.core.util.StrUtil;
import com.alibaba.fastjson2.JSON;
import com.alibaba.fastjson2.JSONArray;
import com.netsdk.lib.NetSDKLib;
import com.netsdk.lib.ToolKits;
import com.sun.jna.Pointer;

import javax.imageio.ImageIO;
import java.awt.image.BufferedImage;
import java.io.ByteArrayInputStream;
import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.util.CollectionUtils;

@Component
public class AnalyzerDataCB implements NetSDKLib.fAnalyzerDataCallBack {
    private static final Logger log = LoggerFactory.getLogger(AnalyzerDataCB.class);

    public static HashMap<String, Object> temMap;

    private int bGlobalScenePic;					//全景图是否存在, 类型为BOOL, 取值为0或者1
    private NetSDKLib.NET_PIC_INFO stuGlobalScenePicInfo;     //全景图片信息


    private NetSDKLib.NET_PIC_INFO stPicInfo;	  			    // 人脸图
    private NetSDKLib.NET_FACE_DATA stuFaceData;			    // 人脸数据

    private int nCandidateNumEx;				    // 当前人脸匹配到的候选对象数量
    private NetSDKLib.CANDIDATE_INFOEX[] stuCandidatesEx;     // 当前人脸匹配到的候选对象信息扩展

    // 全景大图、人脸图、对比图
    private BufferedImage globalBufferedImage = null;
    private BufferedImage personBufferedImage = null;
    private BufferedImage candidateBufferedImage = null;
    String[] faceSexStr = {"未知", "男", "女"};
    // 用于保存对比图的图片缓存,用于多张图片显示
    private ArrayList<BufferedImage> arrayListBuffer = new ArrayList<BufferedImage>();

    @Override
    public int invoke(NetSDKLib.LLong lAnalyzerHandle, int dwAlarmType,
                      Pointer pAlarmInfo, Pointer pBuffer, int dwBufSize,
                      Pointer dwUser, int nSequence, Pointer reserved) {

        // 获取相关事件信息
        getObjectInfo(dwAlarmType, pAlarmInfo);

        /*if(dwAlarmType == NetSDKLib.EVENT_IVS_FACERECOGNITION) {   // 目标识别
            // 保存图片
            savePicture(pBuffer, dwBufSize, bGlobalScenePic, stuGlobalScenePicInfo, stPicInfo, nCandidateNumEx, stuCandidatesEx);

            // 刷新UI时,将目标识别事件抛出处理
            EventQueue eventQueue = Toolkit.getDefaultToolkit().getSystemEventQueue();
            if (eventQueue != null) {
                eventQueue.postEvent(new FaceRecognitionEvent(this,
                        globalBufferedImage,
                        personBufferedImage,
                        stuFaceData,
                        arrayListBuffer,
                        nCandidateNumEx,
                        stuCandidatesEx));
            }
        } else*/ if(dwAlarmType == NetSDKLib.EVENT_IVS_FACEDETECT) {  // 人脸检测
            // 保存图片
            savePicture(pBuffer, dwBufSize, stPicInfo);
        }

        return 0;
    }

    /**
     * 获取相关事件信息
     * @param dwAlarmType 事件类型
     * @param pAlarmInfo 事件信息指针
     */
    public void getObjectInfo(int dwAlarmType, Pointer pAlarmInfo) {
        if(pAlarmInfo == null) {
            return;
        }

        switch(dwAlarmType)
        {
            case NetSDKLib.EVENT_IVS_FACERECOGNITION:  ///< 目标识别事件
            {
                NetSDKLib.DEV_EVENT_FACERECOGNITION_INFO msg = new NetSDKLib.DEV_EVENT_FACERECOGNITION_INFO();
                ToolKits.GetPointerData(pAlarmInfo, msg);

                bGlobalScenePic = msg.bGlobalScenePic;
                stuGlobalScenePicInfo = msg.stuGlobalScenePicInfo;
                stuFaceData = msg.stuFaceData;
                stPicInfo = msg.stuObject.stPicInfo;
                nCandidateNumEx = msg.nRetCandidatesExNum;
                stuCandidatesEx = msg.stuCandidatesEx;

                break;
            }
            case NetSDKLib.EVENT_IVS_FACEDETECT:   ///< 人脸检测
            {
                NetSDKLib.DEV_EVENT_FACEDETECT_INFO msg = new NetSDKLib.DEV_EVENT_FACEDETECT_INFO();
                ToolKits.GetPointerData(pAlarmInfo, msg);

                stPicInfo = msg.stuObject.stPicInfo;  // 检测到的人脸

//                System.out.println("sex:" + faceSexStr[msg.emSex]);
                log.info("口罩状态(0-未知,1-未识别,2-没戴口罩,3-戴口罩了):" + msg.emMask);
                log.info("时间:"+msg.UTC);
                RedisUtils.set("mask",msg.emMask==3?"戴口罩":"未戴口罩");
                RedisUtils.set("time",msg.UTC+"");

                break;
            }
            default:
                break;
        }
    }

    /**
     * 保存目标识别事件图片
     * @param pBuffer 抓拍图片信息
     * @param dwBufSize 抓拍图片大小
     */
   /* public void savePicture(Pointer pBuffer, int dwBufSize,
                            int bGlobalScenePic, NetSDKLib.NET_PIC_INFO stuGlobalScenePicInfo,
                            NetSDKLib.NET_PIC_INFO stPicInfo,
                            int nCandidateNum, NetSDKLib.CANDIDATE_INFOEX[] stuCandidatesEx) {
        File path = new File("./FaceRegonition/");
        if (!path.exists()) {
            path.mkdir();
        }

        if (pBuffer == null || dwBufSize <= 0) {
            return;
        }

        /// 保存全景图 ///
        if(bGlobalScenePic == 1 && stuGlobalScenePicInfo != null) {
            String strGlobalPicPathName = path + "\\" + System.currentTimeMillis() + "Global.jpg";
            byte[] bufferGlobal = pBuffer.getByteArray(stuGlobalScenePicInfo.dwOffSet, stuGlobalScenePicInfo.dwFileLenth);
            ByteArrayInputStream byteArrInputGlobal = new ByteArrayInputStream(bufferGlobal);

            try {
                globalBufferedImage = ImageIO.read(byteArrInputGlobal);
                if(globalBufferedImage == null) {
                    return;
                }
                ImageIO.write(globalBufferedImage, "jpg", new File(strGlobalPicPathName));
            } catch (IOException e2) {
                e2.printStackTrace();
            }
        }

        /// 保存人脸图 /
        if(stPicInfo != null) {
            String strPersonPicPathName = path + "\\" + System.currentTimeMillis() + "Person.jpg";
            byte[] bufferPerson = pBuffer.getByteArray(stPicInfo.dwOffSet, stPicInfo.dwFileLenth);
            ByteArrayInputStream byteArrInputPerson = new ByteArrayInputStream(bufferPerson);

            try {
                personBufferedImage = ImageIO.read(byteArrInputPerson);
                if(personBufferedImage == null) {
                    return;
                }
                ImageIO.write(personBufferedImage, "jpg", new File(strPersonPicPathName));
            } catch (IOException e2) {
                e2.printStackTrace();
            }
        }

        / 保存对比图 //
        arrayListBuffer.clear();
        if(nCandidateNum > 0 && stuCandidatesEx != null) {
            for(int i = 0; i < nCandidateNum; i++) {
                String strCandidatePicPathName = path + "\\" + System.currentTimeMillis() + "Candidate.jpg";
                // 多张对比图
                for(int j = 0; j < stuCandidatesEx[i].stPersonInfo.wFacePicNum; j++) {
                    byte[] bufferCandidate = pBuffer.getByteArray(stuCandidatesEx[i].stPersonInfo.szFacePicInfo[j].dwOffSet, stuCandidatesEx[i].stPersonInfo.szFacePicInfo[j].dwFileLenth);
                    ByteArrayInputStream byteArrInputCandidate = new ByteArrayInputStream(bufferCandidate);

                    try {
                        candidateBufferedImage = ImageIO.read(byteArrInputCandidate);
                        if(candidateBufferedImage == null) {
                            return;
                        }
                        ImageIO.write(candidateBufferedImage, "jpg", new File(strCandidatePicPathName));
                    } catch (IOException e2) {
                        e2.printStackTrace();
                    }
                    arrayListBuffer.add(candidateBufferedImage);
                }
            }
        }
    }*/

    /**
     * 保存人脸检测事件图片 ===
     * @param pBuffer 抓拍图片信息
     * @param dwBufSize 抓拍图片大小
     */
    public void savePicture(Pointer pBuffer, int dwBufSize, NetSDKLib.NET_PIC_INFO stPicInfo) {
        File path = new File("./FaceDetected/");
        if (!path.exists()) {
            path.mkdir();
        }

        if (pBuffer == null || dwBufSize <= 0) {
            return;
        }

        /// 保存全景图 ///
      /*  String strGlobalPicPathName = path + "\\" + System.currentTimeMillis() + "Global.jpg";
        byte[] bufferGlobal = pBuffer.getByteArray(0, dwBufSize);
        ByteArrayInputStream byteArrInputGlobal = new ByteArrayInputStream(bufferGlobal);

        try {
            globalBufferedImage = ImageIO.read(byteArrInputGlobal);
            if(globalBufferedImage == null) {
                return;
            }
            ImageIO.write(globalBufferedImage, "jpg", new File(strGlobalPicPathName));

        } catch (IOException e2) {
            e2.printStackTrace();
        }*/

        /// 保存人脸图 /
        if(stPicInfo != null) {
            String strPersonPicPathName = path + "\\" + System.currentTimeMillis() + "Person.jpg";
            byte[] bufferPerson = pBuffer.getByteArray(stPicInfo.dwOffSet, stPicInfo.dwFileLenth);
            ByteArrayInputStream byteArrInputPerson = new ByteArrayInputStream(bufferPerson);

            try {
                personBufferedImage = ImageIO.read(byteArrInputPerson);
                if(personBufferedImage == null) {
                    return;
                }
                ImageIO.write(personBufferedImage, "jpg", new File(strPersonPicPathName));

                //  把图片保存到resultMap中
                String base64 = Base64.encode(new File(strPersonPicPathName));
                log.info("base64图片:data:image/jpeg;base64,"+base64);

                RedisUtils.set("img","data:image/jpeg;base64,"+base64);

                String listStr = (String) RedisUtils.get("dahuaList");

                List<HashMap> list = JSONArray.parseArray(listStr,HashMap.class);
                HashMap<String,String> tmpResult = new HashMap<String,String>();
                tmpResult.put("img",(String) RedisUtils.get("img"));
                tmpResult.put("time",(String) RedisUtils.get("time"));
                tmpResult.put("mask",(String) RedisUtils.get("mask"));

                if(CollectionUtils.isEmpty(list)){
                    list = new ArrayList<>();
                    list.add(tmpResult);
                }else {
                    list.add(tmpResult);
                }

                if(list.size()>5){
                    RedisUtils.set("dahuaList",JSON.toJSONString(list.subList(list.size()-5,list.size())));
                }else {
                    RedisUtils.set("dahuaList",JSON.toJSONString(list));
                }


            } catch (IOException e2) {
                e2.printStackTrace();
            }
        }
    }


}

人脸识别事件类

package ahpu.aip.controller.dahua;

import com.netsdk.lib.NetSDKLib;

import java.awt.*;
import java.awt.image.BufferedImage;
import java.io.UnsupportedEncodingException;
import java.util.ArrayList;
import org.springframework.stereotype.Component;

public class FaceRecognitionEvent extends AWTEvent {
    private static final long serialVersionUID = 1L;
    public static final int EVENT_ID = AWTEvent.RESERVED_ID_MAX + 1;

    private BufferedImage globalImage = null;
    private BufferedImage personImage = null;
    private NetSDKLib.NET_FACE_DATA stuFaceData;
    private ArrayList<BufferedImage> arrayList = null;
    private int nCandidateNum;
    private ArrayList<String[]> candidateList;

    // 用于保存对比图的人脸库id、名称、人员名称、相似度
    private static String[] candidateStr = new String[4];
    private static final String encode = "UTF-8";

    public FaceRecognitionEvent(Object target,
                                BufferedImage globalImage,
                                BufferedImage personImage,
                                NetSDKLib.NET_FACE_DATA stuFaceData,
                                ArrayList<BufferedImage> arrayList,
                                int nCandidateNum,
                                NetSDKLib.CANDIDATE_INFOEX[] stuCandidatesEx) {
        super(target,EVENT_ID);
        this.globalImage = globalImage;
        this.personImage = personImage;
        this.stuFaceData = stuFaceData;
        this.arrayList = arrayList;
        this.nCandidateNum = nCandidateNum;
        this.candidateList = new ArrayList<String[]>();

        this.candidateList.clear();
        for(int i = 0; i < nCandidateNum; i++) {
            try {
                candidateStr[0] = new String(stuCandidatesEx[i].stPersonInfo.szGroupID, encode).trim();
                candidateStr[1] = new String(stuCandidatesEx[i].stPersonInfo.szGroupName, encode).trim();
                candidateStr[2] = new String(stuCandidatesEx[i].stPersonInfo.szPersonName, encode).trim();
            } catch (UnsupportedEncodingException e) {
                e.printStackTrace();
            }
            candidateStr[3] = String.valueOf(0xff & stuCandidatesEx[i].bySimilarity);

            this.candidateList.add(candidateStr);
        }
    }
}

获取结果接口类

@RestController
@Validated
@RequestMapping("dahua/")
public class DahuaController {

    @ApiOperation(value = "大华人脸",tags = "大华人脸")
    @GetMapping("getFaceList")
    public R face() {
        String dahuaList = (String) RedisUtils.get("dahuaList");
        List<HashMap> list = JSONArray.parseArray(dahuaList,HashMap.class);
        return R.succ().attach(list);
    }

}

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

2023夏季营销报告新鲜出炉!(小红书平台)

夏季温度持续走高&#xff0c;大众需求也在升级。品牌如何借势和部署相关内容&#xff1f; 本期&#xff0c;千瓜推出《千瓜2023夏季营销策略数据报告&#xff08;小红书平台》&#xff08;本文非完整版报告&#xff09;&#xff0c;围绕七大行业&#xff08;美妆|个护|食品|家…

能翻译维吾尔语的软件有哪些?这几个可以用用看

能翻译维吾尔语的软件有哪些&#xff1f;在如今全球化的背景下&#xff0c;不同语言之间的沟通交流变得尤为重要。维吾尔语作为中国特有的少数民族语言之一&#xff0c;它的翻译需求日益增长。本文将介绍几款精选的维吾尔语翻译软件&#xff0c;帮助大家顺利实现跨语言沟通。 智…

creator 滑动循环展示图片 自动展示

import MyBaseView from "./MyBaseView";const { ccclass, property } cc._decorator;ccclass export default class ScrollCard extends MyBaseView {property({ tooltip: "是否自动展示" })Move_zidong: boolean true;property({ tooltip: "自动展…

【机器学习】特征降维 - 方差选择法VarianceThreshold

「作者主页」&#xff1a;士别三日wyx 「作者简介」&#xff1a;CSDN top100、阿里云博客专家、华为云享专家、网络安全领域优质创作者 「推荐专栏」&#xff1a;对网络安全感兴趣的小伙伴可以关注专栏《网络安全入门到精通》 方差选择法 一、方差科普二、方差选择API三、获取数…

炎炎夏日,相约Polkadot Decoded 2023上海

​上周&#xff0c;Moonbeam现身胡志明&#xff0c;参与GM Vietnam峰会活动&#xff0c;并与Chainlink和AWS等知名公司的代表一同畅谈Web3。 这周&#xff0c;Moonbeam中文社区将出席Polkadot未来论坛上海站&#xff0c;与来自波卡生态中不同平行链的代表一同探讨波卡新一代生…

小区物业管理系统需求分析

小区物业管理系统核心在于加强管理&#xff0c;提升效率&#xff0c;降低成本。实现物业核心业务信息化&#xff0c;为员工提供流畅运营模式&#xff0c;为业主提供高品质服务&#xff0c;有助于公司做强做大&#xff0c;系统优势主要有以下几方面&#xff1a; • 服务数字化&a…

Systemd服务单元

Systemd服务单元 service服务文件基本格式自定义service文件systemctl定时重启service文件中的type systemctl管理service查看服务状态查看服务是否运行查看服务是否被启用 查看开机自启服务列表设置开机启动开机启动的原理&#xff1a; 取消开机启动启动/暂停/重启服务重新加载…

day04 重新学python——数据容器

文章目录 一、数据容器1.数据容器&#xff1a;list(列表)2.list(列表)的遍历3.数据容器&#xff1a;tuple(元组)4.数据容器&#xff1a;str(字符串)5.数据容器的切片6.数据容器&#xff1a;set(集合)7.数据容器&#xff1a;dict(字典、映射)8.数据容器的通用操作 一、数据容器 …

Vue2:简单使用Animate.css动画效果

简单的使用一下Animate的动画效果&#xff08;安装&#xff0c;使用&#xff0c;速度&#xff09; 官网&#xff1a;动画.css |CSS动画的跨浏览器库。 (animate.style)https://animate.style/ 1、通过npm安装&#xff1a; npm install animate.css --save 2、导入到组件 i…

第一百零六天学习记录:数据结构与算法基础:单链表(王卓教学视频)

线性表的链式表示和实现 结点在存储器中的位置是任意的&#xff0c;即逻辑上相邻的数据元素在物理上不一定相邻 线性表的链式表示又称为非顺序映像或链式映像。 用一组物理位置任意的存储单元来存放线性表的数据元素。 这组存储单元既可以是连续的&#xff0c;也可以是不连续的…

Thymeleaf th名称空间-表达式语法-访问域对象-获取请求参数-内置对象

基本语法&#xff1a;th名称空间 基本语法&#xff1a;表达式语法 修改标签文本值 代码示例&#xff1a; <p th:text"标签体新值">标签体原始值</p>th:text作用 不经过服务器解析&#xff0c;直接用浏览器打开HTML文件&#xff0c;看到的是『标签体原…

使用C语言连接MySQL

目录 一、引入库 1.1 下载库文件 1.2 在项目中引入库 二、使用库 2.1 连接数据库 2.2 SQL请求 2.3 获取查询结果 2.4 使用案例 一、引入库 1.1 下载库文件 要使用C语言连接MySQL&#xff0c;需使用MySQL官网提供的库 MySQL :: Download Connector/Chttps://dev.mysq…

家政服务小程序开发预约功能

家政服务的需求也越来越大&#xff0c;为了更加方便用户预约服务&#xff0c;很多家政服务平台开始开发微信小程序&#xff0c;为用户提供在线预约服务。那么&#xff0c;如何开发家政服务小程序的预约功能呢&#xff1f;下面我们将结合一些参考信息&#xff0c;为大家详细介绍…

vue-element-admin || 后台管理三级/多级菜单设置

如图&#xff0c;基于vue-element-admin前端框架实现三级菜单&#xff0c;其中页面只对应三级菜单&#xff0c;无二级菜单的页面。 文件组织&#xff0c;在views文件夹下如下组织文件结构&#xff0c;其中第三级的菜单就是具体的.vue文件 在一级菜单hxb_sys下&#xff0c;要…

PROFIBUS-DP主站转ETHERCAT网关连接canopen协议报文解析实例

大家好&#xff0c;今天要给大家介绍一款远创智控的神秘产品&#xff0c;它的名字叫YC-DPM-ECT&#xff0c;是一款兼具PROFIBUS-DP主站功能的通讯网关。想象一下&#xff0c;它既能和PROFIBUS总线打交道&#xff0c;又能与ETHERCAT网络愉快地交流&#xff0c;是不是感觉很神奇&…

【Arduino小车实践】PID应用之四驱小车

一、 PID公式 二、 PID应用的必要性 1. 四驱小车运动 左边两个驱动轮和右边两个驱动轮的速度相同直线右边轮子的速度大于左边轮子的速度左偏右边轮子的速度小于左边轮子的速度 右偏 2. 产生多种运动的原因 小车的4个电机&#xff0c;减速箱以及车轮在物理层面上存在误差&am…

Spark(21):SparkStreaming之DStream入门

目录 0. 相关文章链接 1. WordCount 案例实操 1.1. 需求 1.2. 添加依赖 1.3. 编写代码 1.4. 启动程序并通过netcat发送数据 2. WordCount 解析 0. 相关文章链接 Spark文章汇总 1. WordCount 案例实操 1.1. 需求 使用 netcat 工具向 9999 端口不断的发送数据&#xf…

Flutter系列文章-Flutter环境搭建和Dart基础

Flutter是Google推出的一个开源的、高性能的移动应用开发框架&#xff0c;可以用一套代码库开发Android和iOS应用。Dart则是Flutter所使用的编程语言。让我们来看看如何搭建Flutter开发环境&#xff0c;并了解Dart语言的基础知识。 一、Flutter环境搭建 1. 安装Flutter SDK …

Blender 3.6 LTS更新的5个新功能,一定要试试

Blender基金会已正式发布Blender 3.6 LTS&#xff08;长期支持&#xff09;。它是备受期待的该公司开源 3D 软件的长期支持版本&#xff0c;也是 Blender 3.x 系列的最终 LTS 版本。Blender 3.6有一个用于设置基于粒子的模拟的模拟节点和一个升级的 UV 封装系统&#xff0c;其中…

IDEA自动添加注释作者版本时间等信息

File | Settings | Editor | Live Templates 点击加号&#xff0c;选择第二项 设置一个名称 再次点击加号&#xff0c;选择第一项 填写名称&#xff08;设置完成后再代码中输入该名称即可插入该注释内容&#xff09;&#xff0c;描述&#xff0c;及内容 /*** author 名字…