feat: configurations
This commit is contained in:
@@ -6,12 +6,13 @@ from pathlib import Path
|
||||
from typing import Literal, Optional, Tuple
|
||||
from PIL import Image
|
||||
|
||||
FeatureMethod = Literal["orb", "sift", "surf", "akaze", "brisk"]
|
||||
FeatureMethod = Literal["orb", "sift", "akaze", "brisk"]
|
||||
DEFAULT_METHOD = "akaze"
|
||||
|
||||
@dataclass
|
||||
class VisionChunk:
|
||||
image: Image.Image
|
||||
feature_method: FeatureMethod = "orb"
|
||||
feature_method: FeatureMethod = DEFAULT_METHOD
|
||||
|
||||
keypoints: Optional[list] = field(default=None, init=False)
|
||||
descriptors: Optional[np.ndarray] = field(default=None, init=False)
|
||||
@@ -26,7 +27,7 @@ class VisionChunk:
|
||||
self._detector = cv2.ORB_create(
|
||||
nfeatures=1000,
|
||||
scaleFactor=1.2,
|
||||
nlevels=8,
|
||||
nlevels=32,
|
||||
edgeThreshold=31,
|
||||
firstLevel=0,
|
||||
WTA_K=2,
|
||||
@@ -35,18 +36,11 @@ class VisionChunk:
|
||||
)
|
||||
elif self.feature_method == "sift":
|
||||
self._detector = cv2.SIFT_create(
|
||||
nfeatures=1000,
|
||||
nOctaveLayers=3,
|
||||
contrastThreshold=0.04,
|
||||
edgeThreshold=10,
|
||||
sigma=1.6
|
||||
)
|
||||
elif self.feature_method == "surf":
|
||||
self._detector = cv2.xfeatures2d.SURF_create(
|
||||
hessianThreshold=400.0,
|
||||
nOctaveLayers=3,
|
||||
# nOctaveLayers=4,
|
||||
upright=False
|
||||
nfeatures=1500,
|
||||
nOctaveLayers=2,
|
||||
contrastThreshold=0.01,
|
||||
edgeThreshold=15,
|
||||
sigma=3.3
|
||||
)
|
||||
elif self.feature_method == "akaze":
|
||||
self._detector = cv2.AKAZE_create(
|
||||
@@ -59,8 +53,8 @@ class VisionChunk:
|
||||
)
|
||||
elif self.feature_method == "brisk":
|
||||
self._detector = cv2.BRISK_create(
|
||||
thresh=30,
|
||||
octaves=3,
|
||||
thresh=70,
|
||||
octaves=7,
|
||||
patternScale=1.0
|
||||
)
|
||||
else:
|
||||
@@ -69,15 +63,10 @@ class VisionChunk:
|
||||
|
||||
def _get_matcher(self) -> cv2.DescriptorMatcher:
|
||||
if self._matcher is None:
|
||||
self._matcher = cv2.BFMatcher(cv2.NORM_HAMMING, crossCheck=False)
|
||||
return self._matcher
|
||||
if self.feature_method == 'orb':
|
||||
if self.feature_method == 'sift':
|
||||
self._matcher = cv2.BFMatcher(cv2.NORM_L2, crossCheck=False)
|
||||
else:
|
||||
self._matcher = cv2.BFMatcher(cv2.NORM_HAMMING, crossCheck=False)
|
||||
elif self.feature_method == 'sift':
|
||||
FLANN_INDEX_LSH = 6
|
||||
index_params = dict(algorithm=FLANN_INDEX_LSH, table_number=6, key_size=12, multi_probe_level=1)
|
||||
search_params = dict(checks=50)
|
||||
self._matcher = cv2.FlannBasedMatcher(index_params, search_params)
|
||||
return self._matcher
|
||||
|
||||
def _preprocess(self, img_np: np.ndarray) -> np.ndarray:
|
||||
@@ -90,7 +79,7 @@ class VisionChunk:
|
||||
clahe = cv2.createCLAHE(clipLimit=3.0, tileGridSize=(8, 8))
|
||||
return clahe.apply(gray)
|
||||
|
||||
def compute_keypoints(self, force: bool = False) -> Tuple[list, Optional[np.ndarray]]:
|
||||
def compute_keypoints(self, force: bool = False) -> Tuple[list[cv2.KeyPoint], Optional[np.ndarray]]:
|
||||
if self.keypoints is not None and self.descriptors is not None and not force:
|
||||
return self.keypoints, self.descriptors
|
||||
|
||||
@@ -103,11 +92,21 @@ class VisionChunk:
|
||||
|
||||
# CLAHE предобработка
|
||||
preprocessed = self._preprocess(img_np)
|
||||
kps, desc = detector.detectAndCompute(preprocessed, None)
|
||||
keypoints, descriptors = detector.detectAndCompute(preprocessed, None)
|
||||
|
||||
self.keypoints = kps
|
||||
self.descriptors = desc
|
||||
return kps, desc
|
||||
# Получаем массив response для всех точек
|
||||
responses = np.array([kp.response for kp in keypoints])
|
||||
|
||||
# Находим индексы топ-100
|
||||
top_indices = np.argsort(responses)[-2500:][::-1]
|
||||
|
||||
# Отбираем keypoints и descriptors
|
||||
best_keypoints = [keypoints[i] for i in top_indices]
|
||||
best_descriptors = descriptors[top_indices]
|
||||
|
||||
self.keypoints = best_keypoints
|
||||
self.descriptors = best_descriptors
|
||||
return self.keypoints, self.descriptors
|
||||
|
||||
def detect_and_match_keypoints(
|
||||
self,
|
||||
@@ -193,7 +192,7 @@ class VisionChunk:
|
||||
return np.array(self.image)
|
||||
|
||||
@classmethod
|
||||
def load_image(cls, path: Path | str, feature_method: FeatureMethod = "orb") -> "VisionChunk":
|
||||
def load_image(cls, path: Path | str, feature_method: FeatureMethod = DEFAULT_METHOD) -> "VisionChunk":
|
||||
path = Path(path)
|
||||
image = Image.open(path)
|
||||
return cls(image=image, feature_method=feature_method)
|
||||
|
||||
Reference in New Issue
Block a user