主頁 > 後端開發 > JavaCV人臉識別三部曲之一:視頻中的人臉保存為圖片

JavaCV人臉識別三部曲之一:視頻中的人臉保存為圖片

2023-06-28 09:08:58 後端開發

歡迎訪問我的GitHub

這里分類和匯總了欣宸的全部原創(含配套原始碼):https://github.com/zq2599/blog_demos

關于人臉識別

  • 本文是《JavaCV人臉識別三部曲》的第一篇,在《JavaCV的攝像頭實戰之八:人臉檢測》一文中,實作了檢測人臉并用方框標注出來,但僅框出人臉作用不大,最好是識別出此人的身份,這樣就能做很多事情了,例如簽到、告警等,這就是接下來咱們要挑戰的人臉識別

  • 人臉識別涉及到兩個步驟:訓練和識別,接下來簡單說明解釋一下

  • 先看什么是訓練,如下圖,用兩位天王的六張照片來訓練,一共兩個類別,訓練完成后得到模型檔案faceRecognizer.xml
    在這里插入圖片描述

  • 訓練成功后, 我們拿一張新的照片給模型去識別,得到的結果是訓練時的類別,如此識別完成,我們已確定了新照片的身份:
    在這里插入圖片描述

  • 下面用流程圖將訓練和識別說得更詳細一些:
    在這里插入圖片描述

關于《JavaCV人臉識別三部曲》

《JavaCV人臉識別三部曲》一共三篇文章,內容如下:

  1. 《視頻中的人臉保存為圖片》:本篇介紹如何通過JavaCV將攝像頭中的每個人臉都檢測出來,并且把每個人臉保存為圖片,這種方法可以讓我們快速獲取大量人臉照片用于訓練
  2. 《訓練》:講述如何用分類好的照片去訓練模型
  3. 《識別和預覽》:拿到訓練好的模型,去識別視頻中每一幀的人臉,把結果標注到圖片上預覽
  • 整個三部曲也是《JavaCV的攝像頭實戰》系列的一部分,分別是《JavaCV的攝像頭實戰》系列的的第九、第十、第十一篇

本篇概覽

  • 本篇要做的事情就是把訓練用的照片準備好
  • 您可能會疑惑:我自己去找一些照片不就行了嗎?去網上搜、去相冊搜、去拍照不都可以嗎?沒錯,只要找到您想識別的人臉即可,而本篇介紹的是另一種方法:借助攝像頭檢測人臉,然后將人臉大小的照片保存在硬碟,用這些照片來訓練,實測多張照片訓練處的模型在檢測新照片時效果更好
  • 具體做法如下:
  1. 寫個程式,對攝像頭的照片做人臉檢測,每個檢測到的人臉,都作一張圖片保存,注意不是攝像頭視頻幀的完整圖片,而是檢測出每張人臉,把這個人臉的矩形作為圖片保存,而且保存的是灰度圖片,不是彩色圖片(訓練和檢測只需要灰度圖片)
  2. 然后找個沒人的地方運行程式,一個人對著攝像頭,開始......搔首弄姿,各種光線明暗、各種角度、各種表情都用上,作為圖片保存
  • 用這些圖片訓練出的模型,由于覆寫了各種亮度、角度、表情,最終的識別效果會更好
  • 接下來我們就來寫這段程式吧

原始碼下載

  • 《JavaCV的攝像頭實戰》的完整原始碼可在GitHub下載到,地址和鏈接資訊如下表所示(https://github.com/zq2599/blog_demos):
名稱 鏈接 備注
專案主頁 https://github.com/zq2599/blog_demos 該專案在GitHub上的主頁
git倉庫地址(https) https://github.com/zq2599/blog_demos.git 該專案原始碼的倉庫地址,https協議
git倉庫地址(ssh) [email protected]:zq2599/blog_demos.git 該專案原始碼的倉庫地址,ssh協議
  • 這個git專案中有多個檔案夾,本篇的原始碼在javacv-tutorials檔案夾下,如下圖紅框所示:
    在這里插入圖片描述
  • javacv-tutorials里面有多個子工程,《JavaCV的攝像頭實戰》系列的代碼在simple-grab-push工程下:
    在這里插入圖片描述

編碼:檢測服務

  • 先定義一個檢測有關的介面DetectService.java,如下,主要是定義了三個方法init、convert、releaseOutputResource,其中init用于初始化檢測服務,convert負責處理單個幀(本篇就是檢測出人臉、把人臉照片保存在硬碟),releaseOutputResource在結束的時候被執行,用于釋放資源,另外還有個靜態方法buildGrayImage,很簡單,生成灰度圖片對應的Mat物件:
package com.bolingcavalry.grabpush.extend;

import com.bolingcavalry.grabpush.Constants;
import org.bytedeco.javacv.Frame;
import org.bytedeco.javacv.OpenCVFrameConverter;
import org.bytedeco.opencv.opencv_core.*;
import org.bytedeco.opencv.opencv_objdetect.CascadeClassifier;
import static org.bytedeco.opencv.global.opencv_core.CV_8UC1;
import static org.bytedeco.opencv.global.opencv_imgcodecs.imwrite;
import static org.bytedeco.opencv.global.opencv_imgproc.*;

/**
 * @author willzhao
 * @version 1.0
 * @description 檢測工具的通用介面
 * @date 2021/12/5 10:57
 */
public interface DetectService {

    /**
     * 根據傳入的MAT構造相同尺寸的MAT,存放灰度圖片用于以后的檢測
     * @param src 原始圖片的MAT物件
     * @return 相同尺寸的灰度圖片的MAT物件
     */
    static Mat buildGrayImage(Mat src) {
        return new Mat(src.rows(), src.cols(), CV_8UC1);
    }
    
    /**
     * 初始化操作,例如模型下載
     * @throws Exception
     */
    void init() throws Exception;

    /**
     * 得到原始幀,做識別,添加框選
     * @param frame
     * @return
     */
    Frame convert(Frame frame);

    /**
     * 釋放資源
     */
    void releaseOutputResource();
}
  • 然后就是DetectService的實作類DetectAndSaveService.java,完整代碼如下,有幾處要注意的地方稍后提到:
package com.bolingcavalry.grabpush.extend;

import com.bolingcavalry.grabpush.Constants;
import lombok.extern.slf4j.Slf4j;
import org.bytedeco.javacpp.Loader;
import org.bytedeco.javacv.Frame;
import org.bytedeco.javacv.OpenCVFrameConverter;
import org.bytedeco.opencv.opencv_core.*;
import org.bytedeco.opencv.opencv_objdetect.CascadeClassifier;
import java.io.File;
import java.net.URL;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.concurrent.atomic.AtomicInteger;
import static org.bytedeco.opencv.global.opencv_imgcodecs.imwrite;
import static org.bytedeco.opencv.global.opencv_imgproc.*;

/**
 * @author willzhao
 * @version 1.0
 * @description 檢測人臉并保存到硬碟的服務
 * @date 2021/12/3 8:09
 */
@Slf4j
public class DetectAndSaveService implements DetectService {

    /**
     * 每一幀原始圖片的物件
     */
    private Mat grabbedImage = null;

    /**
     * 原始圖片對應的灰度圖片物件
     */
    private Mat grayImage = null;

    /**
     * 分類器
     */
    private CascadeClassifier classifier;

    /**
     * 轉換器
     */
    private OpenCVFrameConverter.ToMat converter = new OpenCVFrameConverter.ToMat();

    /**
     * 模型檔案的下載地址
     */
    private String modelFileUrl;

    /**
     * 存放人臉圖片的位置
     */
    private String basePath;

    /**
     * 記錄圖片總數
     */
    private final AtomicInteger num = new AtomicInteger();

    /**
     * 訓練的圖片尺寸
     */
    Size size = new Size(Constants.RESIZE_WIDTH, Constants.RESIZE_HEIGHT);

    /**
     * 構造方法,在此指定模型檔案的下載地址
     * @param modelFileUrl 人臉檢測模型地址
     * @param basePath 檢測出的人臉小圖在硬碟上的存放地址
     */
    public DetectAndSaveService(String modelFileUrl, String basePath) {
        this.modelFileUrl = modelFileUrl;
        
        // 圖片保存在硬碟的位置,注意檔案名的固定前綴是當前的年月日時分秒
        this.basePath = basePath
                      + new SimpleDateFormat("yyyyMMddHHmmss").format(new Date())
                      + "-";
    }

    /**
     * 音頻采樣物件的初始化
     * @throws Exception
     */
    @Override
    public void init() throws Exception {
        // 下載模型檔案
        URL url = new URL(modelFileUrl);

        File file = Loader.cacheResource(url);

        // 模型檔案下載后的完整地址
        String classifierName = file.getAbsolutePath();

        // 根據模型檔案實體化分類器
        classifier = new CascadeClassifier(classifierName);

        if (classifier == null) {
            log.error("Error loading classifier file [{}]", classifierName);
            System.exit(1);
        }
    }

    @Override
    public Frame convert(Frame frame) {
        // 由幀轉為Mat
        grabbedImage = converter.convert(frame);

        // 灰度Mat,用于檢測
        if (null==grayImage) {
            grayImage = DetectService.buildGrayImage(grabbedImage);
        }

        String filePath = basePath + num.incrementAndGet();

        // 進行人臉識別,根據結果做處理得到預覽視窗顯示的幀
        return detectAndSave(classifier, converter, frame, grabbedImage, grayImage, filePath , size);
    }

    /**
     * 程式結束前,釋放人臉識別的資源
     */
    @Override
    public void releaseOutputResource() {
        if (null!=grabbedImage) {
            grabbedImage.release();
        }

        if (null!=grayImage) {
            grayImage.release();
        }

        if (null==classifier) {
            classifier.close();
        }
    }

    /**
     *
     * @param classifier 分類器
     * @param converter 轉換工具
     * @param rawFrame 原始幀
     * @param grabbedImage 原始圖片的Mat物件
     * @param grayImage 原始圖片對應的灰度圖片的Mat物件
     * @param basePath 圖片的基本路徑
     * @param size 訓練時要求的圖片大小
     * @return
     */
    static Frame detectAndSave(CascadeClassifier classifier,
                               OpenCVFrameConverter.ToMat converter,
                               Frame rawFrame,
                               Mat grabbedImage,
                               Mat grayImage,
                               String basePath,
                               Size size) {

        // 當前圖片轉為灰度圖片
        cvtColor(grabbedImage, grayImage, CV_BGR2GRAY);

        // 存放檢測結果的容器
        RectVector objects = new RectVector();

        // 開始檢測
        classifier.detectMultiScale(grayImage, objects);

        // 檢測結果總數
        long total = objects.size();

        // 如果沒有檢測到結果就提前回傳
        if (total<1) {
            return rawFrame;
        }

        // 假設現在是一個人對著攝像頭,因為此時檢測的結果如果大于1,顯然是檢測有問題
        if (total>1) {
            return rawFrame;
        }

        Mat faceMat;

        // 如果有檢測結果,就根據結果的資料構造矩形框,畫在原圖上
        // 前面的判斷確保了此時只有一個人臉
        Rect r = objects.get(0);

        // 從完整的灰度圖中取得一個矩形小圖的Mat物件
        faceMat = new Mat(grayImage, r);

        // 訓練時用的圖片尺寸是固定的,因此這里要調整大小
        resize(faceMat, faceMat, size);

        // 圖片的保存位置
        String imagePath = basePath + "." + Constants.IMG_TYPE;

        // 保存圖片到硬碟
        imwrite(imagePath, faceMat);

        // 人臉的位置資訊
        int x = r.x(), y = r.y(), w = r.width(), h = r.height();

        // 在人臉上畫矩形
        rectangle(grabbedImage, new Point(x, y), new Point(x + w, y + h), Scalar.RED, 1, CV_AA, 0);

        // 釋放檢測結果資源
        objects.close();

        // 將標注過的圖片轉為幀,回傳
        return converter.convert(grabbedImage);
    }
}
  • 上述代碼有幾處要注意:
  1. detectAndSave方法中,當前照片檢測出的人臉數如果大于1就提前回傳不做處理了,這是因為假定運行程式的時候,攝像頭前面只有一個人,所以如果檢測出超過一張人臉,就認為當前照片的檢測不準確,就不再處理當前照片了(實際使用中發現常有檢測失誤的情況,例如把一個矩形盒子檢測為人臉),這個提前回傳的邏輯,您可以根據自己的環境去調整
  2. imwrite方法可以將Mat以圖片的形式保存到硬碟
  3. 保存檔案到磁盤前呼叫了resize方法,將圖片調整為164*164大小,這是因為后面的訓練和檢測統一使用該尺寸
  • 現在核心代碼已經寫完,需要再寫一些代碼來使用DetectAndSaveService

編碼:運行框架

  • 《JavaCV的攝像頭實戰之一:基礎》創建的simple-grab-push工程中已經準備好了父類AbstractCameraApplication,所以本篇繼續使用該工程,創建子類實作那些抽象方法即可
  • 編碼前先回顧父類的基礎結構,如下圖,粗體是父類定義的各個方法,紅色塊都是需要子類來實作抽象方法,所以接下來,咱們以本地視窗預覽為目標實作這三個紅色方法即可:
    在這里插入圖片描述
  • 新建檔案PreviewCameraWithDetectAndSave.java,這是AbstractCameraApplication的子類,其代碼很簡單,接下來按上圖順序依次說明
  • 先定義CanvasFrame型別的成員變數previewCanvas,這是展示視頻幀的本地視窗:
protected CanvasFrame previewCanvas
  • 把前面創建的DetectService作為成員變數,后面檢測的時候會用到:
    /**
     * 檢測工具介面
     */
    private DetectService detectService;
  • PreviewCameraWithDetectAndSave的構造方法,接受DetectService的實體:
    /**
     * 不同的檢測工具,可以通過構造方法傳入
     * @param detectService
     */
    public PreviewCameraWithDetectAndSave(DetectService detectService) {
        this.detectService = detectService;
    }
  • 然后是初始化操作,可見是previewCanvas的實體化和引數設定:
    @Override
    protected void initOutput() throws Exception {
        previewCanvas = new CanvasFrame("攝像頭預覽,檢測人臉并保存在硬碟", CanvasFrame.getDefaultGamma() / grabber.getGamma());
        previewCanvas.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        previewCanvas.setAlwaysOnTop(true);

        // 檢測服務的初始化操作
        detectService.init();
    }
  • 接下來是output方法,定義了拿到每一幀視頻資料后做什么事情,這里呼叫了detectService.convert檢測人臉并保存圖片,然后在本地視窗顯示:
    @Override
    protected void output(Frame frame) {
        // 原始幀先交給檢測服務處理,這個處理包括物體檢測,再將檢測結果標注在原始圖片上,
        // 然后轉換為幀回傳
        Frame detectedFrame = detectService.convert(frame);
        // 預覽視窗上顯示的幀是標注了檢測結果的幀
        previewCanvas.showImage(detectedFrame);
    }
  • 最后是處理視頻的回圈結束后,程式退出前要做的事情,先關閉本地視窗,再釋放檢測服務的資源:
    @Override
    protected void releaseOutputResource() {
        if (null!= previewCanvas) {
            previewCanvas.dispose();
        }

        // 檢測工具也要釋放資源
        detectService.releaseOutputResource();
    }
  • 由于檢測有些耗時,所以兩幀之間的間隔時間要低于普通預覽:
    @Override
    protected int getInterval() {
        return super.getInterval()/8;
    }
  • 至此,功能已開發完成,再寫上main方法,在實體化DetectAndSaveService的時候注意入參有兩個,第一個是人臉檢測模型的下載地址,第二個是人臉照片保存在本地的位置,還有action方法的引數1000表示預覽持續時間是1000秒:
    public static void main(String[] args) {
        String modelFileUrl = "https://raw.github.com/opencv/opencv/master/data/haarcascades/haarcascade_frontalface_alt.xml";
        new PreviewCameraWithDetectAndSave(
                new DetectAndSaveService(
                        modelFileUrl, 
                        "E:\\temp\\202112\\18\\001\\man"))
                .action(1000);
    }

抓取第一個人的照片

  • 運行main方法,然后請群眾演員A登場,看著他一個人對著攝像頭,開始......搔首弄姿,各種光線明暗、各種角度、各種表情都用上吧,哎,不忍直視...

  • 由于開啟了預覽視窗,因此可以看到攝像頭拍攝的效果,出現紅框的矩形最終都會被保存為圖片,請注意調整角度和表情,群眾演員A好像很熱衷于自拍,玩得不亦樂乎,好吧,讓他放飛自我:
    在這里插入圖片描述

  • 檢測的圖片到了一定數量就可以結束了,我這里保存了259張,如下圖:
    在這里插入圖片描述

  • 對以上照片,建議是用肉眼檢查一遍所有照片,把不是人臉的全部洗掉,我發現了十多張不是人臉的照片,例如下面這張把臉上的一部分識別成了人臉,顯然是有問題的,這樣的照片就洗掉吧,不要用在訓練了:
    在這里插入圖片描述

  • 上述照片全部保存在E:\temp\202112\18\001\man目錄下

抓取第二個人的照片

  • 修改代碼,把main方法中存放圖片的目錄改成E:\temp\202112\18\001\woman,然后再次運行程式,請群眾演員B登場,懇求她像前一位群眾演員那樣一個人對著攝像頭,開始......搔首弄姿,各種光線明暗、各種角度、各種表情都用上吧

  • 于是,我們又順利拿到第二位群眾演員的大量人臉圖片,記得要肉眼觀察每一張照片,把不準確的都洗掉掉

  • 至此,借助前面撰寫的程式,我們輕松拿到了兩位群眾演員的大量人臉照片,其中A的照片保存在E:\temp\202112\18\001\man,B的照片保存在E:\temp\202112\18\001\woman
    在這里插入圖片描述

  • 至此,本篇的任務已經完成,下一篇會用這些照片進行訓練,為最終的識別做好準備;

歡迎關注博客園:程式員欣宸

學習路上,你不孤單,欣宸原創一路相伴...

轉載請註明出處,本文鏈接:https://www.uj5u.com/houduan/556114.html

標籤:其他

上一篇:C++面試八股文:用過std::set/std::map嗎?

下一篇:返回列表

標籤雲
其他(161716) Python(38255) JavaScript(25515) Java(18266) C(15238) 區塊鏈(8273) C#(7972) AI(7469) 爪哇(7425) MySQL(7270) html(6777) 基礎類(6313) sql(6102) 熊猫(6058) PHP(5875) 数组(5741) R(5409) Linux(5347) 反应(5209) 腳本語言(PerlPython)(5129) 非技術區(4971) Android(4607) 数据框(4311) css(4259) 节点.js(4032) C語言(3288) json(3245) 列表(3129) 扑(3119) C++語言(3117) 安卓(2998) 打字稿(2995) VBA(2789) Java相關(2746) 疑難問題(2699) 细绳(2522) 單片機工控(2479) iOS(2437) ASP.NET(2404) MongoDB(2323) 麻木的(2285) 正则表达式(2254) 字典(2211) 循环(2198) 迅速(2185) 擅长(2169) 镖(2155) .NET技术(1985) HtmlCss(1974) 功能(1967) Web開發(1951) C++(1942) python-3.x(1918) 弹簧靴(1913) xml(1889) PostgreSQL(1881) .NETCore(1863) 谷歌表格(1846) Unity3D(1843) for循环(1842)

熱門瀏覽
  • 【C++】Microsoft C++、C 和匯編程式檔案

    ......

    uj5u.com 2020-09-10 00:57:23 more
  • 例外宣告

    相比于斷言適用于排除邏輯上不可能存在的狀態,例外通常是用于邏輯上可能發生的錯誤。 例外宣告 Item 1:當函式不可能拋出例外或不能接受拋出例外時,使用noexcept 理由 如果不打算拋出例外的話,程式就會認為無法處理這種錯誤,并且應當盡早終止,如此可以有效地阻止例外的傳播與擴散。 示例 //不可 ......

    uj5u.com 2020-09-10 00:57:27 more
  • Codeforces 1400E Clear the Multiset(貪心 + 分治)

    鏈接:https://codeforces.com/problemset/problem/1400/E 來源:Codeforces 思路:給你一個陣列,現在你可以進行兩種操作,操作1:將一段沒有 0 的區間進行減一的操作,操作2:將 i 位置上的元素歸零。最終問:將這個陣列的全部元素歸零后操作的最少 ......

    uj5u.com 2020-09-10 00:57:30 more
  • UVA11610 【Reverse Prime】

    本人看到此題沒有翻譯,就附帶了一個自己的翻譯版本 思考 這一題,它的第一個要求是找出所有 $7$ 位反向質數及其質因數的個數。 我們應該需要質數篩篩選1~$10^{7}$的所有數,這里就不慢慢介紹了。但是,重讀題,我們突然發現反向質數都是 $7$ 位,而將它反過來后的數字卻是 $6$ 位數,這就說明 ......

    uj5u.com 2020-09-10 00:57:36 more
  • 統計區間素數數量

    1 #pragma GCC optimize(2) 2 #include <bits/stdc++.h> 3 using namespace std; 4 bool isprime[1000000010]; 5 vector<int> prime; 6 inline int getlist(int ......

    uj5u.com 2020-09-10 00:57:47 more
  • C/C++編程筆記:C++中的 const 變數詳解,教你正確認識const用法

    1、C中的const 1、區域const變數存放在堆疊區中,會分配記憶體(也就是說可以通過地址間接修改變數的值)。測驗代碼如下: 運行結果: 2、全域const變數存放在只讀資料段(不能通過地址修改,會發生寫入錯誤), 默認為外部聯編,可以給其他源檔案使用(需要用extern關鍵字修飾) 運行結果: ......

    uj5u.com 2020-09-10 00:58:04 more
  • 【C++犯錯記錄】VS2019 MFC添加資源不懂如何修改資源宏ID

    1. 首先在資源視圖中,添加資源 2. 點擊新添加的資源,復制自動生成的ID 3. 在解決方案資源管理器中找到Resource.h檔案,編輯,使用整個專案搜索和替換的方式快速替換 宏宣告 4. Ctrl+Shift+F 全域搜索,點擊查找全部,然后逐個替換 5. 為什么使用搜索替換而不使用屬性視窗直 ......

    uj5u.com 2020-09-10 00:59:11 more
  • 【C++犯錯記錄】VS2019 MFC不懂的批量添加資源

    1. 打開資源頭檔案Resource.h,在其中預先定義好宏 ID(不清楚其實ID值應該設定多少,可以先新建一個相同的資源項,再在這個資源的ID值的基礎上遞增即可) 2. 在資源視圖中選中專案資源,按F7編輯資源檔案,按 ID 型別 相對路徑的形式添加 資源。(別忘了先把檔案拷貝到專案中的res檔案 ......

    uj5u.com 2020-09-10 01:00:19 more
  • C/C++編程筆記:關于C++的參考型別,專供新手入門使用

    今天要講的是C++中我最喜歡的一個用法——參考,也叫別名。 參考就是給一個變數名取一個變數名,方便我們間接地使用這個變數。我們可以給一個變數創建N個參考,這N + 1個變數共享了同一塊記憶體區域。(參考型別的變數會占用記憶體空間,占用的記憶體空間的大小和指標型別的大小是相同的。雖然參考是一個物件的別名,但 ......

    uj5u.com 2020-09-10 01:00:22 more
  • 【C/C++編程筆記】從頭開始學習C ++:初學者完整指南

    眾所周知,C ++的學習曲線陡峭,但是花時間學習這種語言將為您的職業帶來奇跡,并使您與其他開發人員區分開。您會更輕松地學習新語言,形成真正的解決問題的技能,并在編程的基礎上打下堅實的基礎。 C ++將幫助您養成良好的編程習慣(即清晰一致的編碼風格,在撰寫代碼時注釋代碼,并限制類內部的可見性),并且由 ......

    uj5u.com 2020-09-10 01:00:41 more
最新发布
  • JavaCV人臉識別三部曲之一:視頻中的人臉保存為圖片

    ### 歡迎訪問我的GitHub > 這里分類和匯總了欣宸的全部原創(含配套原始碼):[https://github.com/zq2599/blog_demos](https://github.com/zq2599/blog_demos) ### 關于人臉識別 - 本文是《JavaCV人臉識別三部曲》 ......

    uj5u.com 2023-06-28 09:08:58 more
  • C++面試八股文:用過std::set/std::map嗎?

    某日二師兄參加XXX科技公司的C++工程師開發崗位第27面: > 面試官:用過`std::set/std::map`嗎? > > 二師兄:用過。 > > 面試官:能介紹一下二者嗎? > > 二師兄:`std::set`是一個有序的集合,其中的元素是唯一的,即每個元素只能出現一次。一般用于去重和自動排 ......

    uj5u.com 2023-06-28 09:08:47 more
  • 執行緒池

    # 執行緒池 ## 簡介 執行緒池是一種基于池化思想的執行緒管理工具。 ## 優點 - 降低資源消耗 - 提高回應速度 - 提高執行緒的可管理性 - 提供可擴展性 ## 使用場景 - 連接池 - 執行緒隔離 - 開發中需要創建5個以上的執行緒就可以考慮使用執行緒池 ## 執行緒池核心引數 | 引數名 | 型別 | ......

    uj5u.com 2023-06-28 09:08:44 more
  • Golang空結構體struct{}的作用?

    ### 介紹 在平時做專案得時候,經常會看到很多包里面定義了結構體。 e.g. 在`context`包里面`Context`介面中的`Done()`方法,`Done()`回傳一個是以空結構體定義資料的通道`chan struct{}`,那這里他是有什么特殊用意嗎?我們接下來分析`struct{}`的 ......

    uj5u.com 2023-06-28 09:08:40 more
  • PHP代碼加密實戰程序 Swoole Loader

    幫一個客戶處理一個小程式bug修復,前面不知道客戶是直接購買一個倒閉的公司產品,還是破解版本的。 其中一些核心工具類代碼進行了加密,通過排查就找到了 Swoole Compiler 今天演示下如何進行代碼加密: 大致步驟 如下: 注冊 Swoole Compiler 賬號 地址:Swoole-Com ......

    uj5u.com 2023-06-28 09:08:26 more
  • C++獲取當前毫秒數

    在 C++11 中,可以使用 <chrono> 頭檔案中的 std::chrono::system_clock 類來獲取當前時間戳。它提供了多種精度和解析度的時鐘型別,其中最常用的是系統時鐘。 以下是一個示例程式,演示如何使用 std::chrono::system_clock 類獲取當前毫秒數: ......

    uj5u.com 2023-06-28 09:08:16 more
  • [滲透測驗]—5.2 網路協議漏洞

    在這一章節中,我們將學習網路協議漏洞,如ARP欺騙、DNS欺騙等,并通過實體來講解如何利用這些漏洞進行網路滲透測驗。請放心,我們會盡量講得詳細、通俗易懂,并提供盡可能多的實體。 ### 5.1 網路協議漏洞 網路協議是計算機網路中設備之間通信的規則。然而,許多網路協議在設計時并未充分考慮安全性,因此 ......

    uj5u.com 2023-06-28 09:08:10 more
  • Python開發中自動化構建專案結構樣式

    摘要:在專案開發程序中,一個良好的專案結構對于團隊的協作和代碼的可維護性起著重要作用。通過使用自動生成專案結構文字樣式的工具。不僅節省了手動撰寫專案結構的麻煩,還確保了結構的一致性和準確性。 本文分享自華為云社區《【Python】自動化構建專案結構樣式》,作者: frica01。 引言 在使用 Py ......

    uj5u.com 2023-06-28 09:08:01 more
  • springboot~spring-javaformat插件惹的禍

    # 起因 我們在寫代碼時,有時間代碼過高,尤其是stream流的時間,可能有多個map,filter,sort組成,這樣我們更希望看到的是一種可讀性更好的風格 * 我的代碼是這樣的 ![](https://img2023.cnblogs.com/blog/118538/202306/118538-2 ......

    uj5u.com 2023-06-28 09:07:51 more
  • [滲透測驗]—6.3 無線網路滲透測驗工具

    在本章節中,我們將學習一些常用的無線網路滲透測驗工具,如Aircrack-ng、Reaver等。我們將盡量講解得詳細、通俗易懂,并提供盡可能多的實體。 ### 6.1 Aircrack-ng套件 Aircrack-ng是一個用于測驗無線網路安全的工具集,包括捕獲資料包、破解WEP和WPA/WPA2- ......

    uj5u.com 2023-06-28 08:40:47 more