### 歡迎訪問我的GitHub > 這裡分類和彙總了欣宸的全部原創(含配套源碼):[https://github.com/zq2599/blog_demos](https://github.com/zq2599/blog_demos) ### 本篇概覽 - 本文是《JavaCV的攝像頭實戰》系列的 ...
歡迎訪問我的GitHub
這裡分類和彙總了欣宸的全部原創(含配套源碼):https://github.com/zq2599/blog_demos
本篇概覽
-
本文是《JavaCV的攝像頭實戰》系列的第十三篇,前文《JavaCV的攝像頭實戰之十二:性別檢測》中,藉助訓練好的捲積神經網路模型開發出了識別性別的應用,今天在前文基礎上做少量改動,實現年齡識別的功能,效果如下圖:
-
應用主要功能如下圖所示:
-
如果您看過《JavaCV的攝像頭實戰》系列的其他文章,就會發現上圖中只有藍色部分是新增內容,其餘的步驟都是固定套路,《JavaCV的攝像頭實戰》系列的每一個應用玩的都是相同套路:別看步驟挺多,其實都是同一個流程
關於性別和年齡檢測
- 使用捲積神經網路推理性別和年齡的更多技術細節,這裡有更詳細的說明:
https://talhassner.github.io/home/publication/2015_CVPR - 本篇會使用已訓練好的Caffe 模型,訓練該模型的數據來自Flickr相冊,通過從 iPhone5(或更高版本)智能手機設備自動上傳組裝而成,並由其作者根據知識共用 (CC) 許可向公眾發佈,共有26580張照片,涉及2284人,這些人的年齡一共被標識成八組:(0-2、4-6、8-13、15-20、25-32、38-43、48-53、60 -)
- 關於數據源的更多詳細,請參考:https://talhassner.github.io/home/projects/Adience/Adience-data.html
- 論文地址:https://talhassner.github.io/home/projects/cnn_agegender/CVPR2015_CNN_AgeGenderEstimation.pdf
源碼下載
- 《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工程下:
準備:文件下載
- 本次實戰需要三個文件:
- 人臉檢測的模型文件:https://raw.github.com/opencv/opencv/master/data/haarcascades/haarcascade_frontalface_alt.xml
- 年齡識別的配置文件:https://raw.githubusercontent.com/GilLevi/AgeGenderDeepLearning/master/age_net_definitions/deploy.prototxt
- 年齡識別的模型文件:https://raw.githubusercontent.com/GilLevi/AgeGenderDeepLearning/master/models/age_net.caffemodel
- 我已將上述文件打包上傳到CSDN,您也可以在CSDN下載(無需積分):
https://download.csdn.net/download/boling_cavalry/70730586
準備:代碼介面簡介
- 編碼前,先把涉及到的所有java文件說明一下:
- AbstractCameraApplication.java:主程式的抽象類,這裡面定義了打開攝像頭、抓取每一幀、處理每一幀的基本框架,避免每個應用都把這些事情重覆做一遍
- PreviewCameraWithGenderAge.java:主程式,是AbstractCameraApplication的實現類,本次實戰的核心功能人臉檢測和年齡檢測,都委托給它的成員變數detectService去完成
- DetectService.java:檢測服務的介面,裡面定義了幾個重要的api,例如初始化、處理每一幀、釋放資源等
- AgeDetectService.java:前文GenderDetectService的子類,僅僅是處理推理結果的邏輯與前文的性別識別略有不同,其餘功能完全繼承自性別識別
- 以上代碼,咱們已經在前文寫過一次了,今天當然不需要重覆再做一次,今天是在上述代碼基礎上做兩處小幅度修改,接下來就開始吧
改動一:主程式(PreviewCameraWithGenderAge.java)
- 捲積神經網路所需的配置和模型文件,是在主程式的main方法內設置的,上一章是性別檢測,這裡替換為年齡檢測的文件,如下所示,請您將路徑換為自己電腦上的文件路徑:
public static void main(String[] args) {
String base = "E:\\temp\\202112\\25\\opencv\\";
DetectService detectService = new AgeDetectService(
base + "haarcascade_frontalface_alt.xml",
base + "age\\deploy.prototxt",
base + "age\\age_net.caffemodel");
new PreviewCameraWithGenderAge(detectService).action(1000);
}
改動二:檢測服務實現(GenderDetectService的子類)
- 前文《性別檢測》的核心功能都集中在GenderDetectService.java中,今天要做的年齡檢測,除了推理結果的處理邏輯略有不同,其餘功能與《性別檢測》完全一致
- 所以,實現年齡檢測的最簡單方法就是寫一個子類繼承GenderDetectService,這個子類中只有神經網路推理結果的處理邏輯,完整代碼如下,註釋中已經有了詳細說明,就不多贅述了:
package com.bolingcavalry.grabpush.extend;
import lombok.extern.slf4j.Slf4j;
import org.bytedeco.javacpp.DoublePointer;
import org.bytedeco.opencv.opencv_core.Mat;
import org.bytedeco.opencv.opencv_core.Point;
import static org.bytedeco.opencv.global.opencv_core.minMaxLoc;
/**
* @author willzhao
* @version 1.0
* @description 檢測年齡的服務
* @date 2021/12/3 8:09
*/
@Slf4j
public class AgeDetectService extends GenderDetectService {
/**
* 設置訓練模型時劃分的年齡段,所以推理結果也是這樣的年齡段
*/
private static final String[] AGES = new String[]{"0-2", "4-6", "8-13", "15-20", "25-32", "38-43", "48-53", "60-"};
/**
* 構造方法,在此指定proto和模型文件的下載地址
*
* @param classifierModelFilePath
* @param cnnProtoFilePath
* @param cnnModelFilePath
*/
public AgeDetectService(String classifierModelFilePath, String cnnProtoFilePath, String cnnModelFilePath) {
super(classifierModelFilePath, cnnProtoFilePath, cnnModelFilePath);
}
@Override
protected String getDescriptionFromPredictResult(Mat prob) {
DoublePointer pointer = new DoublePointer(new double[1]);
Point max = new Point();
// 把prob理解為一個數組,
// 第一個元素是"0-2"的置信度
// 第二個元素是"4-6"的置信度
// 第三個元素是"8-13"的置信度
// 第四個元素是"15-20"的置信度
// ...
// 第八個元素是"60-"的置信度
// minMaxLoc方法幫忙我們找出了置信度最高的元素,max是元素位置,pointer是這個元素的置信度
minMaxLoc(prob, null, pointer, null, max, null);
// 如果置信度太低,那就是"難以置信",就返回空字元串
if (pointer.get()<0.6d) {
return "";
} else {
// 如果置信度可信,就返回該元素對應的年齡範圍
return AGES[max.x()];
}
}
}
- 至此,編碼完成,按套路出牌讓咱們省下不少時間,接下來開始驗證
驗證
- 確保攝像頭工作正常,運行PreviewCameraWithGenderAge類的main方法(再次提醒,main方法中文件的位置,註意是年齡檢測的模型文件,不是性別檢測的)
- 天氣很冷,為了領到免費盒飯,群眾演員早就等得不耐煩了,讓他站在攝像頭前,如下圖,年齡識別成功,且實時展示:
- 至此,本地視窗預覽集成人臉檢測和年齡檢測的功能就完成了,得益於JavaCV的強大,整個過程是如此的輕鬆愉快,接下來請繼續關註欣宸原創,《JavaCV的攝像頭實戰》系列還會呈現更多豐富的應用;
關於性別+年齡識別
- 如果您關註過網上關於性別和年齡識別相關的技術文章,您會發現通常這些文章會將兩種識別集成在一起講,並且代碼的效果也是繼承了兩種識別的,如下圖:
- 也行您會有疑問:欣宸為何不把兩種識別放在一篇文章和一個demo中,這樣內容更完整demo也更強大?
- 之所以分文兩篇,是因為年齡和性別識別的套路比較接近,如果在一篇文中講完,無非是多寫幾行代碼多打幾行字,不會對技術帶來提升,那還不如每篇只聚焦一個功能,把初始化、使用、資源釋放等技術點說清楚,至於單獨用還是組合用,留給聰明的讀者按自己的需求去自由組合即可