This commit is contained in:
2024-12-05 17:06:54 +08:00
parent a55ce7a7d0
commit d8739754be
3 changed files with 119 additions and 0 deletions

8
README.md Normal file
View File

@ -0,0 +1,8 @@
# ChArUco experiments
go to [`opencv_contrib/modules/aruco/misc/pattern_generator`](https://github.com/opencv/opencv_contrib/tree/4.x/modules/aruco/misc/pattern_generator) to generate custom patterns.
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)

64
dlt.md Normal file
View File

@ -0,0 +1,64 @@
Direct Linear Transform (DLT) is fundamentally connected to triangulation through its ability to solve the intersection of projection rays. Here's how they relate:
**Mathematical Foundation:**
1. **Projection Model**
- A 3D point $X = [X,Y,Z,1]^T$ projects to 2D point $x = [u,v,1]^T$ through:
$\lambda x = PX$
where $P$ is the 3×4 projection matrix
$\lambda$ is the projective depth
2. **DLT Formulation**
- For each image point, we can write:
$\lambda u = \frac{P_{1}^TX}{P_{3}^TX}$
$\lambda v = \frac{P_{2}^TX}{P_{3}^TX}$
- This leads to linear equations:
$uP_{3}^TX - P_{1}^TX = 0$
$vP_{3}^TX - P_{2}^TX = 0$
3. **Triangulation System**
- For two views with points $x_1=(u_1,v_1)$ and $x_2=(u_2,v_2)$:
$$\begin{bmatrix}
u_1P_{3,1}^T - P_{1,1}^T \\
v_1P_{3,1}^T - P_{2,1}^T \\
u_2P_{3,2}^T - P_{1,2}^T \\
v_2P_{3,2}^T - P_{2,2}^T
\end{bmatrix} X = 0$$
**Why DLT Works for Triangulation:**
1. **Geometric Interpretation**
- DLT finds the 3D point that minimizes algebraic error
- Each row in the equation system represents a constraint from one coordinate
- The solution is the intersection of projection rays in 3D space
2. **Solution Method**
- The system $AX = 0$ is solved using SVD
- The solution is the eigenvector corresponding to smallest singular value
- This provides the optimal 3D point in a least-squares sense
3. **Implementation Connection**
In your code:
```python
A = [
point1[1]*P1[2,:] - P1[1,:],
P1[0,:] - point1[0]*P1[2,:],
point2[1]*P2[2,:] - P2[1,:],
P2[0,:] - point2[0]*P2[2,:],
]
```
This directly implements the linear system described above.
**Advantages:**
- Linear solution
- Simple to implement
- Works with multiple views
- Computationally efficient
**Limitations:**
- Sensitive to noise
- Assumes perfect point correspondences
- Minimizes algebraic (not geometric) error

47
gen.sh Normal file
View File

@ -0,0 +1,47 @@
SQUARE_MM=115
MARKER_MM=90
MARKER_SEP_MM=$(echo "scale=4; $SQUARE_MM - $MARKER_MM" | bc)
if [ $MARKER_SEP_MM -lt 0 ]; then
echo "Marker size must be smaller than square size"
exit 1
fi
SQUARE_SIZE=$(echo "scale=4; $SQUARE_MM / 1000" | bc)
MARKER_SIZE=$(echo "scale=4; $MARKER_MM / 1000" | bc)
MARKER_SEP=$(echo "scale=4; $MARKER_SEP_MM / 1000" | bc)
PAGE_PADDING_MM=10
PAGE_PADDING=$(echo "scale=4; $PAGE_PADDING_MM / 1000" | bc)
# A0
PAGE_WIDTH_MM=1189
PAGE_HEIGHT_MM=841
BOARD_WIDTH_IN_SQUARE=$(echo "scale=0; ($PAGE_WIDTH_MM - $PAGE_PADDING_MM) / $SQUARE_MM" | bc)
BOARD_HEIGHT_IN_SQUARE=$(echo "scale=0; ($PAGE_HEIGHT_MM - $PAGE_PADDING_MM) / $SQUARE_MM" | bc)
START_MARKER_ID=10
OUTPUT_FILENAME="charuco_${PAGE_WIDTH_MM}x${PAGE_HEIGHT_MM}_${BOARD_WIDTH_IN_SQUARE}x${BOARD_HEIGHT_IN_SQUARE}_s${SQUARE_MM}_m${MARKER_MM}.pdf"
# DICT_4X4_1000
# DICT_5X5_1000
# DICT_6X6_1000
# DICT_7X7_1000
# DICT_ARUCO_ORIGINAL
# DICT_APRILTAG_16h5
# DICT_APRILTAG_25h9
# DICT_APRILTAG_36h10
# DICT_APRILTAG_36h11
python MarkerPrinter.py --charuco \
--file $OUTPUT_FILENAME \
--dictionary DICT_4X4_1000 \
--page_border_x $PAGE_PADDING \
--page_border_y $PAGE_PADDING \
--square_length $SQUARE_SIZE \
--marker_length $MARKER_SIZE \
--marker_separation $MARKER_SEP \
--charuco_size_x $BOARD_WIDTH_IN_SQUARE \
--charuco_size_y $BOARD_HEIGHT_IN_SQUARE \
--first_marker $START_MARKER_ID