Communitygithub.com

starx1n9/video-watermark-remover-skill

ProPainter 기반 영상 인페인팅을 활용하여 고정 로고, 모서리 로고, 워터마크, 하드코딩된 자막을 로컬에서 제거합니다. 요소를 자동으로 찾고, 사용자 확인을 위해 마스크 미리보기를 제공한 후 인페인팅, 품질 검사(QC)를 거쳐 원본 영상과 전후 비교 이미지, 새로운 로고/자막 배치를 위한 좌표 문서를 함께 제공합니다.

video-watermark-remover-skill란 무엇인가요?

이 스킬은 고정된 위치의 로고, 모서리 마크, 워터마크, 하드코딩 자막 등 비디오에 내장된 요소를 제거하는 강력한 도구입니다. ProPainter 비디오 인페인팅 모델을 기반으로 하며, NVIDIA GPU에서 최적의 성능을 발휘합니다. 자동으로 요소의 위치와 등장 구간을 탐지하고, 마스크 미리보기를 통해 사용자에게 확인을 받은 후 정밀하게 인페인팅합니다. 또한 QC(품질 검사)를 통해 잔상, 깜빡임, 이음새 등의 결함을 수치와 시각적으로 검증하여 높은 품질의 결과물을 보장합니다. 영상 외에도 전후 비교 이미지와 새로운 로고/자막 배치를 위한 좌표 문서를 함께 제공하여, 후속 편집 작업의 생산성을 크게 향상시킵니다. 지원하는 플랫폼은 Claude Code, Cursor, Codex 등 AI 에이전트 환경이며, 로컬 환경에서 실행되므로 데이터 보안에 유리합니다.

지원 대상✓Claude Code~Codex CLI~Cursor
npx skills add https://github.com/starx1n9/video-watermark-remover-skill/tree/HEAD/skills/video-watermark-remover

즐겨 사용하는 AI에게 물어보기

이 에이전트 스킬이 미리 로드된 새 채팅을 엽니다.

문서

영상 로고/자막 제거 (video-watermark-remover)

ProPainter를 사용하여 비디오에서 고정 위치의 로고, 모서리 마크 및 자막(화면에 고정된)을 제거합니다. 요소 주변의 ROI(관심 영역)만 잘라서 인페인팅한 후, 가장자리를 부드럽게 혼합하여 원본 영상에 다시 붙입니다. ROI 외부의 픽셀은 변경되지 않습니다.

⚠ ProPainter의 라이선스는 S-Lab License 1.0입니다. 비상업적 용도로만 사용 가능하며, 상업적 사용을 위해서는 원저작자에게 별도 문의해야 합니다. 또한, 사용자는 처리 권한이 있는 콘텐츠에만 이 도구를 사용해야 합니다.

0. 환경 설정 (최초 사용)

모든 스크립트는 scripts/ 디렉토리에 있습니다. 작업 디렉토리를 이 스킬 디렉토리(즉, SKILL.md 파일이 있는 곳)로 설정해야 합니다.

python scripts/setup_env.py      # ffmpeg / PyTorch(CUDA) 확인, 고정 버전의 ProPainter 클론, config.json 생성
python scripts/selftest.py       # 합성 테스트 비디오로 전체 흐름 실행, 정답과 비교하여 PASS/FAIL 출력
  • config.json이 없으면 setup_env.py가 누락된 항목과 설치 방법을 안내합니다. PyTorch는 사용자가 자신의 그래픽 카드에 맞는 CUDA 버전을 설치해야 합니다.
  • 자체 테스트가 통과하지 않으면 계속 진행하지 말고, 먼저 안내에 따라 환경을 수정하세요.
  • 아래의 python은 setup_env.py가 config.json에 기록한 인터프리터(즉, setup_env.py를 실행할 때 사용한 환경)를 가리킵니다.

사용자가 제공해야 할 정보

항목필수설명
비디오 파일✅하나 이상의 비디오 파일
제거할 대상✅일상적인 표현으로 충분: "왼쪽 위 로고", "중앙 큰 로고", "하단 자막"
위치 힌트선택동일한 유형의 요소가 여러 개 있을 때만 필요
시간 구간선택기본값: 자동 감지. 일부 구간을 유지하려는 경우에만 필요
후속 작업 계획권장 질문새 로고 오버레이 여부, 자막 재삽입 여부, 새 자막에 배경 막대가 있는지 여부. 배경 막대가 있으면 인페인팅 대신 흐림 처리만으로 충분

필수 항목이 없으면 사용자에게 질문하고, 선택 항목은 묻지 마세요.

기능 범위 (작업 시작 전 확인, 범위를 벗어나는 경우 먼저 사용자에게 알림)

  • ✅ 고정 위치의 로고, 모서리 마크, 워터마크 (반투명, 페이드 인/아웃, 오프닝/엔딩 전환 장면에서 흐려진 경우 포함).
  • ✅ 고정 위치, 수평 중앙, 단일 행의 자막 (화면에 고정된), 흰색 또는 어두운 글자, 그림자 유무 관계없음.
  • ⚠️ 움직이거나 크기가 변하는 로고, 스크롤 자막, 여러 행 자막, 중앙에 없는 자막: 스크립트가 자동으로 추적할 수 없으며, 사용자가 시간 구간을 지정한 후 --block, --grow-from 옵션으로 수동 처리해야 하며, 결과물 품질이 저하될 수 있습니다.
  • ⚠️ 화면에 원래 있는 텍스트(간판, 화면 내 글자)가 제거 대상 요소와 겹치는 경우 함께 흐려질 수 있습니다. 식별 목록에서 사용자에게 이 사실을 알려야 합니다.
  • NVIDIA GPU 필요, 가용 VRAM 4GB 이상 권장. CPU만으로도 실행 가능하지만 매우 느립니다.

프로세스 (8단계, 순차 진행)

중간 파일은 임시 작업 디렉토리 $W에 저장됩니다. 최종 결과물은 원본 비디오 옆에, 품질 검사 이미지는 <비디오 디렉토리>/qc/에 저장됩니다.

1. 탐지

python scripts/probe.py IN1.mp4 [IN2.mp4] --out-dir $W

샘플 프레임 모자이크를 보고 다음을 판단합니다:

  • 요소 위치
  • 모서리 마크인지 중앙 큰 로고인지
  • 페이드 인 (로고가 안정적으로 나타나는 프레임 구간 기록), 블랙 장면, 확대/축소 또는 흐림 전환 장면 유무
  • 자막 유무

2. 위치 파악 (정적 로고)

python scripts/locate_static.py --video IN1.mp4@시작프레임:종료프레임 [--video IN2.mp4@a:b] --out-dir $W
  • 시작/종료 프레임은 페이드 인, 블랙 장면, 전환 장면을 피해야 합니다.
  • 여러 비디오에 동일한 로고가 있을 경우 함께 전달합니다. 스크립트는 "모든 비디오에서 정지된" 픽셀만 선택하여 배경에서 우연히 정지된 블록을 배제합니다.
  • static_rel.png (어두울수록 정지된 영역)을 보고, 이를 기준으로 로고의 대략적인 박스 --box와 임계값 결정: 단색 로고 0.3–0.5, 반투명 로고 0.6–0.75.

3. 마스크 생성 및 반드시 사용자 확인

정적 로고:

python scripts/mask_logo.py --rel $W/static_rel.npy --box x0,y0,x1,y1 --thresh 0.5 \
    [--block 사각형] [--clear 영역 --block 영역] --preview IN1.mp4@프레임 [--preview IN2.mp4@프레임] --out-dir $W
  • 가느다란 요소(텍스트, 선, 줄)는 획 단위로 마스킹합니다. 획 사이의 실제 배경은 모델이 참조할 수 있도록 남겨둡니다.
  • --block 사각형은 두 가지 경우에만 사용합니다: 단색 큰 블록이거나, 너무 가늘어 완전히 마스킹하기 어려운 작은 글자(예: 작은 영문 한 줄).
  • ❌ 가느다란 요소를 통째로 덮지 마십시오. 카메라가 천천히 확대될 때, 덮인 부분에서 실제 배경이 거의 노출되지 않아 모델이 픽셀을凭空 생성해야 하며, 이로 인해 "비늘 모양 텍스처"가 나타날 수 있습니다.
  • 미리보기 이미지에서 요소의 가장자리와 꼬리 부분이 누락되었는지 확인하십시오. 누락된 부분은 인페인팅 시 내부로 끌려 들어와 컬러 라인을 남깁니다.

자막:

python scripts/mask_subtitle.py IN.mp4 --out-dir $W [--rows y0,y1] [--dark] [--shadow 0,0]
  • --rows를 지정하지 않으면 화면 하단 40% 범위에서 자동으로 자막 줄을 찾습니다. 잘못 찾은 경우 수동으로 지정하십시오.
  • 출력에서 "화면 가장자리에 가까움" 경고를 주의하십시오.

사용자 확인: mask_preview.png 또는 subtitle_mask_preview.png를 사용자에게 보여주고, 식별 목록도 함께 제공하십시오. 좌표는 mask_logo.py가 출력한 값을 사용합니다. 예:

① 왼쪽 상단 로고: 인페인팅 박스 (21,15)–(124,50), 전체 구간 등장 ② 하단 자막: y485–524, 총 47개 문장 ③ 1:34 지점의 화면 간판이 인페인팅 영역 내에 있어 함께 흐려질 수 있음

사용자 확인 후에만 5단계로 진행합니다.

4. 구간 분할

python scripts/shots.py IN.mp4 --out $W/bounds.json [--extra 178]

하드 컷과 페이드 인/아웃 전환 장면이 모두 분할됩니다. 구간 분할 없이 실행하면, 정적인 장면에서 인접 장면 색상의 "알약 모양 색 블록"이 나타날 수 있습니다.

5+6. 인페인팅 + 합성

긴 비디오는 백그라운드에서 실행하고, 주기적으로 로그를 확인하며 사용자에게 진행 상황을 능동적으로 알리십시오.

python scripts/inpaint.py --video IN.mp4 (--mask $W/mask.npy | --masks $W/masks.npz) --bounds $W/bounds.json \
    --workdir $W/run --out OUT.mp4 [--mask-dilation 2] [--grow-from 178:14] [--workers 2]
  • --mask-dilation: 기본 2; 반투명 또는 글로우가 있는 로고는 4를 사용하십시오.
  • --grow-from 프레임:픽셀: 특정 프레임부터 마스크를 추가로 확장하여, 확대/축소 또는 흐림 전환 장면에서 흐트러진 로고를 덮습니다.
  • 동일한 비디오에서 로고와 자막을 모두 제거해야 하는 경우, 두 번 나누어 실행하십시오. 두 번째 실행의 --video는 첫 번째 출력을 사용하고, 두 ROI를 하나의 큰 박스로 합치지 마십시오.
  • 중단 시 동일한 명령어로 다시 실행하면, 이미 완료된 구간은 건너뜁니다.
  • 출력 파일 이름은 원래이름-nologo.mp4 또는 원래이름-nologo-nosub.mp4 형식입니다. 스크립트는 원본 파일을 덮어쓰지 않습니다.
  • 소요 시간 참고 (RTX 3060, 2병렬): 960×540 해상도 126초 비디오, 왼쪽 상단 로그 약 17분, 자막 포함 약 21분; 5초짜리 중앙 큰 로고 약 1분.

7. 품질 검사 (QC)

python scripts/qc.py --orig IN.mp4 --out OUT.mp4 (--mask .. | --masks ..) --bounds $W/bounds.json --workdir $W/run \
    [--residue blue] [--times 3,12,20] --out-dir <비디오 디렉토리>/qc/xxx

수치 지표:

  • 잔상: 결과 프레임의 분산이 외부 영역 분산과 거의 같아야 함.
  • 깜빡임: 중앙값 비율이 1 또는 그 이하여야 하며, 급격한 점프 프레임이 거의 없어야 함.
  • 이음새: 비율이 약 1이어야 함.
  • 외부 오류: 2 미만.
  • 잔류 색상: 0에 가깝게 감소해야 함.
  • 완전 검은 프레임: 0프레임.

⚠ 모든 수치 지표가 통과하더라도 국부적인 문제가 있을 수 있으므로, 반드시 sheet_XX.png를 한 페이지씩 열어 육안으로 검사하십시오 (색 블록, 비늘 텍스처, 잔여 글자, 컬러 라인). 문제 발견 시 해당 단계로 돌아가 수정하십시오:

  • 색 블록: shots.py --extra로 컷 포인트 추가.
  • 비늘 텍스처: 획 단위 마스킹으로 변경.
  • 잔여 라인: --block 옵션 추가.

수정 후에는 영향을 받은 부분만 다시 실행하고, 다시 QC를 수행하십시오.

8. 전달

  • 결과 비디오와 비교 이미지의 절대 경로를 제공하고, before_after.png를 사용자에게 보여주십시오.
  • 여러 비디오를 연결해야 하는 경우 python scripts/concat.py A.mp4 B.mp4 C.mp4 --out FULL.mp4 명령어를 사용하십시오. 스크립트가 총 프레임 수가 각 부분의 합과 일치하는지 검증합니다.
  • 좌표 문서를 작성하십시오. 템플릿은 references/positions-template.md를 참조하십시오. 각 요소에 대해 세 가지 레이어 박스를 작성합니다: 원래 요소 범위, 실제 인페인팅 범위, 블렌딩된 가장 바깥쪽 범위 (새 로고가 덮을 권장 영역). 자막의 경우 subtitle_info.json의 union_box를 사용하십시오.
  • 알려진 결함은 시간별로 명확히 나열하고 숨기지 마십시오.

하드 규칙 (모두 실제 테스트에서 얻은 교훈)

  1. ROI의 너비와 높이는 모두 ≥160이어야 합니다. 높이가 96이면 ProPainter가 마스크 영역에서 완전 검은색을 출력하며, fp32로 변경해도 동일합니다. inpaint.py는 ROI를 선택할 때 이미 이 조건을 보장합니다.
  2. 전환 장면은 반드시 분할해야 합니다. 하드 컷만 분할하면 페이드 인/아웃이 누락되어 ProPainter가 다른 장면의 픽셀을 차용하여 색 블록이 나타납니다. 마스크 확장이나 fp32 사용으로는 해결할 수 없습니다.
  3. 가느다란 요소는 획 단위로 마스킹하고, 통째로 덮지 마십시오.
  4. 자막은 중앙 대칭으로 잘라야 하며, 동일한 문장에는 동일한 마스크를 사용해야 합니다. 대칭 자르기를 하지 않으면 배경의 밝은 줄이 마스크에 포함되고, 동일한 문장에 다른 마스크를 사용하면 깜빡임이 발생하며, 페이드 인 시에도 누락이 발생합니다.
  5. 수치 지표만으로는 문제를 놓칠 수 있으므로, 반드시 한 페이지씩 육안으로 검사하십시오.
  6. 인페인팅 전에 반드시 사용자에게 마스크를 확인받아야 합니다. 원본 파일을 덮어쓰거나 사용자의 파일을 삭제하지 마십시오.
  7. 백그라운드 서브 프로세스는 창을 띄우지 않습니다 (스크립트에 내장됨). 긴 작업은 백그라운드에서 실행하고, 진행 상황을 적극적으로 보고하십시오.

관련 스킬