티스토리 뷰

일단 코드를 보자

PC에 장착된 웹캠으로 촬영 중인 영상을 OpenCV로 읽어들인 다음 영상 안에서 필기체 숫자를 검출하는 예제입니다.

필기체 숫자는 랜덤 포레스트 방식으로 미리 학습된 모델을 통해 예측하는 방식으로 검출합니다. 

학습은 다음 이미지를 통해 진행하였습니다. 

digits.png
0.69MB

 

코드 보시죠!

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
# 웹캠을 이용한 필기체 숫자 인식
import cv2
import numpy as np
import pickle
from sklearn.model_selection import train_test_split
from sklearn.ensemble import RandomForestClassifier
 
# 필기체 숫자 데이터 불러오기
img = cv2.imread('digits.png', cv2.IMREAD_GRAYSCALE)
cells = [np.hsplit(row,100for row in np.vsplit(img,50)]
= np.array(cells)
= x[:,:].reshape(-1,400).astype(np.float32)
= np.repeat(np.arange(10),500)
train_X, test_X, train_y, test_y = train_test_split(X, y, test_size=0.3)
test_y[:100]
model = RandomForestClassifier()
model.fit(train_X, train_y)
model.score(test_X, test_y)
 
# 모델 저장하기
with open("digits.model""wb"as f:
    pickle.dump(model, f)
 
# 모델 읽어들이기
with open("digits.model""rb"as f:
    model = pickle.load(f)    
 
# 실시간으로 영상 읽어들이며 숫자 인식해보기
cap = cv2.VideoCapture(0)
if cap.isOpened():
    while True:
        ret, img = cap.read()
        if ret:
            g_img = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
            thr, bin_img = cv2.threshold(g_img, 110255, cv2.THRESH_BINARY_INV)
            contours, hierarchy = cv2.findContours(bin_img, cv2.RETR_EXTERNAL, 
                                                   cv2.CHAIN_APPROX_SIMPLE)
            try:
                for i in range(len(contours)):
                    contour = contours[i]
                    (x,y), radius = cv2.minEnclosingCircle(contour)
                    if radius > 3:
                        xs, xe = int(x-radius), int(x+radius)
                        ys, ye = int(y-radius), int(y+radius)
                        cv2.rectangle(bin_img, (xs,ys), (xe,ye), (200,0,0), 1)
                        roi = bin_img[ys:ye, xs:xe]
                        dst = cv2.resize(roi, dsize=(5050), interpolation=cv2.INTER_AREA)
                        dst = cv2.resize(dst, dsize=(1616), interpolation=cv2.INTER_AREA)
                        A = np.zeros((20,20))
                        A[2:-2,2:-2= dst[:,:]
                        A = A.reshape(-1,400)
                        num = model.predict(A)
                        cv2.putText(bin_img, str(num), (xs, ys), cv2.FONT_HERSHEY_PLAIN, 2, (200,0,0))
            except Exception as e:
                #print(e)
                pass
            cv2.imshow("Video Capture", bin_img)
            key = cv2.waitKey(1)
            if key == 27
                # ESC 키 입력 시에는, 
                break
        else:
            print("No Frame...")
            break
else :
    print("Camera not opened...")
    
cap.release()
cv2.destroyAllWindows()

 

 

주석문 기준으로 예제의 시나리오(?)를 간단히 정리 

 

#필기체 숫자 데이터 불러오기 

에서는 말 그대로 필기체 숫자 데이터를 불러옵니다. 필기체 숫자로 채워진 이미지를 읽어다가 영역을 일정한 크기의 셀(cell) 나누고, 그 중 일정량을 학습용 데이터로, 일정량을 검증 테스트용 데이터로 나누어 학습 결과를 확인합니다. 코드의 16번째 줄을 보면 여기에서는 랜덤 포레스트 분류가 사용된 것을 볼 수 있습니다. 랜덤 포레스트 방식에 대한 설명을 정리하려면 글이 길어질 수밖에 없을 듯하여... 이에 대해 잘 모르신다면 따로 자료를 찾아보시길....^^;;

 

#모델 저장하기 모델 읽어들이기

모델 저장하기의 경우는 모델을 다른 파이썬 스크립트에서도 사용할 수 있도록 바이너리 프로토콜로 내보내는 과정이고, 모델 읽어들이기는 해당 모델을 다시 읽어들이는 과정입니다. 따라서 이 두 과정은 위 예제에서 없어도 괜찮은 부분이긴 합니다. 

 

#실시간으로 영상 읽어들이며 숫자 인식해보기

29번 줄에서는 OpenCV의 VideoCapture 함수를 사용해 웹캠으로부터 영상을 읽어들입니다. 이때 영상을 한번만 읽어들이면 정지영상이 나타나게 되므로 while 반복문을 통해 계속적으로 영상을 읽어들이도록 했습니다. 

35, 36번 줄에서는 영상을 회색조로 만들고 임계값을 조절하여 물체가 더 잘 검출되도록 했습니다. 오로지 숫자만 검출되는 것이 아닌, 물체라고 판단되는 것을 모조리 검출하므로 주의해야 합니다. 

영상 속에서 물체가 검출될 경우 해당 영역에 네모를 그려 물체가 검출되었음을 나타내고(45번), 모델이 숫자를 예측하여(52번) 숫자를 표시하는 방식(53번)으로 작업을 수행합니다.  

 

아래 이미지는 위 예제를 실행한 후 웹캠에 숫자 5가 쓰인 종이를 들이댔을(?) 때의 결과 화면입니다.

 

댓글
공지사항