Move own-solver/neurogolf_solver/solvers/edge.py to own-solver/
Browse files
own-solver/neurogolf_solver/solvers/edge.py
ADDED
|
@@ -0,0 +1,99 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
#!/usr/bin/env python3
|
| 2 |
+
"""Edge/boundary detection solver — Laplacian Conv.
|
| 3 |
+
|
| 4 |
+
v5.2: 0 matches in current task set (edge definition too strict).
|
| 5 |
+
Kept for future variants (per-color edges, interior-only edges, etc.).
|
| 6 |
+
"""
|
| 7 |
+
|
| 8 |
+
import numpy as np
|
| 9 |
+
from onnx import helper, numpy_helper
|
| 10 |
+
from ..onnx_helpers import mk, _make_int64_init, _build_pad_node
|
| 11 |
+
from ..data_loader import get_exs, fixed_shapes
|
| 12 |
+
from ..constants import GH, GW
|
| 13 |
+
|
| 14 |
+
|
| 15 |
+
def _has_edges(inp, out, edge_color, bg_color=0):
|
| 16 |
+
"""Check if output is edge detection of input."""
|
| 17 |
+
h, w = inp.shape
|
| 18 |
+
for r in range(h):
|
| 19 |
+
for c in range(w):
|
| 20 |
+
pix = inp[r, c]
|
| 21 |
+
is_edge = False
|
| 22 |
+
if pix != bg_color:
|
| 23 |
+
for dr, dc in [(-1, 0), (1, 0), (0, -1), (0, 1)]:
|
| 24 |
+
nr, nc = r + dr, c + dc
|
| 25 |
+
if 0 <= nr < h and 0 <= nc < w:
|
| 26 |
+
if inp[nr, nc] != pix:
|
| 27 |
+
is_edge = True
|
| 28 |
+
break
|
| 29 |
+
else:
|
| 30 |
+
is_edge = True
|
| 31 |
+
break
|
| 32 |
+
expected = edge_color if is_edge else bg_color
|
| 33 |
+
if out[r, c] != expected:
|
| 34 |
+
return False
|
| 35 |
+
return True
|
| 36 |
+
|
| 37 |
+
|
| 38 |
+
def _build_edge_model(IH, IW, edge_color, bg_color=0):
|
| 39 |
+
"""Build ONNX model for edge detection via Laplacian conv."""
|
| 40 |
+
pad_h, pad_w = GH - IH, GW - IW
|
| 41 |
+
|
| 42 |
+
ch_sel = np.zeros((1, 10, 1, 1), dtype=np.float32)
|
| 43 |
+
for c in range(10):
|
| 44 |
+
if c != bg_color:
|
| 45 |
+
ch_sel[0, c, 0, 0] = 1.0
|
| 46 |
+
|
| 47 |
+
lap_k = np.array([[0, -1, 0],
|
| 48 |
+
[-1, 4, -1],
|
| 49 |
+
[0, -1, 0]], dtype=np.float32).reshape(1, 1, 3, 3)
|
| 50 |
+
|
| 51 |
+
edge_oh = np.zeros((1, 10, 1, 1), dtype=np.float32)
|
| 52 |
+
edge_oh[0, edge_color, 0, 0] = 1.0
|
| 53 |
+
bg_oh = np.zeros((1, 10, 1, 1), dtype=np.float32)
|
| 54 |
+
bg_oh[0, bg_color, 0, 0] = 1.0
|
| 55 |
+
|
| 56 |
+
inits = [
|
| 57 |
+
_make_int64_init('sl_st', [0, 0, 0, 0]),
|
| 58 |
+
_make_int64_init('sl_en', [1, 10, IH, IW]),
|
| 59 |
+
numpy_helper.from_array(ch_sel, 'ch_sel'),
|
| 60 |
+
numpy_helper.from_array(lap_k, 'lap_k'),
|
| 61 |
+
numpy_helper.from_array(np.float32(0.5), 'thresh'),
|
| 62 |
+
numpy_helper.from_array(edge_oh, 'edge_oh'),
|
| 63 |
+
numpy_helper.from_array(bg_oh, 'bg_oh'),
|
| 64 |
+
]
|
| 65 |
+
|
| 66 |
+
nodes = [
|
| 67 |
+
helper.make_node('Slice', ['input', 'sl_st', 'sl_en'], ['cropped']),
|
| 68 |
+
helper.make_node('Conv', ['cropped', 'ch_sel'], ['occ'], kernel_shape=[1, 1]),
|
| 69 |
+
helper.make_node('Conv', ['occ', 'lap_k'], ['lap_out'], kernel_shape=[3, 3], pads=[1, 1, 1, 1]),
|
| 70 |
+
helper.make_node('Abs', ['lap_out'], ['lap_abs']),
|
| 71 |
+
helper.make_node('Greater', ['lap_abs', 'thresh'], ['is_edge_raw']),
|
| 72 |
+
helper.make_node('Greater', ['occ', 'thresh'], ['is_occ']),
|
| 73 |
+
helper.make_node('And', ['is_edge_raw', 'is_occ'], ['is_edge']),
|
| 74 |
+
helper.make_node('Where', ['is_edge', 'edge_oh', 'bg_oh'], ['result_small']),
|
| 75 |
+
]
|
| 76 |
+
nodes.append(_build_pad_node('result_small', 'output', pad_h, pad_w, inits))
|
| 77 |
+
return mk(nodes, inits)
|
| 78 |
+
|
| 79 |
+
|
| 80 |
+
def s_edge_detect(td):
|
| 81 |
+
"""Edge detection solver: output = boundary pixels of input shapes."""
|
| 82 |
+
exs = get_exs(td)
|
| 83 |
+
sp = fixed_shapes(td)
|
| 84 |
+
if sp is None:
|
| 85 |
+
return None
|
| 86 |
+
(IH, IW), (OH, OW) = sp
|
| 87 |
+
if (IH, IW) != (OH, OW):
|
| 88 |
+
return None
|
| 89 |
+
|
| 90 |
+
for bg_color in [0]:
|
| 91 |
+
out_colors = set()
|
| 92 |
+
for _, out in exs:
|
| 93 |
+
out_colors.update(out.flatten())
|
| 94 |
+
for edge_color in out_colors:
|
| 95 |
+
if edge_color == bg_color:
|
| 96 |
+
continue
|
| 97 |
+
if all(_has_edges(inp, out, edge_color, bg_color) for inp, out in exs):
|
| 98 |
+
return _build_edge_model(IH, IW, edge_color, bg_color)
|
| 99 |
+
return None
|