feat: aruco box instead of charuco

This commit is contained in:
2026-02-06 14:31:09 +08:00
parent e593c7b363
commit aeff8fd5c2
19 changed files with 316 additions and 67 deletions
+3 -1
View File
@@ -1,4 +1,6 @@
{
"python.analysis.typeCheckingMode": "standard",
"python.analysis.autoImportCompletions": true
"python.analysis.autoImportCompletions": true,
"python-envs.defaultEnvManager": "ms-python.python:system",
"python-envs.pythonProjects": []
}
+70 -11
View File
File diff suppressed because one or more lines are too long
+17 -6
View File
@@ -1,4 +1,5 @@
import cv2
import subprocess
from cv2 import aruco
from datetime import datetime
from loguru import logger
@@ -9,9 +10,11 @@ from cv2.typing import MatLike
import numpy as np
NDArray = np.ndarray
CALIBRATION_PARQUET = Path("output") / "usbcam_cal.parquet"
# CALIBRATION_PARQUET = Path("output") / "usbcam_cal.parquet"
CALIBRATION_PARQUET = None
# 7x7
DICTIONARY: Final[int] = aruco.DICT_7X7_1000
# DICTIONARY: Final[int] = aruco.DICT_7X7_1000
DICTIONARY: Final[int] = aruco.DICT_APRILTAG_36H11
# 400mm
MARKER_LENGTH: Final[float] = 0.4
RED = (0, 0, 255)
@@ -33,9 +36,17 @@ def gen():
def main():
aruco_dict = aruco.getPredefinedDictionary(DICTIONARY)
cal = ak.from_parquet(CALIBRATION_PARQUET)[0]
camera_matrix = cast(MatLike, ak.to_numpy(cal["camera_matrix"]))
distortion_coefficients = cast(MatLike, ak.to_numpy(cal["distortion_coefficients"]))
cal = (
None if CALIBRATION_PARQUET is None else ak.from_parquet(CALIBRATION_PARQUET)[0]
)
camera_matrix = (
None if cal is None else cast(MatLike, ak.to_numpy(cal["camera_matrix"]))
)
distortion_coefficients = (
None
if cal is None
else cast(MatLike, ak.to_numpy(cal["distortion_coefficients"]))
)
detector = aruco.ArucoDetector(
dictionary=aruco_dict, detectorParams=aruco.DetectorParameters()
)
@@ -52,7 +63,7 @@ def main():
# logger.info("markers={}, ids={}", np.array(markers).shape, np.array(ids).shape)
for m, i in zip(markers, ids):
center = np.mean(m, axis=0).astype(int)
logger.info("id={}, center={}", i, center)
# logger.info("id={}, center={}", i, center)
cv2.circle(frame, tuple(center), 5, RED, -1)
cv2.putText(
frame,
File diff suppressed because one or more lines are too long
-18
View File
@@ -1,18 +0,0 @@
# %%
import numpy as np
# %%
# %% [markdown]
# # Extract the 3D coordinates of the ArUco markers from the image
#
# 1. Load the image
# 2. Detect the ArUco markers
# 3. Get the 3D coordinates of the markers
# 4. Save the 3D coordinates to a file
# %%
# %%
Binary file not shown.
+52
View File
@@ -0,0 +1,52 @@
import cv2
import time
def test_props():
# Force AVFoundation
cap = cv2.VideoCapture(0, cv2.CAP_AVFOUNDATION)
if not cap.isOpened():
print("Cannot open camera")
return
print(f"Backend: {cap.getBackendName()}")
# Properties to test
props = {
"EXPOSURE": cv2.CAP_PROP_EXPOSURE,
"BRIGHTNESS": cv2.CAP_PROP_BRIGHTNESS,
"GAIN": cv2.CAP_PROP_GAIN,
"SATURATION": cv2.CAP_PROP_SATURATION,
"CONTRAST": cv2.CAP_PROP_CONTRAST,
"AUTO_EXPOSURE": cv2.CAP_PROP_AUTO_EXPOSURE,
"IRIS": cv2.CAP_PROP_IRIS,
"SETTINGS": cv2.CAP_PROP_SETTINGS,
}
print("\nInitial Values:")
for name, prop_id in props.items():
val = cap.get(prop_id)
print(f" {name}: {val}")
print("\nAttempting to set EXPOSURE to various values...")
# Try typical ranges. Some backends use -10..10, others 0..1, others raw ms
test_vals = [-5.0, -1.0, 0.0, 0.5, 50.0]
for v in test_vals:
print(f" Setting EXPOSURE to {v}...", end="")
cap.set(cv2.CAP_PROP_EXPOSURE, v)
time.sleep(0.5)
new_val = cap.get(cv2.CAP_PROP_EXPOSURE)
print(f" -> Result: {new_val}")
print("\nAttempting to open Settings Dialog (CAP_PROP_SETTINGS)...")
cap.set(cv2.CAP_PROP_SETTINGS, 1)
print(" (Did a window pop up?)")
time.sleep(2)
cap.release()
if __name__ == "__main__":
test_props()