在訓練影像辨識模型之前,需要先收集適合的樣本。這篇從測試相機開始,記錄影片輸出、逐幀擷取、資料夾管理與截圖範例,將拍攝到整理資料的流程連接起來。
本篇重點- 先確認相機能正常讀取與顯示畫面
- 錄製影片,再擷取需要的影像樣本
- 整理檔案與資料夾,並查閱畫面/人臉截圖範例
原始實作記錄於 2020 年;以下操作畫面與程式範例保留當時版本。
shutil 與 os 都是 Python 標準函式庫,可直接 import,不需要另外用 pip 安裝。下列舊版安裝範例僅保留作為原始紀錄。查閱 Python 文件
本文把樣本蒐集分成三段:確認相機、錄製與擷取畫面、整理輸出檔案。先跑通最小的相機測試,再接上後面的範例,較容易找出問題發生在哪一步。
安裝所需模組
安裝 OpenCV
1
| pip install opencv-python
|
使用 shutil(Python 內建模組)
shutil 是 Python 標準函式庫,可直接 import。下方 pip 指令是原始紀錄,不需要執行。查閱 Python 文件
1
| pip install pytest-shutil
|
安裝 dlib
確認相機能否讀取
先確認相機權限、裝置索引與是否被其他程式占用。每次讀取後都要檢查成功旗標;畫面正常顯示後,再測試結束按鍵及資源釋放。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
| import cv2
cap = cv2.VideoCapture(0)
while(True): ret, frame = cap.read()
cv2.imshow('frame', frame) if cv2.waitKey(1) & 0xFF == ord('q'): break
cap.release()
cv2.destroyAllWindows()
|
操作說明
錄影時核對輸出路徑、影像尺寸、幀率與編碼格式是否一致。逐幀擷取會產生很多相近圖片,可依用途選取有代表性的畫面,避免只累積重複樣本。
錄製並輸出影片
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29
| import cv2
cap = cv2.VideoCapture(0)
sz = (int(cap.get(cv2.CAP_PROP_FRAME_WIDTH)), int(cap.get(cv2.CAP_PROP_FRAME_HEIGHT)))
fps = 30
fourcc = cv2.VideoWriter_fourcc(*'mp4v')
vout = cv2.VideoWriter() vout.open('output.mp4', fourcc, fps, sz, True)
cnt = 1 while cnt <= 600: _, frame = cap.read() cv2.putText(frame, str(cnt), (10, 20), cv2.FONT_HERSHEY_PLAIN, 0.8, (0, 255, 0), 1, cv2.LINE_AA) vout.write(frame) cnt += 1
cv2.imshow('vidio', frame) cv2.waitKey(30)
vout.release() cap.release()
|
從影片逐幀擷取圖片
1 2 3 4 5 6 7 8 9 10 11 12 13
| import cv2 vc=cv2.VideoCapture("output.mp4") c=1 if vc.isOpened(): rval,frame=vc.read() else: rval=False while rval: rval,frame=vc.read() cv2.imwrite('test'+str(c)+'.jpg',frame) c=c+1 cv2.waitKey(1) vc.release()
|
建立資料夾
1 2 3 4
| import os a=input("輸入檔名:") print("新建"+str(a)+"資料夾中...") os.mkdir(str(a))
|
移動圖片
先建立測試圖片 test.jpg 與資料夾 test,再執行搬移範例,確認目的地出現圖片且原位置已移除。
1 2 3
| import shutil shutil.move('test'+'.jpg',"test") print("圖片移動完成")
|
刪除檔案
可以建立一個名為 test.jpg 的圖檔,進行測試。
1 2
| import os os.remove('test'+'.jpg')
|
作品參考
以下保留當時的畫面與人臉截圖程式。執行前先查看程式所需的相機、模型檔與輸出目錄;能保存圖片不代表資料集已完成,仍需檢查模糊、重複、類別與標註品質。
畫面截圖
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67
| import cv2 import os import shutil
a=input("請輸入檔案英文名稱:") b=input("請輸入張數:") enter=int(b)+1
cap = cv2.VideoCapture(0)
sz = (int(cap.get(cv2.CAP_PROP_FRAME_WIDTH)), int(cap.get(cv2.CAP_PROP_FRAME_HEIGHT)))
fps = 60
fourcc = cv2.VideoWriter_fourcc(*'mp4v')
vout = cv2.VideoWriter() vout.open('output.mp4', fourcc, fps, sz, True)
cnt = 1 while cnt <= enter: _, frame = cap.read() cv2.putText(frame, str(cnt), (10, 20), cv2.FONT_HERSHEY_PLAIN, 1, (0, 255, 0), 1, cv2.LINE_AA) vout.write(frame) cnt += 1
cv2.imshow('vidio', frame) cv2.waitKey(30)
vout.release() cap.release()
print("正在裁切影片,形成圖片中...") vc=cv2.VideoCapture("output.mp4") c=1 if vc.isOpened(): rval,frame=vc.read() else: rval=False while rval: rval,frame=vc.read() cv2.imwrite(str(a)+str(c)+'.jpg',frame) c=c+1
cv2.waitKey(1) vc.release()
os.mkdir(str(a)) print('已新建【'+str(a)+'】資料夾')
os.remove(str(a)+str(enter)+'.jpg')
count=0 print("圖片正在移動至【"+str(a)+"】資料夾中...") while count < int(b): count+=1 shutil.move(str(a)+str(count)+'.jpg',str(a))
print("圖片移動完成")
|
人臉截圖
完整程式範例(127 行)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127
| import dlib import cv2 import imutils import shutil import os import time
name=input("請輸入英文檔案名稱 :") num=input("請輸入預定張數 :") enter=int(num)+1
os.mkdir(str(name)) print('新建【'+str(name)+'】資料夾')
cap = cv2.VideoCapture(0)
sz = (int(cap.get(cv2.CAP_PROP_FRAME_WIDTH)), int(cap.get(cv2.CAP_PROP_FRAME_HEIGHT)))
fps = 30
fourcc = cv2.VideoWriter_fourcc(*'mp4v')
vout = cv2.VideoWriter() vout.open('output.mp4', fourcc, fps, sz, True)
cnt = 0 while cnt < enter: _, frame = cap.read() cv2.putText(frame, str(cnt), (10, 20), cv2.FONT_HERSHEY_PLAIN, 0.8, (0, 255, 0), 1, cv2.LINE_AA) vout.write(frame) cnt += 1
cv2.imshow('vidio', frame) cv2.waitKey(30)
vout.release() cap.release()
cv2.destroyAllWindows()
print("正在裁切影片,形成圖片中...") vc=cv2.VideoCapture("output.mp4") Caimg=0 c=1 if vc.isOpened(): rval,frame=vc.read() else: rval=False while rval: rval,frame=vc.read() cv2.imwrite(str(name)+str(c)+'.jpg',frame) c=c+1 vc.release()
print("圖片形成完成")
os.remove(str(name)+str(enter)+'.jpg')
print("頭像圖片裁切中...")
sum=0 de=0 count=1 while count <= int(str(num)): print (str(name).format(count)+str(count)+".jpg"+" | 完成度 "+'{:.1%}'.format(count/int(str(num))), end="\r") img1 = cv2.imread(str(name)+str(count)+'.jpg')
detector = dlib.get_frontal_face_detector()
face_rects = detector(img1, 1) if len(face_rects) == 0 : print(' | 偵測不到人臉,刪除 '+str(name)+str(count)+'.jpg 的圖檔 | ') de+=1 os.remove(str(name)+str(count)+'.jpg') count+=1 else : for i, d in enumerate(face_rects): x1 = d.left() y1 = d.top() x2 = d.right() y2 = d.bottom() x = x1 y = y1
w = x2 h = y2 img2 = img1[y:h, x:w] img2 = imutils.resize(img2, width=360) cv2.imwrite(str(name)+str(count)+'.jpg', img2) shutil.move(str(name)+str(count)+'.jpg',str(name)) sum+=1 count+=1 print("\n頭像圖片裁切完成")
shutil.move(str(name),'images')
print("相片已刪除 "+str(de)+ "張") print("相片實際輸出為 "+str(sum)+"張")
|
從截圖到可用樣本
先抽查輸出的檔案能否開啟,再挑選不同距離、角度與光線的畫面。訓練與驗證資料應分開安排,避免把同一段影片中幾乎相同的畫面分散到兩邊,讓評估失去代表性。
參考:OpenCV 官方影片讀寫說明。