### ex1-1 ### # Anaconda 下載 https://www.anaconda.com/products/individual ### ex1-2 ### >>> "abc".upper() # 使用字串物件 "abc" 的 upper() 方法,將字串轉成大寫 >>> "abc".find('b') # find() 方法尋找 'b' 的位置 (從 0 開始) >>> "abc".replace('b', 'z') # replace() 方法將所有的 'b' 取代成 'z' ### ex1-3 ### >>> 111 + 111 # 將兩個整數物件相加 >>> "111" + "111" # 將兩個字串物件串聯 ### ex1-4 ### >>> 111 + "111" # 不同型別的資料相加發生錯誤 ### ex1-5 ### >>> str(111) + "111" # 透過 str() 函數,將整數物件轉換成字串型別 >>> 111 + int("111") # 透過 int() 函數,將字串物件轉換成整數型別 ### ex1-6 ### >>> 10 + 5.5 # 相加 >>> 10 - 5.5 # 相減 >>> 10 * 5.5 # 相乘 >>> 10 / 5.5 # 除法取商 >>> 10 // 5.5 # 除法取整數商 >>> 10 % 5.5 # 除法取餘數 >>> 4 ** 0.5, 8 ** (1/3) # 指數運算 ### ex1-7 ### >>> n1 = 123456789 # 將整數物件 123456789 指派給變數 n1 >>> n2 = 987654321 # 將整數物件 987654321 指派給變數 n2 >>> n1 + n2 # 實際上是 123456789 + 987654321 ### ex1-8 ### >>> x = 1 >>> x = x + 1 >>> x # 顯示變數 x 目前的值 ### ex1-9 ### pi = 3.1 radius = 2.2 # 使用公式計算圓面積 circle_area = pi * radius * radius print(circle_area) # 在螢幕上顯示變數 circle_area 的值 ### ex1-10 ### >>> print("abc") # 顯示字串物件 >>> print("abc".upper()) # 顯示字串物件.方法的執行結果 >>> print(111 + 111) # 顯示整數物件運算的結果 ### ex1-11 ### >>> import time # 匯入時間相關的 time 模組 >>> time.sleep(3) # 執行 time 模組的 sleep() 函式,暫停 3 秒 >>> from time import sleep # 從 time 模組裡匯入 sleep() 函式 >>> sleep(5) # 執行 sleep() 函式,暫停 5 秒 ### ex1-12 ### # 暫停 3 秒後,印出 Hello World! from time import sleep sleep(3) print("Hello World!") ### ex1-13 ### # 手機當電腦鏡頭的步驟 https://bit.ly/3yEVgF9 ### ex1-14 ### # iTunes 64 位元 https://www.apple.com/itunes/download/win64 # iTunes 32 位元 https://www.apple.com/itunes/download/win32 ### ex1-15 ### # 以 Python 3.9.7 為例 # 步驟一:安裝 OpenCV 的相關支援模組 >>> pip install numpy >>> pip install matplotlib >>> pip install imutils # 步驟二:安裝 OpenCV >>> pip install opencv-python >>> pip install opencv-contrib-python # 輸入指令來檢視虛擬環境安裝的套件清單: >>> pip list # 步驟三:檢查 OpenCV 是否成功安裝,通過匯入模組,我們可以首先檢查 OpenCV 是否匯入: >>> import cv2 # 執行後沒有任何反應,代表匯入成功 # 查詢 OpenCV 版本: >>> cv2.__version__ # 若是舊版,以 Python 3.7.X 為例,需降級模組的版本 # 步驟一:安裝 OpenCV 的相關支援模組 >>> pip install numpy==1.21.4 >>> pip install matplotlib >>> pip install imutils # 步驟二:安裝 OpenCV >>> pip install opencv-python==4.5.4.60 >>> pip install opencv-contrib-python==4.5.4.60 ### ex1-16 ### # 第一章的程式碼下載 https://max543.com/debugger/class/python02/影像辨識/code/ch01.zip ### ex1-17 (1-1.py) ### import cv2 # 匯入 opencv img = cv2.imread("koala.jpg") # imread() 讀取圖檔。第 1 個參數:檔案路徑 (字串) cv2.imshow("Koala", img) # imshow() 顯示圖片。第 1 個參數:視窗的文字名稱 (字串),第 2 個參數:圖片內容 gray_img = cv2.imread("koala.jpg", cv2.IMREAD_GRAYSCALE) # imread() 讀取圖檔。第 2 個參數:可以指定 3 種的讀取格式 cv2.imshow("Koala:gray", gray_img) cv2.waitKey(0) # waitKey(0) 等待使用者按下任何鍵 cv2.destroyAllWindows() # 最後呼叫 destroyAllWindows() 方法關閉視窗 ### ex1-18 (1-1a.py) ### import cv2 img = cv2.imread("koala.jpg") img2 = cv2.imread("koala.jpg", cv2.IMREAD_GRAYSCALE) print(img.shape) # 使用 shape 屬性取得圖片的尺寸與色彩數,並顯示出來 print(img2.shape) h, w, c = img.shape # 宣告 3 個變數儲存回傳的 shape 屬性 print("圖片高:", h) print("圖片寬:", w) ### ex1-19 (1-1b.py) ### import cv2, imutils # 匯入 imutils 模組,來調整圖片的尺寸 img = cv2.imread("koala.jpg") print(img.shape) resized_img = imutils.resize(img, width = 300) # imutils.resize() 調整尺寸。第 1 個參數:圖片內容,第 2 個參數:指定 width 或 height 參數值來調整尺寸 (只需指定其中之一) print(resized_img.shape) cv2.imshow("Koala", img) cv2.imshow("Koala:resized", resized_img) cv2.waitKey(0) cv2.destroyAllWindows() ### ex1-20 #### # 字串容器 >>> string = "52python" # 字串容器:由字元組成 >>> string[0] # 字串以索引取值,結果為:'5' # tuple 容器 >>> tuple = (1, '2', 3) # tuple 容器:由資料物件組成 >>> tuple[0] # tuple 以索引取值,結果為:1 # 串列容器 (list) >>> list = [1, '2', 3] # 串列容器:由資料物件組成 >>> list[2] # 串列以索引取值,結果為:'2' # 集合容器 (set) >>> set = {1, '2', 3} # 集合容器:由資料物件組成,無序所以沒有索引取值 # 字典容器 (directory) >>> dick = {'A':1, 'B':'2', 'C':3} # 字典容器:由資料物件組成,以鍵:值表示 >>> dick['B'] # 字典以鍵取值,結果為:'2' ### ex1-21 ### import numpy as np # 匯入 numpy 模組,並使用 np 簡寫代表 a = np.array([10, 2, 45, 32, 24]) # 建立五個元素的 1-D 陣列 >>> len(a) # 計算元素個數 >>> a[2:4] # 取出第 2、3 個元素 >>> a[:4] # 取出第 1 ~ 3 個元素 ### ex1-22 ### import numpy as np A = np.array([[1, 4, 2], [3, 2, 0]]) # 建立兩個元素 2-D 矩陣 B = A[1:, 1:3] # 2-D array 切片,第一個索引以列切片,第二個索引以行為切片 ### ex1-23 (1-1c.py) ### import cv2 img = cv2.imread("koala.jpg") cv2.imshow("Koala", img) print(img.shape) x = 10; y = 10 # 設定切片頂點 (x, y) w = 150; h= 200 # 設定切片的寬 (w) 與高 (h) crop_img = img[y:y + h, x:x + w] # 2-D array 切片,第一個索引以列切片,第二個索引以行為切片 cv2.imshow("Koala", img) cv2.imshow("corp_Koala", crop_img) print(crop_img.shape) cv2.waitKey(0) cv2.destroyAllWindows() ### ex1-24 (1-1d.py) ### import cv2, imutils img = cv2.imread("koala.jpg") rotated_img = imutils.rotate(img, angle = 90) # rotate() 旋轉圖片。第 1 個參數:圖片內容,第 2 個參數:angle 參數是旋轉角度 fliped_img = cv2.flip(img, -1) # 使用 cv2.flip() 也可旋轉圖片。第 1 個參數:圖片內容,第 2 個參數:0 是沿 x 軸垂直翻轉;1 是沿 y 軸水平翻轉 (鏡射);-1 是沿水平和垂直都翻轉 translated_img = imutils.translate(img, 25, -75) # translate() 位移圖片。第 1 個參數:圖片內容,第 2 個參數:若是正值向右位移;負值向左位移,第 3 個參數:若是正值向下位移;負值向上位移 cv2.imshow("Koala:rotated", rotated_img) cv2.imshow("Koala:fliped", fliped_img) cv2.imshow("Koala:translated", translated_img) cv2.waitKey(0) cv2.destroyAllWindows() ### ex1-25 (1-1e.py) ### import cv2 img = cv2.imread("koala.jpg") gray_img = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY) # cvtColor() 轉換彩色圖片成為灰階圖片。第 1 個參數:圖片內容,第 2 個參數:cv2.COLOR_BGR2GRAY 將 BGR 格式轉成灰階 bgr_img = cv2.cvtColor(img, cv2.COLOR_RGB2BGR) # cv2.COLOR_RGB2BGR 將 RGB 格式轉成 BGR cv2.imshow("Koala:gray", gray_img) cv2.imshow("Koala:bgr", bgr_img) cv2.waitKey(0) cv2.destroyAllWindows() ### ex1-26 (1-1f.py) ### import cv2, imutils url = "https://fchart.github.io/img/koala.png" # 宣告變數 url 儲存圖片的 URL 網址 img = imutils.url_to_image(url) # imutils.url_to_image() 讀取此網址的圖片 cv2.imshow("Koala", img) cv2.waitKey(0) cv2.destroyAllWindows() ### ex1-27 (1-1g.py) ### import cv2 img = cv2.imread("koala.jpg") cv2.line(img, (0,0), (200,200), (0,0,255), 5) # cv2.line(影像, 開始座標, 結束座標, 顏色, 線寬) cv2.rectangle(img, (20,70), (120,160), (0,255,0), 2) # cv2.rectangle(影像, 開始座標, 結束座標, 顏色, 線寬) cv2.rectangle(img, (40,80), (100,140), (255,0,0), -1) cv2.circle(img,(90,210), 30, (0,255,255), 3) # cv2.circle(影像, 圓心座標, 半徑, 顏色, 線寬) cv2.circle(img,(140,170), 15, (255,0,0), -1) cv2.putText(img, 'OpenCV', (10, 40), cv2.FONT_HERSHEY_SIMPLEX, 1, (0,255,255), 5, cv2.LINE_AA) # cv2.putText(影像, 文字, 座標, 字型, 大小, 顏色, 線寬, 線條種類) cv2.imshow("Koala", img) cv2.waitKey(0) cv2.destroyAllWindows() ### ex1-28 (1-1h.py) ### import cv2 img = cv2.imread("koala.jpg") gray_img = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY) cv2.imwrite("result_gray.jpg", gray_img) # imwrite() 將圖片內容寫入圖檔。第 1 個參數:欲儲存的圖檔名稱,第 2 個參數:圖片內容 cv2.imwrite("result.png", img) ### ex1-29 (1-2.py) ### import cv2 cap = cv2.VideoCapture("YouTube.mp4") # 第 1 個參數:影片檔路徑 while cap.isOpened(): # isOpened() 檢查影片是否開啟 ret, frame = cap.read() # read() 讀取每一個影格 (幀)。變數 ret:讀取成功 (1);讀取失敗 (0),frame:影格內容 if ret: # 如果 ret == True (1),則顯示影格 cv2.imshow("frame",frame) if cv2.waitKey(1) == 27: # 如果顯示一幀,持續至少 1 ms,且使用者按下 q 鍵,則跳離迴圈 (ord()可以將字符轉化為對應的整數 ASCII碼) break cap.release() # 釋放 VideoCapture 物件 cv2.destroyAllWindows() # 關閉視窗 ### ex1-30 (1-2a.py) ### import cv2 cap = cv2.VideoCapture("YouTube.mp4") def decode_fourcc(v): # decode_fourcc() 將編碼轉成可閱讀的編碼名稱 v = int(v) return "".join([chr((v >> 8 * i) & 0xFF) for i in range(4)]) width = cap.get(cv2.CAP_PROP_FRAME_WIDTH) height = cap.get(cv2.CAP_PROP_FRAME_HEIGHT) print("圖片尺寸:", width, 'x', height) fourcc = cap.get(cv2.CAP_PROP_FOURCC) # 取得影片編碼。參數用法:https://docs.opencv.org/4.5.3/d4/d15/group__videoio__flags__base.html#baeb8dd9c89c10a5c63c139bf7c4f5704d codec = decode_fourcc(fourcc) # 呼叫 decode_fourcc(),轉換可閱讀的編碼字串 print("Codec編碼:", codec) ### ex1-31 (1-2b.py) ### import cv2 cap = cv2.VideoCapture("YouTube.mp4") while cap.isOpened(): ret, frame = cap.read() if ret: gray_frame = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY) # 圖片處理的 cv2.COLOR_BGR2GRAY,同樣適用於影片 cv2.imshow("frame", gray_frame) if cv2.waitKey(1) == 27: break cap.release() cv2.destroyAllWindows() ### ex1-32 (1-3.py) ### import cv2 cap = cv2.VideoCapture(0) # 代表第一支相機 while cap.isOpened(): ret, frame = cap.read() frame = cv2.rotate(frame, rotateCode = 1) # 垂直旋轉相機 180 度 (因為我們的相機安裝是反的) cv2.imshow("frame", frame) if cv2.waitKey(1) == 27: break cap.release() cv2.destroyAllWindows() ### ex1-33 (1-3a.py) ### import cv2 cap = cv2.VideoCapture(0) cap.set(cv2.CAP_PROP_FRAME_WIDTH, 320) cap.set(cv2.CAP_PROP_FRAME_HEIGHT, 180) cap.set(cv2.CAP_PROP_FPS, 25) while cap.isOpened(): ret, frame = cap.read() cv2.imshow("frame",frame) if cv2.waitKey(1) == 27: break cap.release() cv2.destroyAllWindows() ### ex1-34 (1-3b.py) ### import cv2 cap = cv2.VideoCapture(0) fourcc = cv2.VideoWriter_fourcc(*'XVID') # 首先建立影片編碼 fourcc,指定為 .avi 格式 out = cv2.VideoWriter('output.avi', fourcc, 20, (640, 480)) # 建立 VideoWriter 物件來寫入影片檔。第 1 個參數:欲儲存的影片檔案名稱,第 2 個參數:編碼,第 3 個參數:FPS,第 4 個參數:影格尺寸 while cap.isOpened(): ret, frame = cap.read() if ret == True: out.write(frame) # 呼叫 write() 將影格一一寫入影片檔 cv2.imshow('frame', frame) if cv2.waitKey(1) == 27: break else: break cap.release() out.release() cv2.destroyAllWindows() ### ex1-35 (1-4.py) ### import cv2 face_cascade = cv2.CascadeClassifier('haarcascade_frontalface_alt2.xml') # 載入正面較精準的 alt2 image = cv2.imread('demo.jpeg') # 載入圖檔 gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY) # 轉成灰階 (影片辨識採灰階) faces = face_cascade.detectMultiScale(gray, 1.1, 3) # 利用 detectMultiScale(image, scaleFactor = 1.1, minNeighbors = 3) 尋找圖片中的人臉 # faces = face_cascade.detectMultiScale(gray, 1.05, 4) # scaleFactor 代表每次檢測窗口的放大級距,最小值為 1,minNeighbors 代表需通過幾次才算是人臉 # 找到人臉後,傳回左上角座標 (x, y),及長寬範圍,畫出一個矩形 for (x, y, w, h) in faces: frame = cv2.rectangle(frame, (x, y), (x + w, y + h), (0, 255, 0), 3) cv2.namedWindow('frame', cv2.WINDOW_NORMAL) # 當圖片太大,使用 namedWindow() 得到的視窗就可以自行调整大小。WINDOW_NORMAL:視窗大小可改變 cv2.imshow('frame', frame) cv2.waitKey(0) # 按任何鍵結束程式 cv2.destroyAllWindows() ### ex1-36 (1-5.py) ### import cv2 face_cascade = cv2.CascadeClassifier('haarcascade_frontalface_alt2.xml') eye_cascade = cv2.CascadeClassifier('haarcascade_eye.xml') # 載入眼睛分類器 frame = cv2.imread('demo.jpeg') gray = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY) # faces = face_cascade.detectMultiScale(gray, 1.1, 3) faces = face_cascade.detectMultiScale(gray, 1.05, 4) # 畫出辨識的人臉 for (x, y, w, h) in faces: frame = cv2.rectangle(frame, (x, y), (x + w, y + h), (0, 255, 0), 3) face_rect = gray[y:y + h, x:x + w] eyes = eye_cascade.detectMultiScale(face_rect, 1.3, 8) # 辨識出人臉後,再辨識眼睛 # 畫出辨識的眼睛 for (ex, ey, ew, eh) in eyes: frame = cv2.rectangle(frame, (x + ex, y + ey), (x + ex + ew, y + ey + eh), (0, 255, 0), 2) cv2.namedWindow('frame', cv2.WINDOW_NORMAL) cv2.imshow('frame', frame) cv2.waitKey(0) cv2.destroyAllWindows() ### ex1-37 (1-6.py) #### import cv2 faceCascade = cv2.CascadeClassifier("haarcascade_frontalface_default.xml") # 載入全角度較精準的預設人臉分類器 cap = cv2.VideoCapture(0) cap.set(cv2.CAP_PROP_FRAME_WIDTH, 640) cap.set(cv2.CAP_PROP_FRAME_HEIGHT, 480) while True: ret, frame = cap.read() frame = cv2.rotate(frame, rotateCode = 1) gray = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY) faces = faceCascade.detectMultiScale(gray, scaleFactor = 1.1, minNeighbors = 5, minSize = (30, 30)) # minSize:低於 minSize 的話,不會被檢測出來 print("人臉數:", len(faces)) # 計算出現的人臉數 for (x, y, w, h) in faces: cv2.rectangle(frame, (x, y), (x+w, y+h), (0, 255, 0), 2) cv2.imshow("preview", frame) if cv2.waitKey(1) == 27: break cap.release() cv2.destroyAllWindows() ### ex1-38 (1-7.py) #### import cv2 faceCascade = cv2.CascadeClassifier("haarcascade_frontalface_default.xml") eye_cascade = cv2.CascadeClassifier("haarcascade_eye.xml") cap = cv2.VideoCapture(0) cap.set(cv2.CAP_PROP_FRAME_WIDTH, 640) cap.set(cv2.CAP_PROP_FRAME_HEIGHT, 480) while True: ret, frame = cap.read() frame = cv2.rotate(frame, rotateCode = 1) gray = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY) faces = faceCascade.detectMultiScale(gray, scaleFactor = 1.1, minNeighbors = 5, minSize = (30, 30)) print("人臉數:", len(faces)) for (x, y, w, h) in faces: frame = cv2.rectangle(frame, (x, y), (x + w, y + h), (0, 255, 0), 3) face_rect = gray[y:y + h, x:x + w] eyes = eye_cascade.detectMultiScale(face_rect, 1.3, 8) for (ex, ey, ew, eh) in eyes: cv2.rectangle(frame, (x + ex, y + ey), (x + ex + ew, y + ey + eh), (0, 255, 0), 2) cv2.imshow("preview", frame) if cv2.waitKey(1) == 27: break cap.release() cv2.destroyAllWindows() ### ex1-39 (1-8-1-capture.py) ### import cv2 ESC = 27 # 設定將以 ESC 鍵作為離開程式 n = 1 # 畫面數量計數 index = 0 # 存檔檔名用 total = 100 # 人臉取樣總數 # 自訂函數,images 與 h0 要自己先建立。若有第二個人就建立 h1 def saveImage(face_image, index): filename = 'images/h0/{:03d}.pgm'.format(index) cv2.imwrite(filename, face_image) print(filename) # 載入聯集分類器與開啟攝影機 face_cascade = cv2.CascadeClassifier('haarcascade_frontalface_default.xml') cap = cv2.VideoCapture(0) ratio = cap.get(cv2.CAP_PROP_FRAME_WIDTH) / cap.get(cv2.CAP_PROP_FRAME_HEIGHT) WIDTH = 400 HEIGHT = int(WIDTH / ratio) cv2.namedWindow('video', cv2.WINDOW_NORMAL) # 讀取影像並轉成灰階 while n > 0: ret, frame = cap.read() frame = cv2.resize(frame, (WIDTH, HEIGHT)) frame = cv2.rotate(frame, rotateCode = 1) # 垂直旋轉相機 180 度 (因為我們的相機安裝是反的) frame = cv2.flip(frame, 1) # 水平翻轉 180 度 (鏡像) gray = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY) # 轉成灰階 # 偵測人臉,並且每 5 張人臉存檔一次 faces = face_cascade.detectMultiScale(gray, 1.1, 3) # 辨識人臉 for (x, y, w, h) in faces: frame = cv2.rectangle(frame, (x, y), (x + w, y + h), (0, 255, 0), 3) if n % 5 == 0: # 每 5 張存檔一次,目的是要讓使用者變換姿勢 face_img = gray[y: y + h, x: x + w] face_img = cv2.resize(face_img, (400, 400)) # 訓練用圖片解析度為 400x400,最小為 50x50 saveImage(face_img, index) # 儲存訓練圖片 index += 1 if index >= total: # 若拍照滿 100 張,則跳離 for 迴圈 print('get training data done') n = -1 break n += 1 # 將攝影機拍到的影像顯示出來 cv2.imshow('video', frame) if cv2.waitKey(1) == ESC: cv2.destroyAllWindows() break ### ex1-40 (1-8-2-train.py) ### import cv2 import numpy as np images = [] # 空串列,儲存照片 labels = [] # 空串列,儲存人臉的標籤序號 for index in range(100): filename = 'images/h0/{:03d}.pgm'.format(index) print('read ' + filename) img = cv2.imread(filename, cv2.COLOR_BGR2GRAY) images.append(img) labels.append(0) # 第一張人臉的標籤為 0 print('training...') model = cv2.face.LBPHFaceRecognizer_create() # 建立模型,使用 LBPH 演算法 model.train(np.asarray(images), np.asarray(labels)) # train() 只能接收 numpy 格式的陣列,asarry() 方法將輸入的物件轉成陣列 model.save('faces.data') # 儲存訓練好的辨識檔 print('training done') ### ex1-41 (1-8-3-recognition.py) ### import cv2 model = cv2.face.LBPHFaceRecognizer_create() # 建立模型,使用 LBPH 演算法 model.read('faces.data') # 載入訓練好的辨識檔 print('load training data done') face_cascade = cv2.CascadeClassifier('haarcascade_frontalface_default.xml') # 載入聯集分類器 (需與取樣時的分類器一致),並開啟攝影機 cap = cv2.VideoCapture(0) cv2.namedWindow('video', cv2.WINDOW_NORMAL) # 可識別化名稱,請自行更改 names = ['pllai'] # 讀取攝影機資料,並轉換成灰階影像 while True: ret, frame = cap.read() frame = cv2.resize(frame, (600, 336)) frame = cv2.flip(frame, 1) gray = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY) faces = face_cascade.detectMultiScale(gray, 1.1, 3) # 偵測人臉,並與訓練資料比對 for (x, y, w, h) in faces: frame = cv2.rectangle(frame, (x, y), (x + w, y + h), (0, 255, 0), 3) face_img = gray[y: y + h, x: x + w] face_img = cv2.resize(face_img, (400, 400)) val = model.predict(face_img) # predict() 會傳回標籤編號與信心值 print('label:{}, conf:{:.1f}'.format(val[0], val[1])) if val[1] < 50: # 若是 LBPH 演算法 < 50 是可接受的,信心值越低越好 cv2.putText(frame, names[val[0]], (x, y - 10), cv2.FONT_HERSHEY_SIMPLEX, 1, (255,255,0), 3) cv2.imshow('video', frame) if cv2.waitKey(1) == 27: cv2.destroyAllWindows() break