ラズベリーパイでAIを使った顔識別

この動画で紹介されていることを実践してみました。
https://www.youtube.com/watch?v=9P-Hq8Dh1R0

ホントは、git cloneしてinstallOpenCV.shを実行して3時間待って、顔撮影して、学習させて、画像認識実行すれば完了できますが、うまくいかなかったのでその際の手順を書きます。

2つのラズパイで試しましたが1台はうまくいって、もう1台はうまくいかなかったです。


## 環境
ラズパイ4B+
ノートパソコン(ラズパイリモート用)

## ラズパイセットアップ VNCリモート設定まで。
https://qiita.com/arisaEN/items/476399577755da1fcd86

## プログラムをダウンロード
コンソールから実行してください。
```
git clone https://github.com/kotamorishi/installOpenCV
```
Cドライブ直下にダウンロードされるはず？
installOpenCV.shを実行
```
cd /home/pcmainte/installOpenCV
```
```
./installOpenCV.sh
```
※OpenCVとその他がインストールされます。2,3時間かかります。]

## カメラを有効化
```
vcgencmd get_camera
```

全部0なら無効になってる
```
sudo nano /boot/firmware/config.txt
```
```
rlay=dwc2,dr_mode=host
 [all] 
start_x=1 gpu_mem=128

sudo reboot

vcgencmd get_camera
```
この通り編集してください。
もう一度カメラ有効か確認して、
1,0,1ならOK

## 顔写真撮影プログラム実行
※自分の場合うまくいかなかったので次を試しました。

ライブラリインストール
```
sudo apt update
sudo apt install libgtk2.0-dev pkg-config
cd /home/arisa2/installOpenCV/OpenCV
mkdir build
cd build
cmake -D CMAKE_BUILD_TYPE=Release -D
make -j$(nproc)
sudo make install
```

```
sudo apt install python3-libcamera python3-picamera2
```

headshots.pyのプログラム修正
```
from picamera2 import Picamera2	
import os	
import cv2	
	
name = input("Type your name: ")	
try:	
    userDirPath = "dataset/" + name	
    os.mkdir(userDirPath)	
except:	
    print("Datasets are already exists. ")	
    sys.exit()	
	
picam2 = Picamera2()	
picam2.start()	
	
cv2.namedWindow("press space to take a photo", cv2.WINDOW_NORMAL)	
cv2.resizeWindow("press space to take a photo", 500, 300)	
	
img_counter = 0	
	
while True:	
    frame = picam2.capture_array()	
	
    cv2.imshow("press space to take a photo", frame)	
	
    k = cv2.waitKey(1)	
    if k % 256 == 27:	
        print("Escape hit, closing...")	
        break	
    elif k % 256 == 32:	
        img_name = "dataset/" + name + "/image_{}.jpg".format(img_counter)	
        cv2.imwrite(img_name, frame)	
        print("{} written!".format(img_name))	
        img_counter += 1	
	
cv2.destroyAllWindows()	

```
スペースボタンで撮影

## 撮影した写真をAIが学習
またライブラリが足りないそうなのでインストール
```
sudo pip install imutils --break-system-packages

sudo apt-get update
sudo apt-get install build-essential cmake libopenblas-dev liblapack-dev libx11-dev libgtk-3-dev

sudo pip install dlib --break-system-packages

sudo pip install face_recognition --break-system-packages

```

実行
train_model.py

## 画像認識プログラム実行
facial_req.py
プレビュー画面開けなかったのでプログラム修正
```
from picamera2 import Picamera2						
from imutils.video import FPS						
import face_recognition						
import imutils						
import pickle						
import cv2						
import time						
						
# Initialize 'currentname' to trigger only when a new person is identified.						
currentname = "unknown"						
# Load face encodings and Haar cascade						
encodingsP = "encodings.pickle"						
cascade = "haarcascade_frontalface_default.xml"						
						
# Load the known faces and embeddings along with OpenCV's Haar cascade for face detection						
print("[INFO] loading encodings + face detector...")						
data = pickle.loads(open(encodingsP, "rb").read())						
detector = cv2.CascadeClassifier(cascade)						
						
# Initialize Picamera2 and allow the camera sensor to warm up						
print("[INFO] starting video stream...")						
picam2 = Picamera2()  # 修正: Picamera2を使用						
picam2.start()						
						
time.sleep(2.0)  # Let the camera warm up						
						
# Start the FPS counter						
fps = FPS().start()						
						
# Loop over frames from the video stream						
while True:						
    # Capture frame from Picamera2						
    frame = picam2.capture_array()						
    						
    if frame is None:						
        print("Error: Failed to grab frame.")						
        break						
						
    # Resize the frame for faster processing						
    frame = imutils.resize(frame, width=500)						
						
    # Convert the frame to grayscale (for face detection) and RGB (for face recognition)						
    gray = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)						
    rgb = cv2.cvtColor(frame, cv2.COLOR_BGR2RGB)						
						
    # Detect faces in the grayscale frame						
    rects = detector.detectMultiScale(gray, scaleFactor=1.1, minNeighbors=5, minSize=(30, 30),						
                                      flags=cv2.CASCADE_SCALE_IMAGE)						
						
    # Convert bounding box coordinates from (x, y, w, h) to (top, right, bottom, left) order						
    boxes = [(y, x + w, y + h, x) for (x, y, w, h) in rects]						
						
    # Compute facial embeddings for each face bounding box						
    encodings = face_recognition.face_encodings(rgb, boxes)						
    names = []						
						
    # Loop over the facial encodings						
    for encoding in encodings:						
        # Attempt to match each face in the input image to our known encodings						
        matches = face_recognition.compare_faces(data["encodings"], encoding)						
        name = "Unknown"						
						
        # Check if a match was found						
        if True in matches:						
            matchedIdxs = [i for (i, b) in enumerate(matches) if b]						
            counts = {}						
						
            # Count each recognized face						
            for i in matchedIdxs:						
                name = data["names"][i]						
                counts[name] = counts.get(name, 0) + 1						
						
            # Determine the recognized face with the largest number of votes						
            name = max(counts, key=counts.get)						
						
            # If a new person is identified, print their name						
            if currentname != name:						
                currentname = name						
                print(currentname)						
						
        names.append(name)						
						
    # Draw the bounding box and name for each recognized face						
    for ((top, right, bottom, left), name) in zip(boxes, names):						
        cv2.rectangle(frame, (left, top), (right, bottom), (0, 255, 225), 2)						
        y = top - 15 if top - 15 > 15 else top + 15						
        cv2.putText(frame, name, (left, y), cv2.FONT_HERSHEY_SIMPLEX, .8, (0, 255, 255), 2)						
						
    # Display the output frame						
    cv2.imshow("Facial Recognition is Running", frame)						
    key = cv2.waitKey(1) & 0xFF						
						
    # Break the loop if 'q' is pressed						
    if key == ord("q"):						
        break						
						
    # Update the FPS counter						
    fps.update()						
						
# Stop the FPS counter and display information						
fps.stop()						
print("[INFO] elapsed time: {:.2f}".format(fps.elapsed()))						
print("[INFO] approx. FPS: {:.2f}".format(fps.fps()))						
						
# Cleanup						
cv2.destroyAllWindows()						
picam2.close()						

```

実行