영상인식
import cv2
import mediapipe as mp
import numpy as np
import random
import pygame
import serial # 라이브러리 불러오기
choice = ['rock', 'scissors', 'paper']
computer_selec = -1
def calculate_angle(a, b, c):
"""a, b, c는 각각 landmark의 좌표. b는 가운데 점."""
ba = np.array([a.x - b.x, a.y - b.y])
bc = np.array([c.x - b.x, c.y - b.y])
cosine_angle = np.dot(ba, bc) / (np.linalg.norm(ba) * np.linalg.norm(bc))
angle = np.arccos(cosine_angle)
return np.degrees(angle)
def get_random_choice():
computer_selec = random.randint(0,2)
return choice[computer_selec]
def play_game():
global uart
# Pygame 초기화 및 MP3 파일 재생
pygame.mixer.init()
pygame.mixer.music.load('가위바위보.mp3')
pygame.mixer.music.play()
# MP3 파일 재생이 끝날 때까지 대기
while pygame.mixer.music.get_busy():
continue
computer_choice = get_random_choice()
send_data = ''
while True:
ret, frame = cap.read()
if not ret:
break
frame = cv2.flip(frame, 1)
image = cv2.cvtColor(frame, cv2.COLOR_BGR2RGB)
results = hands.process(image)
user_choice = None
if results.multi_hand_landmarks:
folding = ""
angle_list=[]
for hand_landmarks in results.multi_hand_landmarks:
h1 = hand_landmarks.landmark
mp_drawing.draw_landmarks(
frame, hand_landmarks, mp_hands.HAND_CONNECTIONS, circle_style, line_style)
for mcp, dip, tip in compare:
angle = abs(calculate_angle(h1[mcp], h1[dip], h1[tip]))
angle_list.append(angle)
folding += "01"[angle > 140] # 각도가 140도보다 크면 손가락을 폈다.
#print( folding)
#print( angle_list[0], angle_list[1], angle_list[2], angle_list[3], angle_list[4])
cv2.putText( frame, folding, (50,50), cv2.FONT_HERSHEY_SCRIPT_SIMPLEX, 1, (0,0,0), 2)
# 가위바위보 판정
if folding == "00000" or folding == "10000":
user_choice = 'rock'
elif folding == "11111":
user_choice = 'paper'
elif folding == "01000" or folding == "01100" or folding == "11000" or folding == "11100":
user_choice = 'scissors'
else:
user_choice = 'none'
if user_choice:
cv2.putText(frame, f"User: {user_choice}", (50, 100), cv2.FONT_HERSHEY_SIMPLEX, 1, (0, 0, 0), 2)
cv2.putText(frame, f"Computer: {computer_choice}", (50, 150), cv2.FONT_HERSHEY_SIMPLEX, 1, (0, 0, 0), 2)
# 컴퓨터 선택 이미지 표시
comp_img = computer_images[computer_choice]
if comp_img is not None:
comp_img = cv2.resize(comp_img, (200, 200)) # 이미지 크기 조정
frame[50:250, -250:-50] = comp_img # 화면에 이미지 표시
if send_data == '':
# 부저 소리 재생
if computer_choice == user_choice:
send_data = 'd'
elif (user_choice == 'rock' and computer_choice == 'scissors') or \
(user_choice == 'paper' and computer_choice == 'rock') or \
(user_choice == 'scissors' and computer_choice == 'paper'):
send_data = 'w'
else:
send_data = 'l'
uart.write(bytes(send_data,'utf8'))
#win_selec = choice[(computer_selec+1)%3]
#if send_data == '':
# if computer_choice == user_choice:
# send_data = 'd'
# elif user_choice == win_selec:
# send_data = 'l'
# else:
# send_data = 'w'
# uart.write(bytes(send_data,'utf8'))
cv2.putText(frame, f"send_data: {send_data}", (50, 200), cv2.FONT_HERSHEY_SIMPLEX, 1, (0, 0, 0), 2)
cv2.imshow('Hand Tracking', frame)
key = cv2.waitKey(1)
if key == 27: # 27 == 'ESC'
break
elif key == ord('r'): # 'r' 키를 눌러 게임을 다시 시작
return True
return False
# 시리얼 통신을 위한 인스턴스 생성
uart = serial.Serial("COM4",115200)
# Mediapipe 설정
mp_hands = mp.solutions.hands
mp_drawing = mp.solutions.drawing_utils
hands = mp_hands.Hands(max_num_hands=1)
line_style = mp_drawing.DrawingSpec(
color=(166, 151, 18),
thickness=5
)
circle_style = mp_drawing.DrawingSpec(
color=(166, 115, 31),
thickness=2,
circle_radius=5
)
# 비디오 캡처 설정
cap = cv2.VideoCapture(0)
cap.set(cv2.CAP_PROP_FRAME_WIDTH, 1080)
cap.set(cv2.CAP_PROP_FRAME_HEIGHT, 720)
width = cap.get(cv2.CAP_PROP_FRAME_WIDTH)
height = cap.get(cv2.CAP_PROP_FRAME_HEIGHT)
# 엄지손가락을 제외한 네 개의 손가락 비교
compare = [(2, 3, 4), (5, 6, 8), (9, 11, 12), (13, 15, 16), (17, 19, 20)]
# 컴퓨터의 선택 이미지 불러오기
computer_images = {
'rock': cv2.imread('rock.png'),
'paper': cv2.imread('paper.png'),
'scissors': cv2.imread('scissors.png')
}
# 값 보내기
uart.write(bytes('s','utf8'))
while True:
if not play_game():
break
cap.release()
cv2.destroyAllWindows()
보드
# UART 모듈 불러오기
from machine import Pin, UART
from neopixel import NeoPixel
from time import sleep
import random
from buzzer import *
# UART 시리얼 통신 인스턴스 생성 및 시작
# tx와 rx가 각각 1번, 3번 핀
uart=UART(2, baudrate=115200, tx=17, rx=16)
uart.init()
NUM_OF_LED=16
np=NeoPixel(Pin(18),NUM_OF_LED)
# 부저 설정
bu = BUZZER(2)
# 각 결과에 따른 멜로디
win_melody = [C4, D4, E4, F4, G4, A4, B4, C5]
lose_melody = [C5, B4, A4, G4, F4, E4, D4, C4]
draw_melody = [G4, G4, G4, G4, G4, G4, G4, G4]
def start():
bu.play(draw_melody, 100)
for i in range(16):
np[i]=(0,0,0)
np.write()
def win():
bu.play(win_melody, 100)
for i in range(16):
np[(i-2)%16]=(0,0,0)
np[(i-1)%16]=(0,0,0)
np[(i)%16]=(random.randint(1, 255),random.randint(1, 255),random.randint(1, 255))
np[(i+1)%16]=(random.randint(1, 255),random.randint(1, 255),random.randint(1, 255))
np[(i+2)%16]=(random.randint(1, 255),random.randint(1, 255),random.randint(1, 255))
np.write()
sleep(0.05)
for i in range(16):
np[i]=(0,0,0)
np.write()
def lose():
bu.play(lose_melody, 100)
for i in range(16):
np[i]=(255,0,0)
np.write()
sleep(1)
for i in range(16):
np[i]=(0,0,0)
np.write()
def draw():
bu.play(draw_melody, 100)
for i in range(16):
np[i]=(0,255,0)
np.write()
sleep(1)
for i in range(16):
np[i]=(0,0,0)
np.write()
# UART로부터 값을 읽는 함수
def uart_receive():
# 앞에서 정의한 uart 변수 사용
global uart
# uart로부터 받는 신호가 포착되면
if uart.any():
# 그 줄을 읽어서
data = uart.readline()
data = data.decode('ascii').rstrip()
# 바이트 값을 ascii코드로 해석
# rstrip: 줄의 오른쪽 끝의 줄바꿈, 띄어쓰기 제거
# 읽어낸 값을 내보냄
print(data)
return data
# 포착된 신호가 없다면 None을 내보
return None
# 계속 반복
while 1:
# uart 통신으로 데이터 받기
# 전화기를 귀에 대고 있어야 들리는 것과 같음
# 지속적으로 값을 받아야함
data = uart_receive()
# 그 데이터가 각각 r,g,b값에 해당하면 해당 LED 색 켜기
if data:
print(data)
if data == 's':
start()
elif data == 'w':
win()
elif data == 'd':
draw()
elif data == 'l':
lose()
'작업 > python opencv, mediapipe & micro python' 카테고리의 다른 글
| 마이크로파이썬 실행 예제 (0) | 2024.07.31 |
|---|---|
| 마이크로 파이썬 개발 환경 설치 (0) | 2024.07.31 |
| face mesh (0) | 2024.07.30 |
| 코끝으로 마우스 제어 (0) | 2024.07.30 |
| pyautogui (0) | 2024.07.30 |