webcam에서 사진 찍은 걸 저장하는 과정을 완료했으니,
그 사진을 가지고 와서 인식하는 작업을 해보자!
opencv는 참 좋은 환경이다.. 이런 다양한 기능까지 할 수 있게 해주고
혼자 감격의 눈물 백번은 쏟음.
일단 여기까지 해오면서 가장 중요하다고 생각했던 것은
파일 명을 어떻게 지정하느냐, 또 imwrite랑 imread의 이해가 제일 먼저 중요하다.
나는 맨땅에 해딩식으로 하면서 익힌 스타일이라 시간이 오래걸렸지만,
뭐 다음에 할 때는 응용해서 좀 더 숙련됐다고 치지 뭐 ^_____^
아무튼 처음에 파일명을 지정할 때 저장되는 시간을 파일명으로 지정했다.
아무 생각없이 월/일 시간/분/초 로 지정을 해줬고
imread로 읽을 때도 그 파일명을 불러오기로 했는데 아무리 해도 에러가 났다.
아니 샘플 사진은 잘만 가져오더니 왜 내 사진은 못가져오는것인가!! 했는데,
당연한 것이었다. 초까지 설정을 했으니 당연히 바로 가져온다고 해도 오차 범위가 날게 뻔한 것이었다.
키를 설정할 것이 아니라 캡쳐 후에 바로 그 사진에 대한 것까지 가져올 수 있도록 하거나,
캡쳐와 사진 불러와 인식하는 기능을 따로 구현하고 싶으면 초단위를 없애면 된다.
나는 따로 구현하고 싶어서 key 로 다 나눠놓았기 때문에,
과감히 초단위를 삭제함.. 그랬더니 정상적으로 가져오게 되었다.
img = cv2.imread("D:/captureimage/" + str(now) + ".png", cv2.IMREAD_COLOR)
img_gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
img_gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)에서
img_gray는 출력할 이미지, img는 입력할 이미지, cv2.COLOR_BGR2GRAY는 색상 변환 코드이다.
사진이 저장된 곳에서 사진은 읽어오고 gray로 색을 바꿔주자.
그 후에는 이미지의 특징점인 모서리들을 출력해줄것이다.
다양한 방법들이 있었는데, Harris Corner Detection는 조명 변화에 유연한 특징이 있다고 해서 사용하기로 했다.
corner = cv2.cornerHarris(img_gray, 2, 3, 0.04)
순서대로
(코너 검출할 그레이 스케일 이미지, 검출할 코너 갯수, 코너로 판단할 문력값, 검출할 코너 사이의 최소거리) 이다.
마지막 최소거리는 이 거리 이내에 있으면 무시하겠다는 의미이다.
그 다음으로 변화량 결과의 최대값 10% 이상의 좌표를 구했다.
coord = np.where(corner > 0.1 * corner.max())
coord = np.stack((coord[1], coord[0]), axis=-1)
cv2.cornerHarris() 함수의 변환 결과는 입력 이미지와 크기가 같은 1차원 배열이기 때문에
배열에서 코너값이 코너의 최대값*0.1인 부분보다 큰 값의 색인 위치를 coord라는 변수에 지정한다.
np.where() 함수는 조건에 부합하는 값을 찾는 함수이다.
그리고 난 후 np.stack()이라는 함수를 사용하여 배열을 합쳐 coord에 저장해준다.
np.stack()는 동일한 길이를 가져야한다. 특정 축인 axis를 따라서 합치게 된다.
그리고 코너로 인식된 좌표들에 동그라미로 표시를 해주도록 하겠다.
for x, y in coord:
cv2.circle(img, (x, y), 5, (0, 0, 255), 1, cv2.LINE_AA)
cv2.circle(img, (x, y), 5, (0, 0, 255), 1, cv2.LINE_AA)에서
img는 그림을 그릴 입력 이미지, (x,y)는 원의 중심 좌표 즉 그림을 그릴 지점, (0,0,255)는 반지름이다.
그리고 1은 BRG형태의 COLOR이다.
corner_norm = cv2.normalize(corner, None, 0, 255, cv2.NORM_MINMAX, cv2.CV_8U)
그리고 그 변화량을 영상으로 표현하기 위해서 0~255로 정규화 해준다.
다 되었다. 표현한 것을 다시 화면에 출력해주면 끝!
corner_norm = cv2.cvtColor(corner_norm, cv2.COLOR_GRAY2BGR)
merged = np.hstack((corner_norm, img))
cv2.imshow('Harris Corner', merged)
cv2.waitKey()
cv2.destroyAllWindows()
이렇게 화면에 출력하고 나면 빨간색 동그라미가 표시된 부분들이 코너 부분임을 알 수 있다.
코너에서 픽셀의 변화량이 가장 크기 때문이라고 하는데 너무 신기한 사실이지 않은가..
어떤 사진을 인식하냐에 따라서 오차 범위가 많이 달라지긴 하지만
단일 배경과 명확한 코너가 있는 사진이라면 확실한 결과를 가져올 수 있을 것 같다.
나는 손가락을 인식시켜서 수화앱을 만드는 것이 목적이라 앞으로도
좀 더 많은 수정이 필요할 것 같지만 이렇게 결과값이 나오는 것만 해도 아주 만족스럽다... 헿
<전체코드>
# python -m pip install opencv-python 필요
import cv2
import time
import datetime
import numpy as np
video = cv2.VideoCapture(0) # WebCam의 경우 0 또는 1
# 비디오 파일의 경우 '경로/파일명.확장자'
prev_time = 0 # 이전 프레임 재생 시간 값 0으로 초기화
FPS = 100
a = 0
while True:
ret, frame = video.read() # ret = frame 읽기가 성공하면 while문의 true 값 반환, frame = 배열 형식의 영상 프레임 값을 반환
frame = cv2.flip(frame, 1)
current_time = time.time() - prev_time # 현재 시간 - 이전 프레임 재생 시간
# ret이 true의 값을 가진다면 영상을 재생
if (ret is True) and (current_time > 1. / FPS): # 비교
prev_time = time.time()
cv2.imshow("VideoCapture", frame) # imshow(윈도우 창의 이름, cv2.VideoCapture()의 리턴값)
now = datetime.datetime.now().strftime("%m-%d (%H;%M)")
key = cv2.waitKey(30) & 0xff
if key == 27: # esc 아스키 코드 번호 27
break
elif key == 32: # space 아스키 코드 번호 32
print("캡쳐완료" + ' ' + now)
cv2.imwrite("D:/captureimage/" + str(now) + ".png", frame)
# window에서 imwrite 사용 시 한글 포함 경로를 저장하지 못함, 또한 파일명에 사용할 수 없는 특수기호 포함 시
# 실행에는 문제없지만 파일 저장은 안되기 때문에 주의하기
elif key == 24: # control-x
print("최근 파일 색상 검출")
img_color = cv2.imread("D:/captureimage/" + str(now) + ".png")
print('shape: ', img_color.shape)
height, width = img_color.shape[:2]
img_hsv = cv2.cvtColor(img_color, cv2.COLOR_BGR2HSV) # cvtColor 함수를 이용하여 hsv 색공간으로 변환
lower_blue = (120 - 10, 30, 30) # hsv 이미지에서 바이너리 이미지로 생성 , 적당한 값 30
upper_blue = (120 + 10, 255, 255)
img_mask = cv2.inRange(img_hsv, lower_blue, upper_blue)
# lower_blue = np.array([120 - 10, 30, 30]) # hsv 이미지에서 바이너리 이미지로 생성 , 적당한 값 30
# upper_blue = np.array([120 + 10, 255, 255])
# img_mask = cv2.inRange(img_hsv, lower_blue, upper_blue) # 범위내의 픽셀들은 흰색, 나머지 검은색
img_result = cv2.bitwise_and(img_color, img_color,
mask=img_mask) # 바이너리 이미지를 마스크로 사용하여 원본이미지에서 범위값에 해당하는 영상부분을 획득
cv2.imshow('img_origin', img_color) # 원본
cv2.imshow('img_mask', img_mask) # 색상 추출 파일
cv2.imshow('img_color', img_result) # 하얀색으로 변환환
elif key == 107: # 키보드 k 입력
print("최근 파일 모서리 검출")
img = cv2.imread("D:/captureimage/" + str(now) + ".png", cv2.IMREAD_COLOR)
img_gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
# 모서리 검출
corner = cv2.cornerHarris(img_gray, 2, 3, 0.04)
# (코너 검출할 그레이 스케일 이미지, 검출할 코너 갯수, 코너로 판단할 문력값, 검출할 코너 사이의 최소거리, 이 거리 이내에 있으면 무시)
# 10% 지표구하기
coord = np.where(corner > 0.1 * corner.max())
coord = np.stack((coord[1], coord[0]), axis=-1)
for x, y in coord:
cv2.circle(img, (x, y), 5, (0, 0, 255), 1, cv2.LINE_AA)
corner_norm = cv2.normalize(corner, None, 0, 255, cv2.NORM_MINMAX, cv2.CV_8U)
corner_norm = cv2.cvtColor(corner_norm, cv2.COLOR_GRAY2BGR)
merged = np.hstack((corner_norm, img))
cv2.imshow('Harris Corner', merged)
cv2.waitKey()
cv2.destroyAllWindows()
참고 (아주 설명을 잘해주셨다! 짱이다!)
OpenCV - 26. 이미지의 특징점(Keypoints)과 특징점 검출기(Keypoints detector)
이번 포스팅에서는 이미지의 특징점과 특징점 검출기 대해 알아보겠습니다. 이번 포스팅 역시 '파이썬으로 만드는 OpenCV 프로젝트(이세우 저)'를 정리한 것임을 밝힙니다. 코드: github.com/BaekKyunShi
bkshin.tistory.com
<결과값>

'코딩 수업 기록 > 수화 인식 프로젝트' 카테고리의 다른 글
| [수화 인식 프로젝트] 5주차 수업 _ webcam 영상에서 물체 테두리 따기 (0) | 2021.11.10 |
|---|---|
| [수화 인식 프로젝트] 2주차 수업 _ opencv 에서 webcam 캡쳐하여 파일 저장하기_분명 오류는 안나는데 저장이 안될 때 (0) | 2021.09.15 |
| [수화 인식 프로젝트] 1주차 수업 _ opencv 이용하여 webcam 켜기 (0) | 2021.09.11 |