Capstone Project(Finger Count)

박광욱·2023년 2월 14일
0

Computer Vision

목록 보기
8/8

📕 캡스톤 프로젝트

  • 캡스톤 프로젝트란 일반적으로 고등학교 또는 중학교 마지막 학년, 학력 프로그램 또는 학습 경로 말기에 학생들에게 최고의 학업 및 지적 경험 역할을 하는 다면 과제이다.
  • 이 강의를 수강하면서 배운 내용들을 총 동원하여 손가락의 개수를 셀 수있는 프로그램을 만드는 것이 목표이다.

Finger Count

import cv2
import numpy as np
from sklearn.metrics import pairwise  # 손가락의 거리를 계산해 몇개인지 확인

#################################
######## Global Variance ########
#################################

background = None			# 배경이 인식 되었는지 확인
accumulated_weight = 0.5	# 누적 weight
roi_top = 100				# 관심을 두려는 픽셀 값
roi_bottom = 300			#		  ''
roi_right = 300				#         ''
roi_left = 600				#         ''

#################################
########## Function #############
#################################

# 처음엔 전체 배경 값을 가져온다.
def calc_accum_avg(frame, accumulated_weight):
    
    global background
    
    if background is None:	# 배경 값이 없다면 (초기 상태)
        background = frame.copy().astype('float')	# 처음 화면을 가져옴
        return None
    
    cv2.accumulateWeighted(frame, background, accumulated_weight)	# 현재 화면과 배경에 대해 누적 합을 구해준다.
    
    
# 손을 배경이랑 구분해줌.
def segment(frame, threshold_min=25):
    
    diff = cv2.absdiff(background.astype('uint8'), frame)	# 배경과의 차이 구함
    
    ret, thresholded = cv2.threshold(diff, threshold_min, 255, cv2.THRESH_BINARY)	# 설정한 threshold랑 비교하여 픽셀 값들을 재조정해줌.
    
    image, contours, hierarchy = cv2.findContours(thresholded.copy(), cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)	# 외부 윤곽에 관심을 둠.
    
    if len(contours) == 0:	# 윤곽을 못 잡았다는 예외처리
        return None
    
    else:
        # 관심 영역의 가장 큰 외부 윤곽이 손이라고 가정함
        hand_segment = max(contours, key=cv2.contourArea)
        
        return (thresholded, hand_segment)
        

# 손가락을 count
def count_fingers(thresholded, hand_segment):
    
    conv_hull = cv2.convexHull(hand_segment)
    
    # 극단의 점을 찾아냄.
    top = tuple(conv_hull[conv_hull[:,:,1].argmin()[0]])
    bottom = tuple(conv_hull[conv_hull[:, :, 1].argmax()][0])    
    left   = tuple(conv_hull[conv_hull[:, :, 0].argmin()][0])    
    right  = tuple(conv_hull[conv_hull[:, :, 0].argmax()][0])    
    
    # 중앙 값
    cX = (left[0] + right[0]) // 2
    cY = (top[1] + bottom[1]) // 2
    
    distance = pairwise.euclidean_distances([cX, cY], Y=[left,right,top,bottom])[0] 	# 상단 및 하단의 거리 계산
    
    # 최고 길이의 90퍼센트를 봐서 손의 모양을 파악할 수 있다
    max_distance = distance.max()
    
    radius = int(0.9 * max_distance)
    circumfrence = (2 * np.pi * radius)
    
    # 관심 영역을 원을 그려준다
    circular_roi = np.zeros(thresholded[:2], dtype='uint8')
    
    cv2.circle(circular_roi, (cX,cY), radius, 255, 10)
    
    circular_roi = cv2.bitwise_and(thresholded, thresholded, mask=circular_roi)
    
    iamge, contours, hierarchy = cv2.findContours(circular_roi.copy(), cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_NONE)
    
    count = 0	# 손가락을 펼치지 않은 상태
    
    for cnt in contours:
        
        (x, y, w, h) = cv2.boundingRect(cnt)
        
        out_of_wrist = (cY + (cY * 0.25)) > (y + h)
        
        limit_points = ((circumfrence * 0.25) > cnt.shape[0])
        
        if out_of_wrist and limit_points:
            count += 1
            
    return count
    
    
#################################
#### Count Finger On Camera #####
#################################

cam = cv2.VideoCapture(0)	# 내부 카메라 연결

num_frames = 0

while True:
    
    ret, frame = cam.read()
    
    frame_copy = frame.copy()
    
    roi = frame[roi_top:roi_bottom, roi_right:roi_left]
    
    gray = cv2.cvtColor(roi, cv2.COLOR_BGR2GRAY)
    
    gray = cv2.GaussianBlur(gray, (7,7), 0)
    
    # frame의 수가 60이 넘어갈 때까지 배경의 누적합 계산해줌
    if num_frames < 60:
        calc_accum_avg(gray, accumulated_weight)
        
        if num_frames <= 59:
            cv2.putText(frame_copy, 'WAIT, GETTING BACKGROUND', (200, 300), cv2.FONT_HERSHEY_SIMPLEX, 1, (0,0,255), 2)
            cv2.imshow('Finger Count', frame_copy)
    # 손가락의 개수를 세어 화면에 표시해 주는 부분
    else:
        hand = segment(gray)
        
        if hand is not None:
            thresholded, hand_segment = hand
            
            cv2.drawContours(frame_copy, [hand_segment+(roi_right, roi_top)], -1, (255,0,0), 5)
            
            fingers = count_fingers(thresholded, hand_segment)
            
            cv2.putText(frame_copy, str(fingers), (70, 50), cv2.FONT_HERSHEY_SIMPLEX, 1, (0,0,255), 2)
            
            cv2.imshow('Thresholded', thresholded)
            
    cv2.rectangle(frame_copy, (roi_left, roi_top), (roi_right, roi_bottom), (0,0,255), 5)
    
    num_frames += 1
    
    cv2.imshow('Finger Count', frame_copy)
    
    k = cv2.waitKey(1) & 0xFF
    
    if k == 27:
        break
        
cam.release()
cv2.destroyAllWindows()
    
profile
Vancouver

0개의 댓글