From 1c77de040712e8d13b324bc9ac24de4dc4f89430 Mon Sep 17 00:00:00 2001 From: Christian <s224389@dtu.dk> Date: Wed, 15 Jan 2025 13:23:29 +0100 Subject: [PATCH] Bug fixes and added ability to use 'centerline' method instead --- GUI_draft.py | 4 +-- live_wire.py | 90 ++++++++++++++++++++++++++++++++++++++++++++++++++-- 2 files changed, 90 insertions(+), 4 deletions(-) diff --git a/GUI_draft.py b/GUI_draft.py index fb0231c..a28f30f 100644 --- a/GUI_draft.py +++ b/GUI_draft.py @@ -100,7 +100,7 @@ class ImageGraphicsView(QGraphicsView): self.editor_mode = False self.dot_radius = 4 self.path_radius = 1 - self.radius_something = 3 # cost-lowering radius + self.radius_cost_image = 2 # cost-lowering radius self._img_w = 0 self._img_h = 0 @@ -198,7 +198,7 @@ class ImageGraphicsView(QGraphicsView): return for i, (ax, ay) in enumerate(self.anchor_points): if self.point_items[i].is_removable(): - self._lower_cost_in_circle(ax, ay, self.radius_something) + self._lower_cost_in_circle(ax, ay, self.radius_cost_image) def _lower_cost_in_circle(self, x_f, y_f, radius): """Set cost_image row,col in circle of radius -> global min.""" diff --git a/live_wire.py b/live_wire.py index 9b49d97..e42f7d5 100644 --- a/live_wire.py +++ b/live_wire.py @@ -6,9 +6,10 @@ from skimage import exposure from skimage.filters import gaussian from skimage.feature import canny from skimage.graph import route_through_array +from scipy.signal import convolve2d -#### Helper functions #### - +''' +### Canny Edge cost image def compute_cost_image(path, sigma=3): ### Load image @@ -28,6 +29,49 @@ def compute_cost_image(path, sigma=3): return cost_img +def find_path(cost_image, points): + + if len(points) != 2: + raise ValueError("Points should be a list of 2 points: seed and target.") + + seed_rc, target_rc = points + + path_rc, cost = route_through_array( + cost_image, + start=seed_rc, + end=target_rc, + fully_connected=True + ) + + return path_rc +''' + +### Disk live wire cost image +def compute_cost_image(path, sigma=3, disk_size=15): + + ### Load image + image = cv2.imread(path, cv2.IMREAD_GRAYSCALE) + + # Apply histogram equalization + image_contrasted = exposure.equalize_adapthist(image, clip_limit=0.01) + + # Apply smoothing + smoothed_img = gaussian(image_contrasted, sigma=sigma) + + # Apply Canny edge detection + canny_img = canny(smoothed_img) + + # Do disk thing + binary_img = canny_img + k_size = 17 + kernel = circle_edge_kernel(k_size=disk_size) + convolved = convolve2d(binary_img, kernel, mode='same', boundary='fill') + + # Create cost image + cost_img = (convolved.max() - convolved)**4 # Invert edges: higher cost where edges are stronger + + return cost_img + def find_path(cost_image, points): @@ -46,8 +90,50 @@ def find_path(cost_image, points): return path_rc +def circle_edge_kernel(k_size=5, radius=None): + """ + Create a k_size x k_size array whose values increase linearly + from 0 at the center to 1 at the circle boundary (radius). + + Parameters + ---------- + k_size : int + The size (width and height) of the kernel array. + radius : float, optional + The circle's radius. By default, set to (k_size-1)/2. + + Returns + ------- + kernel : 2D numpy array of shape (k_size, k_size) + The circle-edge-weighted kernel. + """ + if radius is None: + # By default, let the radius be half the kernel size + radius = (k_size - 1) / 2 + + # Create an empty kernel + kernel = np.zeros((k_size, k_size), dtype=float) + + # Coordinates of the center + center = radius # same as (k_size-1)/2 if radius is default + + # Fill the kernel + for y in range(k_size): + for x in range(k_size): + dist = np.sqrt((x - center)**2 + (y - center)**2) + if dist <= radius: + # Weight = distance / radius => 0 at center, 1 at boundary + kernel[y, x] = dist / radius + + return kernel + + + + + +# Other functions def downscale(img, points, scale_percent): """ Downsample `img` to `scale_percent` size and scale the given points accordingly. -- GitLab