copy_move op• 데이터 종류: image2d → table
• 호출: import fullseye as fs; fs.ledger.copy_move_regions(image, method: 'str' = 'keypoint', min_matches: 'int' = 4, min_offset: 'float' = 16.0, offset_tol: 'float' = 2.0, ratio: 'float' = 0.6, patch: 'int' = 11, block: 'int' = 8, step: 'int' = 1, n_dct: 'int' = 10, min_variance: 'float' = 0.0001, max_feature_dist: 'float' = 0.02, neighbours: 'int' = 2, ransac_thresh: 'float' = 3.0, ransac_iters: 'int' = 300, seed: 'int' = 0) -> 'list'(구현을 직접 호출하려면 import imgforensics; imgforensics.copy_move_regions(image, method: 'str' = 'keypoint', min_matches: 'int' = 4, min_offset: 'float' = 16.0, offset_tol: 'float' = 2.0, ratio: 'float' = 0.6, patch: 'int' = 11, block: 'int' = 8, step: 'int' = 1, n_dct: 'int' = 10, min_variance: 'float' = 0.0001, max_feature_dist: 'float' = 0.02, neighbours: 'int' = 2, ransac_thresh: 'float' = 3.0, ransac_iters: 'int' = 300, seed: 'int' = 0) -> 'list', 원장에서 가져오려면 opsimgforensics.get("copy_move_regions"))
한 이미지 안의 복사-이동(자기 복제) 영역 쌍. table.
method="keypoint"(기본값)
features.harris_corners로 코너를 구하고,
features.describe_patches로 정규화 패치 기술자를 만들어,
자기 자신에서 min_offset px 이상 떨어진 최근접과 Lowe의 비율 검정으로 대응을 만든다
(_self_match). 대응을 시프트 벡터로 묶고, 군마다
mosaic.proj_match_points_ransac로 기하 정합을 확인한다.
상사 변환은 fit_transform.vector_to_similarity(Umeyama)로 맞추어
similarity에 넣는다.
method="block"
Fridrich, Soukal & Lukáš 2003. block 정사각의 겹치는 블록을 step px
스텝으로 취하고(기본값 step=1 —— 이것은 장식이 아니다. 아래 "보폭" 참조),
각 블록의 DCT 저주파 n_dct 계수를 특징으로 하여 사전순으로 늘어놓고,
사전순으로 가까운 neighbours건까지를 후보로 하며, 특징 거리가
max_feature_dist 이하인 것만을 시프트 벡터로 센다.
회전·확대에는 효과가 없지만, 코너가 적은 화상에서 keypoint 법보다 많이 잡는다.
분산이 min_variance 미만인 블록은 버린다(균일한 하늘을 하늘에 복사해도같은 특징이 된다 = 검출기가 반드시 만드는 위양성의 주된 원인).
보폭(step)을 1로 해 둔 이유(실측으로 정했다): 블록 법이 "같은 특징"을찾을 수 있는 것은 복제원과 복제처가 같은 격자에 올라탔을 때뿐이다. step=4로 하면 시프트가 4의 배수가 아닌 복제(예를 들어 (110, 128))는 원리적으로 한 번도 일치하지 않는다. 실측에서 step=4는 참 시프트를 1건도 반환하지 않고, 대신 가짜 군을 60건 반환했다. step=1이면 참 시프트가 제1군으로 온다. 큰 화상에서 무거울 때는 step을 올려도 되지만, 올린 보폭의 배수의 시프트밖에 찾을 수 없게 된다는 것을 알고서 올릴 것.
반환은 영역 쌍의 list(대응 수가 많은 순). 각 요소:
offset 시프트 (dy, dx)(row, col). 방향은 위치로 정규화되어 있다
(사전순으로 양이 되는 방향) —— 첨자로 정하면 같은 복제가
(110, 128)도 (-110, -128)도 된다(실측해서 고쳤다)
n_matches 그 군의 대응 수
n_inliers RANSAC의 내점 수(method="block"에서는 n_matches와 같음)
inlier_ratio 내점률 src_bbox / dst_bbox (r0, c0, r1, c1) src_points / dst_points (N, 2)의 (row, col)
similarity Umeyama로 맞춘 3x3(method="keypoint"만, 없으면 None)
method 사용한 방법
caveats 이 결과가 말할 수 없는 것
정답이 손에 있으므로 맞힐 수 있다는 것을 수치로 고정해 두었다 (tests/test_imgforensics.py::test_copy_move_finds_the_known_offset, 256x256 텍스처 화상의 (40, 32)에 있는 64x64를 (150, 160)으로 복제 = 참 시프트 (110, 128)):
============ ================= ============ ========= ==============
method 제1군 offset n_matches 군의 수 오차
============ ================= ============ ========= ==============
keypoint (110.0, 128.0) 15 1 0 px
block (110.0, 128.0) 3249 1 0 px
============ ================= ============ ========= ==============
위양성도 재어 두었다: 변조하지 않은 같은 종류의 화상 3장에서는 keypoint 법·block 법 모두 군 0건(seed 4/5/6).
말할 수 없는 것(모두 같은 테스트로 재어 두었다):
• 균일한 영역(하늘·벽)은 복제하지 않아도 같은 특징이 된다. 위쪽 절반을 균일한 "하늘"로한(변조하지 않은) 화상에서 min_variance=1e-4와 1e-6은 둘 다 0건이지만, min_variance=0으로 하면 264쌍의 가짜 군이 1건 나온다(시프트 (1, -247) = 하늘 안의 적당한 대응).
• method="keypoint"는 정규화 패치 기술자이므로 회전에 효과가 없다. 복제를 돌려서 붙이면 군의 수는 0도 1건 → 5도 0건 → 15도 0건 → 30도 0건. similarity에 회전이 들어가서 반환되는 일은 실질적으로 없다.
• method="block"도 회전에 전혀 효과가 없다(5도에서 0건).
• 검출 제로 = 복제가 없다, 는 아니다. 재압축을 낀 복제는 특징 거리가 늘어나 max_feature_dist를 넘는다. 실측(같은 복제 화상을 JPEG에 통과시킨 뒤 검출):
========== ============================ ==========================
품질 keypoint 제1군의 n_matches block 제1군의 n_matches
========== ============================ ==========================
무압축 15 3249
95 10 138
85 7 10
75 7 0건(군 없음)
========== ============================ ==========================
시프트는 어느 품질에서도 (110.0, 128.0) 그대로 올바르다. 망가지는 것은 "찾을 수 있는가"이지, 찾았을 때의 답이 아니다.
• 샘플 데이터 카탈로그(DL URL / 라이선스) —— 2-D 는 skimage.data(BSD/public)+ 합성, 3-D 는 실데이터 소스(Stanford/PDS 등)의 DL URL.
• 연산자의 내력·참고문헌 —— 이 연산자 족의 바탕이 된 연구/기법의 출처.
• 알고리즘의 정전(저자·연도)과 용도는 위의 패밀리 사용 가이드에 적혀 있습니다.
• image_forensics_audit — py -3.11 examples/image_forensics_audit.py
• poc_forensics_roc — py -3.11 examples/poc_forensics_roc.py
table 를 입력으로 받는 것)copy_move)—
*Provenance: imgforensics.py — IMGFORENSICS 연산자 레지스트리. 이 op 노트는 tools/opdocs.py md 가 자동 생성합니다(직접 편집하지 마세요).*
© 2026 Kazufumi Furuse — Fullseye operator documentation. Licensed under Apache-2.0.