본문 바로가기
Project

수화 인식 Project - [3일차] 손 인식하기(openCV)

by 배애앰이 좋아 2020. 2. 2.
반응형

1, 2일차는 openCV에 대해 공부 및 따로 게시글을 작성하지 않았습니다.

 

import cv2
import numpy as np

def cont():
    try:
        cap=cv2.VideoCapture(0)
    except:
        print('camera_errro')
        return

    while True:
        ret, frame = cap.read()
        
        if not ret:
            print('camera2_error')
            break

        dst = frame.copy()
        test = cv2.cvtColor(frame, cv2.COLOR_BGR2YCrCb)
        mask_hand = cv2.inRange(test, np.array([0,133,77]),np.array([255,173,127]))
        #test = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)
        ret, thr = cv2.threshold(mask_hand, 127, 255, cv2.THRESH_BINARY_INV)
        _, contours, hierachy=cv2.findContours(thr, cv2.RETR_CCOMP, cv2.CHAIN_APPROX_NONE)
        
        for i in contours:
            hull = cv2.convexHull(i,clockwise=True)
            cv2.drawContours(dst, [hull], 0, (0,0,255),2)
            
        cv2.imshow('dst', dst)
        cv2.imshow('mask_hand', mask_hand)

        k = cv2.waitKey(1) & 0xFF
        if k == 27:
            break
            
    cap.release()
    cv2.destroyAllWindows()
    
cont()

 

try ~ break 까지 비디오를 통해서 영상 가져오고 오류 검사

test = cv2.cvtColor(frame, cv2.COLOR_BGR2YCrCb) 에서는 해당 비디오를 BGR색상을 YCrCb 변환

mask_hand = cv2.inRange(test, np.array([0,133,77]),np.array([255,173,127])) 에서는 inRange로 ycrcb의 이미지를 해당 범위에 속하는 픽셀들만 masking한다. 즉 살색만 흰색을 만들고 그 나머지는 검은색으로 변환

ret, thr = cv2.threshold(mask_hand, 127, 255, cv2.THRESH_BINARY_INV) 관련 설명은 밑 사이트 참고

 

https://opencv-python.readthedocs.io/en/latest/doc/09.imageThresholding/imageThresholding.html

 

이미지 임계처리 — gramman 0.1 documentation

기본 임계처리 이진화 처리는 간단하지만, 쉽지 않은 문제를 가지고 있다. 이진화란 영상을 흑/백으로 분류하여 처리하는 것을 말합니다. 이때 기준이 되는 임계값을 어떻게 결정할 것인지가 중요한 문제가 됩니다. 임계값보다 크면 백, 작으면 흑이 됩니다. 기본 임계처리는 사용자가 고정된 임계값을 결정하고 그 결과를 보여주는 단순한 형태입니다. 이때 사용하는 함수가 cv2.threshold() 입니다. cv2.threshold(src, thresh, maxval

opencv-python.readthedocs.io

 

thr에 사진에 대한 정보가 들어가 있다.  cv2.imshow('thr', thr)를 하면 확인 가능하다.

 

 

하지만 ret, thr = cv2.threshold(mask_hand, 127, 255, cv2.THRESH_BINARY_INV) 를 빼고 적용시켜 본 결과 딱히 큰 차이 없는 듯 이 부분은 없어도 되는 거 같다.

_, contours, hierachy=cv2.findContours(mask_hand, cv2.RETR_CCOMP, cv2.CHAIN_APPROX_NONE) 에서 원래는 

images, contours, hierachy = cv2.findContours(image, mode, method)

  • image: 흑백이미지 또는 이진화된 이미지

  • mode : 컨투어를 찾는 방법

    • cv2.RETR_EXTERNAL: 컨투어 라인 중 가장 바깥쪽의 라인만 찾음

    • cv2.RETR_LIST: 모든 컨투어 라인을 찾지만, 상하구조(hierachy)관계를 구성하지 않음

    • cv2.RETR_CCOMP: 모든 컨투어 라인을 찾고, 상하구조는 2 단계로 구성함

    • cv2.RETR_TREE: 모든 컨투어 라인을 찾고, 모든 상하구조를 구성함

  • method : 컨투어를 찾을 때 사용하는 근사화 방법

    • cv2.CHAIN_APPROX_NONE: 모든 컨투어 포인트를 반환

    • cv2.CHAIN_APPROX_SIMPLE: 컨투어 라인을 그릴 수 있는 포인트만 반환

    • cv2.CHAIN_APPROX_TC89_L1: Teh_Chin 연결 근사 알고리즘 L1 버전을 적용하여 컨투어 포인트를 줄임

    • cv2.CHAIN_APPROX_TC89_KCOS: Teh_Chin 연결 근사 알고리즘 KCOS 버전을 적용하여 컨투어 포인트를 줄임

 

컨투어 정보는 컨투어를 구성하는 점들로 이루어진 배열의 리스트다.

출처 : https://datascienceschool.net/view-notebook/f9f8983941254a34bf0fee42c66c5539/

 

Data Science School

Data Science School is an open space!

datascienceschool.net

 

hull = cv2.convexHull(i,clockwise=True) 는 cv2.convexHull()를 활용해 윤곽선에서 블록 껍질을 검출합니다.

cv2.convexHull(윤곽선, 방향)을 의미합니다.

윤곽선은 윤곽선 검출 함수에서 반환되는 구조를 사용합니다.

방향은 검출된 볼록 껍질의 볼록점들의 인덱스 순서를 의미합니다.

블록 껍질 함수는 단일 형태에서만 검출이 가능합니다.

그러므로, 반복문을 활용해 단일 형태의 윤곽선 구조에서 블록 껍질을 검출합니다.

  • Tip : 윤곽선 구조는 윤곽선 검출 함수의 반환값과 형태가 동일하다면, 임의의 배열에서도 검출이 가능합니다.

  • Tip : 방향이 True라면 시계 방향, False라면 반시계 방향으로 정렬됩니다.

 

convexHull에 대한 알고리즘 참고 사이트 : https://hns17.tistory.com/entry/%EC%95%8C%EA%B3%A0%EB%A6%AC%EC%A6%98-ConvexHull-Grahams-Scan

 

알고리즘 : ConvexHull (Graham's Scan)

외곽선 찾기(ConvexHull) 알고리즘 1. 개요 2차원 평면에 N개의 점이 주어졌을 때, 이들 중 몇 개의 점을 골라 나머지 모든 점을 내부에 포함하는 다각형을 만든다. 이를 볼록 껍질(CONVEX HULL) 이라 한다. 아래..

hns17.tistory.com

https://www.crocus.co.kr/1288

 

컨벡스 헐 알고리즘(Convex Hull Algorithm)

목차 1. 컨벡스 헐 알고리즘(Convex Hull Algorithm)이란? 2. 컨벡스 헐 알고리즘(Convex Hull Algorithm) 동작 원리 3. 컨벡스 헐 알고리즘(Convex Hull Algorithm) 구현 4. 관련 문제 1. 컨벡스 헐 알고리즘(Con..

www.crocus.co.kr

 

만약 convexHull을 안 썼을 때 위 코드에서 일부를 밑처럼 수정

 

_, contours, hierachy=cv2.findContours(mask_hand, cv2.RETR_CCOMP, cv2.CHAIN_APPROX_NONE)
        
        for i in contours:
            #hull = cv2.convexHull(i,clockwise=True)
            cv2.drawContours(dst, [i], 0, (0,0,255),2)
            
        cv2.imshow('dst', dst)
        cv2.imshow('mask_hand', mask_hand)

 

해당 결과 : 라인이 다 그려짐

 

 

 

외곽선과 convexhull의 선이 겹치는 지점이 손가락 끝점이라 보고 찾을 수 있는데 아래 시도해본 코드

 

points1 = []
        
        for i in contours:
            M = cv2.moments(i, False)
            try:
                cx = int(M['m10']/M['m00'])
                cy = int(M['m01']/M['m00'])
            except ZeroDivisionError:
                print("ZeroDivision")

        contours = cv2.approxPolyDP(contours,0.02*cv2.arcLength(contours,True),True)
        hull = cv2.convexHull(contours[0])

        for point in hull:
            if cy > point[0][1]:
                  points1.append(tuple(point[0])) 

        cv2.drawContours(mask_hand, [hull], 0, (0,255,0), 2)
        for point in points1:
            cv.circle(mask_hand, tuple(point), 15, [ 0, 0, 0], -1)

 

손가락 끝 점 출력 코드라고 하는데 오류가  ZeroDivisionError 가 계속 난다. 실시간 동영상인 것이 아마 원인이지 않을까 싶다.

 

 _, contours, hierachy=cv2.findContours(mask_hand, cv2.RETR_CCOMP, cv2.CHAIN_APPROX_NONE)
        
        points1 = []
        result_cx = []
        result_cy = []
        
        for i in contours:
            M = cv2.moments(i)
            if M["m00"] != 0:
                cx = int(M["m10"] / M["m00"])
                cy = int(M["m01"] / M["m00"])
            else:
                # set values as what you need in the situation
                cX, cY = 0, 0
                
        for cnt in contours:
            approx = cv2.approxPolyDP(cnt,0.02*cv2.arcLength(cnt,True),True)
            #cv2.drawContours(dst, [approx], 0, (0,255,0), 3)
            hull = cv2.convexHull(approx)
            for point in hull:
                if cy > point[0][1]:
                      points1.append(tuple(point[0])) 
            cv2.drawContours(dst, [hull], 0, (0,0,255),2)
            
        for point in points1:
            cv2.circle(dst, tuple(point), 15, [255, 0, 0], -1)
            
            
        cv2.imshow('dst', dst)

 

코드 오류 안 나게 수정한 부분...

 

 

그럼에도 원이 표시되지만 이상하게 뜨네요. 아마 원인은 손만 나와야하는데 주변에 잡인식이 많아서 그런 것 같네요. 다음에는 일단 배경 정리부터 다시 해야할 듯 하네요.

밑에는 풀코드.. 주석처리도 많고 더럽네요 나중에 오류 해결하면 코드 정리해야겠어요ㅠ

 

import cv2
import numpy as np

def cont():
    try:
        cap=cv2.VideoCapture(0)
    except:
        print('camera_errro')
        return

    while True:
        ret, frame = cap.read()
        
        if not ret:
            print('camera2_error')
            break

        dst = frame.copy()
        #cv2.imshow('frame', frame)
        #gray = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)
        #gray = cv2.equalizeHist(gray)
        #rects = detect(gray, debug=False)

        #height,width = frame.shape[:2]

        #for x1, y1, x2, y2 in rects:
        #    cv.rectangle(frame, (x1-10, 0), (x2+10, height), (0,0,0), -1)
            
        #cv2.imshow('frame1', frame1)

        test = cv2.cvtColor(frame, cv2.COLOR_BGR2YCrCb)
        mask_hand = cv2.inRange(test, np.array([0,133,77]),np.array([255,173,127]))
        #cv2.imshow('mask_hand', mask_hand)
        #test = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)
        #ret, thr = cv2.threshold(mask_hand, 127, 255, cv2.THRESH_BINARY_INV)
        #cv2.imshow('thr', thr)
        
        _, contours, hierachy=cv2.findContours(mask_hand, cv2.RETR_CCOMP, cv2.CHAIN_APPROX_NONE)
        
        points1 = []
        result_cx = []
        result_cy = []
        
        for i in contours:
            M = cv2.moments(i)
            if M["m00"] != 0:
                cx = int(M["m10"] / M["m00"])
                cy = int(M["m01"] / M["m00"])
            else:
                # set values as what you need in the situation
                cX, cY = 0, 0
                
        for cnt in contours:
            approx = cv2.approxPolyDP(cnt,0.02*cv2.arcLength(cnt,True),True)
            #cv2.drawContours(dst, [approx], 0, (0,255,0), 3)
            hull = cv2.convexHull(approx)
            for point in hull:
                if cy > point[0][1]:
                      points1.append(tuple(point[0])) 
            cv2.drawContours(dst, [hull], 0, (0,0,255),2)
            
        for point in points1:
            cv2.circle(dst, tuple(point), 15, [255, 0, 0], -1)
            
        cv2.imshow('dst', dst)

        k = cv2.waitKey(1) & 0xFF
        if k == 27:
            break
            
    cap.release()
    cv2.destroyAllWindows()
    
cont()

 

그 밖에 참고 사이트 : https://webnautes.tistory.com/1378

 

OpenCV를 사용하여 손 검출 및 인식하기(Hand Detection and Recognition using OpenCV)

OpenCV를 사용하여 손을 검출 및 인식하는 방법에 대해 다룹니다. 현재 두가지 방법으로 코드가 작성되었습니다. Background Subtraction을 사용한 방법과 HSV 공간에서 살색을 검출한 방법입니다. Background Sub..

webnautes.tistory.com

 

https://076923.github.io/posts/Python-opencv-25/

 

Python OpenCV 강좌 : 제 25강 - 모멘트 | 076923

모멘트(Moments)

076923.github.io

 

https://m.blog.naver.com/PostView.nhn?blogId=jinhuk1313&logNo=220618953390&proxyReferer=https%3A%2F%2Fwww.google.com%2F

 

[OpenCV]Finger Keyboard - 사용자 손 검출

사용자 피부색 인식 영상에서 사용자의 손을 검출하기 위해 사용자 피부색을 저장한다. 이것은 히스토그램...

blog.naver.com

https://ngost.tistory.com/category/%ED%94%84%EB%A1%9C%EA%B7%B8%EB%9E%98%EB%B0%8D/%EC%98%81%EC%83%81%EC%B2%98%EB%A6%AC?page=2

 

'프로그래밍/영상처리' 카테고리의 글 목록 (2 Page)

안녕하세요!

ngost.tistory.com

https://m.blog.naver.com/pckbj123/100203325426

 

[OpenCV] 손 동작 인식, 거리 변환 행렬(Distance Transform)을 이용한 손바닥 중심 구하기

[링크] [OpenCV] 손 동작 인식, 스킨 컬러를 이용한 손 검출[링크] [OpenCV] 손 동작 인식, 손 영역...

blog.naver.com

나중에 참고할 사이트 : https://dbpia.co.kr/journal/articleDetail?nodeId=NODE02367971#none

 

손가락 끝점을 이용한 제스처 인식

본 논문은 RGB-D센서와 손가락 끝점을 사용해 한손 중국식 손가락 숫자 인식 방법을 제안 하였다. 한손 중국식 손가락 숫자을 인식 하기 위해 컬러영상으로부터 피부색 영역을 추출하고 적외선영상으로부터 깊이정보와 근접영역의 이진화를 실시하여 이를 통해 피부색 영역과 근접 영역의 AND연산을 관심 영역인 손의 모양을 추출 하였다.
추출된 손

www.dbpia.co.kr

https://m.blog.naver.com/PostView.nhn?blogId=samsjang&logNo=220516822775&proxyReferer=https%3A%2F%2Fwww.google.com%2F

 

[18편] 이미지 Contour 응용1

이미지 프로세싱 & 컴퓨터 비전OpenCV-Python 강좌 18편 : 이미지 contour 응용하기 1부 필요환경:...

blog.naver.com

 

반응형

댓글