This commit is contained in:
2024-12-17 12:06:00 +08:00
parent 3d364bd237
commit 287b33a9f3
13 changed files with 447 additions and 54 deletions

4
.gitattributes vendored
View File

@ -1 +1,5 @@
*.parquet filter=lfs diff=lfs merge=lfs -text *.parquet filter=lfs diff=lfs merge=lfs -text
charuco_400x400_3x3_s130_m100_no_24.pdf filter=lfs diff=lfs merge=lfs -text
charuco_1189x841_10x7_s115_m90.pdf filter=lfs diff=lfs merge=lfs -text
charuco_400x400_3x3_s130_m100_no_16.pdf filter=lfs diff=lfs merge=lfs -text
charuco_400x400_3x3_s130_m100_no_20.pdf filter=lfs diff=lfs merge=lfs -text

1
.gitignore vendored
View File

@ -1,6 +1,5 @@
*.jpg *.jpg
*.jpeg *.jpeg
*.pdf
*.png *.png
# Byte-compiled / optimized / DLL files # Byte-compiled / optimized / DLL files

View File

@ -6,3 +6,13 @@ See also [gen.sh](gen.sh) (put it in the same directory as the pattern generator
- A0 size, 10x7, square 115mm, marker 90mm - A0 size, 10x7, square 115mm, marker 90mm
- 400mm x 400mm ArUco board (4x4, 0-5 id) - 400mm x 400mm ArUco board (4x4, 0-5 id)
## Diamond
9.7cm (97mm) square for marker
12.7cm (127mm) square for diamond
9mm border (in average)
- [16, 17, 18, 19]
- [20, 21, 22, 23]
- [24, 25, 26, 27]

View File

@ -37,10 +37,10 @@ class ArucoDictionary(Enum):
Dict_ArUco_ORIGINAL = aruco.DICT_ARUCO_ORIGINAL Dict_ArUco_ORIGINAL = aruco.DICT_ARUCO_ORIGINAL
IMAGE_FOLDER = Path("dumped/b") IMAGE_FOLDER = Path("dumped/usbcam")
OUTPUT_FOLDER = Path("output") OUTPUT_FOLDER = Path("output")
DICTIONARY = ArucoDictionary.Dict_4X4_50 DICTIONARY = ArucoDictionary.Dict_4X4_50
CALIBRATION_PARQUET: Optional[Path] = OUTPUT_FOLDER / "calibration.parquet" CALIBRATION_PARQUET: Optional[Path] = OUTPUT_FOLDER / "usbcam_cal.parquet"
class CameraParams(TypedDict): class CameraParams(TypedDict):

33
capture.py Normal file
View File

@ -0,0 +1,33 @@
import cv2
from datetime import datetime
from loguru import logger
from pathlib import Path
BASE_PATH = Path("dumped/cam")
def gen():
API = cv2.CAP_AVFOUNDATION
cap = cv2.VideoCapture(0, API)
while True:
ret, frame = cap.read()
if not ret:
logger.warning("Failed to grab frame")
break
yield frame
def main():
for frame in gen():
cv2.imshow("frame", frame)
k = cv2.waitKey(1)
if k == ord("q"):
break
elif k == ord("s"):
now = datetime.now()
filename = BASE_PATH / f"capture_{now.strftime('%Y%m%d%H%M%S')}.jpg"
logger.warning(f"Saving to {filename}")
cv2.imwrite(str(filename), frame)
else:
...
if __name__ == "__main__":
main()

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

83
find_cute_box.py Normal file
View File

@ -0,0 +1,83 @@
import cv2
from cv2 import aruco
from datetime import datetime
from loguru import logger
from pathlib import Path
from typing import cast, Final
import awkward as ak
from cv2.typing import MatLike
import numpy as np
NDArray = np.ndarray
CALIBRATION_PARQUET = Path("output") / "usbcam_cal.parquet"
DICTIONARY: Final[int] = aruco.DICT_4X4_50
# 400mm
MARKER_LENGTH: Final[float] = 0.4
def gen():
API = cv2.CAP_AVFOUNDATION
cap = cv2.VideoCapture(0, API)
while True:
ret, frame = cap.read()
if not ret:
logger.warning("Failed to grab frame")
break
yield frame
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"]))
detector = aruco.ArucoDetector(
dictionary=aruco_dict, detectorParams=aruco.DetectorParameters()
)
for frame in gen():
grey = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)
# pylint: disable-next=unpacking-non-sequence
markers, ids, rejected = detector.detectMarkers(grey)
# `markers` is [N, 1, 4, 2]
# `ids` is [N, 1]
if ids is not None:
markers = np.reshape(markers, (-1, 4, 2))
ids = np.reshape(ids, (-1, 1))
# 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)
GREY = (128, 128, 128)
logger.info("id={}, center={}", i, center)
cv2.circle(frame, tuple(center), 5, GREY, -1)
cv2.putText(
frame,
str(i),
tuple(center),
cv2.FONT_HERSHEY_SIMPLEX,
1,
GREY,
2,
)
# BGR
RED = (0, 0, 255)
GREEN = (0, 255, 0)
BLUE = (255, 0, 0)
YELLOW = (0, 255, 255)
color_map = [RED, GREEN, BLUE, YELLOW]
for color, corners in zip(color_map, m):
corners = corners.astype(int)
frame = cv2.circle(frame, corners, 5, color, -1)
cv2.imshow("frame", frame)
if (k := cv2.waitKey(1)) == ord("q"):
logger.info("Exiting")
break
elif k == ord("s"):
now = datetime.now().strftime("%Y%m%d%H%M%S")
file_name = f"aruco_{now}.png"
logger.info("Saving to {}", file_name)
cv2.imwrite(file_name, frame)
if __name__ == "__main__":
main()

BIN
output/usbcam_cal.parquet LFS Normal file

Binary file not shown.

File diff suppressed because one or more lines are too long

39
videos.toml Normal file
View File

@ -0,0 +1,39 @@
[cameras.a]
name = "three-four-right"
videos = [
"video-20241206-161501.mp4",
"video-20241206-162615.mp4",
"video-20241206-163043.mp4",
"video-20241206-164116.mp4",
"video-20241206-164541.mp4",
"video-20241206-164956.mp4",
]
[cameras.b]
name = "right"
videos = [
"video-20241206-162045.mp4",
"video-20241206-163050.mp4",
"video-20241206-164124.mp4",
"video-20241206-164536.mp4",
"video-20241206-164952.mp4",
"video-20241206-165800.mp4",
]
[cameras.c]
name = "bottom"
videos = [
"video-20241206-162055.mp4",
"video-20241206-163037.mp4",
"video-20241206-164107.mp4",
"video-20241206-164548.mp4",
"video-20241206-165818.mp4",
]
[cameras.d]
name = "hk"
videos = [
"Video_20241206163609771.avi",
"Video_20241206164041621.avi",
"Video_20241206164534460.avi",
"Video_20241206165004982.avi",
"Video_20241206165831395.avi",
]
# https://superuser.com/questions/650291/how-to-get-video-duration-in-seconds