Robotics

[OpenCV] 3. 객체 탐지를 위한 이미지 전처리 프로세싱 (Image Processing)

로보고니 2024. 12. 3. 15:20

서론

상자를 분류하기 위해서는 가장 먼저 해당 상자의 길이를 측정할 수 있어야 한다. 상자의 길이를 측정해야 특정 값을 기준으로 상자를 분류할 수 있기 때문이다. 그래서 이번 글에서는 상자의 길이를 측정하기 전에 이미지 프로세싱을 통해서 이미지를 가공하는 방법에 대해서 알아볼 것이다.

상자 길이 측정


객체 길이 측정 방법

객체의 길이를 측정하기 위한 알고리즘을 한 번 생각해 보자. 가장 간단한 방법은 이미 알고 있는 물체의 길이를 사용해서 비례적으로 타겟 객체의 길이를 계산하는 방법이다. 하지만 이렇게 간단한 방법을 하기 위해서 우리가 해야 할 작업이 몇 가지가 있다.

 

객체 탐지 알고리즘

이미 우리가 길이를 알고 있는 객체가 있다고 하더라도, 우리는 그 객체를 탐지하고 인식해야 그 길이 정보를 사용할 수 있다. 또한, 우리가 측정하고자 하는 타겟 객체도 탐지하고 인식해야 비례식을 세워서 사용할 수 있다. 그렇기에 우리가 가장 먼저 해야 할 것은 객체를 탐지하는 것이다.

 

그렇다면 어떻게 해야 객체를 탐지할 수 있을까? 이것은 Image Processing (이미지 처리) 기술에서 객체를 탐지하는 방법을 알아야 한다.

  1. RGB 이미지를 Gray 이미지로 변환하기
  2. Blur를 사용하여 이미지의 노이즈 줄이기
  3. Canny와 같은 edge 탐지 알고리즘을 사용해 윤곽선 남기기
  4. Dilate와 Erode를 가지고 자잘한 윤곽선 지우기
  5. 남은 윤곽선을 가공해서 저장하기

위에서 언급한 방법이 객체를 탐지하기 위한 가장 기본적인 절차이다. 그리고 그 세부적인 내용을 수정하면서 정확도를 높이거나 원하는 객체의 모양에 맞게 최적화 할 수 있다.

 

오늘 알아볼 것은 그 중에서도 이미지 전처리에 해당하는 이미지 프로세싱에 대해서 알아볼 것이다.


기본 이미지

mid_box.jpg

우리가 탐지하고자 하는 객체가 있는 이미지가 필요하다. 왼쪽 위에 있는 박스는 우체국 3호 박스이고, 오른쪽 밑에 있는 박스는 우체국 1호 박스이다. 그리고 왼쪽 아래 있는 하얀색 박스가 기준 물체이다.

 

우리는 이 기준 물체의 길이를 모두 알고 있다는 가정으로 알고리즘을 작성할 것이다. 그렇기 위해서는 각 박스들을 인식할 수 있도록, 이미지를 가공해주어야 한다.


Gray Scale Image

Gray Scale Image

이미지 프로세싱을 위해서 가장 먼저 하는 작업이다. 이미지는 원래 RBG 형태로 있지만, 이것을 다르게 말한다면 Red, Blue, Green의 세 가지 값이 필요하다. 게다가 각 값은 0~255의 값이기 때문에 3byte의 큰 값이 필요하다.

 

하지만 Gray Scale의 경우에는 검은색인 0부터 흰색인 255까지 오직 1byte만 다루면 된다. 그래서 우리가 회색 이미지를 사용하는 것이다.


Gaussian Blur

 

Gaussian Blured Image

이미지를 사용하기 전에 해야 하는 작업이 하나 더 있다. 바로 블러 처리를 해주는 것이다. Blur는 우리말로 하면 흐릿하게 만들다라는 뜻이다. 혹은 모자이크라고 할 수 있다. 그리고 Blur를 하는 방법은 가우시안 블러가 있다.

 

가우시안 블러를 하는 이유는 노이즈를 줄이기 위함이다. 노이즈라고 하면, 우리 눈에는 보이지 않더라도 이미지의 픽셀값이 확 튀는 지점이 있을 수 있다. 그러한 점을 남겨둔 상태로 이미지 프로세싱을 하게 된다면, 그러한 변수들로 인해서 우리가 원하는 결과가 나오지 않을 것이다.

 

그렇기 때문에 노이즈로 인한 변수를 줄이고자 블러 처리를 하는 것이다. 위의 이미지를 보면 확실히 이미지가 흐려진 것을 볼 수 있다.


Canny Edge Detection

Canny Edged Image

이번에는 객체의 엣지 (모서리)를 검출하는 것이다. 그리고 엣지 검출 알고리즘에서 가장 많이 사용하는 것이 Canny Edge Detection이다.

 

여기서 말하는 Edge는 경계선 혹은 모서리를 의미한다. 그리고 그 모서리를 정의하는 것은 픽셀의 값이 갑자기 커지거나 갑자기 작아지는 부분을 의미한다. 즉, 검은색 배경에서 갑자기 흰색 박스가 있다면, 그 색이 변하는 경계선을 엣지라고 인식하는 것이다.


Dilation

Dilated Image

Dilate는 팽창하다라는 뜻이다. 즉, 탐지한 경계선을 팽창시켜서 두껍게 만든다. 그렇다면 이 Dilate를 왜 사용하는 것일까?

우리는 Canny를 사용하여 엣지를 검출했다. 하지만 그 엣지가 너무 가깝게 붙어 있을 수 있다. 이러한 미세하게 나누어진 경계선들은 이미지 처리 과정에서 방해가 될 수 있다. 혹은 모서리 부분이 완벽한 네모가 아니라 약간 삐져나올 수 있다. 이러한 사소한 선들을 제거하기 위해서 Dilate를 사용한다.

 

Dilate를 사용할 경우, 선들이 팽창하여 두꺼워진다. 계수에 따라서 선들이 많이 두꺼워져 서로 붙을 수 있다. 만약 선이 붙는다면, 이제 이 선은 하나의 선이 되는 것이다. 이후에 나올 Erode를 사용해서 그 선을 얇게 만들어준다면 우리는 두 개의 선을 하나의 선으로 바꿀 수 있는 것이다.

 

혹은 사소한 구멍이 있을 때 그 구멍을 매우는 역할로 사용하기도 한다.


Erode

Eroded Image

 

Erode는 축소하다라는 뜻이다. 이것은 Dilate랑 반대되는 개념이지만, 이 둘은 거의 항상 같이 쓰인다.

 

Erode와 Dilate를 사용하는 순서에 따라서 완전히 결과물이 달라질 수도 있다. 만약 아주 작은 구멍이 있는 상태에서 Dilate를 사용하고 Erode를 사용한다면 그 구멍은 매워질 것이다. 하지만 반대로 사용하거나 Erode만 사용한다면 그 구멍은 커질 것이다. 이처럼 이 둘의 순서와 계수를 조절하면서 우리의 이미지를 가공할 수 있다.


전체 코드

import cv2

image_path = "./images/mid_box.jpg"  # 이미지 경로를 직접 지정하세요


# 이미지 로드 및 전처리
image = cv2.imread(image_path)

gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
cv2.imshow("Gray Scale Image", gray)
gray = cv2.GaussianBlur(gray, (7, 7), 0)
cv2.imshow("Blured Image", gray)

# 엣지 검출 및 윤곽선 처리
edged = cv2.Canny(gray, 100, 200)
cv2.imshow("Canny Edged Image", edged)
edged = cv2.dilate(edged, None, iterations=1)
cv2.imshow("Dilated Image", edged)
edged = cv2.erode(edged, None, iterations=1)
cv2.imshow("Eroded Image", edged)

cv2.waitKey(0)
cv2.destroyAllWindows()

정해진 경로에 저장된 이미지를 사용하여 위의 예시에 나온 사진들을 보여주는 코드이다. 여러 파라미터들을 바꾸어가며 각 파라미터가 어떤 것을 의미하는지 확인하면 좋다. 키보드의 아무 키나 입력할 경우 창이 모두 꺼지며 종료된다.


마무리

오늘은 이미지 객체 탐지를 하기 전에 이미지 전처리를 하는 과정을 다루었다. 이것은 이미지 프로세싱 혹은 동영상을 다루기 위해 필수적으로 필요한 과정이다. 우리가 사용하고자 하는 사진 혹은 영상의 특성에 맞게 여러 가지 기능들을 사용해서 이미지를 가공한다면 보다 더 정교하게 우리가 원하는 결과를 얻을 수 있을 것이다.

 

다음 글에서는 전처리가 끝난 이미지를 가지고 모서리의 좌표를 얻고, 그것을 사용하여 박스의 위치와 박스의 길이, 박스가 회전한 각도를 측정할 것이다.