Object Detection 

Tello 카메라를 통해 받아온 영상의 색상을 검출하는 과정은 다음과 같다.

  1. Camera&OpenCV로 받아온 BGR 컬러 영상을  HSV로 변환
  2. 설정된 HSV 채널 이진화
  3. 중점 찾기

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 연산을 통해 정확도를 높이는 법을 배워보자. 🤩

sebinChu