Update mrcal-java (#2214)

## Description

Updating to take advantage of the now independent mrcal-java (no longer
need to install SuiteSparse and friends!)

## Meta

Merge checklist:
- [x] Pull Request title is [short, imperative
summary](https://cbea.ms/git-commit/) of proposed changes
- [x] The description documents the _what_ and _why_
- [ ] If this PR changes behavior or adds a feature, user documentation
is updated
- [ ] If this PR touches photon-serde, all messages have been
regenerated and hashes have not changed unexpectedly
- [ ] If this PR touches configuration, this is backwards compatible
with settings back to v2025.3.2
- [ ] If this PR touches pipeline settings or anything related to data
exchange, the frontend typing is updated
- [ ] If this PR addresses a bug, a regression test for it is added

---------

Co-authored-by: Matt Morley <matthew.morley.ca@gmail.com>
This commit is contained in:
Gold856
2025-12-06 13:10:47 -05:00
committed by GitHub
parent 16751e9ecd
commit 5e830fae57
11 changed files with 40 additions and 115 deletions

View File

@@ -50,15 +50,24 @@ jobs:
distribution: temurin
- name: Install RoboRIO Toolchain
run: ./gradlew installRoboRioToolchain
- name: Delete duplicate toolchains
run: |
find ~/.gradle/cache/ -name *roborio-academic* -exec rm -rf {} +
du -h . | sort -h
if: matrix.os == 'ubuntu-22.04'
# Need to publish to maven local first, so that C++ sim can pick it up
- name: Publish photonlib to maven local
run: ./gradlew photon-targeting:publishtomavenlocal photon-lib:publishtomavenlocal -x check
- name: Build Java examples
working-directory: photonlib-java-examples
run: ./gradlew build
run: |
./gradlew build
./gradlew clean
- name: Build C++ examples
working-directory: photonlib-cpp-examples
run: ./gradlew build
run: |
./gradlew build
./gradlew clean
playwright-tests:
name: "Playwright E2E tests"
runs-on: ubuntu-22.04
@@ -84,8 +93,6 @@ jobs:
uses: actions/setup-node@v4
with:
node-version: 22
- name: Install mrcal deps
run: sudo apt-get update && sudo apt-get install -y libcholmod3 liblapack3 libsuitesparseconfig5
- name: Setup tests
working-directory: photon-client
run: |
@@ -127,8 +134,6 @@ jobs:
uses: actions/setup-node@v4
with:
node-version: 22
- name: Install mrcal deps
run: sudo apt-get update && sudo apt-get install -y libcholmod3 liblapack3 libsuitesparseconfig5
- name: Gradle Build
run: ./gradlew photon-targeting:build photon-core:build photon-server:build -x check
- name: Gradle Tests and Coverage
@@ -399,12 +404,6 @@ jobs:
- uses: actions/download-artifact@v4
with:
name: ${{ matrix.artifact-name }}
# On linux, install mrcal packages
- run: |
sudo apt-get update
sudo apt-get install --yes libcholmod3 liblapack3 libsuitesparseconfig5
if: ${{ (matrix.os) == 'ubuntu-24.04' }}
# and actually run the jar
- run: java -jar ${{ matrix.extraOpts }} *.jar --smoketest
if: ${{ (matrix.os) != 'windows-latest' }}
- run: ls *.jar | %{ Write-Host "Running $($_.Name)"; Start-Process "java" -ArgumentList "-jar `"$($_.FullName)`" --smoketest" -NoNewWindow -Wait; break }

View File

@@ -58,14 +58,6 @@ PhotonVision uses the following additional out-of-source repositories for buildi
- Custom build of OpenCV with GStreamer/Protobuf/other custom flags: https://github.com/PhotonVision/thirdparty-opencv
- JNI code for aruco-nano: https://github.com/PhotonVision/aruconano-jni
## Additional packages
For now, using mrcal requires installing these additional packages on Linux systems:
```
sudo apt install libcholmod3 liblapack3 libsuitesparseconfig5
```
## Acknowledgments
PhotonVision was forked from [Chameleon Vision](https://github.com/Chameleon-Vision/chameleon-vision/). Thank you to everyone who worked on the original project.

View File

@@ -41,7 +41,7 @@ ext {
rknnVersion = "dev-v2025.0.0-5-g666c0c6"
rubikVersion = "dev-v2025.1.0-6-g4a5e508"
frcYear = "2025"
mrcalVersion = "v2025.0.0";
mrcalVersion = "dev-v2025.0.0-2-g2adb187";
pubVersion = versionString

View File

@@ -56,7 +56,7 @@ dependencies {
"osxx86-64",
"osxarm64"
])) {
implementation("org.photonvision:photon-mrcal-jni:$mrcalVersion:$wpilibNativeName") {
wpilibNatives("org.photonvision:photon-mrcal-jni:$mrcalVersion:$wpilibNativeName") {
transitive = false
}
}

View File

@@ -25,7 +25,7 @@ import org.photonvision.common.dataflow.networktables.NetworkTablesManager;
import org.photonvision.common.hardware.Platform;
import org.photonvision.common.networking.NetworkManager;
import org.photonvision.common.networking.NetworkUtils;
import org.photonvision.mrcal.MrCalJNILoader;
import org.photonvision.common.util.TestUtils;
import org.photonvision.raspi.LibCameraJNILoader;
import org.photonvision.vision.processes.VisionModule;
import org.photonvision.vision.processes.VisionSourceManager;
@@ -54,7 +54,7 @@ public class UIPhotonConfiguration {
PhotonVersion.versionString,
// TODO add support for other types of GPU accel
LibCameraJNILoader.getInstance().isSupported() ? "Zerocopy Libcamera Working" : "",
MrCalJNILoader.getInstance().isLoaded(),
TestUtils.isMrcalLoaded(),
c.neuralNetworkPropertyManager().getModels(),
NeuralNetworkModelManager.getInstance().getSupportedBackends(),
c.getHardwareConfig().deviceName.isEmpty()

View File

@@ -20,6 +20,7 @@ package org.photonvision.common.util;
import com.fasterxml.jackson.databind.ObjectMapper;
import edu.wpi.first.math.geometry.Translation2d;
import edu.wpi.first.math.util.Units;
import edu.wpi.first.util.CombinedRuntimeLoader;
import java.awt.HeadlessException;
import java.io.File;
import java.io.IOException;
@@ -32,10 +33,28 @@ import org.photonvision.vision.pipeline.result.CVPipelineResult;
import org.photonvision.vision.target.TrackedTarget;
public class TestUtils {
private static boolean hasMrcalLoaded = false;
public static boolean loadLibraries() {
return LibraryLoader.loadWpiLibraries() && LibraryLoader.loadTargeting();
}
public static boolean loadMrcal() {
if (hasMrcalLoaded) return true;
try {
CombinedRuntimeLoader.loadLibraries(TestUtils.class, "mrcal_jni");
hasMrcalLoaded = true;
} catch (IOException e) {
e.printStackTrace();
hasMrcalLoaded = false;
}
return hasMrcalLoaded;
}
public static boolean isMrcalLoaded() {
return hasMrcalLoaded;
}
@SuppressWarnings("unused")
public enum WPI2019Image {
kCargoAngledDark48in(1.2192),

View File

@@ -1,82 +0,0 @@
/*
* Copyright (C) Photon Vision.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package org.photonvision.mrcal;
import java.io.IOException;
import java.util.List;
import org.photonvision.common.hardware.Platform;
import org.photonvision.common.util.TestUtils;
import org.photonvision.jni.PhotonJNICommon;
public class MrCalJNILoader extends PhotonJNICommon {
private boolean isLoaded;
private static MrCalJNILoader instance = null;
private MrCalJNILoader() {
isLoaded = false;
}
public static synchronized MrCalJNILoader getInstance() {
if (instance == null) instance = new MrCalJNILoader();
return instance;
}
public static synchronized void forceLoad() throws IOException {
// Force load opencv
TestUtils.loadLibraries();
// Library naming is dumb and has "lib" appended for Windows when it ought not to
if (Platform.isWindows()) {
// Order is correct to match dependencies of libraries
forceLoad(
MrCalJNILoader.getInstance(),
MrCalJNILoader.class,
List.of(
"libamd",
"libcamd",
"libcolamd",
"libccolamd",
"openblas",
"libwinpthread-1",
"libgcc_s_seh-1",
"libquadmath-0",
"libgfortran-5",
"liblapack",
"libcholmod",
"mrcal_jni"));
} else {
// Nothing else to do on linux
forceLoad(MrCalJNILoader.getInstance(), MrCalJNILoader.class, List.of("mrcal_jni"));
}
if (!MrCalJNILoader.getInstance().isLoaded()) {
throw new IOException("Unable to load mrcal JNI!");
}
}
@Override
public boolean isLoaded() {
return isLoaded;
}
@Override
public void setLoaded(boolean state) {
isLoaded = state;
}
}

View File

@@ -29,10 +29,10 @@ import org.opencv.core.*;
import org.opencv.imgcodecs.Imgcodecs;
import org.photonvision.common.logging.LogGroup;
import org.photonvision.common.logging.Logger;
import org.photonvision.common.util.TestUtils;
import org.photonvision.common.util.math.MathUtils;
import org.photonvision.mrcal.MrCalJNI;
import org.photonvision.mrcal.MrCalJNI.MrCalResult;
import org.photonvision.mrcal.MrCalJNILoader;
import org.photonvision.vision.calibration.BoardObservation;
import org.photonvision.vision.calibration.CameraCalibrationCoefficients;
import org.photonvision.vision.calibration.CameraLensModel;
@@ -94,7 +94,7 @@ public class Calibrate3dPipe
CameraCalibrationCoefficients ret;
var start = System.nanoTime();
if (MrCalJNILoader.getInstance().isLoaded() && params.useMrCal) {
if (TestUtils.isMrcalLoaded() && params.useMrCal) {
logger.debug("Calibrating with mrcal!");
ret =
calibrateMrcal(

View File

@@ -37,7 +37,6 @@ import org.photonvision.common.logging.LogGroup;
import org.photonvision.common.logging.LogLevel;
import org.photonvision.common.logging.Logger;
import org.photonvision.common.util.TestUtils;
import org.photonvision.mrcal.MrCalJNILoader;
import org.photonvision.vision.calibration.CameraCalibrationCoefficients;
import org.photonvision.vision.camera.QuirkyCamera;
import org.photonvision.vision.frame.Frame;
@@ -52,7 +51,7 @@ public class Calibrate3dPipeTest {
@BeforeAll
public static void init() throws IOException {
TestUtils.loadLibraries();
MrCalJNILoader.forceLoad();
TestUtils.loadMrcal();
var logLevel = LogLevel.DEBUG;
Logger.setLevel(LogGroup.Camera, logLevel);

View File

@@ -35,7 +35,6 @@ import org.photonvision.common.logging.LogLevel;
import org.photonvision.common.logging.Logger;
import org.photonvision.common.util.TestUtils;
import org.photonvision.estimation.OpenCVHelp;
import org.photonvision.mrcal.MrCalJNILoader;
import org.photonvision.vision.calibration.CameraCalibrationCoefficients;
import org.photonvision.vision.calibration.CameraLensModel;
import org.photonvision.vision.calibration.JsonMatOfDouble;
@@ -50,7 +49,7 @@ public class CalibrationRotationPipeTest {
@BeforeAll
public static void init() throws IOException {
TestUtils.loadLibraries();
MrCalJNILoader.forceLoad();
TestUtils.loadMrcal();
var logLevel = LogLevel.DEBUG;
Logger.setLevel(LogGroup.Camera, logLevel);

View File

@@ -41,7 +41,6 @@ import org.photonvision.common.util.TestUtils;
import org.photonvision.jni.LibraryLoader;
import org.photonvision.jni.RknnDetectorJNI;
import org.photonvision.jni.RubikDetectorJNI;
import org.photonvision.mrcal.MrCalJNILoader;
import org.photonvision.raspi.LibCameraJNILoader;
import org.photonvision.server.Server;
import org.photonvision.vision.apriltag.AprilTagFamily;
@@ -262,8 +261,8 @@ public class Main {
logger.error("Failed to load rubik-JNI!", e);
}
try {
MrCalJNILoader.forceLoad();
} catch (IOException e) {
TestUtils.loadMrcal();
} catch (Exception e) {
logger.warn(
"Failed to load mrcal-JNI! Camera calibration will fall back to opencv\n"
+ e.getMessage());