노이즈가 있는 3D 데이터 복원하기

Jinyoung Kim nuvilab
Nuvilab 누비랩
Published in
9 min readFeb 8, 2023

안녕하세요! 누비랩 Future Tech팀 엔지니어 김진용입니다.

들어가며

누비랩에서는 3D 데이터, RGB 이미지를 활용하여 음식의 부피를 계산하고 있습니다. RGB 이미지를 통해 음식의 위치와 종류를 파악하고 3D 데이터를 통해 음식의 3D 형상을 추정하고 있는데요. 이때, 3D 데이터의 노이즈 여부가 음식의 3D 형상을 추정할 때 굉장히 중요한 요소로 작용합니다. 데이터 취득 시 외부 광원(형광등 빛, 햇빛 등)으로 인해서 빛 반사가 발생하면 이는 상당한 노이즈를 야기하여 부피 측정에 악영향을 줍니다. 이번 포스팅에서는 이러한 문제점을 개선하기 위해 개발했던 기술에 대해 공유하려 합니다.

이슈 트래킹

왼쪽은 음식의 이미지를 오른쪽은 음식의 깊이 값을 나타낸 3D 데이터입니다. 왼쪽의 음식 이미지에서 배식받은 국의 이미지를 보면 빛 반사가 발생한 것을 볼 수 있는데요. 오른쪽의 3D 데이터에서 같은 영역에 빛 반사로 인해 데이터에 노이즈가 발생한 것을 확인할 수 있습니다.

노이즈의 종류

위의 사진에서 볼 수 있듯이 노이즈의 형태는 2가지로 구분할 수 있습니다.

  1. 값이 측정되지 않은 결측값(어두운 남색으로 노이즈의 대부분 영역을 차지)
  2. 값이 존재하지만, 노이즈로 분류할 수 있는 아웃라이어(노란색 등의 색으로 일부 영역을 차지)

참고) 3D 데이터는 matplotlib.pyplot.imshow() 함수를 통해 표출하였고, 픽셀의 값이 작을수록 어두운 남색, 값이 클수록 밝은 노란색을 띱니다. 이때, 픽셀의 값은 카메라로부터 떨어진 거리를 의미합니다. 즉, 카메라로부터 가까울수록 어두운 남색, 카메라로부터 멀어질수록 밝은 노란색을 띱니다.

해결 과정

  1. 결측값을 복구하기 위해 노이즈가 심하게 껴있는 3D 데이터에 Depth Completion을 수행해봅니다.
왼쪽 : Raw data / 오른쪽 : Depth Completion 수행 후
  • Depth Completion은 3D 데이터에서 깊이 결측값을 예측하는 컴퓨터 비전 기법입니다. Depth Completion 알고리즘의 성능을 평가하는 유명한 데이터셋 중 하나는 자율주행 데이터셋인 KITTI가 있습니다.
  • Depth Completion의 여러 기법 중 우수한 성능과 AI 학습 비용이 들지 않는다는 점이 장점인 알고리즘을 택해 나이브한 접근 방식으로 바로 적용해보았습니다.
  • 적용한 결과를 보면, 노이즈가 껴있는 영역 중 결측값 부분은 일부 복구됐지만 아웃라이어 또한 그 영역을 넓혀간다는 문제점이 새롭게 발생했습니다. 그 이유는 컴퓨터 비전 필터가 주변 값을 활용하여 결측값을 복구하기 때문입니다.
  • 여기서 목표를 조금 더 구체화했습니다. 집중해야 할 부분은 식판 위의 음식이고, 음식에 존재하는 아웃라이어를 제거하고 결측값 영역을 주변 식판의 깊이와 비슷하도록 복구하는 것을 목표로 합니다.

2. 음식 Mask 내에 존재하는 아웃라이어를 제거하고 결측값 영역에 대해 Binary Mask Index를 저장합니다.

음식 Mask 내에 존재하는 아웃라이어가 제거되고 결측값만 남은 3D 데이터
  • 1번에서 발생한 문제를 해결하기 위해 아웃라이어를 먼저 제거해야 합니다.
  • 누비랩은 음식의 Mask를 탐지하는 AI 모델을 보유하고 있고 이를 통해 음식의 영역을 쉽게 파악할 수 있습니다. 음식 Mask 내에서 깊이 값의 아웃라이어 범위를 탐지하고 정상적인 범위를 벗어나는 깊이 값은 0으로 바꿔주는 작업을 수행합니다.
  • 노이즈가 있는 영역을 복구할 때 사용하기 위해 아웃라이어를 제거한 결측값 영역의 Binary Mask Index를 저장합니다.

3. Depth Completion을 수행합니다.

완전히 복구되지 않은 3D 데이터
  • Depth Completion을 수행하게 되면 주변 깊이 값으로 결측값 영역이 복구됩니다. 이때, 필터의 크기에 비해 복구해야 할 결측값 영역이 너무 크다 보면 위 사진처럼 전부 복구되지 않을 수 있습니다.
  • 결측값 주변으로 경계선처럼 보이는 아웃라이어가 노랗게 생긴 것을 확인할 수 있습니다.

4. 각 음식 Mask를 활용하여 경계선 아웃라이어를 제거하고 결측값 영역을 복구하는 작업을 수행합니다.

복구된 3D 데이터
  • 결측값 영역이 큰 경우에 모두 복구되지 않을 수도 있다는 사실을 알았습니다. 따라서 모든 결측값을 복구하는 것을 보장하기 위해서 Depth Completion 수행 후 잔여 결측값 영역을 파악해야 합니다.
  • 경계선 부분의 아웃라이어를 제거합니다. 각 음식 Mask 내에 존재하는 결측값을 배제하고 깊이 값의 평균값을 계산하여 잔여 결측값 영역을 평균값으로 복구합니다.

5. 4번의 복구된 3D 데이터로부터 원본 3D 데이터의 결측값 영역을 복구합니다.

  • 최종적으로 2번에서 저장했던 결측값이 존재하는 Binary Mask Index에 대하여 원본 3D 데이터를 4번의 복구된 3D 데이터의 값으로 복구합니다.
  • Depth Completion을 적용하게 되면 노이즈가 있는 영역뿐 아니라 원본 3D 데이터가 갖고 있던 기존의 정상적인 깊이 값이 약간 훼손되는 문제가 발생합니다. Depth completion의 목적은 노이즈가 있는 영역을 복원하는 것이기 때문에 노이즈가 없는 부분은 원본을 사용하고, 노이즈가 있는 부분에 대해서만 Depth Completion을 적용하도록 하였습니다.
  • Depth Completion을 적용했음에도 식판 내에 음식이 아닌 부분에 노이즈가 있는 모습을 볼 수 있는데 식판이 아닌 음식에 초점을 맞춰 노이즈를 제거했기 때문입니다.

의사 코드(Pseudo Code)

# 3D 데이터를 불러옵니다.
depth_origin = read_depth_file()

# 음식 Mask 내에 존재하는 아웃라이어를 제거합니다.
depth_origin_filtered = remove_outlier(depth_origin, food_mask)

# 음식 Mask 내에 존재하는 결측값 영역의 Binary Mask Index를 저장합니다.
food_missing_value_binary_mask_index = find_missing_value_area_index(depth_origin_filtered, food_mask) # missing value : 결측값

# Depth Completion을 수행합니다.
depth_reconstruction = depth_completion(depth_origin_filtered)

# 반복문
# 각 음식 Mask 내에 존재하는 아웃라이어를 제거합니다.
# 음식 Mask 내에 존재하는 결측값 영역의 Binary Mask Index를 저장합니다.
# 각 음식 Mask 내에 존재하는 결측값을 제외하고 평균값을 계산합니다.
# 잔여 결측값 영역을 복구합니다.
while each_food_mask_list
depth_reconstruction = remove_outlier(depth_reconstruction, each_food_mask)
each_food_residual_missing_value_binary_mask_index = find_missing_value_area_index(depth_reconstruction, each_food_mask)
food_depth_average = average(depth_reconstruction, each_food_mask)
depth_reconstruction[each_food_residual_missing_value_binary_mask_index] = average
endwhile

# 원본 3D 데이터의 결측값 영역을 복구된 3D 데이터를 활용해 복구합니다.
depth_origin_filtered[food_missing_value_binary_mask_index] = depth_reconstruction[food_missing_value_binary_mask_index]
  • 의사 코드는 실제 코드와 다르며 알고리즘 로직에 집중할 수 있도록 구현하였습니다.

복원 결과

왼쪽 : 원본 | 오른쪽 : 복원 결과

다음 글

이번 글에서는 정성적으로 노이즈가 있는 영역이 얼마나 좋아지는지 살펴봤었습니다. 다음 글에서는 Depth Completion을 적용했을 때 정량적인 지표를 설정하여 얼마만큼의 개선이 이루어졌는지 평가하기 위해 진행했던 실험에 대해 공유해드리도록 하겠습니다.

마치며..

첫 포스팅으로 3D 데이터에 노이즈가 있는 영역을 복구하는 기술을 공유해드렸습니다. 데이터 분석을 하다 보면 현장에서는 잘 정제된 데이터와는 달리 엣지 케이스도 다양하고 노이즈가 있어 사용하기 어려운 데이터로 인해 난관에 봉착하는 경우가 있습니다. 하지만 함께 고민하다 보면 어려운 문제들도 극복해 나갈 수 있다는 것을 이번 경험을 통해 깨달을 수 있었습니다.

이 기술 개발은 누비랩에서만 할 수 있었던 작업이었습니다. 음식 Mask를 찾는 AI가 있었고, 귀중한 시간을 내어 아이디어 공유와 개선 방안을 같이 고민해주셨던 동현 님, 지환 님, 제윤 님, 승우 님이 계셨습니다. 말씀드리지 않은 많은 분께도 감사의 말씀 드리며 글을 줄입니다.

--

--