
RVM과 MatAnyone2의 비디오 매팅(Video Matting) 헤일로(halo)는 '촬영 유래'인가 '코드 유래'인가 구분하기
요약
비디오 매팅 모델인 RVM과 MatAnyone2에서 발생하는 녹색 테두리(halo) 현상의 원인을 분석합니다. RVM은 촬영 시 발생하는 녹색광 반사가 원인인 반면, MatAnyone2는 추론 스크립트의 구현 문제로 인해 발생함을 밝힙니다.
핵심 포인트
- RVM의 halo는 촬영 환경의 녹색광 반사(green spill)로 인한 물리적 현상임
- MatAnyone2의 halo는 추론 스크립트가 반투명 영역에 녹색을 칠하는 코드 오류임
- ΔG 지표를 활용하여 윤곽선 영역의 녹색 번짐 정도를 정량적으로 측정 가능함
- MatAnyone2 사용 시 PyAV를 활용한 비디오 프레임 읽기 및 환경 설정 필요
Video matting (비디오 매팅) 증상 중에는 "투과 처리 후, 윤곽선에 녹색 테두리(halo)가 남는" 현상이 있습니다. 처음에는 "모델의 학습 편향(bias)이다"라고 생각했지만, Mac M2에서 RVM과 MatAnyone 2를 돌려보고 코드를 읽어보니 서로 다른 두 가지 원인이 얽혀 있었습니다.
RVM의 halo: 촬영 시의 녹색광 반사(green spill). 녹색 배경(green back)에서 촬영했기 때문에 녹색 빛이 윤곽선에 반사된 것일 뿐, 모델의 문제는 아님 -
MatAnyone 2의 halo: 추론 스크립트가 반투명 영역에 녹색을 칠하고 있음. 입력 배경색과 상관없이, 녹색 배경 이외의 소재에서도 edge (가장자리)에 녹색이 묻어남 (빨간색 배경 합성 시 두드러짐)
녹색 번짐의 지표로서 ΔG = G − (R+B)/2 (윤곽선 3px 대역의 평균색으로 계산, +12 전후가 육안 식별 경계선, 본 기사에서만 사용하는 간이 지표)를 사용합니다. 녹색 배경 / 자연 배경의 2가지 조건으로 측정하면 원인을 분리할 수 있습니다.
과정을 기술합니다.

비교 모델
| 모델 | 발표 | 특징 |
|---|---|---|
| Robust Video Matting (RVM) mobilenetv3 | WACV 2022 | auto matting (자동 매팅). 인물을 자동 검출하며, 사전 mask (마스크)가 필요 없음 |
| MatAnyone 2 | CVPR 2026 Highlight | target-guided matting (타겟 가이드 매팅). 첫 번째 프레임의 mask를 전달하는 것을 전제로 함 |
MatAnyone 2는 fine hair (가는 머리카락), semi-transparent fabric (반투명 천), motion blur (모션 블러), cluttered background (복잡한 배경)가 강점입니다. halo 대책의 주전장은 아니지만, edge가 깨끗하다면 halo도 줄어들 것이라 예상하여 나란히 배치했습니다.
환경과 입력
- 하드웨어: Mac mini M2 24GB (MPS)
- 환경: Python 3.11 + torch 2.12 (MPS)
- 입력: mixkit의 녹색 배경 talking head 영상 1280x720 60fps 16초 956프레임
셋업
MatAnyone 2의 pyproject는 CUDA index를 전제로 하므로 덮어씁니다. GUI 의존적인 cchardet은 빌드 시 문제가 발생하므로 --no-deps로 회피합니다.
uv venv --python 3.11 .venv
source .venv/bin/activate
uv pip install 'torch>=2.4' 'torchvision'
...
torchvision.io.read_video가 새로운 torchvision에서 삭제되었으므로, MatAnyone 2의 read_frame_from_videos를 PyAV로 다시 작성합니다. 단 한 곳입니다.
MatAnyone 2는 초기 mask가 필요합니다. 입력이 녹색 배경이므로, HSV를 이용해 녹색을 제거하고 largest connected component (가장 큰 연결 요소)를 인물로 간주하는 간이 chroma key (크로마 키) 방식으로 생성했습니다.
출력을 나란히 보기
프레임 480/956을 흰색 배경에 합성한 결과입니다.

윤곽선 근접 크롭:

빨간색 배경에 합성하면 녹색 번짐이 가장 명확하게 나타납니다.

foreground (전경)를 alpha (알파) 없이 표시하면, 양쪽 모두 투명 영역이 녹색입니다. 여기서 "모델이 녹색을 학습했다"라고 결론 내릴 뻔했지만, 나중에 보니 이는 잘못된 것이었습니다.

alpha 단독. 반투명 대역은 MatAnyone 2 쪽이 더 좁고, 기울기(gradient)도 강합니다 (이후 측정에서 MatAnyone 2는 edge 0.4-0.5%, RVM은 0.6-0.7%). MatAnyone 2가 더 hard alpha (딱딱한 알파)에 가깝습니다.

정량적 결과
동일한 입력과 동일한 절차로 프레임 50 / 200 / 400 / 600 / 800을 측정했습니다.
| 지표 | MatAnyone 2 | RVM (mobilenetv3) |
|---|---|---|
| alpha 투명 (α<10) | 73.5-74.3% | 73.5-74.3% |
| ... |
두 모델 모두 비슷한 정도의 녹색 번짐이 남습니다. 숫자만으로는 원인을 알 수 없기에 foreground 생성 코드를 읽었습니다.
foreground 생성 코드를 다시 읽기
각 모델의 추론 코드에서 foreground
무엇을 출력하는지 확인합니다.
RVM (model/model.py:62):
fgr = fgr_residual + src
fgr = fgr.clamp(0., 1.)
RVM의 foreground는 **입력 + 보정 잔차 (residual)**입니다. 투명 영역은 학습 과정에서 마스킹(masked)되어 (그 부분의 색을 올바르게 만드는 손실 함수가 없기 때문에) 잔차가 자유로운 값을 가질 수 있으며, 실측 결과 공간 의존적인 잔차가 더해져 입력 색상보다 어둡게 억제됩니다. 학습된 색상은 아니지만, passthrough(입력 그대로 통과)도 아닙니다. 그린 백그라운드 입력의 경우 입력 기반 + 잔차이므로 결과적으로 초록색에 가깝게 나타납니다.
MatAnyone 2 (inference_matanyone2.py:72, 111):
bgr = (np.array([120, 255, 155], dtype=np.float32)/255) # green screen to paste fgr
...
com_np = image_np / 255. * pha + bgr * (1 - pha)
MatAnyone 2의 foreground는 모델의 예측값이 아니라, 추론 스크립트가 alpha=0 영역을 (120, 255, 155)로 채우고 있을 뿐입니다. 학습이나 편향(bias)의 문제가 아닌, 단순한 후처리(post-processing)입니다.
foreground의 raw RGB를 보고 "모델이 초록색을 내뱉고 있다"라고 말하는 것은 빗나간 분석입니다:
- RVM은 입력 기반의 잔차이므로, 투명 부분이 초록색인 것은 입력의 초록색이 바탕이 되었기 때문입니다.
- MatAnyone 2는 추론 스크립트가 임의로 초록색을 채우고 있습니다.
그렇다면 ΔG +12의 halo는 무엇인가
윤곽선 3px 대역의 ΔG +12 초록색은 입력을 바꾸지 않으면 구분할 수 없으므로, 다음 절에서 자연 배경의 talking head를 통해 확인하겠습니다. 예상 결과:
- 물리적 현상(촬영 시의 green spill)이라면 그린 백그라운드에 의존하므로 → 자연 배경에서 halo가 사라질 것입니다.
- 모델/스크립트 유래라면 입력에 의존하지 않으므로 → 자연 배경에서도 halo가 남을 것입니다.
이를 실측을 통해 구분하겠습니다.
자연 배경에서 검증
Pexels의 의료 사무실 스타일 talking head(15초, 720p, 30fps, 초록색 요소 없음)로 동일한 파이프라인(pipeline)을 실행했습니다.

흰색 배경에 합성:

빨간색 배경에 합성:

foreground의 raw RGB:

정량적 결과 (프레임 50/150/250/350)
| 지표 | MatAnyone 2 | RVM |
|---|---|---|
| alpha 투명도 | 79.4% | 79.3-79.4% |
| ... | halo ΔG | |
| +13 | −5.5 |
알게 된 점
RVM의 halo ΔG는 −5.5로, 초록색은커녕 약간 자줏빛(red-purple)에 가깝습니다. 그린 백그라운드에서의 +12가 사라졌습니다. halo의 초록색은 물리적인 green spill 유래임이 확정되었습니다.
MatAnyone 2의 halo ΔG는 +13으로 그린 백그라운드 때와 변함이 없습니다. 이는 입력 색상이 아니라, 추론 스크립트의 bgr = [120, 255, 155]가 반투명 대역을 통해 edge로 스며 나오는 부작용입니다. 입력을 바꿔도 사라지지 않습니다. 채우는 색을 검은색 [0, 0, 0]으로 바꾸면 이것도 사라집니다. 추가 관찰: RVM의 foreground 네 모서리는 입력과 색상이 상당히 다릅니다. 입력이 (226, 194, 185)인 밝은 벽이라 하더라도 RVM foreground는 (125, 99, 107)까지 떨어졌습니다. 투명 영역은 손실 함수(loss)로 제약되지 않기 때문에, 네트워크가 공간 의존적인 잔차로 자유로운 색을 출력하고 있습니다. 결과에는 영향을 주지 않는 영역이므로 실질적인 해는 없으나, "passthrough"라기보다는 "입력 기반 + 큰 잔차"라고 표현하는 것이 정확합니다.
빨간색 배경에서 보면 MatAnyone 2의 초록색 번짐이 시각적으로 결정적임
위의 흰색 배경 합성에서는 ΔG가 +13과 +5로 "약간 초록색에 가깝다" 정도의 차이지만, 빨간색 배경에 합성하면 보색(complementary) 관계 때문에 MatAnyone 2의 초록색 번짐이 현저하게 드러납니다. 위의 빨간색 배경 이미지를 다시 보면, MatAnyone 2의 머리카락 윤곽에는 초록색 테두리가 뚜렷하게 보이는 반면, RVM은 윤곽이 빨간색에 자연스럽게 녹아들어 있습니다.
빨간색 배경 edge zone의 RGB를 측정하면:
| 모델 | edge zone 평균(R,G,B) | G − B |
|---|---|---|
| MatAnyone 2 | (181, 54, 43) | +11 (녹색 번짐) |
| RVM | (180, 52, 58) | −6 (약간의 청색, 녹색 없음) |
미세한 수치 차이라도 빨간색 배경과의 보색 대비로 인해 크게 보입니다. 용도에 따라 MatAnyone 2의 이 halo(헤일로)는 치명적일 수 있습니다 (투명 배경 소재로 추출하여 임의의 배경에 얹는 유스케이스라면 확실히 결과가 무너집니다). RVM은 edge의 green fill(녹색 채우기)을 가지고 있지 않은 덕분에, 임의 배경 합성 시 외관이 깔끔합니다.
MatAnyone 2 측은 추론 스크립트의 bgr = [120, 255, 155]를 [0, 0, 0]으로 변경하면 edge의 green bleed(녹색 번짐)를 없앨 수 있습니다. 소재화하는 용도로 MatAnyone 2를 사용한다면 이 수정은 필수입니다.
그럼 어떻게 없애는가
모델 교체만으로는 사라지지 않으므로, matting 후단에 **despill(디스필)**을 넣습니다:
# G를 (R+B)/2로 제한
g = np.minimum(g, (r.astype(np.int32) + b.astype(np.int32)) // 2)
alpha-gated 방식으로 인물 측에만 적용하면, 피사체가 녹색 옷을 입고 있지 않는 한 부작용 없이 halo를 제거할 수 있습니다. edge의 임계값(threshold) 설정은 halo 제거와 녹색 의상 보호 사이의 트레이드오프(trade-off)가 됩니다.
MatAnyone 2는 추론 스크립트의 bgr = [120, 255, 155]를 [0, 0, 0]으로 바꾸는 것만으로 '투명 영역이 녹색인' 문제 자체는 해결됩니다. 다만 물리적인 spill(번짐)은 남기 때문에 despill 처리가 필요합니다.
속도 메모
Mac M2 MPS 환경에서 1280x720 956 프레임의 추론 시간:
- RVM (mobilenetv3): 약 48초 (~20 fps)
- MatAnyone 2: 수 분 (RVM의 5~7배 정도, 정확한 측정은 별도 포스팅에서)
소재화(투명 배경으로 추출하여 임의 배경에 합성하는) 용도로는 RVM이 우세합니다. 녹색 배경에서는 양쪽 모두 대등하지만, 자연 배경에서는 MatAnyone 2의 스크립트 유래 녹색 번짐이 남아 빨간색 배경 합성 시 두드러지기 때문입니다. MatAnyone 2 측의 채우기 색상을 [0, 0, 0]으로 수정하면 대등해집니다.
cluttered background(복잡한 배경)나 fine hair(가는 머리카락)의 edge quality(경계 품질)를 추적하는 용도는 MatAnyone 2의 영역이지만, 별도의 검증이 필요합니다.
요약
- 두 모델 모두 foreground(전경)의 RGB를 alpha 없이 보면 투명 영역이 녹색임.
- 학습 편향(bias)이 아니라 코드의 사양임 (RVM은 잔차(residual) 기반으로 입력 색상에 가까운 값을 가짐, MatAnyone 2는 고정 색상 채우기 방식).
- 녹색 배경 시 윤곽 3px 대역의 ΔG +12는 모델의 halo가 아니라 촬영 시의 green spill임. 자연 배경에서 테스트하면 RVM은 ΔG −5.5(녹색 사라짐), MatAnyone 2는 +13(채우기 색상의 부작용으로 남음).
- 빨간색 배경 합성 시 MatAnyone 2의 녹색 번짐이 시각적으로 결정적인 결함이 됨 (G−B = +11 vs RVM의 −6). 소재화하여 임의 배경에 얹는 용도라면 MatAnyone 2의 스크립트를 수정하지 않으면 결과가 무너짐.
- 대책은 alpha-gated despill을 사용하는 것과, MatAnyone 2 측은
bgr = [0, 0, 0]으로 변경하는 것임. 모델 교체만으로는 해결되지 않음. - 수치만으로 결론 내지 말고 구현부를 읽고, 여러 입력 조건에서 검증하는 것이 돌아가는 것 같아도 가장 확실한 방법임.
코드 전체는 blog-examples/2026/07-02-matting-halo-comparison에 올려두었습니다 (uv script 하나로 두 모델을 실행하여 정량적 결과를 얻을 수 있습니다).
Discussion

AI 자동 생성 콘텐츠
본 콘텐츠는 Zenn AI의 원문을 AI가 자동으로 요약·번역·분석한 것입니다. 원 저작권은 원저작자에게 있으며, 정확한 내용은 반드시 원문을 확인해 주세요.
원문 바로가기