scikit-image
213 строк · 5.9 Кб
1import numpy as np2
3from ..util import img_as_float4from .._shared.utils import (5_supported_float_type,6check_nD,7)
8
9
10class FeatureDetector:11def __init__(self):12self.keypoints_ = np.array([])13
14def detect(self, image):15"""Detect keypoints in image.16
17Parameters
18----------
19image : 2D array
20Input image.
21
22"""
23raise NotImplementedError()24
25
26class DescriptorExtractor:27def __init__(self):28self.descriptors_ = np.array([])29
30def extract(self, image, keypoints):31"""Extract feature descriptors in image for given keypoints.32
33Parameters
34----------
35image : 2D array
36Input image.
37keypoints : (N, 2) array
38Keypoint locations as ``(row, col)``.
39
40"""
41raise NotImplementedError()42
43
44def plot_matched_features(45image0,46image1,47*,48keypoints0,49keypoints1,50matches,51ax,52keypoints_color='k',53matches_color=None,54only_matches=False,55alignment='horizontal',56):57"""Plot matched features between two images.58
59.. versionadded:: 0.23
60
61Parameters
62----------
63image0 : (N, M [, 3]) array
64First image.
65image1 : (N, M [, 3]) array
66Second image.
67keypoints0 : (K1, 2) array
68First keypoint coordinates as ``(row, col)``.
69keypoints1 : (K2, 2) array
70Second keypoint coordinates as ``(row, col)``.
71matches : (Q, 2) array
72Indices of corresponding matches in first and second sets of
73descriptors, where `matches[:, 0]` (resp. `matches[:, 1]`) contains
74the indices in the first (resp. second) set of descriptors.
75ax : matplotlib.axes.Axes
76The Axes object where the images and their matched features are drawn.
77keypoints_color : matplotlib color, optional
78Color for keypoint locations.
79matches_color : matplotlib color, optional
80Color for lines which connect keypoint matches. By default the
81color is chosen randomly.
82only_matches : bool, optional
83Set to True to plot matches only and not the keypoint locations.
84alignment : {'horizontal', 'vertical'}, optional
85Whether to show the two images side by side (`'horizontal'`), or one above
86the other (`'vertical'`).
87
88"""
89image0 = img_as_float(image0)90image1 = img_as_float(image1)91
92new_shape0 = list(image0.shape)93new_shape1 = list(image1.shape)94
95if image0.shape[0] < image1.shape[0]:96new_shape0[0] = image1.shape[0]97elif image0.shape[0] > image1.shape[0]:98new_shape1[0] = image0.shape[0]99
100if image0.shape[1] < image1.shape[1]:101new_shape0[1] = image1.shape[1]102elif image0.shape[1] > image1.shape[1]:103new_shape1[1] = image0.shape[1]104
105if new_shape0 != image0.shape:106new_image0 = np.zeros(new_shape0, dtype=image0.dtype)107new_image0[: image0.shape[0], : image0.shape[1]] = image0108image0 = new_image0109
110if new_shape1 != image1.shape:111new_image1 = np.zeros(new_shape1, dtype=image1.dtype)112new_image1[: image1.shape[0], : image1.shape[1]] = image1113image1 = new_image1114
115offset = np.array(image0.shape)116if alignment == 'horizontal':117image = np.concatenate([image0, image1], axis=1)118offset[0] = 0119elif alignment == 'vertical':120image = np.concatenate([image0, image1], axis=0)121offset[1] = 0122else:123mesg = (124f"`plot_matched_features` accepts either 'horizontal' or 'vertical' for "125f"alignment, but '{alignment}' was given. See "126f"https://scikit-image.org/docs/dev/api/skimage.feature.html#skimage.feature.plot_matched_features " # noqa127f"for details."128)129raise ValueError(mesg)130
131if not only_matches:132ax.scatter(133keypoints0[:, 1],134keypoints0[:, 0],135facecolors='none',136edgecolors=keypoints_color,137)138ax.scatter(139keypoints1[:, 1] + offset[1],140keypoints1[:, 0] + offset[0],141facecolors='none',142edgecolors=keypoints_color,143)144
145ax.imshow(image, cmap='gray')146ax.axis((0, image0.shape[1] + offset[1], image0.shape[0] + offset[0], 0))147
148rng = np.random.default_rng()149
150for i in range(matches.shape[0]):151idx0 = matches[i, 0]152idx1 = matches[i, 1]153
154if matches_color is None:155color = rng.random(3)156else:157color = matches_color158
159ax.plot(160(keypoints0[idx0, 1], keypoints1[idx1, 1] + offset[1]),161(keypoints0[idx0, 0], keypoints1[idx1, 0] + offset[0]),162'-',163color=color,164)165
166
167def _prepare_grayscale_input_2D(image):168image = np.squeeze(image)169check_nD(image, 2)170image = img_as_float(image)171float_dtype = _supported_float_type(image.dtype)172return image.astype(float_dtype, copy=False)173
174
175def _prepare_grayscale_input_nD(image):176image = np.squeeze(image)177check_nD(image, range(2, 6))178image = img_as_float(image)179float_dtype = _supported_float_type(image.dtype)180return image.astype(float_dtype, copy=False)181
182
183def _mask_border_keypoints(image_shape, keypoints, distance):184"""Mask coordinates that are within certain distance from the image border.185
186Parameters
187----------
188image_shape : (2,) array_like
189Shape of the image as ``(rows, cols)``.
190keypoints : (N, 2) array
191Keypoint coordinates as ``(rows, cols)``.
192distance : int
193Image border distance.
194
195Returns
196-------
197mask : (N,) bool array
198Mask indicating if pixels are within the image (``True``) or in the
199border region of the image (``False``).
200
201"""
202
203rows = image_shape[0]204cols = image_shape[1]205
206mask = (207((distance - 1) < keypoints[:, 0])208& (keypoints[:, 0] < (rows - distance + 1))209& ((distance - 1) < keypoints[:, 1])210& (keypoints[:, 1] < (cols - distance + 1))211)212
213return mask214