VitalyVorobyev's picture
dl_adapters from dexined and superpoint
aaa448c
from typing import Any, Dict, Tuple
import cv2
import numpy as np
from .common import to_bgr, to_rgb
def detect_classical(
image: np.ndarray,
detector: str,
canny_low: int,
canny_high: int,
harris_k: float,
harris_block: int,
harris_ksize: int,
hough_thresh: int,
hough_min_len: int,
hough_max_gap: int,
ellipse_min_area: int,
max_ellipses: int,
line_detector: str = "hough",
) -> Tuple[np.ndarray, Dict[str, Any]]:
bgr = to_bgr(image)
gray = cv2.cvtColor(bgr, cv2.COLOR_BGR2GRAY)
overlay = bgr.copy()
meta: Dict[str, Any] = {"path": "classical"}
if detector == "Edges (Canny)":
edges = cv2.Canny(gray, canny_low, canny_high, L2gradient=True)
overlay[edges > 0] = (0, 255, 0)
meta["num_edge_pixels"] = int(np.count_nonzero(edges))
elif detector == "Corners (Harris)":
gray32 = np.float32(gray)
dst = cv2.cornerHarris(gray32, blockSize=harris_block, ksize=harris_ksize, k=harris_k)
dst = cv2.dilate(dst, None)
thresh = 0.01 * dst.max() if dst.max() > 0 else 0.0
corners = np.argwhere(dst > thresh)
for (y, x) in corners:
cv2.circle(overlay, (int(x), int(y)), 2, (0, 255, 255), -1)
meta["num_corners"] = int(len(corners))
elif detector == "Lines (Hough/LSD)":
method = (line_detector or "hough").lower()
if method not in {"hough", "lsd"}:
method = "hough"
meta["line_detector"] = method
if method == "lsd":
if not hasattr(cv2, "createLineSegmentDetector"):
meta["error"] = "OpenCV build lacks Line Segment Detector (LSD) support."
return to_rgb(overlay), meta
lsd = cv2.createLineSegmentDetector(refine=cv2.LSD_REFINE_ADV)
lines = lsd.detect(gray)[0]
n = 0
if lines is not None:
for seg in lines:
x1, y1, x2, y2 = map(int, np.round(seg[0]))
cv2.line(overlay, (x1, y1), (x2, y2), (0, 255, 255), 2)
n = len(lines)
meta["num_lines"] = int(n)
else:
edges = cv2.Canny(gray, canny_low, canny_high, L2gradient=True)
lines = cv2.HoughLinesP(
edges,
rho=1,
theta=np.pi / 180,
threshold=hough_thresh,
minLineLength=hough_min_len,
maxLineGap=hough_max_gap,
)
n = 0
if lines is not None:
for l in lines:
x1, y1, x2, y2 = l[0]
cv2.line(overlay, (x1, y1), (x2, y2), (255, 128, 0), 2)
n = len(lines)
meta["num_lines"] = int(n)
elif detector == "Ellipses (Contours + fitEllipse)":
edges = cv2.Canny(gray, canny_low, canny_high, L2gradient=True)
contours, _ = cv2.findContours(edges, cv2.RETR_LIST, cv2.CHAIN_APPROX_NONE)
ellipses = []
for cnt in contours:
if len(cnt) < 5:
continue
try:
(cx, cy), (MA, ma), angle = cv2.fitEllipse(cnt)
area = float(np.pi * (MA / 2) * (ma / 2))
if area >= ellipse_min_area:
ellipses.append(((cx, cy), (MA, ma), angle, area))
except cv2.error:
continue
ellipses.sort(key=lambda e: e[3], reverse=True)
kept = []
for e in ellipses:
if len(kept) >= max_ellipses:
break
(cx, cy), (MA, ma), angle, area = e
if all((cx - kx) ** 2 + (cy - ky) ** 2 > 100 for ((kx, ky), _, _, _) in kept):
kept.append(e)
for (cx, cy), (MA, ma), angle, area in kept:
cv2.ellipse(overlay, ((int(cx), int(cy)), (int(MA), int(ma)), float(angle)), (0, 200, 255), 2)
cv2.circle(overlay, (int(cx), int(cy)), 2, (0, 200, 255), -1)
meta["num_ellipses"] = int(len(kept))
else:
meta["error"] = f"Unknown detector: {detector}"
return to_rgb(overlay), meta