
시간을 찍는 카메라: 라인 스캔 이미지 처리와 데이터 최적화 경험기
라인 스캔 카메라 데이터를 처리하며 겪은 노이즈 제거와 속도 보정 과정을 통해, 데이터 정규화와 패턴 추출의 중요성을 백엔드 개발자의 시각에서 풀어냅니다.
김영태
테크리드

안녕하세요. 풀링포레스트 테크리드 김영태입니다.
개발자로서 우리는 보통 JSON이나 SQL 테이블처럼 잘 구조화된 데이터를 다루는 데 익숙합니다. 하지만 가끔은 날것 그대로의 바이너리 데이터와 씨름해야 할 때가 있죠. 최근 제가 개인적인 호기심으로 '라인 스캔 카메라(Line Scan Camera)'라는 녀석을 다루면서 겪은 이미지 처리 과정은, 마치 대용량 트래픽 로그에서 유의미한 신호를 찾아내는 백엔드 작업과 놀랍도록 닮아 있었습니다. 오늘은 그 삽질의 기록을 공유해 보려 합니다.

솔직히 말해 처음에는 만만하게 봤습니다. 라인 스캔 카메라는 일반 카메라와 달리 센서가 단 한 줄(또는 두 줄)뿐입니다. 이 한 줄짜리 센서가 아주 빠른 속도로 계속 찍어대고, 그 결과물인 1픽셀 너비의 이미지들을 가로로 쭉 이어 붙이면 우리가 아는 사진이 됩니다. 수평축이 '공간'이 아니라 '시간'인 셈이죠. 덕분에 왜곡 없이 아주 긴 열차 사진을 찍을 수 있습니다.
문제는 데이터의 양과 질이었습니다. 카메라를 켜두면 기차가 지나가든 말든 무식하게 데이터를 쌓습니다. 기차가 없는 빈 배경 데이터, 즉 '노이즈'가 스토리지 용량을 잡아먹는 속도가 어마어마했습니다. 서버 로그로 치면 200 OK 응답만 수 테라바이트가 쌓여서 정작 중요한 500 에러 로그를 찾기 힘든 상황과 같았죠.
가장 먼저 해결해야 할 과제는 관심 영역(ROI, Region of Interest) 검출이었습니다. 단순히 "픽셀 값이 변하면 움직임이다"라고 판단했더니, 바람에 흔들리는 나뭇잎까지 전부 감지해서 실패했습니다. 배경은 정적이기 때문에 시간축(가로)으로 보면 똑같은 픽셀이 반복되어 가로 줄무늬가 생립니다. 반면 움직이는 물체(열차)는 수직에 가까운 구조를 가집니다.
이를 해결하기 위해 '에너지 함수(Energy Function)'를 도입했습니다. 이미지의 x축(시간) 그래디언트와 y축(공간) 그래디언트를 비교하는 방식입니다.
# 개념적인 의사 코드
energy = gradient_x / (0.1 * max_pixel_value + total_gradient_norm)이 수식을 통해 가로로 늘어지는 정적인 배경 노이즈를 걸러내고, 실제로 움직이는 물체만 '청크(Chunk)' 단위로 잘라낼 수 있었습니다. 이 과정에서 휴리스틱 값을 조정하느라 꽤 애를 먹었는데, 역시 어떤 도메인이든 '매직 넘버'를 튜닝하는 건 개발자의 숙명인가 봅니다.
하지만 진짜 위기는 그다음에 찾아왔습니다. 바로 속도 추정 문제입니다. 기차의 속도는 제각각인데 카메라의 스캔 속도는 고정되어 있다 보니, 결과물이 찌그러지거나 길게 늘어져서 나왔습니다. 예전에는 바퀴가 동그랗게 보일 때까지 포토샵으로 비율을 조절하는, 소위 '눈대중'으로 해결했습니다. 하지만 엔지니어로서 자존심이 허락하지 않더군요. 자동화가 필요했습니다.
해결의 실마리는 하드웨어의 특성인 Bayer Array에서 찾았습니다. 제가 사용한 센서는 사실 두 줄의 픽셀 라인을 가지고 있는데, 첫 번째 줄은 Green-Red, 두 번째 줄은 Green-Blue 패턴입니다. 이 두 개의 Green 채널 사이에는 미세한 시간/공간 차이가 존재합니다.

이 두 라인의 시차를 계산하면 물체의 속도를 역산할 수 있습니다. 이를 위해 'Mean Shift' 스타일의 서브픽셀(Subpixel) 보간법을 적용했습니다. 픽셀 단위가 아니라 소수점 단위의 미세한 이동량을 가우시안 가중치를 둬서 계산하는 방식입니다. 데이터에 노이즈가 많았지만, 스플라인(Spline) 곡선을 피팅하니 놀랍게도 기차의 속도 변화 그래프가 그려졌습니다. 이 데이터를 바탕으로 이미지를 리샘플링하니, 찌그러졌던 기차가 마법처럼 원래 비율을 되찾았습니다.
이번 프로젝트를 통해 다시금 깨달았습니다. 우리가 다루는 데이터가 이미지의 픽셀이든, 서버의 트래픽 로그든, 본질은 같습니다. "거대한 노이즈 속에서 유의미한 패턴(Signal)을 찾아내고, 왜곡된 데이터를 정규화하는 것."
처음 raw 데이터를 열어보고 막막했던 순간이 기억납니다. 하지만 수학적 원리를 코드로 옮기고, 하드웨어의 특성을 이용해 문제를 해결했을 때의 짜릿함은 백엔드 시스템을 최적화했을 때의 쾌감과 다르지 않았습니다. 여러분도 익숙한 프레임워크 밖으로 나와, 가끔은 이렇게 날것의 데이터를 다루는 사이드 프로젝트에 도전해 보시는 건 어떨까요? 의외로 현업의 난제를 풀 수 있는 새로운 인사이트를 얻게 될지도 모릅니다.
풀링포레스트 개발팀은 언제나 이런 집요한 호기심을 환영합니다. 감사합니다.


