Skip to content

Commit

Permalink
ver0.1
Browse files Browse the repository at this point in the history
初期追加
  • Loading branch information
usamaru33 authored Jun 14, 2024
1 parent 96e4f8d commit b8e7e4f
Show file tree
Hide file tree
Showing 7 changed files with 375 additions and 0 deletions.
46 changes: 46 additions & 0 deletions EyeTrack_Netsurfing/Crap.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
import pyaudio
import numpy as np
import pyautogui

# 音声キャプチャの設定
CHUNK = 1024
FORMAT = pyaudio.paInt16
CHANNELS = 1
RATE = 44100
THRESHOLD = 2000 # 拍手の音量を検知するための閾値
CLAP_DURATION = 0.1 # 拍手の持続時間(秒)

def detect_clap(data):
"""音声データから拍手を検出する関数"""
audio_data = np.frombuffer(data, dtype=np.int16)
peak = np.max(np.abs(audio_data))

if peak > THRESHOLD:
return True
return False

# PyAudioの初期化
p = pyaudio.PyAudio()

# ストリームの開始
stream = p.open(format=FORMAT,
channels=CHANNELS,
rate=RATE,
input=True,
frames_per_buffer=CHUNK)

print("拍手を検知しています...")

try:
while True:
data = stream.read(CHUNK)
if detect_clap(data):
print("拍手を検知しました!")
pyautogui.click()
except KeyboardInterrupt:
print("終了します...")

# ストリームの停止と解放
stream.stop_stream()
stream.close()
p.terminate()
104 changes: 104 additions & 0 deletions EyeTrack_Netsurfing/EyeTrack.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,104 @@
import numpy as np
import dlib
import cv2
from cv2 import Mat
#顔の特徴点検出モデルの読み込み
face_detector = dlib.get_frontal_face_detector()
# Dlibの顔ランドマーク検出器モデルの読み込み
predictor = dlib.shape_predictor('shape_predictor_68_face_landmarks.dat')

#カメラの設定
cap = cv2.VideoCapture(0) # 0はデフォルトカメラ
ret, frame = cap.read()

#マスク色
bgr_black = (0, 0, 0) # BGR黒色
bgr_white = (255, 255, 255) # BGR白色

# 検出点の色定義
bgr_blue = (255, 0, 0)

# 点の座標を表すためのPointクラス
class Point:
def __init__(self, x, y):
self.x = x
self.y = y

@classmethod
def from_contour(cls, cnt):
# cnt が空の場合は None を返す
if len(cnt) == 0:
return None

# 輪郭の最小外接円の中心座標を取得
(x, y), radius = cv2.minEnclosingCircle(cnt)
center = cls(int(x), int(y))
return center

# 前回の目の座標を保持する (左目、右目)
get_contouring.prev_points = [None, None]

# 評価関数 (前回の座標からの距離が小さいほど高スコア)
def eval_contour(cnt, prev):
if prev is None:
return 0
return 1.0 / (cv2.pointPolygonTest(cnt, (prev.x, prev.y), True) + 1)

def get_one_face(gray_image: Mat) -> Mat | None:
faces = face_detector(gray_image)
if len(faces) == 0:
return None
face = faces[0]

return face

gray_frame = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)
face = get_one_face(gray_frame)

display = frame.copy()

if face is not None:
landmarks = predictor(gray_frame, face) # 特徴点を表す座標のlist(len=68)

def extract_eyes(frame: Mat, lps: list[Point], rps: list[Point]) -> Mat:
# make mask with eyes white and other black
mask = np.zeros(frame.shape[:2], dtype=np.uint8)
mask = make_hole_on_mask(mask, lps)
mask = make_hole_on_mask(mask, rps)
mask = cv2.dilate(mask, np.ones((9, 9), np.uint8), 5)

# attach mask on frame
masked_frame = cv2.bitwise_and(frame, frame, mask=mask)
masked_area = (masked_frame == bgr_black).all(axis=2)
masked_frame[masked_area] = bgr_white
return masked_frame # 目以外が白塗りされた画像


# 目の輪郭を検知して円を描画する関数
def get_contouring(
thresh, face_mid_y, frame=None, is_right: bool = False
) -> Point | None:
index = int(is_right)
cnts, _ = cv2.findContours(
thresh, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_NONE
)
try:
cnt = max(
cnts,
key=lambda cnt: eval_contour(
cnt, get_contouring.prev_points[index]
),
)
c = Point.from_contour(cnt)
if c is None:
raise ValueError("point is Null.")
if is_right:
c.x += face_mid_y
get_contouring.prev_points[index] = c
if frame is not None:
cv2.circle(frame, (c.x, c.y), 2, bgr_blue, 2)
return Point(c.x, c.y)
except ValueError:
pass
except ZeroDivisionError:
pass
9 changes: 9 additions & 0 deletions EyeTrack_Netsurfing/cli.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
import cv2
threshold = 30
_, thresh = cv2.threshold(
eyes_frame_gray, threshold, 255, cv2.THRESH_BINARY
)
thresh_erode = cv2.erode(thresh, None, iterations=2)
thresh_dilate = cv2.dilate(thresh_erode, None, iterations=4)
thresh_blur = cv2.medianBlur(thresh_dilate, 3)
thresh_inv = cv2.bitwise_not(thresh_blur)
47 changes: 47 additions & 0 deletions EyeTrack_Netsurfing/eye_detect.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
import cv2
import numpy as np
import dlib

predictor = dlib.shape_predictor("shape_predictor_68_face_landmarks.dat")

def extract_eyes(frame, lps, rps):
mask = np.zeros(frame.shape[:2], dtype=np.uint8)
if lps:
mask = make_hole_on_mask(mask, lps)
if rps:
mask = make_hole_on_mask(mask, rps)
mask = cv2.dilate(mask, np.ones((9, 9), np.uint8), 5)
masked_frame = cv2.bitwise_and(frame, frame, mask=mask)
masked_area = (masked_frame == [0, 0, 0]).all(axis=2)
masked_frame[masked_area] = [255, 255, 255]
return masked_frame

def make_hole_on_mask(mask, points):
points = np.array(points, dtype=np.int32)
cv2.fillPoly(mask, [points], 255)
return mask

def get_eye_center(points):
n = len(points)
if n == 0:
raise ValueError("List has no item.")
sum_point = np.sum(points, axis=0)
return sum_point // n

def get_eye_contours(thresh, face_mid_y, frame=None, is_right=False):
cnts, _ = cv2.findContours(thresh, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_NONE)
try:
cnt = max(cnts, key=cv2.contourArea)
M = cv2.moments(cnt)
cX = int(M['m10'] / M['m00'])
cY = int(M['m01'] / M['m00'])
if is_right:
cX += face_mid_y
if frame is not None:
cv2.circle(frame, (cX, cY), 2, (255, 0, 0), 2)
return (cX, cY)
except ValueError:
pass
except ZeroDivisionError:
pass
return None
9 changes: 9 additions & 0 deletions EyeTrack_Netsurfing/face_detect.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
import dlib

face_detector = dlib.get_frontal_face_detector()

def get_one_face(gray_image):
faces = face_detector(gray_image)
if len(faces) == 0:
return None
return faces[0]
80 changes: 80 additions & 0 deletions EyeTrack_Netsurfing/main.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
import cv2
import numpy as np
from pynput.mouse import Controller
from face_detect import get_one_face
from eye_detect import extract_eyes, get_eye_center, get_eye_contours
import dlib
import logging

# ログ設定
logging.basicConfig(level=logging.INFO)

# dlibの顔特徴点検出器を初期化
predictor = dlib.shape_predictor("shape_predictor_68_face_landmarks.dat")

# マウスコントローラーの初期化
mouse = Controller()

def scroll_based_on_eye_position(eye_center, frame_center):
"""
黒目の中心位置に基づいてスクロールを実行する関数
"""
diff_x = eye_center[0] - frame_center[0]
if diff_x > 15:
mouse.scroll(0, -1) # 下方向にスクロール
elif diff_x < -15:
mouse.scroll(0, 1) # 上方向にスクロール

def main():
"""
メイン関数:カメラから映像を取得し、黒目の位置を検出してスクロール操作を行う
"""
cap = cv2.VideoCapture(0) # カメラのキャプチャを開始
while True:
ret, frame = cap.read() # フレームをキャプチャ
if not ret:
break

gray_frame = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY) # フレームをグレースケールに変換
face = get_one_face(gray_frame) # 顔を検出
if face is not None:
# 顔のランドマーク(特徴点)を取得
landmarks = predictor(gray_frame, face)
left_eye_points = [(landmarks.part(i).x, landmarks.part(i).y) for i in range(36, 42)]

# 左目の部分を抽出
masked_frame = extract_eyes(frame, left_eye_points, None)
eyes_gray = cv2.cvtColor(masked_frame, cv2.COLOR_BGR2GRAY) # 再度グレースケールに変換

# 閾値処理
threshold = 50 # ここを調整して最適な値を見つける
_, thresh = cv2.threshold(eyes_gray, threshold, 255, cv2.THRESH_BINARY)
thresh = cv2.erode(thresh, None, iterations=2)
thresh = cv2.dilate(thresh, None, iterations=4)
thresh = cv2.medianBlur(thresh, 3)
thresh_inv = cv2.bitwise_not(thresh)

# 顔の中央のy座標を計算
face_mid_y = (face.left() + face.right()) // 2

# 左目の黒目の中心を検出
left_eye_center = get_eye_contours(thresh_inv, face_mid_y, frame, is_right=False)

if left_eye_center:
logging.info(f"Left eye center detected at: {left_eye_center}")
# 左目の黒目の中心を赤色で表示
cv2.circle(frame, left_eye_center, 2, (0, 0, 255), 2)

# フレームの中心を計算
frame_center = (frame.shape[1] // 2, frame.shape[0] // 2)
# スクロール操作を実行
scroll_based_on_eye_position(left_eye_center, frame_center)

cv2.imshow("Eye Tracking", frame) # フレームを表示
if cv2.waitKey(1) & 0xFF == ord('q'): # 'q'キーが押されたらループを終了
break
cap.release() # カメラのキャプチャを解放
cv2.destroyAllWindows() # すべてのOpenCVウィンドウを閉じる

if __name__ == "__main__":
main()
80 changes: 80 additions & 0 deletions EyeTrack_Netsurfing/main_right.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
import cv2
import numpy as np
from pynput.mouse import Controller
from face_detect import get_one_face
from eye_detect import extract_eyes, get_eye_center, get_eye_contours
import dlib
import logging

# ログ設定
logging.basicConfig(level=logging.INFO)

# dlibの顔特徴点検出器を初期化
predictor = dlib.shape_predictor("shape_predictor_68_face_landmarks.dat")

# マウスコントローラーの初期化
mouse = Controller()

def scroll_based_on_eye_position(eye_center, frame_center):
"""
黒目の中心位置に基づいてスクロールを実行する関数
"""
diff_x = eye_center[0] - frame_center[0]
if diff_x > 15:
mouse.scroll(0, -1) # 下方向にスクロール
elif diff_x < -15:
mouse.scroll(0, 1) # 上方向にスクロール

def main():
"""
メイン関数:カメラから映像を取得し、黒目の位置を検出してスクロール操作を行う
"""
cap = cv2.VideoCapture(0) # カメラのキャプチャを開始
while True:
ret, frame = cap.read() # フレームをキャプチャ
if not ret:
break

gray_frame = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY) # フレームをグレースケールに変換
face = get_one_face(gray_frame) # 顔を検出
if face is not None:
# 顔のランドマーク(特徴点)を取得
landmarks = predictor(gray_frame, face)
right_eye_points = [(landmarks.part(i).x, landmarks.part(i).y) for i in range(42, 48)]

# 右目の部分を抽出
masked_frame = extract_eyes(frame, [], right_eye_points)
eyes_gray = cv2.cvtColor(masked_frame, cv2.COLOR_BGR2GRAY) # 再度グレースケールに変換

# 閾値処理
threshold = 50 # ここを調整して最適な値を見つける
_, thresh = cv2.threshold(eyes_gray, threshold, 255, cv2.THRESH_BINARY)
thresh = cv2.erode(thresh, None, iterations=2)
thresh = cv2.dilate(thresh, None, iterations=4)
thresh = cv2.medianBlur(thresh, 3)
thresh_inv = cv2.bitwise_not(thresh)

# 顔の中央のy座標を計算
face_mid_y = (face.left() + face.right()) // 2

# 右目の黒目の中心を検出
right_eye_center = get_eye_contours(thresh_inv, face_mid_y, frame, is_right=True)

if right_eye_center:
logging.info(f"Right eye center detected at: {right_eye_center}")
# 右目の黒目の中心を緑色で表示
cv2.circle(frame, right_eye_center, 2, (0, 255, 0), 2)

# フレームの中心を計算
frame_center = (frame.shape[1] // 2, frame.shape[0] // 2)
# スクロール操作を実行
scroll_based_on_eye_position(right_eye_center, frame_center)

cv2.imshow("Eye Tracking", frame) # フレームを表示
if cv2.waitKey(1) & 0xFF == ord('q'): # 'q'キーが押されたらループを終了
break
cap.release() # カメラのキャプチャを解放
cv2.destroyAllWindows() # すべてのOpenCVウィンドウを閉じる

if __name__ == "__main__":
main()

0 comments on commit b8e7e4f

Please sign in to comment.