1. 도입: 이론과 현장의 괴리, 끝없이 요동치는 뎁스 맵
지난 1편에서는 라이다(LiDAR) 센서를 대체하기 위해 단일 카메라 기반의 딥러닝 Depth Estimation 모델을 산업 현장에 도입했다가 겪었던 치명적인 한계들을 다루었다. 조명의 변화나 그림자를 실제 웅덩이로 오인하는 문제도 심각했지만, 현장에서 실시간으로 시스템을 띄웠을 때 마주한 가장 큰 골칫거리는 바로 '플리커링(Flickering)' 현상이었다.
동일한 위치에서 카메라와 피사체가 1mm도 움직이지 않았음에도 불구하고, 화면에 출력되는 뎁스 맵(Depth Map)의 픽셀 값은 프레임이 바뀔 때마다 미친 듯이 깜빡이고 널뛰기를 반복했다. 이런 불안정한 날것의 데이터(Raw Data)를 로봇 팔의 거리 제어 알고리즘이나 이기종 디바이스 트래킹 트리거(Trigger)에 그대로 연결했다가는 대형 사고로 이어질 것이 뻔했다. 결국 무거운 AI 모델을 다시 뜯어고치는 대신, 파이썬(Python)과 영상 처리의 근본인 OpenCV를 활용하여 뎁스 데이터를 부드럽게 깎고 다듬는 소프트웨어 후처리(Post-processing) 파이프라인을 구축하기로 결심했다.
2. 현장에서 발생한 에러 극복 (1): 엣지를 살리는 바이래터럴 필터
가장 먼저 손을 댄 부분은 한 프레임(정지 이미지) 내에서 자글자글하게 끓어오르는 공간적 노이즈(Spatial Noise)를 제거하는 것이었다. 일반적으로 노이즈를 없앨 때 가장 쉽게 떠올리는 가우시안 블러(Gaussian Blur)를 적용해 보았으나, 치명적인 부작용이 있었다. 노이즈는 사라졌지만 물체의 경계선(Edge)까지 함께 뭉개져 버려서, 어디서부터가 설비 표면이고 어디서부터가 허공인지 구분할 수 없게 된 것이다.
이 딜레마를 해결하기 위해 OpenCV의 cv2.bilateralFilter를 도입했다. 바이래터럴 필터는 픽셀 간의 '거리'뿐만 아니라 '색상(여기서는 뎁스 픽셀 값) 차이'까지 함께 고려하는 고급 필터다. 즉, 평평한 바닥이나 벽면 같은 비슷한 뎁스 값을 가진 영역은 강하게 문질러서 노이즈를 없애주고, 물체와 배경이 분리되는 급격한 뎁스 차이(경계선)가 있는 곳은 블러를 적용하지 않고 칼같이 살려두는 마법 같은 역할을 해주었다. 이 필터 하나만으로도 뎁스 맵의 가독성이 비약적으로 상승했다.

3. 현장에서 발생한 에러 극복 (2): 지수 이동 평균(EMA)의 도입
공간적 노이즈를 잡았음에도, 시간이 흐름에 따라 영상이 깜빡거리는 프레임 간의 떨림(Temporal Noise)은 여전히 남아있었다. 산업용 환경 특유의 미세한 조명 깜빡임(플리커) 기계적 진동이 AI 연산 결과에 매번 다른 영향을 주고 있었기 때문이다.
이를 해결하기 위해 딥러닝과 센서 데이터 안정화에 주로 쓰이는 '지수 이동 평균(EMA, Exponential Moving Average)' 알고리즘을 파이썬 코드로 구현하여 영상 프레임 단위에 적용했다. 직전 프레임의 뎁스 데이터 결과물에 높은 가중치를 두고, 새 프레임의 데이터를 부드럽게 합성하는 방식이다. 이렇게 시계열 스무딩(Smoothing) 처리를 거치자, 뎁스 맵은 마치 카메라 렌즈에 짐벌을 단 것처럼 묵직하고 부드럽게 변했다. 프레임 간의 급격하게 튀는 노이즈 값이 사라지니, 상위 로봇 제어 로직에서도 안정적으로 표면 거리를 판별할 수 있게 되었다.

4. 실전 최적화: 초당 프레임(FPS)의 늪과 멀티 스레딩 아키텍처
센서 데이터를 부드럽게 깎고 다듬는 데는 성공했지만, 정작 시스템의 처리 속도 즉 FPS(Frames Per Second)가 10 이하로 곤두박질치는 양상이 벌어졌다. 장비와 실시간으로 연동하려면 최소 30 FPS 이상은 방어해야 했다.
코드를 프로파일링(Profiling)해보니 범인은 명확했다. 딥러닝 모델은 GPU 위에서 쌩쌩하게 돌아가고 있었지만, 후처리를 위해 텐서(Tensor) 형태의 결과를 CPU 메모리(NumPy 배열)로 끌고 내려오는 병목 과정이 문제였다. 고해상도 픽셀에 바이래터럴 필터와 EMA 연산을 반복하니 파이썬의 단순 계산 오버헤드가 한계치에 다다른 것이다.
"GPU에서 뽑아낸 데이터는 GPU 안에서 모두 처리한다"는 원칙 하에 파이썬 로직을 대대적으로 갈아엎었다.
이전 프레임의 연산 버퍼(Buffer)를 CPU로 내리지 않고 파이토치(PyTorch)의 GPU VRAM에 상주시켜 텐서 병렬 연산을 수행했다. 무거웠던 OpenCV 필터 역시 CuPy 등 GPU 기반 배열 라이브러리를 통해 대체했다.
추가로 메인 루프 안에서 꽉 막혀 돌아가던 순차적 구조를 분해하여 카메라 영상 입출력 스레드, AI 추론 스레드, 모니터링 제어 로직 스레드를 모두 분리했다. 각 스레드 사이를 파이썬의 비동기 Queue(큐) 자료구조로 연결하자 병목이 해소되며 10 FPS 밑으로 버벅대던 속도가 단숨에 30 FPS 수준으로 치고 올라왔다.
5. 결론: 랩실 밖의 AI는 결국 엔지니어링 퀄리티에서 완성된다
몇 날 며칠의 밤샘 최적화 끝에, 마침내 노이즈 하나 없이 묵직하고 부드러운 뎁스 맵이 30 FPS 이상의 쾌적한 속도로 출력되었다.
세상에는 최첨단 SOTA(State-of-the-Art) 모델들이 차고 넘친다. 하지만 통제된 랩실의 깔끔한 코드를 살아 숨 쉬는 거친 산업 현장과 이기종 디바이스 스택에 적용할 때 발생하는 문제들을 해결하는 것은 전혀 다른 차원의 이야기다. 끝없이 튀는 통신 노이즈를 깎아내고, 지독한 연산 속도를 멱살 잡고 끌어올려 기어코 '현장에서 당장 쓸모 있는 데이터'로 가공해 내는 것, 이번 트러블슈팅 프로젝트를 통해 머신비전 엔지니어링의 묘미임을 다시 한번 실감했다.
다음 포스팅에서는 이기종 디바이스 간의 효율적인 실시간 시리얼 데이터 스트리밍 연동 방법에 대해 더 깊이 다루어 보겠다.
'Computer Vision & AI > 영상 처리 & 비디오 분석 (엔지니어)' 카테고리의 다른 글
| Python으로 동영상 압축 및 해상도 자동 조정(Video Compression Automation) (0) | 2025.12.20 |
|---|---|
| Python으로 실시간 스트리밍 영상 처리(Real-Time Video Processing) – WebCam 적용 (0) | 2025.12.19 |
| Python으로 영상에서 다중 언어 환경 OCR(Multilingual OCR) 구현 (0) | 2025.12.18 |
| 감성돔 낚시터의 강한 햇빛, 파이썬 그림자 제거(Shadow Removal)로 AI 인식률 높이기 (0) | 2025.12.17 |
| Python으로 영상 분할(Segmentation) 후 객체별 색상 랜더링(Object Coloring) (0) | 2025.12.16 |