SLDgen / initialize.py
Mightypeacock's picture
Add SLDgen module: SLDgen/SLDgen/painter/initialize.py
2e3780b
Raw History Blame Contribute Delete
5.21 kB
from pathlib import Path
import cv2
import numpy as np
from .tsp_art import init_tsp_art
def initialize_control_points(args, mask=None):
"""Initialize control points based on the specified initialization method.
Parameters
----------
args : object
Configuration object containing:
- init_method : str
Initialization method: 'trefoil', 'contour', or 'tsp'.
- n_control_points : int
Number of control points to generate.
- output_dir : str
Directory for output files (used by 'tsp' method).
mask : torch.Tensor, optional
Binary mask tensor for contour or TSP-based initialization, by default None.
Returns
-------
np.ndarray
Control points of shape (n_control_points, 2), normalized to [0, 1].
Raises
------
NotImplementedError
If the init_method is not one of 'trefoil', 'contour', or 'tsp'.
"""
print(f"\tInitializing control points from {args.init_method}.", flush=True)
if args.init_method == "trefoil":
return initialize_from_trefoil(n_control_points=args.n_control_points, args=args)
elif args.init_method == "contour":
return initialize_from_contour(n_control_points=args.n_control_points, mask=mask)
elif args.init_method == "tsp":
return initialize_from_tsp(
n_control_points=args.n_control_points,
mask=mask,
output_dir=args.output_dir,
debug=args.debug,
fixed_endpoints=args.fixed_endpoints,
)
else:
raise NotImplementedError(f"Initialization method {args.init_method} not implemented.")
def initialize_from_trefoil(n_control_points, args=None):
# Create regular control points on trefoil shape
control_points = np.zeros((n_control_points, 2), dtype=np.float32)
ts = np.linspace(0, 2 * np.pi, n_control_points, endpoint=False)
control_points[:, 0] = np.sin(ts) + 2 * np.sin(2 * ts)
control_points[:, 1] = np.cos(ts) - 2 * np.cos(2 * ts)
if hasattr(args, "scale_w") and hasattr(args, "scale_h"):
print(f"Scaling control points by width: {args.true_scale_w}, height: {args.true_scale_h}")
control_points[:, 0] *= max(args.true_scale_w, args.true_scale_h)
control_points[:, 1] *= max(args.true_scale_w, args.true_scale_h)
# Normalize and shift to roughly fit into [0, 1] canvas coordinates
control_points /= 6
control_points += 0.5
return control_points
def initialize_from_contour(n_control_points, mask):
binary_image = (mask.detach().numpy() > 0.5).astype(np.uint8)
# Find the longest contour on the mask (most points) to use as the main outline
contours, hierarchy = cv2.findContours(
binary_image, mode=cv2.RETR_TREE, method=cv2.CHAIN_APPROX_NONE
)
contours_len = [len(contour) for contour in contours]
longest_contour = contours[np.argmax(contours_len)]
cv2.drawContours(binary_image, [longest_contour], -1, 2, 1)
# Sample `n_control_points` evenly along the chosen contour and normalize
control_points = longest_contour.squeeze()
start = np.random.randint(len(longest_contour)) # Defines where the line starts and ends
control_points = np.concatenate([control_points[start:], control_points[:start]])
control_points_sample = np.linspace(
0, len(control_points) - 1, n_control_points, endpoint=False, dtype=int
)
control_points = control_points[control_points_sample].astype(float)
control_points[:, 0] = control_points[:, 0] / binary_image.shape[1]
control_points[:, 1] = control_points[:, 1] / binary_image.shape[0]
return control_points
def get_longest_polyline_segment(polyline):
# Find the index of the longest segment between consecutive polyline points
max_length = 0
longest_segment = None
for i in range(len(polyline)):
start = polyline[i]
end = polyline[(i + 1) % len(polyline)]
length = np.linalg.norm(end - start)
if length > max_length:
max_length = length
longest_segment = i
return longest_segment
def reorder_polyline(polyline):
# Rotate the polyline so that the longest segment becomes the starting edge
start_longest_segment_index = get_longest_polyline_segment(polyline)
ordered_polyline = np.roll(polyline, -start_longest_segment_index - 1, axis=0)
return ordered_polyline
def initialize_from_tsp(n_control_points, mask, output_dir, debug, fixed_endpoints):
# Create initial ordered points using the TSP-based initializer
control_points = init_tsp_art(
mask.numpy(),
n_point=n_control_points,
n_iter=25,
reverse=True,
output_dir=str(Path(output_dir) / "tsp_init"),
debug=debug,
fixed_endpoints=fixed_endpoints,
)
# Reorder so the polyline starts at the longest segment and convert to array
if not fixed_endpoints:
control_points = reorder_polyline(control_points)
control_points = np.array(control_points)
control_points[:, 0] = control_points[:, 0] / mask.shape[1]
control_points[:, 1] = control_points[:, 1] / mask.shape[0]
return control_points