43 lines
2.5 KiB
Python
43 lines
2.5 KiB
Python
"""Adversarial behavior checks independent of card-specific artwork."""
|
|
from pathlib import Path
|
|
import json
|
|
import numpy as np
|
|
from PIL import Image,ImageDraw
|
|
from line_detector import detect
|
|
ROOT=Path(__file__).resolve().parent
|
|
r=json.loads((ROOT/'recipe.json').read_text())
|
|
def run(a): return detect(Image.fromarray(a),r)
|
|
checks={};w,h=192,192
|
|
# Uniform dark glass is not a line.
|
|
assert not np.any(run(np.full((h,w,3),28,dtype=np.uint8)));checks['uniformDarkPaneRejected']=True
|
|
# A continuous seam at a supported width remains protected.
|
|
a=np.full((h,w,3),145,dtype=np.uint8);a[:,92:99]=10
|
|
v=run(a);assert np.min(v[20:-20,95])>.97;checks['continuousSeamProtected']=True
|
|
# Dark blue interruption exceeds the old max-channel gate but is bracketed.
|
|
b=a.copy();b[94:98,92:99]=[35,48,82]
|
|
q=run(b);unbridged=dict(r,bridgeDistances=[]);q0=detect(Image.fromarray(b),unbridged)
|
|
assert q[96,95]>.8 and q[96,95]>q0[96,95]+.1;checks['shortColoredGapBridged']=True
|
|
# No protection grows into an extended blank area along a terminated seam.
|
|
c=a.copy();c[70:125,92:99]=145
|
|
assert run(c)[96,95]<.01;checks['longBrightGapNotBridged']=True
|
|
# Both sides must be brighter; a wide shadow's interior/step edge are rejected.
|
|
d=np.full((h,w,3),145,dtype=np.uint8);d[:,65:128]=20
|
|
assert run(d)[96,96]<.01 and run(d)[96,65]<.01;checks['broadShadowAndStepEdgeRejected']=True
|
|
# Isolated flecks lack elongated support, including a 5px dark spot.
|
|
e=np.full((h,w,3),145,dtype=np.uint8);e[94:99,94:99]=10
|
|
assert run(e)[96,96]<.2;checks['isolatedTextureSpotRejected']=True
|
|
# Thicker dividers and dark crossing junctions exercise the expanded widths.
|
|
f=np.full((h,w,3),145,dtype=np.uint8);f[:,85:106]=10
|
|
assert run(f)[96,95]>.97;checks['wideDividerProtected']=True
|
|
f=np.full((h,w,3),145,dtype=np.uint8);f[:,92:99]=10;f[93:100,:]=10
|
|
assert run(f)[96,95]>.8;checks['darkCrossingJunctionRecovered']=True
|
|
# A sloping/curved divider does not depend on horizontal/vertical alignment.
|
|
im=Image.new('RGB',(w,h),(145,145,145));draw=ImageDraw.Draw(im)
|
|
draw.line([(40,15),(54,50),(83,92),(115,131),(135,176)],fill=(10,10,10),width=7)
|
|
v=detect(im,r);assert v[92,83]>.8;checks['slopingDividerProtected']=True
|
|
# Shift edges cannot wrap across the opposite side of a card.
|
|
e=np.full((h,w,3),145,dtype=np.uint8);e[:,0:7]=10
|
|
assert not np.any(run(e)[:,170:]);checks['noOppositeEdgeWrap']=True
|
|
(ROOT/'detector-checks.json').write_text(json.dumps({'status':'passed','checks':checks,'gapProtection':float(q[96,95]),'gapWithoutBridge':float(q0[96,95])},indent=2)+'\n')
|
|
print(json.dumps(checks,indent=2))
|