Post

(Samsung CTF 2017) ASM (Addition, Subtract, and Multiplication)

ASM : Addition, Subtract, and Multiplication

웹페이지 접속 start 이미지 가져오기 정답 추론 정답 입력 팝업 안뜨면 정답인것. 정답이면 학습 데이터에 (라벨, 데이터) 쌍 추가하고 다음 문제 이미지 가져오기…반복 오답이면 모은 학습 데이터를 바탕으로 학습…반복

데이터셋을 어떻게 정의할지가 문제인데.

1. 그냥 이미지 전체를 학습시키기.

피연산자들이 한 자리 숫자이면 classification 해야 하는 경우의 수가 그렇게 많지는 않으니까 이렇게 해도 되겠지만 두세 자리 숫자도 나온다. 그렇게 되면 분류해야 하는 경우의 수가 피연산자에 들어갈 수 있는 경우의 수가 각각 999, 연산자 +-/ 경우의 수 3 이니까 999 * 4 * 999가 나오는데, 데이터 셋도 많이 필요하고 이렇게 풀라고 낸 문제가 아닐 듯.

2. 숫자와 연산자를 각각 잘라서 인식하기

하나의 이미지 내에 있는 숫자와 연산자를 하나 씩 잘라서 인식해야 하기 때문에 object detection도 들어가야 하나… 싶지만

!!!!!다행인건 숫자나 연산자 하나가 바뀔 때 마다 색상이 변경된다는 점!!!

색상을 이용해 숫자, 연산자를 하나 씩 추출하는 것이 가능할 것 같다. 나오는 색상도 붉은 색, 초록 색, 파란 색 세 가지다.

이렇게 하면 숫자 등이 겹쳐서 인식이 안되는 경우도 해결 가능할 듯! 이미지 받아와서 컬러 필터링으로 한 char 씩 자르고 이를 맞추는 방식으로 진행해야 할 듯.

ㅠ.. 근데 컬러 필터링 하려면 OpenCV를 사용해야 함. PIL / Pillow로 이것저것 해봤는데, 컬러 필터링은 RGB를 필터링에 용이한 HSV color-space로 변환하고 H만 취하는게 제일 빠르다고…

HSV : 색상(Hue), 채도(Saturation), 명도(Value)
그래서 OpenCV를…

1
2
pip install opencv-python

컬러필터링을 수행하는 단계는 다음과 같습니다. 먼저 카메라를 통해 입력받은 데이터를 먼저 HSV 컬러 시스템으로 변환합니다. HSV 컬러시스템은 컬러필터링에 용이합니다. 다음으로 HSV 컬러 시스템 상에서 필터링 되지 않고 통과되기를 원하는 컬러의 범위를 선정하여, 마스킹 영상을 생성합니다. 마지막으로 원본 영상과 마스킹 영상을 AND 연산을 통해 마스킹 부위만 남기고 다른 부분은 모두 색상정보를 제거합니다. OpenCV에는 색상을 표현하는 컬러시스템간의 전환을 편리하게 하는 함수가 있습니다.

출처

http://opencv-python.readthedocs.io/en/latest/doc/01.imageStart/imageStart.html

Note) OpenCV는 BGR 순서다. 그래서 Matplotlib 같은 RGB 순을 사용하는 라이브러리와 함께 사용할 때 순서를 바꿔주어야 한다.

Note)img.shape하면 size를 출력해주는데, py (y, x) 형태로 출력해주니까 당연히 (x, y)라고 생각하고 코딩하면 시간 엄청 낭비하게됨.

이미지에 나오는 RGB

1
2
3
4
Red : #faa / 255, 170, 170
Green : #afa / 170, 255, 170
Blue : #aaf / 170, 170, 255

BGR 값에 대응되는 HSV 값 알아내기

1
2
3
4
5
6
7
8
9
10
11
12
>>> import cv2
>>> import numpy as np
>>> red = np.uint8([[[170,170,255]]])  # [[[B, G, R]]]
>>> green = np.uint8([[[170,255,170]]])
>>> blue = np.uint8([[[255,170,170]]])
>>> cv2.cvtColor(red, cv2.COLOR\_BGR2HSV)
array([[[  0,  85, 255]]], dtype=uint8)
>>> cv2.cvtColor(green, cv2.COLOR\_BGR2HSV)
array([[[ 60,  85, 255]]], dtype=uint8)
>>> cv2.cvtColor(blue, cv2.COLOR\_BGR2HSV)
array([[[120,  85, 255]]], dtype=uint8)

HSV는 색상(Hue), 채도(Saturation), 명도(Value)이므로 위 결과에서 [H-10, 50, 50][H+10, 255, 255]와 같이 상하한선을 정하여 색 영역을 추출할 수 있다. * 이미지가 단순해서 채도와 명도를 이렇게 크게 잡든, 위 결과와 비슷하게 잡든 상관 없이 잘 인식한다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
colors = {
'red' : {
'lower' : np.array([0, 50, 50]),
'upper' : np.array([10, 255, 255])
},
'green' : {
'lower' : np.array([50, 50, 50]),
'upper' : np.array([70, 255, 255])
},
'blue' : {
'lower' : np.array([110, 50, 50]),
'upper' : np.array([130, 255, 255])
}
}

근데, 이렇게 인식하면 색상이 겹치는 부분이 잘려버린다.
나중에 안 사실이지만 값을 조정하면 색상이 겹치는 부분도 인식할 수 있다.

이제 output 뉴런 수가 10인 MNIST CNN의 output을 +-*를 추가한 13으로 조정하고 MNIST pretrained 된 가중치를 바탕으로 추론 및 학습을 진행하면 해결할 수 있겠다.


여기까지 대회 중 진행한 내용인데 시간이 없어 다 풀지는 못했고, 이후 서버가 열려있는 것을 확인하고 나중에 풀어야겠다고 미뤄두다가 오늘 들어가보니까 서버가 내려간 듯 하다… 그래서 작성한 코드가 숫자가 커졌을 때도 잘 동작하는지는 확인하지 못했다. 다른 분들 풀이를 보니 각 캐릭터에 tilt, size 변형이 일어나지 않는다는 점, 색상이 겹치는 부분도 포함해서 인식할 수 있다는 점을 이용해 이미지 인식으로 해결하셨던데, 나는 이미지 인식에 익숙하지 않아서 예전에 만들어둔 딥러닝 래퍼를 사용했다.

+ 겹치는 부분 인식하기

겹치는 부분 RGB 값

1
2
3
4
Red + Green : 170, 170, 85
Red + Blue : 170, 85, 170
Blue + Green : 85, 170, 170

HSV로 변환

1
2
3
4
5
6
7
8
9
10
>>> rg = np.uint8([[[85,170,170]]])
>>> cv2.cvtColor(rg, cv2.COLOR\_BGR2HSV)
array([[[ 30, 128, 170]]], dtype=uint8)
>>> rb = np.uint8([[[170,85,170]]])
>>> cv2.cvtColor(rb, cv2.COLOR\_BGR2HSV)
array([[[150, 128, 170]]], dtype=uint8)
>>> bg = np.uint8([[[85, 170, 170]]])
>>> cv2.cvtColor(bg, cv2.COLOR\_BGR2HSV)
array([[[ 30, 128, 170]]], dtype=uint8)

Hue가 150이나 되기 때문에 기존 red에 upper로 지정해서 한꺼번에 masking하게되면 다른 색까지 모두 검출되어 버린다. 그래서 mask를 따로따로 적용해야 할 듯.

This post is licensed under CC BY 4.0 by the author.