在Linux环境下利用MTCNN进行人脸检测(基于ncnn架构)

概述

本文将详细介绍如何在Linux环境下部署MTCNN模型进行人脸检测,并使用NCNN框架进行推理。

1. CMake的安装与配置

下载CMake源码

前往CMake官网下载,找到适合您系统的最新版本tar.gz文件链接,或者直接通过wget下载:CMake官方下载页面https://cmake.org/download/

cd ~
wget https://github.com/Kitware/CMake/releases/download/v3.x.x/cmake-3.x.x.tar.gz

请将3.x.x替换为您想要安装的具体版本号。

解压并进入解压后的目录

tar -xzvf cmake-3.x.x.tar.gz
cd cmake-3.x.x

编译与安装

  1. 配置编译选项:使用bootstrap脚本进行配置:

    ./bootstrap
  2. 编译:使用所有可用的核心进行并行编译:

    make -j$(nproc)
  3. 安装:将CMake安装到系统中:

    sudo make install
  4. 刷新共享库缓存(如果需要):

    sudo ldconfig

安装完成后,再次运行以下命令验证安装是否成功:

cmake --version

配置环境变量(可选)

如果您选择自定义安装路径(例如/usr/local/bin以外的路径),可能需要手动配置环境变量以确保系统能够找到新安装的CMake。

编辑~/.bashrc~/.zshrc文件(取决于您使用的shell),添加以下行:

export PATH=/path/to/cmake/bin:$PATH

其中/path/to/cmake/bin是您指定的CMake安装路径下的bin目录。

保存文件后,运行以下命令使更改生效:

source ~/.bashrc  # 对于Bash用户
# 或者
source ~/.zshrc   # 对于Zsh用户

2. Protobuf的安装

更新系统软件包

首先,更新您的系统软件包列表,确保所有现有的包都是最新的:

sudo apt-get update
sudo apt-get upgrade

安装依赖项

安装构建Protobuf所需的各种工具和库:

sudo apt-get install autoconf automake libtool curl make g++ unzip

下载Protobuf源码

您可以从GitHub上克隆官方Protobuf仓库,或者直接下载特定版本的压缩包。这里我们使用Git进行操作:

cd ~
git clone https://github.com/protocolbuffers/protobuf.git
cd protobuf
git submodule update --init --recursive

编译Protobuf

创建并进入构建目录

为了保持源代码目录的整洁,建议在一个新的目录中进行编译:

cd ~/protobuf
mkdir -p build && cd build

使用CMake配置项目

CMake是一个跨平台的构建系统生成器,支持多种IDE和构建工具。

  1. 配置CMake:

    cmake .. -DCMAKE_BUILD_TYPE=Release
  2. 编译Protobuf:

    make -j$(nproc)
  3. 安装Protobuf:

    sudo make install
    sudo ldconfig  # 刷新共享库缓存

验证安装

检查版本信息

验证Protobuf是否正确安装,并检查其版本号:

protoc --version

您应该看到类似如下的输出:

libprotoc 3.x.x

其中3.x.x是具体的版本号。

配置环境变量(可选)

如果希望在任何位置都能直接运行protoc命令,而无需指定完整路径,可以将Protobuf的bin目录添加到系统的PATH环境变量中。编辑~/.bashrc~/.zshrc文件,根据您的shell类型,添加以下行:

export PATH=$PATH:/usr/local/bin

保存文件后,运行以下命令使更改生效:

source ~/.bashrc  # 对于Bash用户
# 或者
source ~/.zshrc   # 对于Zsh用户

3. OpenCV库的安装与配置

更新系统软件包

首先,更新您的系统软件包列表:

sudo apt-get update
sudo apt-get upgrade

安装依赖项

安装构建OpenCV所需的各种工具和库:

sudo apt-get install build-essential cmake git pkg-config libgtk-3-dev
sudo apt-get install libavcodec-dev libavformat-dev libswscale-dev
sudo apt-get install python3-dev python3-numpy libtbb2 libtbb-dev libjpeg-dev libpng-dev libtiff-dev
sudo apt-get install libdc1394-22-dev libopenblas-dev liblapack-dev gfortran
sudo apt-get install libprotobuf-dev protobuf-compiler

下载OpenCV源码

您可以通过Git克隆OpenCV的GitHub仓库来获取最新的稳定版本:

cd ~
git clone https://github.com/opencv/opencv.git
cd opencv
git checkout 4.x # 替换为所需的版本号# 克隆contrib仓库(可选)
cd ~
git clone https://github.com/opencv/opencv_contrib.git
cd opencv_contrib
git checkout 4.x # 确保与主仓库版本一致

编译OpenCV

创建并进入构建目录

cd ~/opencv
mkdir -p build && cd build

使用CMake配置项目

运行CMake以配置构建选项。这里我们指定一些常用的选项,例如启用Python支持、设置安装路径等。如果您不需要这些功能或使用了不同的路径,请相应地调整命令。

cmake -D CMAKE_BUILD_TYPE=Release \-D CMAKE_INSTALL_PREFIX=/usr/local \-D OPENCV_EXTRA_MODULES_PATH=~/opencv_contrib/modules \-D BUILD_opencv_python3=ON \-D PYTHON3_EXECUTABLE=$(which python3) \-D PYTHON3_INCLUDE_DIR=$(python3 -c "from distutils.sysconfig import get_python_inc; print(get_python_inc())") \-D PYTHON3_PACKAGES_PATH=$(python3 -c "from distutils.sysconfig import get_python_lib; print(get_python_lib())") ..

编译

make -j$(nproc)

这可能需要一些时间,具体取决于您的硬件性能。

安装

完成编译后,使用以下命令安装OpenCV到系统中:

sudo make install
sudo ldconfig

验证安装

查找头文件和库文件

安装完成后,OpenCV的头文件通常位于/usr/local/include/opencv4/,而库文件则位于/usr/local/lib/

您可以检查这些位置是否包含必要的文件:

ls /usr/local/include/opencv4/
ls /usr/local/lib/

4. ncnn库在Linux环境下的编译

更新系统软件包

首先,更新您的系统软件包列表,确保所有现有的包都是最新的:

sudo apt-get update
sudo apt-get upgrade

安装依赖项

安装构建NCNN所需的各种工具和库:

sudo apt-get install build-essential cmake git libprotobuf-dev protobuf-compiler
sudo apt-get install libvulkan-dev vulkan-utils  # 如果需要Vulkan支持

libprotobuf-devprotobuf-compiler 是用于处理模型文件(如 .param.bin 文件)的必要依赖项。

下载NCNN源码

您可以通过Git克隆NCNN的GitHub仓库来获取最新的稳定版本:

cd ~
git clone https://github.com/Tencent/ncnn.git
cd ncnn

如果您想要特定的版本,可以切换到对应的分支或标签:

git checkout <branch_or_tag_name>

例如,切换到最新稳定版:

git checkout master

编译NCNN

创建并进入构建目录

为了保持源代码目录的整洁,建议在一个新的目录中进行编译:

mkdir -p build && cd build

使用CMake配置项目

运行CMake以配置构建选项。这里我们指定一些常用的选项,例如启用Vulkan支持、设置安装路径等。如果您不需要这些功能或使用了不同的路径,请相应地调整命令。

cmake .. \-DCMAKE_BUILD_TYPE=Release \-DNCNN_VULKAN=ON \  # 如果你希望使用Vulkan加速,请启用此选项-DNCNN_PROTOBUF_USE_SYSTEM=ON \-DProtobuf_DIR=/usr/lib/x86_64-linux-gnu/pkgconfig \  # 手动指定 Protobuf 的路径-DProtobuf_INCLUDE_DIR=/usr/include \-DProtobuf_LIBRARY=/usr/lib/x86_64-linux-gnu/libprotobuf.so \-DProtobuf_PROTOC_EXECUTABLE=/usr/bin/protoc

    编译

    使用所有可用的核心进行并行编译:

    make -j$(nproc)

    这可能需要一些时间,具体取决于您的硬件性能。

    安装

    完成编译后,使用以下命令安装NCNN到系统中:

    sudo make install
    sudo ldconfig  # 刷新共享库缓存

    默认情况下,头文件会被安装到 /usr/local/include/ncnn,库文件会被安装到 /usr/local/lib

    验证安装

    查找头文件和库文件

    安装完成后,NCNN的头文件通常位于 /usr/local/include/ncnn,而库文件则位于 /usr/local/lib

    您可以检查这些位置是否包含必要的文件:

    ls /usr/local/include/ncnn/
    ls /usr/local/lib/

    5. MTCNN源码

    ncnn框架实现的mtcnn主要包含两个核心代码文件mtcnn.h,mtcnn.cpp

    mtcnn.h代码如下:

    #pragma once#ifndef __MTCNN_NCNN_H__
    #define __MTCNN_NCNN_H__
    #include <ncnn/net.h>
    #include <string>
    #include <vector>
    #include <time.h>
    #include <algorithm>
    #include <map>
    #include <iostream>using namespace std;
    struct Bbox
    {float score;int x1;int y1;int x2;int y2;bool exist;float area;float ppoint[10];float regreCoord[4];
    };class MTCNN {public:MTCNN(const string& model_path);MTCNN(const std::vector<std::string> param_files, const std::vector<std::string> bin_files);~MTCNN();void configure_ncnn(ncnn::Net& net, int num_threads);void SetMinFace(int minSize);void detect(ncnn::Mat& img_, std::vector<Bbox>& finalBbox);
    private:void generateBbox(ncnn::Mat score, ncnn::Mat location, vector<Bbox>& boundingBox_, float scale);void nms(vector<Bbox>& boundingBox_, const float overlap_threshold, string modelname = "Union");void refine(vector<Bbox>& vecBbox, const int& height, const int& width, bool square);void PNet();void RNet();void ONet();ncnn::Net Pnet, Rnet, Onet;ncnn::Mat img;const float nms_threshold[3] = { 0.5f, 0.7f, 0.7f };const float mean_vals[3] = { 127.5, 127.5, 127.5 };const float norm_vals[3] = { 0.0078125, 0.0078125, 0.0078125 };const int MIN_DET_SIZE = 12;std::vector<Bbox> firstBbox_, secondBbox_, thirdBbox_;int img_w, img_h;private://部分可调参数const float threshold[3] = { 0.8f, 0.8f, 0.6f };int minsize = 20;const float pre_facetor = 0.709f;};#endif //__MTCNN_NCNN_H__
    

    mtcnn.cpp代码如下:

    #include "mtcnn.h"bool cmpScore(Bbox lsh, Bbox rsh) {if (lsh.score < rsh.score)return true;elsereturn false;
    }bool cmpArea(Bbox lsh, Bbox rsh) {if (lsh.area < rsh.area)return false;elsereturn true;
    }MTCNN::MTCNN(const std::string& model_path) {std::vector<std::string> param_files = {model_path + "/det1.param",model_path + "/det2.param",model_path + "/det3.param"};std::vector<std::string> bin_files = {model_path + "/det1.bin",model_path + "/det2.bin",model_path + "/det3.bin"};// 配置多线程int num_threads = 4; // 设置线程数configure_ncnn(Pnet, num_threads);configure_ncnn(Rnet, num_threads);configure_ncnn(Onet, num_threads);// 加载模型Pnet.load_param(param_files[0].data());Pnet.load_model(bin_files[0].data());Rnet.load_param(param_files[1].data());Rnet.load_model(bin_files[1].data());Onet.load_param(param_files[2].data());Onet.load_model(bin_files[2].data());
    }MTCNN::~MTCNN(){Pnet.clear();Rnet.clear();Onet.clear();
    }void MTCNN::configure_ncnn(ncnn::Net& net, int num_threads) {ncnn::Option opt;opt.num_threads = num_threads; // 设置线程数opt.use_vulkan_compute = false; // 如果不使用 Vulkan,设置为 falsenet.opt = opt;
    }void MTCNN::SetMinFace(int minSize){minsize = minSize;
    }void MTCNN::generateBbox(ncnn::Mat score, ncnn::Mat location, std::vector<Bbox>& boundingBox_, float scale){const int stride = 2;const int cellsize = 12;//score pfloat *p = score.channel(1);//score.data + score.cstep;//float *plocal = location.data;Bbox bbox;float inv_scale = 1.0f/scale;for(int row=0;row<score.h;row++){for(int col=0;col<score.w;col++){if(*p>threshold[0]){bbox.score = *p;bbox.x1 = round((stride*col+1)*inv_scale);bbox.y1 = round((stride*row+1)*inv_scale);bbox.x2 = round((stride*col+1+cellsize)*inv_scale);bbox.y2 = round((stride*row+1+cellsize)*inv_scale);bbox.area = (bbox.x2 - bbox.x1) * (bbox.y2 - bbox.y1);const int index = row * score.w + col;for(int channel=0;channel<4;channel++){bbox.regreCoord[channel]=location.channel(channel)[index];}boundingBox_.push_back(bbox);}p++;//plocal++;}}
    }void MTCNN::nms(std::vector<Bbox> &boundingBox_, const float overlap_threshold, string modelname){if(boundingBox_.empty()){return;}sort(boundingBox_.begin(), boundingBox_.end(), cmpScore);float IOU = 0;float maxX = 0;float maxY = 0;float minX = 0;float minY = 0;std::vector<int> vPick;int nPick = 0;std::multimap<float, int> vScores;const int num_boxes = boundingBox_.size();vPick.resize(num_boxes);for (int i = 0; i < num_boxes; ++i){vScores.insert(std::pair<float, int>(boundingBox_[i].score, i));}while(vScores.size() > 0){int last = vScores.rbegin()->second;vPick[nPick] = last;nPick += 1;for (std::multimap<float, int>::iterator it = vScores.begin(); it != vScores.end();){int it_idx = it->second;maxX = (std::max)(boundingBox_.at(it_idx).x1, boundingBox_.at(last).x1);maxY = (std::max)(boundingBox_.at(it_idx).y1, boundingBox_.at(last).y1);minX = (std::min)(boundingBox_.at(it_idx).x2, boundingBox_.at(last).x2);minY = (std::min)(boundingBox_.at(it_idx).y2, boundingBox_.at(last).y2);//maxX1 and maxY1 reuse maxX = ((minX-maxX+1)>0)? (minX-maxX+1) : 0;maxY = ((minY-maxY+1)>0)? (minY-maxY+1) : 0;//IOU reuse for the area of two bboxIOU = maxX * maxY;if(!modelname.compare("Union"))IOU = IOU/(boundingBox_.at(it_idx).area + boundingBox_.at(last).area - IOU);else if(!modelname.compare("Min")){IOU = IOU/((boundingBox_.at(it_idx).area < boundingBox_.at(last).area)? boundingBox_.at(it_idx).area : boundingBox_.at(last).area);}if(IOU > overlap_threshold){it = vScores.erase(it);}else{it++;}}}vPick.resize(nPick);std::vector<Bbox> tmp_;tmp_.resize(nPick);for(int i = 0; i < nPick; i++){tmp_[i] = boundingBox_[vPick[i]];}boundingBox_ = tmp_;
    }void MTCNN::refine(vector<Bbox> &vecBbox, const int &height, const int &width, bool square){if(vecBbox.empty()){cout<<"Bbox is empty!!"<<endl;return;}float bbw=0, bbh=0, maxSide=0;float h = 0, w = 0;float x1=0, y1=0, x2=0, y2=0;for(vector<Bbox>::iterator it=vecBbox.begin(); it!=vecBbox.end();it++){bbw = (*it).x2 - (*it).x1 + 1;bbh = (*it).y2 - (*it).y1 + 1;x1 = (*it).x1 + (*it).regreCoord[0]*bbw;y1 = (*it).y1 + (*it).regreCoord[1]*bbh;x2 = (*it).x2 + (*it).regreCoord[2]*bbw;y2 = (*it).y2 + (*it).regreCoord[3]*bbh;if(square){w = x2 - x1 + 1;h = y2 - y1 + 1;maxSide = (h>w)?h:w;x1 = x1 + w*0.5 - maxSide*0.5;y1 = y1 + h*0.5 - maxSide*0.5;(*it).x2 = round(x1 + maxSide - 1);(*it).y2 = round(y1 + maxSide - 1);(*it).x1 = round(x1);(*it).y1 = round(y1);}//boundary checkif((*it).x1<0)(*it).x1=0;if((*it).y1<0)(*it).y1=0;if((*it).x2>width)(*it).x2 = width - 1;if((*it).y2>height)(*it).y2 = height - 1;it->area = (it->x2 - it->x1)*(it->y2 - it->y1);}
    }void MTCNN::PNet(){firstBbox_.clear();float minl = img_w < img_h? img_w: img_h;float m = (float)MIN_DET_SIZE/minsize;minl *= m;float factor = pre_facetor;vector<float> scales_;while(minl>MIN_DET_SIZE){scales_.push_back(m);minl *= factor;m = m*factor;}for (size_t i = 0; i < scales_.size(); i++) {int hs = (int)ceil(img_h*scales_[i]);int ws = (int)ceil(img_w*scales_[i]);ncnn::Mat in;resize_bilinear(img, in, ws, hs);ncnn::Extractor ex = Pnet.create_extractor();//ex.set_num_threads(2);ex.set_light_mode(true);ex.input("data", in);ncnn::Mat score_, location_;ex.extract("prob1", score_);ex.extract("conv4-2", location_);std::vector<Bbox> boundingBox_;generateBbox(score_, location_, boundingBox_, scales_[i]);nms(boundingBox_, nms_threshold[0]);firstBbox_.insert(firstBbox_.end(), boundingBox_.begin(), boundingBox_.end());boundingBox_.clear();}
    }
    void MTCNN::RNet(){secondBbox_.clear();int count = 0;for(vector<Bbox>::iterator it=firstBbox_.begin(); it!=firstBbox_.end();it++){ncnn::Mat tempIm;copy_cut_border(img, tempIm, (*it).y1, img_h-(*it).y2, (*it).x1, img_w-(*it).x2);ncnn::Mat in;resize_bilinear(tempIm, in, 24, 24);ncnn::Extractor ex = Rnet.create_extractor();//ex.set_num_threads(2);ex.set_light_mode(true);ex.input("data", in);ncnn::Mat score, bbox;ex.extract("prob1", score);ex.extract("conv5-2", bbox);if ((float)score[1] > threshold[1]) {for (int channel = 0; channel<4; channel++) {it->regreCoord[channel] = (float)bbox[channel];//*(bbox.data+channel*bbox.cstep);}it->area = (it->x2 - it->x1)*(it->y2 - it->y1);it->score = score.channel(1)[0];//*(score.data+score.cstep);secondBbox_.push_back(*it);}}
    }
    void MTCNN::ONet(){thirdBbox_.clear();for(vector<Bbox>::iterator it=secondBbox_.begin(); it!=secondBbox_.end();it++){ncnn::Mat tempIm;copy_cut_border(img, tempIm, (*it).y1, img_h-(*it).y2, (*it).x1, img_w-(*it).x2);ncnn::Mat in;resize_bilinear(tempIm, in, 48, 48);ncnn::Extractor ex = Onet.create_extractor();//ex.set_num_threads(2);ex.set_light_mode(true);ex.input("data", in);ncnn::Mat score, bbox, keyPoint;ex.extract("prob1", score);ex.extract("conv6-2", bbox);ex.extract("conv6-3", keyPoint);if ((float)score[1] > threshold[2]) {for (int channel = 0; channel < 4; channel++) {it->regreCoord[channel] = (float)bbox[channel];}it->area = (it->x2 - it->x1) * (it->y2 - it->y1);it->score = score.channel(1)[0];for (int num = 0; num<5; num++) {(it->ppoint)[num] = it->x1 + (it->x2 - it->x1) * keyPoint[num];(it->ppoint)[num + 5] = it->y1 + (it->y2 - it->y1) * keyPoint[num + 5];}thirdBbox_.push_back(*it);}}
    }void MTCNN::detect(ncnn::Mat& img_, std::vector<Bbox>& finalBbox_){img = img_;img_w = img.w;img_h = img.h;img.substract_mean_normalize(mean_vals, norm_vals);PNet();//the first stage's nmsif(firstBbox_.size() < 1) return;nms(firstBbox_, nms_threshold[0]);refine(firstBbox_, img_h, img_w, true);//second stageRNet();if(secondBbox_.size() < 1) return;nms(secondBbox_, nms_threshold[1]);refine(secondBbox_, img_h, img_w, true);//third stage ONet();if(thirdBbox_.size() < 1) return;refine(thirdBbox_, img_h, img_w, true);nms(thirdBbox_, nms_threshold[2], "Min");finalBbox_ = thirdBbox_;
    }
    

    6. Linux下进行推理

    在Linux下配置完Opencv和ncnn的环境后编写简单的main.cpp进行模型的推理,代码如下:

    #include "mtcnn.h"
    #include <opencv2/opencv.hpp>
    #include <chrono>using namespace cv;int main()
    {std::string model_path = "./models"; //根据模型权重所在位置修改路径MTCNN mm(model_path);mm.SetMinFace(20);cv::VideoCapture video("./video/video.mp4"); //根据测试视频所在位置修改路径if (!video.isOpened()) {std::cerr << "failed to load video" << std::endl;return -1;}std::vector<Bbox> finalBbox;cv::Mat frame;// 记录开始时间auto start = std::chrono::high_resolution_clock::now();do {finalBbox.clear();video >> frame;if (!frame.data) {std::cerr << "Capture video failed" << std::endl;break;}ncnn::Mat ncnn_img = ncnn::Mat::from_pixels(frame.data, ncnn::Mat::PIXEL_BGR2RGB, frame.cols, frame.rows);mm.detect(ncnn_img, finalBbox);for (vector<Bbox>::iterator it = finalBbox.begin(); it != finalBbox.end(); it++) {if ((*it).exist) {cv::rectangle(frame, cv::Point((*it).x1, (*it).y1), cv::Point((*it).x2, (*it).y2), cv::Scalar(0, 0, 255), 2, 8, 0);}}} while (1);// 释放资源video.release();// 记录结束时间auto end = std::chrono::high_resolution_clock::now();// 计算持续时间std::chrono::duration<double> duration = end - start;// 输出结果(秒)std::cout << "Time taken: " << duration.count() << " seconds" << std::endl;return 0;
    }
    

    测试项目的目录结构如下:

    mtcnn/
    ├── Makefile
    ├── video
    │   └── video.mp4
    ├── include/
    │   └── mtcnn.h
    ├── src/
    │   ├── mtcnn.cpp
    │   └── main.cpp
    └── models├── det1.bin├── det1.param├── det2.bin├── det2.param├── det3.bin└── det3.param
    

    ncnn架构的mtcnn模型权重下载链接如下:

    ncnn架构的mtcnn模型权重下载https://download.csdn.net/download/m0_57010556/90433089Makefile的内容如下:

    # 编译器
    CXX = g++# 编译选项
    CXXFLAGS = -Wall -I./include -O2 -fopenmp `pkg-config --cflags opencv4`# 目标可执行文件名
    TARGET = face_detection# 源文件目录
    SRCDIR = src# 头文件目录
    INCDIR = include# 链接库路径
    OPENCV_LIBS = `pkg-config --libs opencv4`
    OPENCV_CFLAGS = `pkg-config --cflags opencv4`
    NCNN_CFLAGS = -I/home/ncnn/build/install/include
    NCNN_LIBS = -L/home/ncnn/build/install/lib -lncnn# 找到所有源文件
    SOURCES := $(wildcard $(SRCDIR)/*.cpp)# 生成目标文件列表
    OBJECTS := $(patsubst $(SRCDIR)/%.cpp, %.o, $(SOURCES))# 默认目标
    all: $(TARGET)# 链接目标文件生成可执行文件
    $(TARGET): $(OBJECTS)$(CXX) $(CXXFLAGS) $^ -o $@ $(OPENCV_LIBS) $(NCNN_LIBS) -lpthread -ldl -lgomp# 规则:从源文件生成目标文件
    %.o: $(SRCDIR)/%.cpp$(CXX) $(CXXFLAGS) $(OPENCV_CFLAGS) $(NCNN_CFLAGS) -c $< -o $@# 清理生成的文件
    clean:rm -f $(OBJECTS) $(TARGET).PHONY: all clean

    编译和运行

    在项目目录下运行以下命令来编译和运行你的程序:

    编译

    make

    这将编译 src/mtcnn.cppsrc/main.cpp 并生成可执行文件 face_detection

    运行

    ./face_detection

    你应该会看到输出:

    Capture video failed
    Time taken: 22.336 seconds

    此时说明在linux下模型推理成功

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

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

    相关文章

    算法day1 dfs搜索2题

    一 火星人 拿到这种类似于排序的&#xff0c;这个就好比如我们之前学习dfs基础的时候里面的指数型枚举 指数型枚举数据与数据之间没有任何枚举&#xff0c;就比如选这个数字与不选组合型枚举数据与数据之间有联系&#xff0c;下一个数字不可以给上一个数字排列型枚举数据与数…

    CC攻击防御策略全解析:技术实现与代码示例

    CC攻击&#xff08;Challenge Collapsar&#xff09;是一种以消耗服务器资源为目标的分布式拒绝服务攻击&#xff08;DDoS&#xff09;&#xff0c;其特点在于攻击流量伪装成合法请求&#xff0c;难以通过传统防火墙完全防御。本文将从技术实现角度详细解析CC攻击的防御策略&am…

    (九)axios的使用

    1、axios 的基本使用 1.1、简介 在 Web 开发的演进历程中&#xff0c;数据请求方式的变革至关重要。回溯早期&#xff0c;旧浏览器在向服务器请求数据时&#xff0c;存在严重弊端。由于返回的是整个页面数据&#xff0c;每次请求都会导致页面强制刷新&#xff0c;这不仅极大地…

    【MySQL篇】数据库基础

    目录 1&#xff0c;什么是数据库&#xff1f; 2&#xff0c;主流数据库 3&#xff0c;MySQL介绍 1&#xff0c;MySQL架构 2&#xff0c;SQL分类 3&#xff0c;MySQL存储引擎 1&#xff0c;什么是数据库&#xff1f; 数据库&#xff08;Database&#xff0c;简称DB&#xf…

    网络安全事件研判

    &#x1f345; 点击文末小卡片 &#xff0c;免费获取网络安全全套资料&#xff0c;资料在手&#xff0c;涨薪更快 研判&#xff08;入侵检测&#xff09; 研判我理解为人工层面对入侵检测事件进行再分析&#xff0c;即借助已有的设备告警根据经验判断是否为真实action 研判工作…

    python整理文件下

    我们使用 os.path.join() 函数拼接出文件要移动的目标地址。 并使用 os.path.exists() 函数配合 not 关键字找到未创建的文件夹。 这节课&#xff0c;我们会先创建文件夹&#xff0c;然后再移动文件到目标文件夹。如果文件夹不存在&#xff0c;我们需要先创建文件夹&#xff…

    hackmyvm-buster

    题目地址 信息收集 主机发现 ┌──(root㉿kali)-[/home/kali] └─# arp-scan -I eth1 192.168.56.0/24 Interface: eth1, type: EN10MB, MAC: 00:0c:29:34:da:f5, IPv4: 192.168.56.103 WARNING: Cannot open MAC/Vendor file ieee-oui.txt: Permission denied WARNING: C…

    FS800DTU联动OneNET平台数据可视化View

    目录 1 前言 2 环境搭建 2.1 硬件准备 2.2 软件环境 2.3 硬件连接 3 注册OneNET云平台并建立物模型 3.1 参数获取 3.2 连接OneNET 3.3上报数据 4 数据可视化View 4.1 用户信息获取 4.2 启用数据可视化View 4.3 创建项目 4.4 编辑项目 4.5 新增数据源 4.6 数据过滤器配置 4.6 项…

    Dockerfile 中的 COPY 语句:作用与使用详解

    在 Docker 的构建过程中&#xff0c;Dockerfile 是一个核心文件&#xff0c;它定义了镜像的构建步骤和内容。其中&#xff0c;COPY 语句是一个非常重要的指令&#xff0c;用于将文件或目录从构建上下文&#xff08;通常是 Dockerfile 所在的目录及其子目录&#xff09;复制到容…

    大白话Vuex 核心概念(state、mutations、actions)的使用案例与原理

    大白话Vuex 核心概念&#xff08;state、mutations、actions&#xff09;的使用案例与原理 Vuex是Vue.js应用程序中专门用来管理状态的工具&#xff0c;就好像是一个大管家&#xff0c;帮你把项目里一些重要的数据和操作管理得井井有条。下面用大白话结合案例来介绍Vuex核心概…

    机器学习介绍与数据集

    一、机器学习介绍与定义 1.1 机器学习定义 机器学习&#xff08;Machine Learning&#xff09;是让计算机从数据中自动学习规律&#xff0c;并依据这些规律对未来数据进行预测的技术。它涵盖聚类、分类、决策树、贝叶斯、神经网络、深度学习&#xff08;Deep Learning&#xf…

    大模型训练——pycharm连接实验室服务器

    一、引言 我们在运行或者复现大佬论文代码的时候&#xff0c;笔记本的算力不够&#xff0c;需要使用实验室的服务器进行运行。可以直接在服务器的终端上执行&#xff0c;但是这样的话代码调试就不方便。而我们可以使用 pycharm 连接到服务器&#xff0c;既方便了代码调试&…

    【Linux】进程优先级 | 进程调度(三)

    目录 前言&#xff1a; 一、进程优先级&#xff1a; 1.通过nice值修改优先级&#xff1a; 二、进程切换&#xff1a; 三、上下文数据 四、Linux真实调度算法&#xff1a; 五、bitmap位图&#xff1a; 六、命令总结&#xff1a; 总结&#xff1a; 前言&#xff1a; 我…

    【redis】数据类型之hyperloglog

    Redis的HyperLogLog&#xff08;HLL&#xff09;是一种高效的概率数据结构&#xff0c;也是一种基于字符串的数据结构&#xff0c;用于估计大数据集的唯一元素数量&#xff08;基数统计&#xff09;。它通过极低的内存占用&#xff08;约 12KB&#xff09;实现接近线性的时间复…

    【C语言】第八期——指针、二维数组与字符串

    目录 1 初始指针 2 获取变量的地址 3 定义指针变量、取地址、取值 3.1 定义指针变量 3.2 取地址、取值 4 对指针变量进行读写操作 5 指针变量作为函数参数 6 数组与指针 6.1 指针元素指向数组 6.2 指针加减运算&#xff08;了解&#xff09; 6.2.1 指针加减具体数字…

    SpringBoot——生成Excel文件

    在Springboot以及其他的一些项目中&#xff0c;或许我们可能需要将数据查询出来进行生成Excel文件进行数据的展示&#xff0c;或者用于进行邮箱发送进行附件添加 依赖引入 此处demo使用maven依赖进行使用 <dependency><groupId>org.apache.poi</groupId>&…

    mac 下 java 调用 gurobi 不能加载 jar

    在 mac 电脑中的 java 始终不能加载 gurobi 的 jar 包&#xff0c;java 的开发软件 eclipse&#xff0c;idea 总是显示找不到 gurobi 的 jar 包&#xff0c;但是 jar 包明明就在那里。 摸索了三个小时&#xff0c;最后发现原因竟然是&#xff1a; jar 包太新&#xff0c;替换…

    服务端配置TCP探活,超出探活时间后的行为?

    server端启动 &#xff08;完整源码在最后&#xff09; 配置探活 setsockopt(client_fd, IPPROTO_TCP, TCP_KEEPIDLE, &(int){5}, sizeof(int)); // 空闲60秒后探测setsockopt(client_fd, IPPROTO_TCP, TCP_KEEPINTVL, &(int){10}, sizeof(int)); // 探测间隔10秒…

    LLC谐振变换器恒压恒流双竞争闭环simulink仿真

    1.模型简介 本仿真模型基于MATLAB/Simulink&#xff08;版本MATLAB 2017Ra&#xff09;软件。建议采用matlab2017 Ra及以上版本打开。&#xff08;若需要其他版本可联系代为转换&#xff09;针对全桥LLC拓扑&#xff0c;利用Matlab软件搭建模型&#xff0c;分别对轻载&#xf…

    MySQL 中如何查看 SQL 的执行计划?

    SQL 语句前面使用 EXPLAIN 关键字&#xff1a; EXPLAIN SELECT * FROM users WHERE id 1; 字段 含义 id 查询的序号&#xff08;如果是子查询或联合查询&#xff0c;会有多个 id&#xff09;。 select_type 查询的类型&#xff08;简单查询、子查询、联合查询等&#xff…