🌿 자라는 중어느 정도 다듬었지만 계속 자라는 중이에요.
주차장에 오토바이가 입차했다: 이미지 임베딩 기반 차량 판별
문제
현장의 실제 주차 가능 대수와 시스템상 주차 가능 대수가 크게 다른 상황이 반복됐습니다. 가용면수가 틀리면 안내 정보가 틀리고, 결국 민원으로 이어집니다. 운영 중에는 이 차이를 사람이 매일 수동으로 맞추고 있었습니다.
원인: 무엇이 “입차”로 처리되고 있었나
입차 기록을 하나씩 따라가 보니, 가용면수를 차지하고 있던 건 차량만이 아니었습니다.
- 오토바이
- 리어카
- 정기순찰 차량
카메라가 인식한 대상이 주차면을 점유하는 차량인지를 판단하지 않고 모두 입차로 처리하고 있었던 것이 원인이었습니다.
해결: 이미지 임베딩 모델 기반 판별 로직
입차 이미지를 임베딩 모델로 벡터화하고, 이 벡터를 기준으로 “가용면수에 반영할 입차인지”를 판별하는 단계를 입차 처리 앞에 두었습니다.
여기서 중요한 구분이 하나 있었습니다. 정기순찰 차량은 시각적으로는 분명 자동차입니다. 모양만 보면 입차가 맞지만, 비즈니스 관점에서는 가용면수에 반영하면 안 되는 대상이죠. 그래서 판별을 두 단계로 나눴습니다.
// 개념을 설명하기 위해 단순화한 예시
enum VisualClass { CAR, MOTORCYCLE, CART, UNKNOWN } // 무엇처럼 보이는가
enum OccupancyPolicy { COUNT, IGNORE } // 가용면수에 반영하는가
interface OccupancyRule {
Optional<OccupancyPolicy> decide(EntryEvent event, VisualClass visual);
}
// 예: 시각적으로는 CAR여도 순찰 차량이면 IGNORE
class PatrolVehicleRule implements OccupancyRule { /* ... */ }
시각적 분류(모델의 책임)와 비즈니스 분류(규칙의 책임)를 분리해 두면, 새로운 예외가 생겨도 모델을 다시 만들 필요 없이 규칙 하나를 추가하는 것으로 대응할 수 있습니다.
성과
- 운영 중 가용면수 정합성을 맞추기 위한 수정 건수: 일일
NM건 → N건 - 민원 감소로 고객사 만족도 증가, 정합성 보정에 쓰던 작업 시간 감소
회고
정기순찰 차량처럼 시각적 분류와 비즈니스 분류가 다른 사례를 만나면서 두 개념을 분리해야 한다는 걸 배웠습니다. 그리고 예외는 반드시 또 생기기 때문에, 처음부터 새 예외에 유연하게 대응할 수 있는 확장 가능한 판별 구조를 만드는 게 중요하다고 느꼈습니다.
판단 로직을 어디에 두어야 하는가에 대한 고민은 고아 이미지 정리 노트에서도 이어집니다.