Skip to content

Commit e025c86

Browse files
authored
Projection uncertainty (#20)
1 parent 239d80e commit e025c86

File tree

15 files changed

+1145
-81
lines changed

15 files changed

+1145
-81
lines changed

.gitignore

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,3 +37,5 @@ cmake_build/*
3737
bin/
3838

3939
vcpkg_installed
40+
41+
.venv

.vscode/launch.json

Lines changed: 6 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
"name": "(gdb) Attach",
99
"type": "cppdbg",
1010
"request": "attach",
11-
"program": "/home/matt/github/mrcal-java/cmake_build/lib/libmrcal_jni.so",
11+
"program": "${workspaceFolder}/cmake_build/lib/libmrcal_jni.so",
1212
"processId": "${command:pickProcess}",
1313
"MIMode": "gdb",
1414
"setupCommands": [
@@ -23,23 +23,11 @@
2323
"name": "Python debug calibrate cameras",
2424
"type": "debugpy",
2525
"request": "launch",
26-
"program": "/usr/bin/mrcal-calibrate-cameras",
26+
"program": "mrcal-show-projection-uncertainty",
2727
"console": "integratedTerminal",
28-
"cwd": "/home/matt/mrcal_debug_tmp/output_will/images-trimmed",
28+
"cwd": "${workspaceFolder}/mrcal",
2929
"args": [
30-
"--corners-cache",
31-
"corners.vnl",
32-
"--lensmodel",
33-
"LENSMODEL_OPENCV8",
34-
"--focal",
35-
"1200",
36-
"--object-spacing",
37-
"0.03",
38-
"--object-width-n",
39-
"18",
40-
"--object-height-n",
41-
"13",
42-
"*.png"
30+
"./camera-0.cameramodel", "--cbmax","10","--unset","key","--gridn","60","40"
4331
],
4432
"justMyCode": false
4533
},
@@ -65,7 +53,8 @@
6553
"text": "-gdb-set disassembly-flavor intel",
6654
"ignoreFailures": true
6755
}
68-
]
56+
],
57+
"preLaunchTask": "build-test"
6958
},
7059
{
7160
"name": "Python: Current File",

.vscode/tasks.json

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
{
2+
"version": "2.0.0",
3+
"tasks": [
4+
{
5+
"label": "build-test",
6+
"command": "cmake --build cmake_build/",
7+
"type": "shell",
8+
"args": [],
9+
"problemMatcher": [
10+
"$tsc"
11+
],
12+
"presentation": {
13+
"reveal": "always"
14+
},
15+
"group": {
16+
"kind": "build",
17+
"isDefault": true
18+
}
19+
}
20+
]
21+
}

CMakeLists.txt

Lines changed: 35 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -14,16 +14,21 @@ if(WITH_ASAN)
1414
add_compile_options(-fsanitize=address -g -Wall -fsanitize=undefined)
1515
endif()
1616

17+
# Include FetchContent module for downloading dependencies
18+
include(FetchContent)
19+
20+
# OpenCV configuration
1721
# Keep this in sync with build.gradle and with
1822
# https://github.com/PhotonVision/photonvision/blob/main/build.gradle
1923
set(OPENCV_YEAR "frc2025")
2024
set(OPENCV_VERSION "4.10.0-3")
25+
set(WPIMATH_VERSION "2026.2.1")
2126

2227
# type can be "", "debug", "static", or "staticdebug"
2328
set(OPENCV_TYPE "")
2429

25-
# Download opencv, and save the path
26-
include(FetchContent)
30+
message(STATUS "Using FRC OpenCV for architecture: ${OPENCV_ARCH}")
31+
2732
FetchContent_Declare(
2833
opencv_lib
2934
URL
@@ -39,15 +44,24 @@ FetchContent_Declare(
3944
)
4045
FetchContent_MakeAvailable(opencv_header)
4146

42-
# This probably doesn't work great with shared libraries, but I don't care about those right now
4347
file(
4448
GLOB_RECURSE OPENCV_LIB_PATH
4549
"${opencv_lib_SOURCE_DIR}/**/*.lib"
4650
"${opencv_lib_SOURCE_DIR}/**/*.so*"
4751
"${opencv_lib_SOURCE_DIR}/**/*.*.dylib"
4852
)
4953
set(OPENCV_INCLUDE_PATH ${opencv_header_SOURCE_DIR})
50-
message("Depending on opencv ${OPENCV_LIB_PATH}")
54+
set(OPENCV_LIBRARIES ${OPENCV_LIB_PATH})
55+
message(STATUS "Using FRC OpenCV libraries: ${OPENCV_LIB_PATH}")
56+
57+
# Also download wpimath
58+
FetchContent_Declare(
59+
wpimath_header
60+
URL
61+
https://frcmaven.wpi.edu/artifactory/release/edu/wpi/first/wpimath/wpimath-cpp/${WPIMATH_VERSION}/wpimath-cpp-${WPIMATH_VERSION}-headers.zip
62+
)
63+
FetchContent_MakeAvailable(wpimath_header)
64+
set(WPIMATH_INCLUDE_PATH ${wpimath_header_SOURCE_DIR})
5165

5266
# Openblas/suitesparse/friends
5367
# From https://github.com/wpilibsuite/thirdparty-ceres/blob/main/CMakeLists.txt
@@ -136,6 +150,7 @@ set(SRC_HPP)
136150
set(SRC_CPP
137151
src/mrcal_jni.h
138152
src/mrcal_wrapper.cpp
153+
src/mrcal-uncertainty.cpp
139154
src/mrcal_jni.cpp
140155
libdogleg/dogleg.c
141156
mrcal/mrcal.c
@@ -173,17 +188,23 @@ add_library(mrcal_jni SHARED ${INCLUDE_HPP} ${SRC_HPP} ${SRC_CPP})
173188
target_include_directories(
174189
mrcal_jni
175190
SYSTEM
176-
PUBLIC ${JNI_INCLUDE_DIRS} ${OPENCV_INCLUDE_PATH} mrcal libdogleg
191+
PUBLIC
192+
${JNI_INCLUDE_DIRS}
193+
${OPENCV_INCLUDE_PATH}
194+
mrcal
195+
libdogleg
196+
${WPIMATH_INCLUDE_PATH}
177197
)
178198
add_dependencies(mrcal_jni generate_minimath)
179199

180200
target_link_libraries(
181201
mrcal_jni
182-
${OPENCV_LIB_PATH}
183-
SuiteSparse::CHOLMOD_static
184-
SuiteSparse::SuiteSparseConfig_static
185-
${OPENBLAS_TARGET}
186-
lapack
202+
PUBLIC
203+
${OPENCV_LIBRARIES}
204+
SuiteSparse::CHOLMOD_static
205+
SuiteSparse::SuiteSparseConfig_static
206+
${OPENBLAS_TARGET}
207+
lapack
187208
)
188209

189210
# vnlog for the test script
@@ -192,15 +213,18 @@ add_library(vnlog STATIC ${VNLOG_SRC_CPP})
192213
target_include_directories(vnlog SYSTEM PUBLIC ${PROJECT_SOURCE_DIR}/vnlog)
193214

194215
# Test script for checking our linker
216+
195217
add_executable(mrcal_jni_test src/mrcal_test.cpp)
218+
196219
target_link_libraries(mrcal_jni_test PUBLIC mrcal_jni)
220+
197221
target_include_directories(
198222
mrcal_jni_test
199223
SYSTEM
200224
PRIVATE ${PROJECT_SOURCE_DIR}/vnlog
201225
)
202226
add_dependencies(mrcal_jni_test mrcal_jni vnlog)
203-
target_link_libraries(mrcal_jni_test PRIVATE ${OpenCV_LIBS} vnlog)
227+
target_link_libraries(mrcal_jni_test PRIVATE ${OPENCV_LIBRARIES} vnlog)
204228

205229
if(WITH_ASAN)
206230
target_link_libraries(

README.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,3 +19,9 @@ cpan -i List::MoreUtils
1919
cmake -B build -DOPENCV_ARCH=osxuniversal -DCMAKE_OSX_ARCHITECTURES="arm64;x86_64"
2020
cmake --build build
2121
```
22+
23+
# Uncertainty testing
24+
25+
I configure with `cmake -B cmake_build`, build with `cmake --build cmake_build` and run with `time ./cmake_build/bin/mrcal_jni_test > /dev/null`
26+
27+
I benchmark with `perf record -F 99 -g ./cmake_build/bin/mrcal_jni_test`

build.gradle

Lines changed: 48 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -32,12 +32,12 @@ dependencies {
3232
implementation wpilibTools.deps.wpilibOpenCvJava("frc2025", "4.10.0-3")
3333

3434
// Junit
35-
testImplementation("org.junit.jupiter:junit-jupiter-api:5.8.2")
36-
testImplementation("org.junit.jupiter:junit-jupiter-params:5.8.2")
37-
testRuntimeOnly("org.junit.jupiter:junit-jupiter-engine:5.8.2")
35+
testImplementation 'org.junit.jupiter:junit-jupiter:5.7.1'
36+
testRuntimeOnly 'org.junit.platform:junit-platform-launcher'
3837

3938
implementation wpilibTools.deps.wpilibJava("wpimath")
4039
implementation wpilibTools.deps.wpilibJava("wpiunits")
40+
implementation wpilibTools.deps.wpilibJava("wpiutil")
4141
implementation "com.fasterxml.jackson.core:jackson-annotations:2.15.2"
4242
}
4343

@@ -57,6 +57,41 @@ test {
5757
useJUnitPlatform()
5858
}
5959

60+
spotless {
61+
java {
62+
target fileTree('.') {
63+
include '**/*.java'
64+
exclude '**/build/**', '**/build-*/**', '**/src/generated/**', "**/cmake_build/**"
65+
}
66+
toggleOffOn()
67+
googleJavaFormat()
68+
leadingSpacesToTabs(2)
69+
leadingTabsToSpaces(4)
70+
removeUnusedImports()
71+
trimTrailingWhitespace()
72+
endWithNewline()
73+
}
74+
groovyGradle {
75+
target fileTree('.') {
76+
include '**/*.gradle'
77+
exclude '**/build/**', '**/build-*/**', "**/cmake_build/**"
78+
}
79+
greclipse()
80+
leadingTabsToSpaces(4)
81+
trimTrailingWhitespace()
82+
endWithNewline()
83+
}
84+
format 'misc', {
85+
target fileTree('.') {
86+
include '**/*.md', '**/.gitignore'
87+
exclude '**/build/**', '**/build-*/**', '**/node_modules/**', "**/cmake_build/**"
88+
}
89+
trimTrailingWhitespace()
90+
leadingTabsToSpaces(2)
91+
endWithNewline()
92+
}
93+
}
94+
6095
def nativeName = wpilibTools.platformMapper.platformPath
6196
ext.outputsFolder = file("$buildDir/outputs")
6297

@@ -74,4 +109,14 @@ tasks.register('copyNativeLibrary', Sync) {
74109
publish.dependsOn it
75110
}
76111

112+
tasks.named('test', Test) {
113+
useJUnitPlatform()
114+
115+
maxHeapSize = '1G'
116+
117+
testLogging {
118+
events "passed"
119+
}
120+
}
121+
77122
apply from: "publish.gradle"

heatmap-gen.py

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
import math
2+
3+
import matplotlib.pyplot as plt
4+
import numpy as np
5+
6+
# Load CSV-like data
7+
data = np.loadtxt("out", delimiter=",")
8+
9+
x = data[:, 0]
10+
y = data[:, 1]
11+
z = data[:, 2]
12+
13+
plt.figure()
14+
plt.title("Projection Uncertainty (in pixels), looking out to infinity")
15+
16+
print(f"Mean={np.mean(z)}")
17+
18+
# Create contour plot with 1px increments
19+
levels = np.arange(0, math.ceil(np.max(z)), 0.1) # 0, 1, 2, ..., 10
20+
contour = plt.tricontour(x, y, z, levels=levels, colors="black", linewidths=0.5)
21+
contourf = plt.tricontourf(x, y, z, levels=levels, cmap="viridis")
22+
plt.clabel(contour, inline=True, fontsize=8, fmt="%0.1f px")
23+
plt.colorbar(contourf, label="Uncertainty (px)")
24+
25+
plt.xlabel("x")
26+
plt.ylabel("y")
27+
plt.gca().invert_yaxis()
28+
plt.axis("equal")
29+
plt.tight_layout()
30+
31+
# plt.show()
32+
plt.savefig("heatmap.svg")

0 commit comments

Comments
 (0)