/// 标定实验:用数据回答「dot_contrast + margin 机制实际能支撑多强的结论」。
///
/// 实验一:单对照(controls=1,旧判据)在未嵌入图上的 contrast 分布 → 误报率基线。
/// 实验二:多对照(controls=8,现行默认)在同一批样本上的误报率对比。
/// 实验三:自标定显著性检验(多对照 + 本底对比)的误报率。
/// 实验四:溯源锁定质量——1 真 + 8 相邻错误 seed,三类出口占比。
///
/// 全部样本与 seed 固定,输出可复现;判据均调用库内公开 API。
let size : Int32 = 128
/// 伪随机数(LCG,固定初值保证可复现)
fn rng(st : Int64) -> Int64 {
st * 6364136223846793005L + 1442695040888963407L
}
/// 均匀亮度图
fn uniform(v : Int32) -> @lib.RgbaImage {
@lib.RgbaImage::new(size, size, (0xFF << 24) | (v << 16) | (v << 8) | v)
}
/// 双值噪声纹理:dark_frac 比例的像素为暗值,其余为亮值
fn noise(dark_frac : Double, dark : Int32, light : Int32) -> @lib.RgbaImage {
let img = uniform(light)
let mut st = 12345L
let n = size * size
for i in 0..> 33) & 0x7FFFFFFFL).to_double() / 2147483648.0 < dark_frac {
let v = (0xFF << 24) | (dark << 16) | (dark << 8) | dark
img.set_pixel(i % size, i / size, v)
}
}
img
}
/// 水平渐变
fn gradient_h() -> @lib.RgbaImage {
let img = uniform(0)
for y in 0.. @lib.RgbaImage {
let img = uniform(0)
for y in 0.. @lib.RgbaImage {
let img = uniform(180)
for y in 0.. @lib.RgbaImage {
let img = uniform(0)
for y in 0.. @lib.RgbaImage {
let img = uniform(200)
let mut st = 999L
for _ in 0..<12 {
st = rng(st)
let bw = 8 + ((st >> 40) & 15L).to_int()
let bh = 4 + ((st >> 24) & 7L).to_int()
st = rng(st)
let bx = (((st >> 40) & 0x7FFFFFFFL) % (size - bw).to_int64()).to_int()
st = rng(st)
let by = (((st >> 40) & 0x7FFFFFFFL) % (size - bh).to_int64()).to_int()
for dy in 0.. Array[(String, () -> @lib.RgbaImage)] {
[
("uniform_0", fn() { uniform(0) }),
("uniform_80", fn() { uniform(80) }),
("uniform_160", fn() { uniform(160) }),
("uniform_240", fn() { uniform(240) }),
("noise_dark10", fn() { noise(0.1, 20, 150) }),
("noise_dark30", fn() { noise(0.3, 20, 150) }),
("noise_dark50", fn() { noise(0.5, 20, 150) }),
("noise_dark70", fn() { noise(0.7, 20, 150) }),
("gradient_h", fn() { gradient_h() }),
("gradient_v", fn() { gradient_v() }),
("pinstripe_p0", fn() { pinstripe(0) }),
("pinstripe_p1", fn() { pinstripe(1) }),
("pinstripe_p2", fn() { pinstripe(2) }),
("pinstripe_p3", fn() { pinstripe(3) }),
("checker4", fn() { checker() }),
("blocks", fn() { blocks() }),
]
}
/// 自标定本底:8 个独立 null seed 的 contrast 最大值(与库内 null_max 同规则)
fn null_max_of(img : @lib.RgbaImage, k : Int) -> Double {
let mut mx = 0.4
for j in 1..<9 {
let s = 0x243F6A8885A308D3L + Int64::from_int(j) * 7919L
let c = @lib.dot_contrast(
img,
@lib.DotConfig::new(0.05, 3, s, 1.0, 0, 0),
controls=k,
)
if c > mx {
mx = c
}
}
mx
}
/// 实验一 + 实验二:单对照 vs 多对照 FPR(同一批 1024 未嵌入样本)
fn experiment_fpr() -> Unit {
println("实验一/二:未嵌入图误报率(64 seed × 16 图型 = 1024 样本,阈值 0.4)")
println("")
let set = image_set()
let mut fp1 = 0
let mut fp8 = 0
let mut max1 = 0.0
let mut max8 = 0.0
for i in 0..= 0.4 {
f1 = f1 + 1
}
if c8 >= 0.4 {
f8 = f8 + 1
}
if c1 > max1 {
max1 = c1
}
if c8 > max8 {
max8 = c8
}
}
fp1 = fp1 + f1
fp8 = fp8 + f8
println("\{name} 单对照 FPR=\{f1}/64 多对照(k=8) FPR=\{f8}/64")
}
println("")
println(
"合计:单对照 FPR=\{fp1}/1024(max=\{max1}) 多对照(k=8) FPR=\{fp8}/1024(max=\{max8})",
)
}
/// 实验三:自标定显著性检验 FPR(多对照 + 本底对比)
fn experiment_calibrated_fpr() -> Unit {
println("")
println("实验三:自标定规则(c ≥ max(0.4, 本图 null 最大值 + 0.15),多对照 k=8)")
let set = image_set()
let mut fpc = 0
for i in 0..= 0.4 {
let nl = null_max_of(img, 8)
if c >= nl + 0.15 {
fpc = fpc + 1
}
}
}
}
println("自标定后 FPR=\{fpc}/1024")
}
/// 实验四:溯源锁定质量(200 试验,1 真 + 8 相邻错误 seed,多对照默认)
fn experiment_trace() -> Unit {
println("")
println("实验四:溯源锁定质量(200 试验 × 2 条件,每试验 1 真 + 8 相邻错误 seed)")
println("正确=trace 锁定真 seed;安全拒锁=trace=-2;误锁=trace 锁定错误 seed(最坏);未检出=trace=-1")
println("")
for mode in 0..<2 {
let label = if mode == 0 { "无损" } else { "JPEG q85 转码" }
let mut correct = 0
let mut refused = 0
let mut mislock = 0
let mut miss = 0
for t in 0..<200 {
let base = noise(0.1, 20, 190)
let seed = 1000L + Int64::from_int(t) * 7L
let cfg = @lib.DotConfig::new(0.05, 3, seed, 1.0, 0, 0)
let marked = match base.embed_dots(cfg) {
Ok(m) => m
Err(_) => continue
}
let img = if mode == 0 {
marked
} else {
match marked.encode_jpeg(85) {
Ok(j) =>
match @lib.decode_jpeg(j) {
Ok(d) => d
Err(_) => continue
}
Err(_) => continue
}
}
let candidates = []
for k in 0..<9 {
let s = if k == 0 { seed } else { seed + Int64::from_int(k) }
candidates.push(@lib.DotConfig::new(0.05, 3, s, 1.0, 0, 0))
}
match @lib.trace_dots(img, candidates) {
0 => correct = correct + 1
-2 => refused = refused + 1
-1 => miss = miss + 1
_ => mislock = mislock + 1
}
}
println(
"\{label}:正确=\{correct}/200 安全拒锁(-2)=\{refused}/200 误锁=\{mislock}/200 未检出(-1)=\{miss}/200",
)
}
println("")
println("注:实验背景为高频二值噪声纹理(10% 暗像素),属点阵通道拒绝域——")
println(" 该场景下深色命中统计被 3×3 邻域容差饱和,真信号本底仅 ~0.39。")
println(" 点阵通道的设计场景(平滑内容画面)请参考 cmd/e2e 与 README 鲁棒性矩阵。")
}
///| 主入口
fn main {
println("================================================================")
println("moon-watermark 判定机制标定实验(128×128,density=0.05,dot_size=3)")
println("================================================================")
experiment_fpr()
experiment_calibrated_fpr()
experiment_trace()
}