Object Detection
Tello 카메라를 통해 받아온 영상의 색상을 검출하는 과정은 다음과 같다.
- Camera&OpenCV로 받아온 BGR 컬러 영상을 HSV로 변환
- 설정된 HSV 채널 이진화
- 중점 찾기
import cv2
hsv = cv2.cvtColor(frame, cv2.COLOR_BGR2HSV)
lower_red1 = np.array([0//2, 255//3, 40])
upper_red1 = np.array([15//2, 255, 200])
lower_red2 = np.array([345//2, 255//3, 40])
upper_red2 = np.array([360//2, 255, 200])
rowMask = cv2.inRange(hsv, lower_red1, upper_red1)
upperMask = cv2.inRange(hsv, lower_red2, upper_red2)
maskedImage = cv2.bitwise_or(rowMask, upperMask)
contours, _ = cv2.findContours(maskedImage, cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE)
위 코드를 보면 lower_red1, upper_red1, lower_red2, upper_red2라는 네 가지 다른 범위를 정하고, 이를 inRange를 통해 범위로 지정해주었는데 이유는 HSV 채널의 색상은 조명 조건에 따라 다르게 인식될 수 있기 때문이다. 특히 조명의 강도와 방향에 따라 이미지의 색상이 변할 수 있는데 이러한 변화를 감지하고도 정확히 색상값을 추출하기 위해 빨간색 범위를 두 가지 다른 조건으로 정의함으로써, 더 넓은 범위의 빨간색을 검출할 수 있다.
- 첫 번째 빨간색 범위 (lower_red1, upper_red1)는 색상 값이 0도에서 15도 사이에 있는 빨간색을 검출한다.
- 두 번째 빨간색 범위 (lower_red2, upper_red2)는 색상 값이 345도에서 360도 사이에 있는 빨간색을 검출한다.
HSV 색 채널은 원뿔 모양을 띄는데, 이는 360도 돌면 결국 같은 색상임을 의미하기에 빨간색을 좀 더 정확하게 인식하기 위해 위와 같이 범위를 설정해준다. 이렇게 추출한 두 하한선을 비트 연산을 통해 Object Detection을 수행한다.
bitwise_or
python: cv.bitwise_or(src1, src2[, dst[, mask]]) ->dst
Calculates the per-element bit-wise disjunction of two arrays or an array and a scalar. 두 이미지의 동일한 위치에 대한 AND, OR, NOT, XOR 연산을 하는 함수로 bitwise_and, bitwise_or, bitwise_not, bitwise_xor이 있다.
docs.opencv.org
이미지 컨투어(Image Contour)
Contour는 등고선이라는 뜻으로 같은 값을 가진 곳을 연결한 선이다. 이미지에서 컨투어는 동일한 색/강도를 가지는 영역을 연결함을 의미한다. 따라서 Object Detection을 위해 이미지 컨투어를 잘 하는 것이 중요하다.
- 정확도를 높이기 위해 hsv로 추출한 색 채널을 Binary 이미지로 만들어준다.
- cv2.drawContours()는 원본 이미지를 직접 수정하기 때문에, 원본 이미지를 보존하려면 copy() 함수를 사용해야 한다.
- OpenCV에서 컨투어를 찾는 것은 검정 배경의 흰 대상을 찾는 것과 비슷하므로 대상은 흰색, 배경은 검은색으로 하는 것이 좋다.
위에서 설명한 과정대로 변환된 이미지를 가지고 findContours 함수를 통해 이미지에서 컨투어를 찾으면, Object Detection을 수행할 수 있다.
OpenCV & Contour
findContours
python: cv.findContours(image, mode, method[, contours[, hierarchy[, offset]]]) ->contours, hierarchy
image: 8bit 싱글 채널 이미지(8UC1)를 입력 받아 0인 픽셀은 0, 나머지 픽셀은 1로 만들어 이미지를 바이너리 이미지인 것처럼 다룬다. 그래서 단색을 가진 바이너리 이미지로 만들어야 한다. 만약 mode 값이 RETR_CCOMP, RETR_FLOODFILL이라면 입력 이미지로 32SC1도 사용 가능하다.
The function retrieves contours from the binary image using the algorithm. The contours are a useful tool for shape analysis and object detection and recognition.
✨ mode: Contour 추출 알고리즘으로 hierarchy에 영향을 준다.
- RETR_EXTERNAL: 이미지의 가장 바깥쪽 컨투어만 추출
- RETR_TREE: 모든 컨투어를 찾고 모든 계층 관계 추출
- RETR_LIST: 모든 컨투어를 찾지만 계층 구조의 상관관계(hierarchy)를 고려하지 않는다.
- RETR_CCOMP: 모든 컨투어를 찾고 2단계 계층 구조 구성
✨ mothod: 컨투어 근사 알고리즘
- CHAIN_APPROX_NONE: 컨투어를 구성하는 점들을 저장
- CHAIN_APPROX_SIMPLE: 컨투어의 수평, 수직, 대각선 방향의 모든 점을 버리고 끝점만 남겨둔다. 즉, 컨투어 라인을 그릴 수 있는 포인트만 저장한다.
[return value]
✔︎ contours: 검출된 컨투어로, 각각의 컨투어는 컨투어를 구성하는 점들로 이루어진 포인트 벡터 형태(Python List 형태)로 저장된다.
✔︎ hierarchy: 이미지 형상(image topology)에 대한 정보가 포함된 출력벡터로 Contours 간의 관계를 나타내는 값이다.
In Python, hierarchy is nested inside a top level array. Use hierarchy[0][i] to access hierarchical elements of i-th contour.
docs.opencv.org
dsbook.tistory.com
drawContours
Python: cv.drawContours(image, contours, contourIdx, color[, thickness[, lineType[, hierarchy[, maxLevel[, offset]]]]]) ->image
Draws contours outlines or filled contours.
- image: 입력 이미지(ndarray)
- contours: findContours 함수를 통해 입력 받은 모든 Contours들
- contourIdx: 그리고자 하는 컨투어를 나타내는 param.
- tickness: 컨투어 윤곽선의 두께. 이 값이 음수이거나 FiLLED이면 그려진 컨투어의 내부를 채운다.
docs.opencv.org
이렇게 컨투어를 통해 객체 탐지를 하는 방법을 알아봤는데, 여기에 morphology 연산을 통해 정확도를 높이는 법을 배워보자. 🤩
'ML > OpenCV' 카테고리의 다른 글
[자율주행] djitellopy & opencv Object Detection - (1) (0) | 2023.08.06 |
---|---|
[자율주행] OpenCV와 영상처리 | 필터링 | 영상 잡음 전처리 (0) | 2023.07.31 |
[자율주행] Tello SDK 환경 세팅 | 간단한 이착륙 코드 | OpenCV 비디오 스트림 (0) | 2023.07.31 |