人臉識別與檢測(保姆級教程--附帶源碼)

人臉識別與檢測(保姆級教程–附帶源碼)

項目背景

因項目需要招聘了一些日結工人,因此需要對工地現場的工人進行考勤管理,但工地只有海康攝像頭沒有專業考勤設備,因此需要基于視頻流開發人臉識別與檢測功能;因之前沒有做個做一塊所以再技術選型上面要具有,易用性、跨平臺、不用訓練,等等。因此我采用了face_recognition;

技術介紹

face_recognition 是一個流行的Python庫,專門用于執行面部識別任務。它是基于dlib的深度學習模型構建的,特別是基于深度卷積神經網絡的模型。

一、人臉錄入

要進行人臉識別與檢測,首先就是要將圖像中人像的面部編碼提取出來,并保存到數據庫中。

import os
import face_recognition
import mysql.connector
from mysql.connector import Error
import cv2
import numpy as np
import logginglogging.basicConfig(level=logging.INFO, format='%(asctime)s - %(levelname)s - %(message)s')model_path = "../ckpt/face/res10_300x300_ssd_iter_140000_fp16.caffemodel"
det = "../ckpt/face\deploy.prototxt"# 加載預訓練的人臉檢測模型
face_detector = cv2.dnn.readNetFromCaffe(det, model_path)# 數據庫配置
db_config = {'user': 'root','password': 'cqccc132645!!','host': '10.10.12.72','database': 'ai_platform','buffered': True
}def connect_to_database():try:connection = mysql.connector.connect(**db_config)if connection.is_connected():print("成功連接到MySQL數據庫")return connectionexcept Error as e:print(f"連接數據庫時出錯: {e}")return Nonedef check_table_structure(connection):try:cursor = connection.cursor()check_table_query = """SELECT COUNT(*) FROM information_schema.columns WHERE table_schema = 'ai_platform' AND table_name = 'faces' AND column_name IN ('id', 'name', 'embedding', 'image')"""cursor.execute(check_table_query)count = cursor.fetchone()[0]if count == 4:print("faces表結構正確")else:print("faces表結構不正確,請檢查數據庫")return Falsereturn Trueexcept Error as e:print(f"檢查表結構時出錯: {e}")return Falsedef insert_face(connection, name, face_embedding, face_image):try:cursor = connection.cursor()insert_query = "INSERT INTO faces (name, embedding, image) VALUES (%s, %s, %s)"cursor.execute(insert_query, (name, face_embedding.tobytes(), face_image))connection.commit()print(f"成功插入 {name} 的人臉數據")except Error as e:print(f"插入人臉數據時出錯: {e}")def crop_face(image, face_location):top, right, bottom, left = face_locationreturn image[top:bottom, left:right]def load_known_faces(connection):known_face_encodings = []known_face_names = []try:cursor = connection.cursor()query = "SELECT name, embedding FROM faces"cursor.execute(query)for (name, face_encoding) in cursor:known_face_encodings.append(np.frombuffer(face_encoding, dtype=np.float64))known_face_names.append(name)logging.info(f"從數據庫加載了 {len(known_face_names)} 個人臉")except Error as e:logging.error(f"加載人臉數據時出錯: {e}")finally:cursor.close()return known_face_encodings, known_face_namesdef register_faces(image_folder):connection = connect_to_database()if connection is None:returnif not check_table_structure(connection):connection.close()returnknown_face_encodings, known_face_names = load_known_faces(connection)for filename in os.listdir(image_folder):if filename.endswith((".jpg", ".jpeg", ".png")):image_path = os.path.join(image_folder, filename)name = os.path.splitext(filename)[0]  # 使用文件名作為人名# 使用 face_recognition 庫讀取圖像,它可以處理中文路徑image = face_recognition.load_image_file(image_path)rgb_image = cv2.cvtColor(image, cv2.COLOR_BGR2RGB)face_locations = face_recognition.face_locations(rgb_image)face_encodings = face_recognition.face_encodings(rgb_image, face_locations)if face_encodings:face_encoding = face_encodings[0]  # 假設每張圖片只有一張臉face_location = face_locations[0]# 裁剪人臉區域face_image = crop_face(image, face_location)# 將圖像編碼為JPEG格式_, buffer = cv2.imencode('.jpg', face_image)face_image_bytes = buffer.tobytes()face_distances = face_recognition.face_distance(known_face_encodings, face_encoding)best_match_index = np.argmin(face_distances)if face_distances[best_match_index] < 0.5:name2 = known_face_names[best_match_index]print(f"{name}{known_face_names[best_match_index]} 的距離為 {face_distances[best_match_index]}")print(f"{name} 已存在于數據庫中,{name2}")else:insert_face(connection, name, face_encoding, face_image_bytes)else:print(f"在 {filename} 中沒有檢測到人臉")connection.close()if __name__ == "__main__":image_folder = "../face/train/ces/"  # 替換為實際的圖片文件夾路徑register_faces(image_folder)

二、人臉檢測

除了前面講到的使用了face_recognition,我還使用到了res10_300x300_ssd_iter_140000_fp16.caffemodel 深度學習模型文件,用于面部檢測,它是一個使用ResNet作為基礎網絡,輸入尺寸為300x300像素,經過140,000次迭代訓練,并以半精度浮點數格式存儲的SSD對象檢測模型,deploy.prototxt配合使用。

整個流程就是,先加載模型文件,再數據庫中取出之前錄入的人臉編碼,隨后是從視頻流中取出視頻幀(每隔10幀進行一次處理)進行檢測與數據庫中人類編碼進行對比,如果是數據庫中的人臉就將名字打印出來并進行標識,反之著直接跳過,命名為Unknown。其次為了加速檢測效率,因此我采用了多線程的每一個視頻流就添加一個線程。

import cv2
import face_recognition
import mysql.connector
import numpy as np
from mysql.connector import Error
from threading import Thread
import time
import logging
from PIL import Image,ImageDraw,ImageFont# 配置日志
logging.basicConfig(level=logging.INFO, format='%(asctime)s - %(levelname)s - %(message)s')
# logging.basicConfig(level=logging.DEBUG, format='%(asctime)s - %(levelname)s - %(message)s')
# 數據庫配置
db_config = {'user': 'root','password': 'cqccc132645!!','host': '10.10.12.72','database': 'ai_platform','buffered': True
}# model_path = "D:\work\project\py\face_detection\ckpt\face\res10_300x300_ssd_iter_140000_fp16.caffemodel"
model_path = "../ckpt/face/res10_300x300_ssd_iter_140000_fp16.caffemodel"
det = "../ckpt/face\deploy.prototxt"# 加載預訓練的人臉檢測模型
face_detector = cv2.dnn.readNetFromCaffe(det, model_path)def connect_to_database():try:connection = mysql.connector.connect(**db_config)if connection.is_connected():logging.info("成功連接到MySQL數據庫")return connectionexcept Error as e:logging.error(f"連接數據庫時出錯: {e}")return Nonedef load_known_faces(connection):known_face_encodings = []known_face_names = []try:cursor = connection.cursor()query = "SELECT name, embedding FROM faces"cursor.execute(query)for (name, face_encoding) in cursor:known_face_encodings.append(np.frombuffer(face_encoding, dtype=np.float64))known_face_names.append(name)logging.info(f"從數據庫加載了 {len(known_face_names)} 個人臉")except Error as e:logging.error(f"加載人臉數據時出錯: {e}")finally:cursor.close()return known_face_encodings, known_face_namesdef detect_faces(frame, face_detector):start_time = time.time()height, width = frame.shape[:2]blob = cv2.dnn.blobFromImage(cv2.resize(frame, (300, 300)), 1.0, (300, 300), (104.0, 177.0, 123.0))face_detector.setInput(blob)detections = face_detector.forward()face_locations = []for i in range(detections.shape[2]):confidence = detections[0, 0, i, 2]if confidence > 0.8:box = detections[0, 0, i, 3:7] * np.array([width, height, width, height])(startX, startY, endX, endY) = box.astype("int")face_locations.append((startY, endX, endY, startX))end_time = time.time()logging.debug(f"Face detection time: {end_time - start_time:.4f} seconds")return face_locationsdef process_frames(frames_buffer, known_face_encodings, known_face_names, camera_id, face_detector):processed_frames = []faces_detected = Falsefor frame in frames_buffer:face_locations = detect_faces(frame, face_detector)if face_locations:face_encodings = face_recognition.face_encodings(frame, face_locations)for face_encoding in face_encodings:face_distances = face_recognition.face_distance(known_face_encodings, face_encoding)best_match_index = np.argmin(face_distances)if face_distances[best_match_index] < 0.6:name = known_face_names[best_match_index]else:name = "Unknown"logging.info(f"攝像頭 {camera_id} 檢測到 {name}")faces_detected = Truefor (top, right, bottom, left) in face_locations:cv2.rectangle(frame, (left, top), (right, bottom), (0, 0, 255), 2)cv2.rectangle(frame, (left, bottom - 35), (right, bottom), (0, 0, 255), cv2.FILLED)# 顯示中文# frame = cv2_img_add_text(frame, name, left + 6, bottom - 30, text_color=(255, 255, 255),#                          text_size=20)# font = cv2.FONT_HERSHEY_DUPLEX# cv2.putText(frame, name, (left + 6, bottom - 6), font, 0.5, (255, 255, 255), 1)processed_frames.append(frame)return processed_frames, faces_detecteddef video_stream_thread(stream_url, known_face_encodings, known_face_names):camera_id = stream_url.split('@')[1].split('/')[0]# camera_id = stream_url.split('_')[1]  # 提取IP地址作為攝像頭IDcap = cv2.VideoCapture(stream_url)if not cap.isOpened():logging.error(f"無法打開視頻流: {camera_id}")returnframe_count = 0start_time = time.time()faces_detected = Falseframes_buffer = []while True:ret, frame = cap.read()if not ret:logging.warning(f"無法從攝像頭 {camera_id} 獲取幀,嘗試重新連接...")cap.release()time.sleep(5)cap = cv2.VideoCapture(stream_url)if not cap.isOpened():logging.error(f"無法重新連接到攝像頭: {camera_id}")breakcontinueframe_count += 1frames_buffer.append(frame)if len(frames_buffer) == 10:  # 每10幀處理一次# processed_frames, faces_detected = process_frames(frames_buffer, known_face_encodings, known_face_names, camera_id)processed_frames, faces_detected = process_frames(frames_buffer, known_face_encodings, known_face_names,camera_id, face_detector)frames_buffer = []#     # 顯示最后一幀(如果需要的話)#     cv2.imshow(f'Stream: {camera_id}', processed_frames[-1])## if cv2.waitKey(1) & 0xFF == ord('q'):#     break# 每100幀計算和顯示FPSif frame_count % 100 == 0:end_time = time.time()fps = frame_count / (end_time - start_time)if faces_detected:logging.info(f"攝像頭 {camera_id}, FPS: {fps:.2f}, 檢測到人臉")else:logging.info(f"攝像頭 {camera_id}, FPS: {fps:.2f}, 未檢測到人臉")cap.release()cv2.destroyAllWindows()def cv2AddChineseText(img, text, position, textColor, textSize):if (isinstance(img, np.ndarray)):  # 判斷是否OpenCV圖片類型img = Image.fromarray(cv2.cvtColor(img, cv2.COLOR_BGR2RGB))draw = ImageDraw.Draw(img)fontStyle = ImageFont.truetype("C:/WINDOWS/FONTS/ARLRDBD.TTF", textSize, encoding="utf-8")# 繪制文本draw.text(position, text, textColor, font=fontStyle)# 轉換回OpenCV格式return cv2.cvtColor(np.asarray(img), cv2.COLOR_RGB2BGR)def cv2_img_add_text(img, text, left, top, text_color=(255, 255, 255), text_size=20):if isinstance(img, np.ndarray):  # 判斷是否OpenCV圖片類型img = Image.fromarray(cv2.cvtColor(img, cv2.COLOR_BGR2RGB))draw = ImageDraw.Draw(img)font_style = ImageFont.truetype(r"C:\ProgramData\kingsoft\office6\muifont\GBK\FZXBSK.TTF", text_size, encoding="utf-8")  # 請替換為你的中文字體路徑draw.text((left, top), text, text_color, font=font_style)return cv2.cvtColor(np.asarray(img), cv2.COLOR_RGB2BGR)def main():# 檢查CUDA是否可用,如果可用則使用GPUif cv2.cuda.getCudaEnabledDeviceCount() > 0:face_detector.setPreferableBackend(cv2.dnn.DNN_BACKEND_CUDA)face_detector.setPreferableTarget(cv2.dnn.DNN_TARGET_CUDA)logging.info("使用CUDA進行GPU加速")print("使用CUDA進行GPU加速")else:logging.warning("CUDA不可用,使用CPU進行處理")connection = connect_to_database()if connection is None:returnknown_face_encodings, known_face_names = load_known_faces(connection)connection.close()video_streams = ["rtsp://xxxxxxxxx/cam/realmonitor?channel=1&subtype=1",# 添加更多視頻流URL]threads = []for stream_url in video_streams:thread = Thread(target=video_stream_thread, args=(stream_url, known_face_encodings, known_face_names))thread.start()threads.append(thread)for thread in threads:thread.join()if __name__ == "__main__":main()

三、加速

我發現在python中opencv-python并不支持GPU加速僅支持CPU,如果需要GPU加速需求自己下載opencv源碼用cmake和VS2019進行編譯,可以參考這篇文章https://blog.csdn.net/yangyu0515/article/details/133794355

至于有沒有成功,復制這個代碼就知道了,如果cv2.cuda.getCudaEnabledDeviceCount()大于0就是成功了

   import cv2# 檢查CUDA是否可用,如果可用則使用GPUif cv2.cuda.getCudaEnabledDeviceCount() > 0:print("使用CUDA進行GPU加速")else:logging.warning("CUDA不可用,使用CPU進行處理")

opencv源碼 百度網盤地址:

鏈接:https://pan.baidu.com/s/1JzgFHmtnV6pScZLInoa6oA?pwd=u46d
提取碼:u46d

若有需求的可以聯系我
QQ: 2375255615

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/web/44033.shtml
繁體地址,請注明出處:http://hk.pswp.cn/web/44033.shtml
英文地址,請注明出處:http://en.pswp.cn/web/44033.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

Windows 虛擬機服務器項目部署

目錄 一、部署JDK下載JDK安裝JDK1.雙擊 jdk.exe 安裝程序2.點擊【下一步】3.默認安裝位置&#xff0c;點擊【下一步】4.等待提取安裝程序5.默認安裝位置&#xff0c;點擊【下一步】6.等待安裝7.安裝成功&#xff0c;點擊【關閉】 二、部署TomcatTomcat主要特點包括&#xff1a;…

奇怪的錯誤記錄

https://github.com/meta-llama/llama3/issues/80 讀模型沒問題&#xff0c;推理時出現&#xff1a; RuntimeError: “triu_tril_cuda_template” not implemented for ‘BFloat16’ ———————————————— 事發原因 我嘗試了解transformers的AutoProcessor時&a…

感應觸摸芯片集成為MCU,深度應用觸控按鍵技術的VR眼鏡

VR&#xff08;Virtual Reality&#xff09;即虛擬現實&#xff0c;簡稱VR&#xff0c;其具體內涵是綜合利用計算機圖形系統和各種現實及控制等接口設備&#xff0c;在計算機上生成的、可交互的三維環境中提供沉浸感覺的技術。它的工作原理是將左右眼圖像交互顯示在屏幕上的方式…

技術速遞|宣布為 .NET 升級助手提供第三方 API 和包映射支持

作者&#xff1a;Marco Goertz 排版&#xff1a;Alan Wang .NET 升級助手是一個 Visual Studio 擴展和命令行工具&#xff0c;可幫助您將應用從之前的 .NET 和 .NET Framework 升級到最新版本的 .NET。正如我們在之前的文章中所描述的那樣&#xff0c;它為升級 Microsoft 庫和框…

技術總結(1)——方向與成長思考

不知不覺已經發了30篇技術博客&#xff0c;本來最開始想的是回顧自己的技術生涯&#xff0c;怎樣做到失敗的生涯&#xff0c;但是后面發現&#xff0c;開始逐步寫技術博客&#xff0c;慢慢的開始沉浸里面這種回顧技術的感覺。做技術的人通常不喜歡研究市場&#xff0c;而做市場…

模型剪枝知識點整理

模型剪枝知識點整理 剪枝是深度學習模型優化的兩種常見技術&#xff0c;用于減少模型復雜度和提升推理速度&#xff0c;適用于資源受限的環境。 剪枝&#xff08;Pruning&#xff09; 剪枝是一種通過移除模型中不重要或冗余的參數來減少模型大小和計算量的方法。剪枝通常分為…

編程是學什么:探索編程世界的四大核心領域

編程是學什么&#xff1a;探索編程世界的四大核心領域 在數字化時代的浪潮中&#xff0c;編程已成為一項重要的技能。但很多人對于編程的學習內容仍然感到困惑&#xff0c;那么&#xff0c;編程究竟是學什么呢&#xff1f;本文將從四個方面、五個方面、六個方面和七個方面&…

探索TASKCTL和 DataStage 的ETL任務調度協同

在復雜多變的企業環境中&#xff0c;高效、準確的數據處理是支撐業務決策與運營的核心。本文將深入探討任務調度平臺TASKCTL與ETL工具DataStage的深度融合&#xff0c;通過詳盡的代碼示例、結合細節以及實際案例的具體描述&#xff0c;展示這兩個工具如何攜手打造企業數據處理生…

Xcode構建設置自定義:打造個性化的編譯環境

標題&#xff1a;Xcode構建設置自定義&#xff1a;打造個性化的編譯環境 在軟件開發過程中&#xff0c;根據不同的開發階段和需求&#xff0c;經常需要調整編譯設置以優化構建過程。Xcode作為蘋果官方的集成開發環境&#xff08;IDE&#xff09;&#xff0c;提供了豐富的自定義…

簡述 Java 內存模型(JMM),特別是堆與棧的區別?

Java內存模型&#xff08;JMM&#xff09;是Java平臺定義的一種多線程之間的通信規范&#xff0c;它確保了在不同的線程之間能夠正確地共享和協調對內存的訪問。 JMM的關鍵目標是解決并發編程中的可見性、原子性和有序性問題。 簡單來說&#xff0c;它規定了如何在硬件內存、…

【C語言】 —— 預處理詳解(下)

【C語言】 —— 預處理詳解&#xff08;下&#xff09; 前言七、# 和 \##7.1 # 運算符7.2 ## 運算符 八、命名約定九、# u n d e f undef undef十、命令行定義十一、條件編譯11.1、單分支的條件編譯11.2、多分支的條件編譯11.3、判斷是否被定義11.4、嵌套指令 十二、頭文件的包…

淺層神經網絡示例

輸出層采用sigmoid激活&#xff0c;隱藏層采用tanh激活 import h5py import numpy as npfrom project_02.code.planar_utils import load_planar_dataset, plot_decision_boundarydef sigmoid(z):s 1 / (1 np.exp(-z))return sdef init_parameters(n_x, n_h, n_y):"&qu…

如何在 Objective-C 中實現多態性,并且它與其他面向對象編程語言的多態性實現有何差異?

在Objective-C中&#xff0c;多態性可以通過使用父類的指針來調用子類的方法來實現。具體來說&#xff0c;可以定義一個父類的指針&#xff0c;然后將子類的實例賦值給這個指針。這樣&#xff0c;即使使用父類的指針來調用方法&#xff0c;實際上會調用子類的方法。 需要注意的…

Day1每日編程題日記:數字統計、兩個數組的交集、點擊消除

前言&#xff1a;該篇用于記錄自看。曾回看昨天的做題代碼&#xff0c;竟然會覺得陌生&#xff0c;這竟然是我寫的&#xff0c;細細讀了一下&#xff0c;原來我當時是這么想的。因此我覺得記代碼沒有實際用處&#xff0c;重點是領悟了思想&#xff0c;這樣子代碼就在心中&#…

HashMap----源碼解讀

源碼分析&#xff1a; public class HashMap<K,V> extends AbstractMap<K,V>implements Map<K,V>, Cloneable, Serializable 在類的開頭聲明了幾個常量&#xff0c;以下是較為重要的&#xff1a; /*** 定義初始容量大小為16*/ static final int DEFAULT_I…

探索【Python面向對象】編程:新時代的高級編程范式詳解

目錄 1. 面向對象編程概念&#xff08;OOP&#xff09; 1.1 什么是類和對象&#xff1f; 1.2 類的定義 1.3 類和對象的關系 1.4 小李的理解 2. 抽象 2.1 抽象的概念 2.2 抽象類和方法 2.3 小李的理解 3. 類和實例 3.1 類的定義和實例化 3.2 類的屬性和方法 3.3 小…

如何使用Python在企業微信中發送測試結果?操作看這里!

在日常的自動化測試工作中&#xff0c;一般會需要把測試結果同步到工作群里&#xff0c;方便信息同步。那么我們今天就使用企業微信和Pythonrequests庫來演示一下具體如何操作吧&#xff01; 01 準備 開始之前&#xff0c;我們應該確保已經安裝了python環境&#xff0c;并且要…

DNS知識點

??打牌 : da pai ge的個人主頁 ???個人專欄 : da pai ge的博客專欄 ??寶劍鋒從磨礪出,梅花香自苦寒來 ? 目錄 一、DNS概念 二 hosts 文件 三 DNS優缺點 三 客戶端域名解析順序(優先級)…

8.9分王者“水刊”!1區IEEE-Trans,國人主編坐鎮!發文量2倍增長,擴刊趨勢明顯!

關注GZH【歐亞科睿學術】&#xff0c;第一時間了解最新期刊動態&#xff01; 本期&#xff0c;小編給大家推薦的是一本IEEE旗下王者“水刊”。該期刊目前處于擴刊狀態&#xff0c;接收跨學科領域&#xff0c;領域認可度高&#xff0c;還可選擇非OA模式無需版面費&#xff0c;是…

PPTP、L2TP、IPSec、IPS 有什么區別?

隨著互聯網的發展&#xff0c;保護網絡通信的安全越來越重要。PPTP、L2TP、IPSec、IPS是常見的網絡安全協議和技術&#xff0c;在保護網絡通信安全方面發揮著不同的作用和特點。下面介紹PPTP、L2TP、IPSec、IPS之間的區別。 點對點隧道協議&#xff08;PPTP&#xff09;是一種用…