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。以 step px 的步長取 block 見方的
重疊區塊(預設 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),是正確的。壞掉的是「能否找到」,而不是找到時的答案。
• 範例資料目錄(下載 URL / 授權) —— 2-D 用 skimage.data(BSD/公有領域)加合成圖,3-D 給出真實資料源(Stanford/PDS 等)的下載 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 運算子登記表。本條目由 tools/opdocs.py md 自動產生(請勿手動編輯)。*
© 2026 Kazufumi Furuse — Fullseye operator documentation. Licensed under Apache-2.0.