cute box
This commit is contained in:
4
.gitattributes
vendored
4
.gitattributes
vendored
@ -1 +1,5 @@
|
||||
*.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
1
.gitignore
vendored
@ -1,6 +1,5 @@
|
||||
*.jpg
|
||||
*.jpeg
|
||||
*.pdf
|
||||
*.png
|
||||
|
||||
# Byte-compiled / optimized / DLL files
|
||||
|
||||
10
README.md
10
README.md
@ -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
|
||||
- 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]
|
||||
|
||||
4
cali.py
4
cali.py
@ -37,10 +37,10 @@ class ArucoDictionary(Enum):
|
||||
Dict_ArUco_ORIGINAL = aruco.DICT_ARUCO_ORIGINAL
|
||||
|
||||
|
||||
IMAGE_FOLDER = Path("dumped/b")
|
||||
IMAGE_FOLDER = Path("dumped/usbcam")
|
||||
OUTPUT_FOLDER = Path("output")
|
||||
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):
|
||||
|
||||
33
capture.py
Normal file
33
capture.py
Normal 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()
|
||||
BIN
charuco_1189x841_10x7_s115_m90.pdf
LFS
Normal file
BIN
charuco_1189x841_10x7_s115_m90.pdf
LFS
Normal file
Binary file not shown.
BIN
charuco_400x400_3x3_s130_m100_no_16.pdf
LFS
Normal file
BIN
charuco_400x400_3x3_s130_m100_no_16.pdf
LFS
Normal file
Binary file not shown.
BIN
charuco_400x400_3x3_s130_m100_no_20.pdf
LFS
Normal file
BIN
charuco_400x400_3x3_s130_m100_no_20.pdf
LFS
Normal file
Binary file not shown.
BIN
charuco_400x400_3x3_s130_m100_no_24.pdf
LFS
Normal file
BIN
charuco_400x400_3x3_s130_m100_no_24.pdf
LFS
Normal file
Binary file not shown.
83
find_cute_box.py
Normal file
83
find_cute_box.py
Normal 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
BIN
output/usbcam_cal.parquet
LFS
Normal file
Binary file not shown.
312
play.ipynb
312
play.ipynb
File diff suppressed because one or more lines are too long
39
videos.toml
Normal file
39
videos.toml
Normal 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
|
||||
Reference in New Issue
Block a user