본문 바로가기
공부/Computer Vision

[Computer Vision] 원하는 색상을 가진 객체의 윤곽선과 외접 사각형 그리기

by 웅대 2023. 9. 8.
728x90
반응형

https://growth-coder.tistory.com/243

이전 포스팅에서 이미지에서 원하는 색상만 검출해내는 방법을 알아보았다.

 

이번 포스팅에서는 원본 이미지에서 원하는 색상의 객체 주변에 contour와 bounding rectangle을 그리는 방법을 알아보려고 한다.

 

아래 이미지에서 빨간색 사과의 contour와 bounding rectangle을 그려보자.

 

contour 정보 얻어내기

 

우선 이전 포스팅에서 했던 것 처럼 tracking bar를 통해 mask 이미지를 얻어낸다.

tracking bar를 통해 구했다면 HSV의 범위를 알 수 있다.

 

나의 경우 Hue는 0~179, Saturation은 130~255, Val은 0~255가 나왔다.

 

위 이미지는 빨간색만 존재했기 때문에 간단하게 Saturation 범위만 조절해서 mask를 얻어냈다.

 

만약 여러 색상이 존재하는 이미지에서 원하는 색상의 mask를 얻어내고 싶다면 Hue 값 또한 조절하는 편이 더욱 정확하다.

 

위처럼 이진화 된 이미지를 얻어내고 나면 contour 정보를 얻어낼 수 있다.

 

cv2.findContours(이미지, 모드, 메소드)

모드와 메소드에는 많은 종류가 있다.

 

그 중 바깥 Line을 찾는모드인 cv2.RETR_EXTERNAL과 contour line을 그릴 수 있는 포인트를 저장하는cv2.CHAIN_APPROX_SIMPLE을 사용해보겠다.

 

import cv2
import numpy as np
img = cv2.imread("apple.jpg")

# 색 공간 HSV로 변경
img_hsv = cv2.cvtColor(img, cv2.COLOR_BGR2HSV)

# HSV 범위를 통해 mask 얻어내기
lower = np.array([0, 130, 0])
upper = np.array([179, 255, 255])
mask = cv2.inRange(img_hsv, lower, upper)

# mask에서 contour 정보를 얻어내기
contours, hierarchy = cv2.findContours(mask, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
print(len(contours))
print(contours[0])
print(contours[1])

차례대로 마스크, 모드, 메소드를 cv2.findContours의 인자로 넣어주면 contours와 hierarchy를 얻을 수 있다.

 

그리고 contours의 개수와 contours 요소를 출력하도록 해보았다.

 

나의 경우 contours의 요소 개수는 2가 나왔다.

 

또한 contours[0]은 다음과 같았다.

 

[[[412 125]]
 [[412 127]]]

 

contours[1]은 길어서 모두 출력하지는 못했다.

 

[[[259  47]]

 [[256  50]]

 [[249  50]]

 ...

 [[268  49]]

 [[267  48]]

 [[260  48]]]

 

이제 contours를 그려보자.

contour 그리기

cv2.drawContours(이미지, contours, contours의 인덱스, 색상, 두께)
# contour 그리기
img_contours = cv2.drawContours(img, contours, -1, (0, 255, 0), 4)
cv2.imshow("contours", img_contours)
cv2.waitKey(0)

contours에는 contours 자체를 넣어도 되고 contours의 요소 하나를 넣어도 된다.

 

나는 우선 모든 contour를 그리도록 contours 자체를 넣어두었다.

 

contours의 인덱스는 말 그대로 얻은 contours의 인덱스이다.

 

나는 contours 안에 두 개의 contour가 존재했는데 첫 번째 contour만 그리고 싶다면 contours[0]을 넣으면 된다.

 

이제 감지한 모든 contour를 그려보자.

한 번 첫 번째 contour만 출력해보자.

# contour 그리기
img_contours = cv2.drawContours(img, contours, 0, (0, 255, 0), 4)
cv2.imshow("contours", img_contours)
cv2.waitKey(0)

첫 번째 contour는 범위가 작은 모습을 확인할 수 있다.

 

위에서 contours[0]을 출력했었는데 아래와 같이 좌표 두 개가 찍혔었다.

 

[[[412 125]]
 [[412 127]]]

 

좌표에 해당하는 만큼 그린 것이다.

 

contours[1]을 출력했을 때는 굉장히 많은 좌표가 출력되었는데 한 번 두 번째 contour(인덱스 1)도 그려보자.

 

# contour 그리기
img_contours = cv2.drawContours(img, contours, 1, (0, 255, 0), 4)
cv2.imshow("contours", img_contours)
cv2.waitKey(0)

contours[0] 자체가 작게 인식해서 모두 출력했을 때와 별 차이 없어보이지만 실제로는 contours[0]에 해당하는 부분이 빠져있다.

 

bounding rectangle 그리기

bounding rectangle은 contour에 외접하는 사각형을 의미한다.

 

우리가 감지한 두 contour에 대해서 외접 사각형을 그려보자.

 

cv2.boundingRect(contour)

cv2.boundingRect 매소드는 외접 사각형의 왼쪽 위 점의 x, y 값과 외접 사각형의 너비, 높이를 함께 반환한다.

 

반복문을 통해 contours에 담긴 모든 contour에 대해서 bounding rectangle을 그려보자.

 

for cnt in contours:
    x, y, w, h = cv2.boundingRect(cnt)
    cv2.rectangle(img, (x, y), (x+w, y+h) ,(255, 0, 0), 3)
cv2.imshow("bounding rectangle", img)
cv2.waitKey(0)

최종 코드

import cv2
import numpy as np
img = cv2.imread("apple.jpg")

# 색 공간 HSV로 변경
img_hsv = cv2.cvtColor(img, cv2.COLOR_BGR2HSV)

# HSV 범위를 통해 mask 얻어내기
lower = np.array([0, 130, 0])
upper = np.array([179, 255, 255])
mask = cv2.inRange(img_hsv, lower, upper)

# mask에서 contour 정보를 얻어내기
contours, hierarchy = cv2.findContours(mask, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
print(len(contours))
print(contours[1])

# contour 그리기
img_contours = cv2.drawContours(img, contours, 1, (0, 255, 0), 4)
cv2.imshow("contours", img_contours)

for cnt in contours:
    x, y, w, h = cv2.boundingRect(cnt)
    cv2.rectangle(img, (x, y), (x+w, y+h) ,(255, 0, 0), 3)
cv2.imshow("bounding rectangle", img)
cv2.waitKey(0)

이렇게 이번 포스팅에서는 원하는 색상의 객체의 contour를 그리고 bounding rectangle을 그려보았다.

728x90
반응형

댓글