程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式師世界 >> 編程語言 >  >> 更多編程語言 >> Python

基於OpenCv的人臉識別(Python完整代碼)

編輯:Python

大家好,又見面了,我是你們的朋友全棧君。

實驗環境:python 3.6 + opencv-python 3.4.14.51 建議使用 anaconda配置相同環境

背景

人臉識別步驟

圖1:人臉識別流程圖

人臉采集

采集人臉圖片的方法多種多樣,可以直接從網上下載數據集,可以從視頻中提取圖片,還可以從攝像頭實時的采集圖片。

人臉檢測方法

人臉檢測在實際中主要用於人臉識別的預處理,即在圖像中准確標定出人臉的位置和大小。人臉圖像中包含的模式特征十分豐富,如直方圖特征、顏色特征、模板特征、結構特征及Haar特征等。人臉檢測就是把這其中有用的信息挑出來,並利用這些特征實現人臉檢測。

人臉圖像預處理

對於人臉的圖像預處理是基於人臉檢測結果,對圖像進行處理並最終服務於特征提取的過程。系統獲取的原始圖像由於受到各種條件的限制和隨機 干擾,往往不能直接使用,必須在圖像處理的早期階段對它進行灰度校正、噪聲過濾等圖像預處理。對於人臉圖像而言,其預處理過程主要包括人臉圖像的光線補 償、灰度變換、直方圖均衡化、歸一化、幾何校正、濾波以及銳化等。

人臉特征提取

人臉識別系統可使用的特征通常分為視覺特征、像素統計特征、人臉圖像變換系數特征、人臉圖像代數 特征等。人臉特征提取就是針對人臉的某些特征進行的。人臉特征提取,也稱人臉表征,它是對人臉進行特征建模的過程。人臉特征提取的方法歸納起來分為兩大 類:一種是基於知識的表征方法;另外一種是基於代數特征或統計學習的表征方法。

匹配與識別

提取的人臉圖像的特征數據與數據庫中存儲的特征模板進行搜索匹配,通過設定一個阈值,當相似度超過這一阈值,則把匹配得到的結果輸 出。人臉識別就是將待識別的人臉特征與已得到的人臉特征模板進行比較,根據相似程度對人臉的身份信息進行判斷。這一過程又分為兩類:一類是確認,是一對一 進行圖像比較的過程,另一類是辨認,是一對多進行圖像匹配對比的過程。

關於OpenCv

Opencv是一個開源的的跨平台計算機視覺庫,內部實現了圖像處理和計算機視覺方面的很多通用算法,對於python而言,在引用opencv庫的時候需要寫為import cv2。其中,cv2是opencv的C++命名空間名稱,使用它來表示調用的是C++開發的opencv的接口

目前人臉識別有很多較為成熟的方法,這裡調用OpenCv庫,而OpenCV又提供了三種人臉識別方法,分別是LBPH方法、EigenFishfaces方法、Fisherfaces方法。本文采用的是LBPH(Local Binary Patterns Histogram,局部二值模式直方圖)方法。在OpenCV中,可以用函數cv2.face.LBPHFaceRecognizer_create()生成LBPH識別器實例模型,然後應用cv2.face_FaceRecognizer.train()函數完成訓練,最後用cv2.face_FaceRecognizer.predict()函數完成人臉識別。

CascadeClassifier,是Opencv中做人臉檢測的時候的一個級聯分類器。並且既可以使用Haar,也可以使用LBP特征。其中Haar特征是一種反映圖像的灰度變化的,像素分模塊求差值的一種特征。它分為三類:邊緣特征、線性特征、中心特征和對角線特征。

程序設計

人臉識別算法:

圖2:人臉識別模塊圖

1.准備工作

圖3:准備階段

首先讀取config文件,文件中第一行代表當前已經儲存的人名個數,接下來每一行是二元組(id,name)即標簽和對應的人名 讀取結果存到以下兩個全局變量中。

id_dict = {
} # 字典裡存的是id——name鍵值對
Total_face_num = 999 # 已經被識別有用戶名的人臉個數,

def init(): # 將config文件內的信息讀入到字典中

加載人臉檢測分類器Haar,並准備好識別方法LBPH方法

# 加載OpenCV人臉檢測分類器Haar
face_cascade = cv2.CascadeClassifier("haarcascade_frontalface_default.xml")
# 准備好識別方法LBPH方法
recognizer = cv2.face.LBPHFaceRecognizer_create()

然後打開標號為0的攝像頭

camera = cv2.VideoCapture(0) # 攝像頭
success, img = camera.read() # 從攝像頭讀取照片

2.錄入新面容

圖4:錄入人臉

2.1采集面容

創建文件夾data用於儲存本次從攝像頭采集到的照片,每次調用前先清空這個目錄。

然後是一個循環,循環次數為需要采集的樣本數,攝像頭拍攝取樣的數量,越多效果越好,但獲取以及訓練的越慢。

循環內調用camera.read()返回值賦給全局變量success,和img 用於在GUI中實時顯示。

然後調用cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)用於將采集到的圖片轉為灰度圖片減少計算量。

然後利用加載好的人臉分類器將每一幀攝像頭記錄的數據帶入OpenCv中,讓Classifier判斷人臉。

 # 其中gray為要檢測的灰度圖像,1.3為每次圖像尺寸減小的比例,5為minNeighbors
faces = face_cascade.detectMultiScale(gray, 1.3, 5)

faces為在img圖像中檢測到的人臉,然後利用cv2.rectangle在人臉一圈畫個矩形。並把含有人臉的區域儲存進入data文件夾 注意這裡寫入時,每個圖片的標簽時Total_face_num即當前共有多少個可識別用戶(在錄入之前加一),亦即當前用戶的編號

 cv2.rectangle(img, (x, y), (x + w, y + w), (255, 0, 0))
cv2.imwrite("./data/User." + str(T) + '.' + str(sample_num) + '.jpg', gray[y:y + h, x:x + w])

然後在循環末尾最後打印一個進度條,用於提示采集圖像的進度 主要原理就是每次輸出不換行並且將光標移動到當前行的開頭,輸出內容根據進度不斷變化即可,同時在控件的提示框也輸出進度信息

print("\r" + "%{:.1f}".format(sample_num / pictur_num * 100) + "=" * l + "->" + "_" * r, end="")
var.set("%{:.1f}".format(sample_num / pictur_num * 100)) # 控件可視化進度信息
window.update() # 刷新控件以實時顯示進度

2.2訓練識別器

讀取data文件夾,讀取照片內的信息,得到兩個數組,一個faces存的是所有臉部信息、一個ids存的是faces內每一個臉部對應的標簽,然後將這兩個數組傳給 recog.train用於訓練

 # 訓練模型 #將輸入的所有圖片轉成四維數組
recog.train(faces, np.array(ids))

訓練完畢後保存訓練得到的識別器到.yml文件中,文件名為人臉編號+.yml

 recog.save(str(Total_face_num) + ".yml")

2.3修改配置文件

每一次訓練結束都要修改配置文件,具體要修改的地方是第一行和最後一行。 第一行有一個整數代表當前系統已經錄入的人臉的總數,每次修改都加一。這裡修改文件的方式是先讀入內存,然後修改內存中的數據,最後寫回文件。

 f = open('config.txt', 'r+')
flist = f.readlines()
flist[0] = str(int(flist[0]) + 1) + " \n"
f.close()
f = open('config.txt', 'w+')
f.writelines(flist)
f.close()

還要在最後一行加入一個二元組用以標識用戶。 格式為:標簽+空格+用戶名+空格,用戶名默認為Userx(其中x標識用戶編號)

f.write(str(T) + " User" + str(T) + " \n")

3.人臉識別(刷臉)

圖5:刷臉流程圖

由於這裡采用多個.yml文件來儲存識別器(實際操作時儲存在一個文件中識別出錯所以采用這種方式),所以在識別時需要遍歷所有的.yml文件,如果每一個都不能識別才得出無法識別的結果,相反只要有一個可以識別當前對象就返回可以識別的結果。而對於每一個文件都識別十次人臉,若成功五次以上則表示最終結果為可以識別,否則表示當前文件無法識別這個人臉。

識別過程中在GUI的控件中實時顯示拍攝到的內容,並在人臉周圍畫一個矩形框,並根據識別器返回的結果實時顯示在矩形框附近。

idnum, confidence = recognizer.predict(gray[y:y + h, x:x + w])
# 加載一個字體用於輸出識別對象的信息
font = cv2.FONT_HERSHEY_SIMPLEX
# 輸出檢驗結果以及用戶名
cv2.putText(img, str(user_name), (x + 5, y - 5), font, 1, (0, 0, 255), 1)
cv2.putText(img, str(confidence), (x + 5, y + h - 5), font, 1, (0, 0, 0), 1)

多線程:

程序的兩個功能之間可以獨立運行,就需要采用多線程的方法,但當遇到臨界資源的使用時,多個進程/線程之間就要互斥的訪問以免出錯,本程序中具體的設計方法: 本程序采用多線程的方法實現並行。 程序的三個按鈕對應著三個功能,分別是錄入人臉、人臉檢測、退出程序。 由於程序中的用戶界面是利用python中的tkinter庫做的,其按鈕的響應函數用command指出,所以這裡在每個command跳轉到的函數中設置多線程,每敲擊一次就用threading.Thread創建一個新的線程,然後在新的線程的處理函數target中實現按鈕原本對應的功能。

p = threading.Thread(target=f_scan_face_thread)

在涉及到攝像頭的訪問時,線程之間需要互斥的訪問,所以設置了一個全局的變量system_state_lock 來表示當前系統的狀態,用以實現帶有優先級的互斥鎖的功能。 鎖狀態為0表示攝像頭未被使用,1表示正在刷臉,2表示正在錄入新面容。 程序在實際執行的過程中如果狀態為0,則無論是刷臉還是錄入都能順利執行,如果狀態為1表示正在刷臉,如果此時敲擊刷臉按鈕則,系統會提示正在刷臉並拒絕新的請求,如果此時敲擊錄入面容按鈕,由於錄入面容優先級比刷臉高,所以原刷臉線程會被阻塞,

global system_state_lock
while system_state_lock == 2: # 如果正在錄入新面孔就阻塞
pass

新的錄入面容進程開始執行並修改系統狀態為2,錄入完成後狀態變為原狀態,被阻塞的刷臉進程繼續執行,錄入人臉線程剛執行完錄入階段現在正在訓練,此時有兩個線程並行,以此來保證訓練數據的同時不影響系統的使用。

對於退出的功能,直接在函數內調用exit(),但是python的線程會默認等待子線程全部結束再退出,所以用p.setDaemon(True)將線程設置為守護線程,這樣在主線程退出之後其它線程也都退出從而實現退出整個程序的功能。

GUI設計:

程序采用python中的tkinter庫做可視化,優點是占用資源小、輕量化、方便。

  • 首先創建一個窗口命名為window然後設置其大小和標題等屬性。
  • 然後在界面上設定一個綠底的標簽,類似於一個提示窗口的作用
  • 然後分別創建三個按鈕,並設置響應函數和提示字符,放置在window內部。
  • 然後設置一個label類型的控件用於動態的展示攝像頭的內容(將攝像頭顯示嵌入到控件中)。具體方法:創建video_loop()函數,在函數內訪問全局的變量img,img是從攝像頭讀取到的圖像數據。然後把img顯示在label內。 使用window.after方法,在給定時間後調用函數一次,實現固定時間刷新控件,從而達到實時顯示攝像頭畫面在GUI中的效果。
window.after(1, video_loop)
# 這句的意思是一秒以後執行video_loop函數
# 因為這一句是寫在video_loop函數中的所以每過一秒函數執行一次。

運行測試

說明

測試環境:python 3.6 + opencv-python 3.4.14.51 需要的包:

圖6:需要的包

錄入人臉

從數據集錄入

從攝像頭錄入

人臉識別

代碼實現:

# 實驗環境:python 3.6 + opencv-python 3.4.14.51
import cv2
import numpy as np
import os
import shutil
import threading
import tkinter as tk
from PIL import Image, ImageTk
# 首先讀取config文件,第一行代表當前已經儲存的人名個數,接下來每一行是(id,name)標簽和對應的人名
id_dict = {
} # 字典裡存的是id——name鍵值對
Total_face_num = 999 # 已經被識別有用戶名的人臉個數,
def init(): # 將config文件內的信息讀入到字典中
f = open('config.txt')
global Total_face_num
Total_face_num = int(f.readline())
for i in range(int(Total_face_num)):
line = f.readline()
id_name = line.split(' ')
id_dict[int(id_name[0])] = id_name[1]
f.close()
init()
# 加載OpenCV人臉檢測分類器Haar
face_cascade = cv2.CascadeClassifier("haarcascade_frontalface_default.xml")
# 准備好識別方法LBPH方法
recognizer = cv2.face.LBPHFaceRecognizer_create()
# 打開標號為0的攝像頭
camera = cv2.VideoCapture(0) # 攝像頭
success, img = camera.read() # 從攝像頭讀取照片
W_size = 0.1 * camera.get(3)
H_size = 0.1 * camera.get(4)
system_state_lock = 0 # 標志系統狀態的量 0表示無子線程在運行 1表示正在刷臉 2表示正在錄入新面孔。
# 相當於mutex鎖,用於線程同步
''' ============================================================================================ 以上是初始化 ============================================================================================ '''
def Get_new_face():
print("正在從攝像頭錄入新人臉信息 \n")
# 存在目錄data就清空,不存在就創建,確保最後存在空的data目錄
filepath = "data"
if not os.path.exists(filepath):
os.mkdir(filepath)
else:
shutil.rmtree(filepath)
os.mkdir(filepath)
sample_num = 0 # 已經獲得的樣本數
while True: # 從攝像頭讀取圖片
global success
global img # 因為要顯示在可視化的控件內,所以要用全局的
success, img = camera.read()
# 轉為灰度圖片
if success is True:
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
else:
break
# 檢測人臉,將每一幀攝像頭記錄的數據帶入OpenCv中,讓Classifier判斷人臉
# 其中gray為要檢測的灰度圖像,1.3為每次圖像尺寸減小的比例,5為minNeighbors
face_detector = face_cascade
faces = face_detector.detectMultiScale(gray, 1.3, 5)
# 框選人臉,for循環保證一個能檢測的實時動態視頻流
for (x, y, w, h) in faces:
# xy為左上角的坐標,w為寬,h為高,用rectangle為人臉標記畫框
cv2.rectangle(img, (x, y), (x + w, y + w), (255, 0, 0))
# 樣本數加1
sample_num += 1
# 保存圖像,把灰度圖片看成二維數組來檢測人臉區域,這裡是保存在data緩沖文件夾內
T = Total_face_num
cv2.imwrite("./data/User." + str(T) + '.' + str(sample_num) + '.jpg', gray[y:y + h, x:x + w])
pictur_num = 30 # 表示攝像頭拍攝取樣的數量,越多效果越好,但獲取以及訓練的越慢
cv2.waitKey(1)
if sample_num > pictur_num:
break
else: # 控制台內輸出進度條
l = int(sample_num / pictur_num * 50)
r = int((pictur_num - sample_num) / pictur_num * 50)
print("\r" + "%{:.1f}".format(sample_num / pictur_num * 100) + "=" * l + "->" + "_" * r, end="")
var.set("%{:.1f}".format(sample_num / pictur_num * 100)) # 控件可視化進度信息
# tk.Tk().update()
window.update() # 刷新控件以實時顯示進度
def Train_new_face():
print("\n正在訓練")
# cv2.destroyAllWindows()
path = 'data'
# 初始化識別的方法
recog = cv2.face.LBPHFaceRecognizer_create()
# 調用函數並將數據喂給識別器訓練
faces, ids = get_images_and_labels(path)
print('本次用於訓練的識別碼為:') # 調試信息
print(ids) # 輸出識別碼
# 訓練模型 #將輸入的所有圖片轉成四維數組
recog.train(faces, np.array(ids))
# 保存模型
yml = str(Total_face_num) + ".yml"
rec_f = open(yml, "w+")
rec_f.close()
recog.save(yml)
# recog.save('aaa.yml')
# 創建一個函數,用於從數據集文件夾中獲取訓練圖片,並獲取id
# 注意圖片的命名格式為User.id.sampleNum
def get_images_and_labels(path):
image_paths = [os.path.join(path, f) for f in os.listdir(path)]
# 新建連個list用於存放
face_samples = []
ids = []
# 遍歷圖片路徑,導入圖片和id添加到list中
for image_path in image_paths:
# 通過圖片路徑將其轉換為灰度圖片
img = Image.open(image_path).convert('L')
# 將圖片轉化為數組
img_np = np.array(img, 'uint8')
if os.path.split(image_path)[-1].split(".")[-1] != 'jpg':
continue
# 為了獲取id,將圖片和路徑分裂並獲取
id = int(os.path.split(image_path)[-1].split(".")[1])
# 調用熟悉的人臉分類器
detector = cv2.CascadeClassifier('haarcascade_frontalface_default.xml')
faces = detector.detectMultiScale(img_np)
# 將獲取的圖片和id添加到list中
for (x, y, w, h) in faces:
face_samples.append(img_np[y:y + h, x:x + w])
ids.append(id)
return face_samples, ids
def write_config():
print("新人臉訓練結束")
f = open('config.txt', "a")
T = Total_face_num
f.write(str(T) + " User" + str(T) + " \n")
f.close()
id_dict[T] = "User" + str(T)
# 這裡修改文件的方式是先讀入內存,然後修改內存中的數據,最後寫回文件
f = open('config.txt', 'r+')
flist = f.readlines()
flist[0] = str(int(flist[0]) + 1) + " \n"
f.close()
f = open('config.txt', 'w+')
f.writelines(flist)
f.close()
''' ============================================================================================ 以上是錄入新人臉信息功能的實現 ============================================================================================ '''
def scan_face():
# 使用之前訓練好的模型
for i in range(Total_face_num): # 每個識別器都要用
i += 1
yml = str(i) + ".yml"
print("\n本次:" + yml) # 調試信息
recognizer.read(yml)
ave_poss = 0
for times in range(10): # 每個識別器掃描十遍
times += 1
cur_poss = 0
global success
global img
global system_state_lock
while system_state_lock == 2: # 如果正在錄入新面孔就阻塞
print("\r刷臉被錄入面容阻塞", end="")
pass
success, img = camera.read()
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
# 識別人臉
faces = face_cascade.detectMultiScale(
gray,
scaleFactor=1.2,
minNeighbors=5,
minSize=(int(W_size), int(H_size))
)
# 進行校驗
for (x, y, w, h) in faces:
# global system_state_lock
while system_state_lock == 2: # 如果正在錄入新面孔就阻塞
print("\r刷臉被錄入面容阻塞", end="")
pass
# 這裡調用Cv2中的rectangle函數 在人臉周圍畫一個矩形
cv2.rectangle(img, (x, y), (x + w, y + h), (0, 255, 0), 2)
# 調用分類器的預測函數,接收返回值標簽和置信度
idnum, confidence = recognizer.predict(gray[y:y + h, x:x + w])
conf = confidence
# 計算出一個檢驗結果
if confidence < 100: # 可以識別出已經訓練的對象——直接輸出姓名在屏幕上
if idnum in id_dict:
user_name = id_dict[idnum]
else:
# print("無法識別的ID:{}\t".format(idnum), end="")
user_name = "Untagged user:" + str(idnum)
confidence = "{0}%", format(round(100 - confidence))
else: # 無法識別此對象,那麼就開始訓練
user_name = "unknown"
# print("檢測到陌生人臉\n")
# cv2.destroyAllWindows()
# global Total_face_num
# Total_face_num += 1
# Get_new_face() # 采集新人臉
# Train_new_face() # 訓練采集到的新人臉
# write_config() # 修改配置文件
# recognizer.read('aaa.yml') # 讀取新識別器
# 加載一個字體用於輸出識別對象的信息
font = cv2.FONT_HERSHEY_SIMPLEX
# 輸出檢驗結果以及用戶名
cv2.putText(img, str(user_name), (x + 5, y - 5), font, 1, (0, 0, 255), 1)
cv2.putText(img, str(confidence), (x + 5, y + h - 5), font, 1, (0, 0, 0), 1)
# 展示結果
# cv2.imshow('camera', img)
print("conf=" + str(conf), end="\t")
if 15 > conf > 0:
cur_poss = 1 # 表示可以識別
elif 60 > conf > 35:
cur_poss = 1 # 表示可以識別
else:
cur_poss = 0 # 表示不可以識別
k = cv2.waitKey(1)
if k == 27:
# cam.release() # 釋放資源
cv2.destroyAllWindows()
break
ave_poss += cur_poss
if ave_poss >= 5: # 有一半以上識別說明可行則返回
return i
return 0 # 全部過一遍還沒識別出說明無法識別
''' ============================================================================================ 以上是關於刷臉功能的設計 ============================================================================================ '''
def f_scan_face_thread():
# 使用之前訓練好的模型
# recognizer.read('aaa.yml')
var.set('刷臉')
ans = scan_face()
if ans == 0:
print("最終結果:無法識別")
var.set("最終結果:無法識別")
else:
ans_name = "最終結果:" + str(ans) + id_dict[ans]
print(ans_name)
var.set(ans_name)
global system_state_lock
print("鎖被釋放0")
system_state_lock = 0 # 修改system_state_lock,釋放資源
def f_scan_face():
global system_state_lock
print("\n當前鎖的值為:" + str(system_state_lock))
if system_state_lock == 1:
print("阻塞,因為正在刷臉")
return 0
elif system_state_lock == 2: # 如果正在錄入新面孔就阻塞
print("\n刷臉被錄入面容阻塞\n"
"")
return 0
system_state_lock = 1
p = threading.Thread(target=f_scan_face_thread)
p.setDaemon(True) # 把線程P設置為守護線程 若主線程退出 P也跟著退出
p.start()
def f_rec_face_thread():
var.set('錄入')
cv2.destroyAllWindows()
global Total_face_num
Total_face_num += 1
Get_new_face() # 采集新人臉
print("采集完畢,開始訓練")
global system_state_lock # 采集完就可以解開鎖
print("鎖被釋放0")
system_state_lock = 0
Train_new_face() # 訓練采集到的新人臉
write_config() # 修改配置文件
# recognizer.read('aaa.yml') # 讀取新識別器
# global system_state_lock
# print("鎖被釋放0")
# system_state_lock = 0 # 修改system_state_lock,釋放資源
def f_rec_face():
global system_state_lock
print("當前鎖的值為:" + str(system_state_lock))
if system_state_lock == 2:
print("阻塞,因為正在錄入面容")
return 0
else:
system_state_lock = 2 # 修改system_state_lock
print("改為2", end="")
print("當前鎖的值為:" + str(system_state_lock))
p = threading.Thread(target=f_rec_face_thread)
p.setDaemon(True) # 把線程P設置為守護線程 若主線程退出 P也跟著退出
p.start()
# tk.Tk().update()
# system_state_lock = 0 # 修改system_state_lock,釋放資源
def f_exit(): # 退出按鈕
exit()
''' ============================================================================================ 以上是關於多線程的設計 ============================================================================================ '''
window = tk.Tk()
window.title('Cheney\' Face_rec 3.0') # 窗口標題
window.geometry('1000x500') # 這裡的乘是小x
# 在圖形界面上設定標簽,類似於一個提示窗口的作用
var = tk.StringVar()
l = tk.Label(window, textvariable=var, bg='green', fg='white', font=('Arial', 12), width=50, height=4)
# 說明: bg為背景,fg為字體顏色,font為字體,width為長,height為高,這裡的長和高是字符的長和高,比如height=2,就是標簽有2個字符這麼高
l.pack() # 放置l控件
# 在窗口界面設置放置Button按鍵並綁定處理函數
button_a = tk.Button(window, text='開始刷臉', font=('Arial', 12), width=10, height=2, command=f_scan_face)
button_a.place(x=800, y=120)
button_b = tk.Button(window, text='錄入人臉', font=('Arial', 12), width=10, height=2, command=f_rec_face)
button_b.place(x=800, y=220)
button_b = tk.Button(window, text='退出', font=('Arial', 12), width=10, height=2, command=f_exit)
button_b.place(x=800, y=320)
panel = tk.Label(window, width=500, height=350) # 攝像頭模塊大小
panel.place(x=10, y=100) # 攝像頭模塊的位置
window.config(cursor="arrow")
def video_loop(): # 用於在label內動態展示攝像頭內容(攝像頭嵌入控件)
# success, img = camera.read() # 從攝像頭讀取照片
global success
global img
if success:
cv2.waitKey(1)
cv2image = cv2.cvtColor(img, cv2.COLOR_BGR2RGBA) # 轉換顏色從BGR到RGBA
current_image = Image.fromarray(cv2image) # 將圖像轉換成Image對象
imgtk = ImageTk.PhotoImage(image=current_image)
panel.imgtk = imgtk
panel.config(image=imgtk)
window.after(1, video_loop)
video_loop()
# 窗口循環,用於顯示
window.mainloop()
''' ============================================================================================ 以上是關於界面的設計 ============================================================================================ '''

發布者:全棧程序員棧長,轉載請注明出處:https://javaforall.cn/133970.html原文鏈接:https://javaforall.cn


  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式師世界 All Rights Reserved