rogermt's picture
Move own-solver/neurogolf_solver/solvers/edge.py to own-solver/
bb1e82c verified
#!/usr/bin/env python3
"""Edge/boundary detection solver — Laplacian Conv.
v5.2: 0 matches in current task set (edge definition too strict).
Kept for future variants (per-color edges, interior-only edges, etc.).
"""
import numpy as np
from onnx import helper, numpy_helper
from ..onnx_helpers import mk, _make_int64_init, _build_pad_node
from ..data_loader import get_exs, fixed_shapes
from ..constants import GH, GW
def _has_edges(inp, out, edge_color, bg_color=0):
"""Check if output is edge detection of input."""
h, w = inp.shape
for r in range(h):
for c in range(w):
pix = inp[r, c]
is_edge = False
if pix != bg_color:
for dr, dc in [(-1, 0), (1, 0), (0, -1), (0, 1)]:
nr, nc = r + dr, c + dc
if 0 <= nr < h and 0 <= nc < w:
if inp[nr, nc] != pix:
is_edge = True
break
else:
is_edge = True
break
expected = edge_color if is_edge else bg_color
if out[r, c] != expected:
return False
return True
def _build_edge_model(IH, IW, edge_color, bg_color=0):
"""Build ONNX model for edge detection via Laplacian conv."""
pad_h, pad_w = GH - IH, GW - IW
ch_sel = np.zeros((1, 10, 1, 1), dtype=np.float32)
for c in range(10):
if c != bg_color:
ch_sel[0, c, 0, 0] = 1.0
lap_k = np.array([[0, -1, 0],
[-1, 4, -1],
[0, -1, 0]], dtype=np.float32).reshape(1, 1, 3, 3)
edge_oh = np.zeros((1, 10, 1, 1), dtype=np.float32)
edge_oh[0, edge_color, 0, 0] = 1.0
bg_oh = np.zeros((1, 10, 1, 1), dtype=np.float32)
bg_oh[0, bg_color, 0, 0] = 1.0
inits = [
_make_int64_init('sl_st', [0, 0, 0, 0]),
_make_int64_init('sl_en', [1, 10, IH, IW]),
numpy_helper.from_array(ch_sel, 'ch_sel'),
numpy_helper.from_array(lap_k, 'lap_k'),
numpy_helper.from_array(np.float32(0.5), 'thresh'),
numpy_helper.from_array(edge_oh, 'edge_oh'),
numpy_helper.from_array(bg_oh, 'bg_oh'),
]
nodes = [
helper.make_node('Slice', ['input', 'sl_st', 'sl_en'], ['cropped']),
helper.make_node('Conv', ['cropped', 'ch_sel'], ['occ'], kernel_shape=[1, 1]),
helper.make_node('Conv', ['occ', 'lap_k'], ['lap_out'], kernel_shape=[3, 3], pads=[1, 1, 1, 1]),
helper.make_node('Abs', ['lap_out'], ['lap_abs']),
helper.make_node('Greater', ['lap_abs', 'thresh'], ['is_edge_raw']),
helper.make_node('Greater', ['occ', 'thresh'], ['is_occ']),
helper.make_node('And', ['is_edge_raw', 'is_occ'], ['is_edge']),
helper.make_node('Where', ['is_edge', 'edge_oh', 'bg_oh'], ['result_small']),
]
nodes.append(_build_pad_node('result_small', 'output', pad_h, pad_w, inits))
return mk(nodes, inits)
def s_edge_detect(td):
"""Edge detection solver: output = boundary pixels of input shapes."""
exs = get_exs(td)
sp = fixed_shapes(td)
if sp is None:
return None
(IH, IW), (OH, OW) = sp
if (IH, IW) != (OH, OW):
return None
for bg_color in [0]:
out_colors = set()
for _, out in exs:
out_colors.update(out.flatten())
for edge_color in out_colors:
if edge_color == bg_color:
continue
if all(_has_edges(inp, out, edge_color, bg_color) for inp, out in exs):
return _build_edge_model(IH, IW, edge_color, bg_color)
return None