copy_move_regions — IMGFORENSICS 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 作為輸入)

evidence_quantile

同類別(copy_move)

—


*Provenance: imgforensics.py — IMGFORENSICS 運算子登記表。本條目由 tools/opdocs.py md 自動產生(請勿手動編輯)。*

© 2026 Kazufumi Furuse — Fullseye operator documentation. Licensed under Apache-2.0.