anky2002 commited on
Commit
d348aa2
Β·
verified Β·
1 Parent(s): 2d481fb

fix: replace Laplacian bokeh check with local-variance method in autocorrelation override

Browse files

The old Laplacian-based bokeh detection in m05_autocorrelation() failed for macro
DSLR images because the 10%-of-peak-sharpness threshold didn't reliably capture
the bokeh region when the sharp-to-smooth transition was gradual.

New approach uses uniform_filter to compute local variance (E[XΒ²]-E[X]Β²) over
32Γ—32 windows, then thresholds at 5% of the P95 variance. This works because:
- Real bokeh: P95 is high (sharp subject), most pixels are far below β†’ detected
- AI smooth: P95 is low (<50), guard clause blocks bokeh excuse β†’ override fires
- Normal photo: variance spread evenly, few pixels below 5% of P95 β†’ no false trigger

For the Unsplash macro DSLR test image, this should:
- Drop Autocorrelation Peak from +0.80 to +0.15 (bokeh explained)
- Remove override_suppression flag β†’ modality Γ—0.1 can further reduce to +0.015
- Move Generative Model Agent from ~+0.054 to ~-0.02 (neutral/authentic)
- Push P(Fake) from ~46.9% to ~44-45%

Files changed (1) hide show
  1. agents/model_agent.py +43 -27
agents/model_agent.py CHANGED
@@ -78,37 +78,53 @@ def m05_autocorrelation(img):
78
  re=max(h,w)//20; Y,X=np.mgrid[0:h,0:w]; cm=((X-cx)**2+(Y-cy)**2)<re**2; acm[cm]=0
79
  ms=float(np.max(acm))
80
 
81
- # Before firing hard override, check if high autocorrelation is explained by bokeh
82
- # Macro/portrait photos have large uniform bokeh regions that create high autocorrelation
83
- # from optical physics, not AI generation.
 
 
 
 
 
84
  bokeh_explained = False
 
85
  if ms > 0.95:
86
- from scipy.signal import convolve2d
87
- lap = np.array([[0,1,0],[1,-4,1],[0,1,0]], dtype=np.float64)
88
- sharpness = gaussian_filter(np.abs(convolve2d(gray, lap, mode="same", boundary="symm")), sigma=10)
89
 
90
- # Estimate bokeh region: pixels with sharpness below 10% of peak
91
- peak_sharp = float(np.percentile(sharpness, 95))
92
- if peak_sharp > 1:
93
- bokeh_thresh = peak_sharp * 0.1 # Below 10% of peak = blurred
94
- bokeh_region = sharpness < bokeh_thresh
95
- bokeh_fraction = float(np.mean(bokeh_region))
96
-
97
- bokeh_vals = sharpness[bokeh_region] if np.sum(bokeh_region) > 100 else np.array([1])
98
- bokeh_uniformity = 1.0 - min(float(np.std(bokeh_vals)) / (float(np.mean(bokeh_vals)) + 1e-9), 1.0)
99
-
100
- # The non-bokeh region must have genuine sharp detail (not smooth gradient)
101
- has_genuine_sharp = peak_sharp > 10.0
102
-
103
- # Bokeh explains autocorrelation if:
104
- # 1. Large blur region (>25% of image below 10% of peak sharpness)
105
- # 2. AND genuine sharp foreground detail exists
106
- if bokeh_fraction > 0.25 and has_genuine_sharp:
107
- bokeh_explained = True
 
 
 
 
 
108
  else:
109
- # Entire image is smooth β€” no bokeh, just low detail
110
  bokeh_fraction = 0.0
111
- bokeh_explained = False # Smooth everywhere β‰  bokeh
 
 
 
 
 
 
 
112
 
113
  if ms > 0.95 and not bokeh_explained:
114
  s, n = 0.8, f"CRITICAL: Autocorrelation {ms:.3f} exceeds physical camera limit β€” AI generated"
@@ -116,7 +132,7 @@ def m05_autocorrelation(img):
116
  result["override_suppression"] = True
117
  return result
118
  elif ms > 0.95 and bokeh_explained:
119
- s, n = 0.15, f"High autocorrelation ({ms:.3f}) but large bokeh region ({bokeh_fraction:.0%}) β€” likely optical, not AI"
120
  return {"test":"Autocorrelation Peak","max_secondary":round(ms,4),"score":s,"note":n,"bokeh_explained":True}
121
  elif ms>0.3: s,n=0.6,f"Strong secondary peak ({ms:.3f}) β€” GAN checkerboard"
122
  elif ms>0.15: s,n=0.3,f"Moderate peak ({ms:.3f})"
 
78
  re=max(h,w)//20; Y,X=np.mgrid[0:h,0:w]; cm=((X-cx)**2+(Y-cy)**2)<re**2; acm[cm]=0
79
  ms=float(np.max(acm))
80
 
81
+ # Before firing hard override, check if high autocorrelation is explained by bokeh.
82
+ # Macro/portrait/shallow-DoF photos have large uniform bokeh regions that create
83
+ # high autocorrelation from optical physics, not AI generation.
84
+ #
85
+ # Method: Local variance via uniform_filter. Bokeh regions have very low local
86
+ # variance (uniform pixel intensity). This is more robust than the Laplacian
87
+ # approach because it directly measures what bokeh is β€” spatial uniformity β€”
88
+ # rather than inferring it from edge magnitude.
89
  bokeh_explained = False
90
+ bokeh_fraction = 0.0
91
  if ms > 0.95:
92
+ from scipy.ndimage import uniform_filter as uf
 
 
93
 
94
+ # Compute local variance: E[XΒ²] - E[X]Β² over 32Γ—32 windows
95
+ local_mean = uf(gray, size=32)
96
+ local_sq_mean = uf(gray**2, size=32)
97
+ local_var = np.clip(local_sq_mean - local_mean**2, 0, None)
98
+
99
+ # Bimodal variance test: in a real bokeh/macro/shallow-DoF image, the
100
+ # variance distribution is strongly bimodal β€” sharp foreground has high
101
+ # local variance while the defocused background has near-zero variance.
102
+ #
103
+ # Strategy: Use the P95 of local variance (captures the sharp subject's
104
+ # typical variance) and threshold at 5% of that value. Pixels below this
105
+ # threshold are effectively uniform/bokeh. This works because:
106
+ # - Real bokeh: P95 is high (sharp subject), most pixels are far below it
107
+ # - AI smooth: P95 is low, so threshold is tiny, nothing qualifies as
108
+ # "bokeh relative to sharp detail" because there IS no sharp detail
109
+ # - Normal photo: variance is spread out, few pixels are <5% of P95
110
+ p95_var = float(np.percentile(local_var, 95))
111
+
112
+ if p95_var > 50.0: # Guard: sharp region must have real detail
113
+ var_thresh = p95_var * 0.05 # 5% of peak variance
114
+ low_var_mask = local_var < var_thresh
115
+ bokeh_fraction = float(np.mean(low_var_mask))
116
+ has_genuine_detail = True # Already guaranteed by p95 > 50 check
117
  else:
118
+ # No region with genuine high-variance detail β€” not a bokeh image
119
  bokeh_fraction = 0.0
120
+ low_var_mask = np.zeros_like(local_var, dtype=bool)
121
+ has_genuine_detail = False
122
+
123
+ # Bokeh explains autocorrelation if:
124
+ # 1. Large uniform region (>35% of image has variance < 5% of P95)
125
+ # 2. AND genuine sharp detail exists (P95 variance > 50)
126
+ if bokeh_fraction > 0.35 and has_genuine_detail:
127
+ bokeh_explained = True
128
 
129
  if ms > 0.95 and not bokeh_explained:
130
  s, n = 0.8, f"CRITICAL: Autocorrelation {ms:.3f} exceeds physical camera limit β€” AI generated"
 
132
  result["override_suppression"] = True
133
  return result
134
  elif ms > 0.95 and bokeh_explained:
135
+ s, n = 0.15, f"High autocorrelation ({ms:.3f}) but large bokeh region ({bokeh_fraction:.0%} uniform background) β€” likely optical, not AI"
136
  return {"test":"Autocorrelation Peak","max_secondary":round(ms,4),"score":s,"note":n,"bokeh_explained":True}
137
  elif ms>0.3: s,n=0.6,f"Strong secondary peak ({ms:.3f}) β€” GAN checkerboard"
138
  elif ms>0.15: s,n=0.3,f"Moderate peak ({ms:.3f})"