---
# System prepended metadata

title: OpenCV Part2

---

# OpenCV Part2

## 螢幕手寫繪圖 OCR
```python=

```
## 螢幕手寫繪圖 OCR + CNN 模型
```python=

```
## 二質化
* 目的 : 降低變化，只是要取得外觀
* 結論 : 端看要辨識的物品，如果沒有要辨識顏色或複雜細項，畫素能小就小，能二質化就二質化

```python=

```
### opencv + cnn 實作辨識
```python=
# 步驟1 : 模型訓練
from sklearn.model_selection import train_test_split  # 匯入 sklearn 用於分割訓練和測試數據
import glob  # 匯入 glob 模組，用於檔案模式匹配
import numpy as np  # 匯入 NumPy 庫，用於數據處理
import os.path as path  # 匯入 os.path 模組，用於處理路徑
import os  # 匯入 os 模組，用於操作檔案和目錄
import cv2  # 匯入 OpenCV 庫，用於影像處理
import tensorflow as tf  # ��入 TensorFlow ��，用於建立深度�

# 定義影像所在的目錄路徑
IMAGEPATH = 'C:\\openCV\\images'

# 獲取 IMAGEPATH 目錄下的所有子目錄名稱（每個子目錄代表一個類別）
dirs = os.listdir(IMAGEPATH)

# 初始化空列表，用於存放影像資料和標籤
X = []
Y = []

print(dirs)  # 輸出子目錄名稱列表

i = 0  # 初始化標籤計數器

# 遍歷每個子目錄（每個子目錄代表一個類別）
for name in dirs:
    # 獲取子目錄下所有影像檔案的完整路徑
    file_paths = glob.glob(path.join(IMAGEPATH + "/" + name, '*.*'))
    
    # 遍歷每個影像檔案
    for path3 in file_paths:
        img = cv2.imread(path3)  # 讀取影像
        img = cv2.resize(img, (224, 224), interpolation=cv2.INTER_AREA)  # 調整影像大小至 224x224
        im_rgb = cv2.cvtColor(img, cv2.COLOR_BGR2RGB)  # 將影像從 BGR 轉換為 RGB 格式
        X.append(im_rgb)  # 將影像資料添加到 X 列表中
        Y.append(i)  # 將影像的標籤（對應子目錄的索引）添加到 Y 列表中
    
    i = i + 1  # 每處理完一個子目錄，將標籤計數器加一

# 將影像資料和標籤列表轉換為 NumPy 陣列
X = np.asarray(X)
Y = np.asarray(Y)

# 將影像資料轉換為浮點型，並進行標準化處理
X = X.astype('float32')
X = X / 255  # 將像素值歸一化至 [0, 1] 範圍

h=224
w=224
# 將影像資料重塑為 (樣本數量, 224, 224, 3)，3 代表 RGB 三個頻道
X = X.reshape(X.shape[0], h, w, 3)

# 獲取分類數目，即子目錄的數量
category = len(dirs)

# 獲取影像的維度
dim = X.shape[1]

# 將資料集分為訓練集和測試集，測試集佔 5%
x_train, x_test, y_train, y_test = train_test_split(X, Y, test_size=0.05)

# 輸出訓練集的資料形狀
print(x_train.shape)
print(y_train.shape)


 
X = X.astype('float32')
X=X/255
X=X.reshape(X.shape[0],h,w,3)

category=len(dirs)
dim=X.shape[1]
x_train , x_test , y_train , y_test = train_test_split(X,Y,test_size=0.05)
# 將數字轉為 One-hot 向量
y_train2 = tf.keras.utils.to_categorical(y_train, category)
y_test2 = tf.keras.utils.to_categorical(y_test, category)



# 載入資料（將資料打散，放入 train 與 test 資料集）

print(x_train.shape)
datagen = tf.keras.preprocessing.image.ImageDataGenerator(
                            rotation_range=25 ,
                            width_shift_range=[-3,3],
                            height_shift_range=[-3,3] ,
                            zoom_range=0.3 ,
							data_format='channels_last')


# 建立模型
model = tf.keras.models.Sequential()
# 加入 2D 的 Convolution Layer，接著一層 ReLU 的 Activation 函數
model.add(tf.keras.layers.Conv2D(filters=32, kernel_size=(3, 3),
                 padding="same",
                 activation='relu',
                 input_shape=(h,w,3)))
model.add(tf.keras.layers.Flatten())
model.add(tf.keras.layers.Dense(50, activation='relu'))
model.add(tf.keras.layers.Dense(units=category,
    activation=tf.nn.softmax ))


learning_rate = 0.001
opt1 = tf.keras.optimizers.Adam(learning_rate=learning_rate)
model.compile(
    optimizer=opt1,
    loss=tf.keras.losses.categorical_crossentropy,
    metrics=['accuracy'])

model.summary()
"""
with open("model_ImageDataGenerator_myImage.json", "w") as json_file:
    json_file.write(model.to_json())


try:
    with open('model_ImageDataGenerator_myImage.h5', 'r') as load_weights:
        model.load_weights("model_ImageDataGenerator_myImage.h5")
except IOError:
    print("File not exists")

"""
#checkpoint = tf.keras.callbacks.ModelCheckpoint("model_ImageDataGenerator_myImage.weights.keras", monitor='loss', verbose=1,
#    save_best_only=True, mode='auto', save_freq=1)
# 訓練模型

trainData=datagen.flow(x_train,y_train2,batch_size=64)
history = model.fit(trainData,
							  epochs=100,
							  # callbacks=[checkpoint]
                              )
#保存模型權重
model.save_weights("model_ImageDataGenerator_myImage.weights.h5")

#測試
score = model.evaluate(x_test, y_test2, batch_size=128)
# 輸出結果
print("score:",score)

predict = model.predict(x_test)
print("Ans:",np.argmax(predict[0]),np.argmax(predict[1]),np.argmax(predict[2]),np.argmax(predict[3]))

# predict2 = model.predict_classes(x_test)
predict2 = np.argmax(predict, axis=1)
print("predict_classes:",predict2)
print("y_test",y_test[:])
for t1 in predict2:
    print(dirs[t1])

img=x_test[0]
img=img.reshape(h,w,3)
img=img*255
img = img.astype('uint8')
img = cv2.resize(img, (224, 224), interpolation=cv2.INTER_AREA)
im_bgr = cv2.cvtColor(img, cv2.COLOR_RGB2BGR)
i = np.argmax(predict[0])
str1 = dirs[i] + "   " + str(predict[0][i])
print(str1)
im_bgr = cv2.putText(im_bgr, str1, (10,30), cv2.FONT_HERSHEY_SIMPLEX, 1, (255,0, 0), 1, cv2.LINE_AA)
cv2.imshow('image', im_bgr)
cv2.waitKey(0)
cv2.destroyAllWindows()
```
```python=
步驟2 : 執行opencv 進行辨識
import tensorflow as tf
import cv2
import numpy as np
import os.path as path
import os
import time
IMAGEPATH = 'C:\\openCV\\images'
dirs = os.listdir(IMAGEPATH)


"""
json_file = open('model_ImageDataGenerator_myImage.json', 'r')
loaded_model_json = json_file.read()
json_file.close()
model = tf.keras.models.model_from_json(loaded_model_json)
"""
h=224
w=224
category = len(dirs)
# 建立模型
model = tf.keras.models.Sequential()
# 加入 2D 的 Convolution Layer，接著一層 ReLU 的 Activation 函數
model.add(tf.keras.layers.Conv2D(filters=32, kernel_size=(3, 3),
                 padding="same",
                 activation='relu',
                 input_shape=(h,w,3)))
model.add(tf.keras.layers.Flatten())
model.add(tf.keras.layers.Dense(50, activation='relu'))
model.add(tf.keras.layers.Dense(units=category,
    activation=tf.nn.softmax ))


model.compile(loss=tf.keras.losses.categorical_crossentropy,
            optimizer=tf.keras.optimizers.Adadelta(),
            metrics=['accuracy'])

model.load_weights("model_ImageDataGenerator_myImage.weights.h5")

model.summary()
url="http://172.19.106.80:4747/video"
cap = cv2.VideoCapture(url)
# while(True):
#     ret, img = cap.read()
#     if ret==True:
#         resized = cv2.resize(img, (224, 224), interpolation=cv2.INTER_AREA)
#         image = cv2.cvtColor(resized, cv2.COLOR_BGR2RGB)
#         print(image.shape)
#         image = image.reshape((1, image.shape[0], image.shape[1], image.shape[2]))
#         predict = model.predict(image)
#         i=np.argmax(predict[0])
#         str1 =dirs[i] +"   "+str(predict[0][i])
#         print(str1)
#         img = cv2.putText(img, str1, (30, 50), cv2.FONT_HERSHEY_SIMPLEX, 1, (0, 255, 0),2,cv2.LINE_AA)
#         cv2.imshow('image',img)
#         # time.sleep(5)
#     if cv2.waitKey(50) & 0xFF == ord('q'):
#         break
# cap.release()
# cv2.destroyAllWindows()

# start_recognition = False  # 初始化為 False，表示尚未開始辨識

# while True:
#     ret, img = cap.read()

#     if ret == True:
#         key = cv2.waitKey(50) & 0xFF
        
#         if key == ord('c'):
#             resized = cv2.resize(img, (224, 224), interpolation=cv2.INTER_AREA)
#             image = cv2.cvtColor(resized, cv2.COLOR_BGR2RGB)
#             print(image.shape)
#             image = image.reshape((1, image.shape[0], image.shape[1], image.shape[2]))
#             predict = model.predict(image)
#             i = np.argmax(predict[0])
#             str1 = dirs[i] + "   " + str(predict[0][i])
#             print(str1)
#             img = cv2.putText(img, str1, (30, 50), cv2.FONT_HERSHEY_SIMPLEX, 1, (0, 255, 0), 2, cv2.LINE_AA)
        
#         cv2.imshow('image', img)
        
#         if key == ord('q'):
#             break

# cap.release()
# cv2.destroyAllWindows()

freeze_frame = False  # 初始化為 False，表示畫面未凍結

while True:
    if not freeze_frame:  # 當畫面未凍結時，讀取新的影像
        ret, img = cap.read()

    if ret == True:
        key = cv2.waitKey(50) & 0xFF  # 檢查是否有按鍵輸入
        
        if key == ord('c') and not freeze_frame:  # 當按下C鍵且畫面未凍結時進行辨識
            resized = cv2.resize(img, (224, 224), interpolation=cv2.INTER_AREA)  # 調整影像大小
            image = cv2.cvtColor(resized, cv2.COLOR_BGR2RGB)  # 將影像轉換為RGB格式
            print(image.shape)  # 輸出影像的形狀資訊
            image = image.reshape((1, image.shape[0], image.shape[1], image.shape[2]))  # 重新塑形以符合模型輸入
            predict = model.predict(image)  # 執行模型預測
            i = np.argmax(predict[0])  # 找出預測結果中機率最高的類別
            str1 = dirs[i] + "   " + str(predict[0][i])  # 構建顯示的文字訊息
            print(str1)  # 輸出辨識結果
            img = cv2.putText(img, str1, (30, 50), cv2.FONT_HERSHEY_SIMPLEX, 1, (0, 255, 0), 2, cv2.LINE_AA)  # 在影像上顯示結果
            
            freeze_frame = True  # 當按下C鍵後，凍結畫面
    
        cv2.imshow('image', img)  # 顯示影像
    
        if key == ord('c') and freeze_frame:  # 再次按下C鍵時，解除凍結，準備讀取下一幀影像
            freeze_frame = False
    
        if key == ord('q'):
            break  # 按下Q鍵結束程式

cap.release()  # 釋放攝影機資源
cv2.destroyAllWindows()  # 關閉所有OpenCV視窗
```



![image](https://hackmd.io/_uploads/Hk-hCZmjR.png)


![image](https://hackmd.io/_uploads/BkR00bXjC.png)
## 多物件影像辨識


### HSL HSV
* 目的 把顏色與物體拆分


> 多物件
> ![image](https://hackmd.io/_uploads/H1t7AAzsC.png)
參數不會調整，主要是返回值
> 找特徵物件
> 只要是黑色或是白色的邊緣都可以找到輪廓
> 如果是在流水線上面的檢驗，盡量讓背景是差異很大，例如 動畫綠背景，就是為了這個目的

> ![image](https://hackmd.io/_uploads/S1B2zyQjR.png)
>算面積

>![image](https://hackmd.io/_uploads/HJBnQ1XjC.png)
> 寫字
> 框起來

可以透過程式加上及時調整參數方式，找到最好的參數

```python=
# part1
#!/usr/bin/env python
# author: Powen Ko  柯博文老師  www.powenko.com
# -*- coding: utf-8 -*-

from sklearn.model_selection import train_test_split  # 匯入 sklearn 用於分割訓練和測試數據
import glob  # 匯入 glob 模組，用於檔案模式匹配
import numpy as np  # 匯入 NumPy 庫，用於數據處理
import os.path as path  # 匯入 os.path 模組，用於處理路徑
import os  # 匯入 os 模組，用於操作檔案和目錄
import cv2  # 匯入 OpenCV 庫，用於影像處理
import tensorflow as tf  # 匯入 TensorFlow 庫，用於建立深度學習模型

# 定義影像所在的目錄路徑
IMAGEPATH = 'images'

# 獲取 IMAGEPATH 目錄下的所有子目錄名稱（每個子目錄代表一個類別）
dirs = os.listdir(IMAGEPATH)

# 初始化空列表，用於存放影像資料和標籤
X = []
Y = []

print(dirs)  # 輸出子目錄名稱列表

i = 0  # 初始化標籤計數器

# 遍歷每個子目錄（每個子目錄代表一個類別）
for name in dirs:
    # 獲取子目錄下所有影像檔案的完整路徑
    file_paths = glob.glob(path.join(IMAGEPATH + "/" + name, '*.*'))
    
    # 遍歷每個影像檔案
    for path3 in file_paths:
        img = cv2.imread(path3)  # 讀取影像
        img = cv2.resize(img, (224, 224), interpolation=cv2.INTER_AREA)  # 調整影像大小至 224x224
        im_rgb = cv2.cvtColor(img, cv2.COLOR_BGR2RGB)  # 將影像從 BGR 轉換為 RGB 格式
        X.append(im_rgb)  # 將影像資料添加到 X 列表中
        Y.append(i)  # 將影像的標籤（對應子目錄的索引）添加到 Y 列表中
    
    i = i + 1  # 每處理完一個子目錄，將標籤計數器加一

# 將影像資料和標籤列表轉換為 NumPy 陣列
X = np.asarray(X)
Y = np.asarray(Y)

# 將影像資料轉換為浮點型，並進行標準化處理
X = X.astype('float32')
X = X / 255  # 將像素值歸一化至 [0, 1] 範圍

h = 224  # 設定影像的高度
w = 224  # 設定影像的寬度
# 將影像資料重塑為 (樣本數量, 224, 224, 3)，3 代表 RGB 三個頻道
X = X.reshape(X.shape[0], h, w, 3)

# 獲取分類數目，即子目錄的數量
category = len(dirs)

# 獲取影像的維度
dim = X.shape[1]

# 將資料集分為訓練集和測試集，測試集佔 5%
x_train, x_test, y_train, y_test = train_test_split(X, Y, test_size=0.05)

# 輸出訓練集的資料形狀
print(x_train.shape)
print(y_train.shape)

# 再次將影像資料轉換為浮點型，並進行標準化處理（多餘的步驟，已在上面處理過）
X = X.astype('float32')
X = X / 255  # 將像素值歸一化至 [0, 1] 範圍
X = X.reshape(X.shape[0], h, w, 3)  # 重塑影像資料為 (樣本數量, 224, 224, 3)

category = len(dirs)  # 獲取分類數目
dim = X.shape[1]  # 獲取影像的維度
x_train, x_test, y_train, y_test = train_test_split(X, Y, test_size=0.05)  # 分割資料集

# 將數字標籤轉為 One-hot 向量
y_train2 = tf.keras.utils.to_categorical(y_train, category)
y_test2 = tf.keras.utils.to_categorical(y_test, category)

# 建立資料增強器，用於在訓練過程中進行影像增強
datagen = tf.keras.preprocessing.image.ImageDataGenerator(
    rotation_range=25,  # 影像隨機旋轉角度
    width_shift_range=[-3, 3],  # 影像隨機水平平移範圍
    height_shift_range=[-3, 3],  # 影像隨機垂直平移範圍
    zoom_range=0.3,  # 影像隨機縮放範圍
    data_format='channels_last'  # 指定資料格式為 channels_last (即 (height, width, channels))
)

# 建立模型
model = tf.keras.models.Sequential()
# 加入 2D 的 Convolution Layer，使用 ReLU 激活函數
model.add(tf.keras.layers.Conv2D(filters=32, kernel_size=(3, 3),
                                 padding="same",
                                 activation='relu',
                                 input_shape=(h, w, 3)))
# 將多維度的輸出轉為一維
model.add(tf.keras.layers.Flatten())
# 加入全連接層，包含 50 個神經元，使用 ReLU 作為激活函數
model.add(tf.keras.layers.Dense(50, activation='relu'))
# 最後一層使用 softmax 激活函數進行分類，輸出單元數與分類數相同
model.add(tf.keras.layers.Dense(units=category,
                                activation=tf.nn.softmax))

# 設定學習率
learning_rate = 0.001
opt1 = tf.keras.optimizers.Adam(learning_rate=learning_rate)
# 編譯模型，使用 categorical_crossentropy 作為損失函數，評估指標為準確率
model.compile(
    optimizer=opt1,
    loss=tf.keras.losses.categorical_crossentropy,
    metrics=['accuracy'])

# 輸出模型摘要資訊
model.summary()

# 準備訓練資料
trainData = datagen.flow(x_train, y_train2, batch_size=64)

# 訓練模型
history = model.fit(trainData,
                    epochs=100)  # 設定訓練的迭代次數為 100 次

# 保存模型權重
model.save_weights("model_ImageDataGenerator_myImage.weights.h5")

# 測試模型
score = model.evaluate(x_test, y_test2, batch_size=128)
# 輸出結果
print("score:", score)

# 進行預測
predict = model.predict(x_test)
print("Ans:", np.argmax(predict[0]), np.argmax(predict[1]), np.argmax(predict[2]), np.argmax(predict[3]))

# 將預測結果轉為標籤類別
predict2 = np.argmax(predict, axis=1)
print("predict_classes:", predict2)
print("y_test", y_test[:])
for t1 in predict2:
    print(dirs[t1])

# 顯示測試影像及其預測結果
img = x_test[0]  # 取出第一張測試影像
img = img.reshape(h, w, 3)  # 重塑影像為原本形狀
img = img * 255  # 將歸一化的影像像素值還原
img = img.astype('uint8')  # 轉換資料型別為 unsigned 8-bit integer
img = cv2.resize(img, (224, 224), interpolation=cv2.INTER_AREA)  # 調整影像大小
im_bgr = cv2.cvtColor(img, cv2.COLOR_RGB2BGR)  # 將影像從 RGB 轉換回 BGR 格式（OpenCV 使用 BGR）
i = np.argmax(predict[0])  # 獲取預測結果的最大值索引
str1 = dirs[i] + "   " + str(predict[0][i])  # 組合顯示文字
print(str1)
im_bgr = cv2.putText(im_bgr, str1, (10, 30), cv2.FONT_HERSHEY_SIMPLEX, 1, (255, 0, 0), 1, cv2.LINE_AA)  # 在影像上顯示文字
cv2.imshow('image', im_bgr)  # 顯示影像
cv2.imshow('image', im_bgr)  # 顯示影像窗口

cv2.waitKey(0)  # 等待鍵盤輸入，防止窗口自動關閉
cv2.destroyAllWindows()  # 關閉所有 OpenCV 窗口
```
```python=
#part2
#!/usr/bin/env python
# -*- coding=utf-8 -*-
__author__ = "柯博文老師 Powen Ko, www.powenko.com"

import numpy as np
import cv2
import os
import tensorflow as tf

# 定義影像所在的目錄路徑
IMAGEPATH = 'images'

# 獲取 IMAGEPATH 目錄下的所有子目錄名稱（每個子目錄代表一個類別）
dirs = os.listdir(IMAGEPATH)

# 設定影像高度和寬度
h = 224
w = 224

# 獲取分類數目，即子目錄的數量
category = len(dirs) 

# 建立模型
model = tf.keras.models.Sequential()
# 加入 2D 的 Convolution Layer，接著一層 ReLU 的 Activation 函數
model.add(tf.keras.layers.Conv2D(filters=32, kernel_size=(3, 3),
                 padding="same",
                 activation='relu',
                 input_shape=(h, w, 3)))
# 將多維度的輸出轉為一維
model.add(tf.keras.layers.Flatten())
# 加入全連接層，包含 50 個神經元，使用 ReLU 作為激活函數
model.add(tf.keras.layers.Dense(50, activation='relu'))
# 最後一層使用 softmax 激活函數進行分類，輸出單元數與分類數相同
model.add(tf.keras.layers.Dense(units=category,
    activation=tf.nn.softmax ))

# 設定學習率
learning_rate = 0.001
opt1 = tf.keras.optimizers.Adam(learning_rate=learning_rate)
# 編譯模型，使用 categorical_crossentropy 作為損失函數，評估指標為準確率
model.compile(
    optimizer=opt1,
    loss=tf.keras.losses.categorical_crossentropy,
    metrics=['accuracy'])

# 輸出模型摘要資訊
model.summary()

# 讀取已訓練的權重
model.load_weights("model_ImageDataGenerator_myImage.weights.h5") 

# 定義 CNN 模型的預測函數
def CNNPredict(img):
    # 調整影像大小為模型要求的大小
    resized = cv2.resize(img, (224, 224), interpolation=cv2.INTER_AREA)
    # 轉換影像顏色為 RGB
    image = cv2.cvtColor(resized, cv2.COLOR_BGR2RGB)
    # 重塑影像為符合模型輸入格式的四維陣列
    image = image.reshape((1, image.shape[0], image.shape[1], image.shape[2]))
    # 使用模型進行預測
    predict2 = model.predict(image)
    return predict2

# 初始化計數器與影像寬度
counter = 0
w2 = 640

# 定義調整面積閾值的函數
def update_area_threshold(val):
    global area_threshold
    area_threshold = val

# 定義調整 threshold 閾值的函數
def update_threshold(val):
    global threshold_value
    threshold_value = val

# 初始化 OpenCV 視訊捕捉裝置
cap = cv2.VideoCapture(0)

# 建立 OpenCV 視窗與 trackbar
cv2.namedWindow('Objects Detected')
cv2.createTrackbar('Area Threshold', 'Objects Detected', 2000, 40000, update_area_threshold)
cv2.createTrackbar('Threshold', 'Objects Detected', 0, 255, update_threshold)

# 初始化閾值
area_threshold = 2236
threshold_value = 46

while(True):
    # 讀取攝影機畫面
    ret, rawImage = cap.read()
    if ret == True:
        # 調整影像大小，保持寬度為 w2，且保持比例
        resize = cv2.resize(rawImage, (w2, int(rawImage.shape[0] * w2 / rawImage.shape[1])), interpolation=cv2.INTER_AREA)
        # 將影像從 BGR 轉為 HSV 色彩空間
        hsv = cv2.cvtColor(resize, cv2.COLOR_BGR2HSV)
        # 分割 HSV 影像的色調、飽和度與明度
        hue, saturation, value = cv2.split(hsv)
        # 進行二值化處理，使用 OTSU 方法自動決定最佳 threshold
        retval, thresholded = cv2.threshold(saturation, threshold_value, 255, cv2.THRESH_BINARY + cv2.THRESH_OTSU)
        cv2.imshow('thresholded', thresholded)
        # 使用中值濾波來去除噪點
        medianFiltered = cv2.medianBlur(thresholded, 5)
        # 找出影像中的輪廓
        contours, hierarchy = cv2.findContours(medianFiltered, cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE)

        contour_list = []
        # 遍歷所有輪廓，並將面積大於指定值的輪廓加入列表
        for contour in contours:
            area = cv2.contourArea(contour)
            if area > area_threshold:
                contour_list.append(contour)

        # 遍歷符合條件的輪廓，進行影像分類預測
        for contour1 in contour_list:
            contour_list_x = []
            contour_list_y = []
            # 取得輪廓的所有座標點
            for xy in contour1:
                contour_list_x.append(xy[0][0])
                contour_list_y.append(xy[0][1])

            # 找出輪廓的最小與最大座標點
            x = x1 = min(contour_list_x)
            y = y1 = min(contour_list_y)
            x2 = max(contour_list_x)
            y2 = max(contour_list_y)
            
            # 使用模型進行預測
            predict = CNNPredict(resize[y1:y2, x1:x2, :].copy())
            
            # 畫出預測框
            cv2.rectangle(resize, (x1, y1), (x2, y2), (0, 255, 0), 1)
            # 獲得預測結果
            i = np.argmax(predict[0])
            # 組合顯示文字，包括類別名稱、預測機率與面積
            str1 = dirs[i] + " ," + str(predict[0][i]) + " , " + str(cv2.contourArea(contour1))
            # 顯示預測結果文字
            cv2.putText(resize, str(str1), (x, y), cv2.FONT_HERSHEY_SIMPLEX, 1, (255, 0, 0))
        
        # 畫出所有符合條件的輪廓
        cv2.drawContours(resize, contour_list,  -1, (255, 0, 0), 2)
        
        # 顯示處理後的影像
        cv2.imshow('Objects Detected', resize)
        
        # 偵測按鍵，如果按下 'q' 或 'Esc' 鍵，則退出循環
        key = cv2.waitKey(10)
        if key & 0xFF == ord('q') or key == 27:
            break

# 釋放攝影機並關閉所有視窗
cap.release()
cv2.destroyAllWindows()

```

### YOLO

> 先介紹opencv 的 haar cascades
> 進行局部人臉辨識

![image](https://hackmd.io/_uploads/ry4yOX7jA.png)
```python=
#v1
import numpy as np
import cv2

face_cascade = cv2.CascadeClassifier('C:\\03-haar\\haarcascades/haarcascade_frontalface_default.xml') #讀取權重檔


url="http://172.19.106.80:4747/video"
cap = cv2.VideoCapture(url)
while(True):
    k=cv2.waitKey(1)
    if k==27 or k == ord('q'):   # 離開迴圈
        break
    ret, img = cap.read()
    if img is not None:
        img = cv2.resize(img, (640,480), interpolation = cv2.INTER_AREA)# 調整圖片大小
        gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)           # 彩色轉灰階
        faces = face_cascade.detectMultiScale(gray, scaleFactor=1.1, minNeighbors=3, minSize=(100, 100), flags=cv2.CASCADE_SCALE_IMAGE)   # 找物件

        for (x, y, w, h) in faces:   # 位置
            img = cv2.rectangle(img, (x, y), (x + w, y + h), (255, 0, 0), 2)  # 圈出臉的位置

        cv2.imshow('img',img)

cap.release()
cv2.destroyAllWindows()
```

```python=
#v2
import numpy as np
import cv2
import datetime
import os
import time

# 讀取權重檔
cascade_path = 'C:\\opencv/haarcascade_frontalface_default.xml'
face_cascade = cv2.CascadeClassifier(cascade_path)

# 照片存檔路徑與權重檔案相同
save_directory = os.path.dirname(cascade_path)

# 開啟攝影機
cap = cv2.VideoCapture(0)

# 是否開始連續拍照的旗標
save_face = False

while(True):
    k = cv2.waitKey(1)
    if k == 27 or k == ord('q'):   # 按下ESC或q鍵離開迴圈
        break
    elif k == ord('s'):   # 按下s鍵後開始連續拍照
        save_face = True
    
    ret, img = cap.read()
    if img is not None:
        img = cv2.resize(img, (640, 480), interpolation=cv2.INTER_AREA) # 調整圖片大小
        gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)  # 彩色轉灰階
        faces = face_cascade.detectMultiScale(
            gray, 
            scaleFactor=1.05,  # 調整縮放係數，更細緻地檢測較小臉部
            minNeighbors=3, 
            minSize=(50, 50),  # 調整最小臉部大小以便檢測嬰兒臉部
            flags=cv2.CASCADE_SCALE_IMAGE
        )   # 偵測臉部

        for (x, y, w, h) in faces:   # 取得臉部位置
            img = cv2.rectangle(img, (x, y), (x + w, y + h), (255, 0, 0), 2)  # 圈出臉的位置

            if save_face:
                # 取得臉部區域
                face_img = img[y:y+h, x:x+w]

                # 取得當前日期和時間，包括毫秒
                timestamp = datetime.datetime.now().strftime("%Y%m%d_%H%M%S_%f")

                # 設定檔名並存檔到權重檔案相同路徑
                filename = os.path.join(save_directory, f"face_{timestamp}.png")
                cv2.imwrite(filename, face_img)
                print(f"圖片已存檔為: {filename}")

                # 每秒拍攝一張
                time.sleep(1)

        # 顯示圖片
        cv2.imshow('img', img)

# 釋放攝影機資源並關閉視窗
cap.release()
cv2.destroyAllWindows()

```

### 專題做法
1. 先拍照透過haar抓臉，
2. 丟CNN訓練
3. 得到權重檔後，
4. 再透過haar 拍照抓臉，丟比對



> 用google colab執行人家的權重 與設定檔


### VOC

一個XML + JPG檔案

![image](https://hackmd.io/_uploads/HyT9VMVoC.png)


因為在做標籤時使用VOC，所以要將VOC型態轉yolo需要的型態
![image](https://hackmd.io/_uploads/H1pfqGEj0.png)

如果檔案有問題可以刪除或是修檔案
![image](https://hackmd.io/_uploads/SkjbpzNjC.png)

如果準度不理想可以調整這裡(訓練次數)
![image](https://hackmd.io/_uploads/BkH4kQ4oC.png)

訓練完後最值錢的權重檔案
![image](https://hackmd.io/_uploads/HyLcemVi0.png)

![image](https://hackmd.io/_uploads/B1b_DQNjR.png)
