mirror of
https://github.com/PhotonVision/photonvision
synced 2026-07-02 02:51:40 +00:00
Compare commits
11 Commits
v2027.0.0-
...
Dev
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
bab156312c | ||
|
|
8f560e5b1f | ||
|
|
bd8fa28ab7 | ||
|
|
6155fb9534 | ||
|
|
10f38268e6 | ||
|
|
d3503226b3 | ||
|
|
0e2563111c | ||
|
|
0a07263f74 | ||
|
|
e41be8e858 | ||
|
|
bd9f899514 | ||
|
|
c04c8d76ed |
101
.github/workflows/build.yml
vendored
101
.github/workflows/build.yml
vendored
@@ -91,27 +91,6 @@ jobs:
|
|||||||
# ./gradlew build
|
# ./gradlew build
|
||||||
# ./gradlew clean
|
# ./gradlew clean
|
||||||
|
|
||||||
typecheck-client:
|
|
||||||
name: "Typecheck Client"
|
|
||||||
runs-on: ubuntu-24.04
|
|
||||||
steps:
|
|
||||||
- name: Checkout code
|
|
||||||
uses: actions/checkout@v6
|
|
||||||
- name: Install pnpm
|
|
||||||
uses: pnpm/action-setup@v5
|
|
||||||
with:
|
|
||||||
version: 10
|
|
||||||
- name: Setup Node.js
|
|
||||||
uses: actions/setup-node@v6
|
|
||||||
with:
|
|
||||||
node-version: 24
|
|
||||||
cache: pnpm
|
|
||||||
cache-dependency-path: photon-client/pnpm-lock.yaml
|
|
||||||
- name: Typecheck Client
|
|
||||||
working-directory: photon-client
|
|
||||||
run: |
|
|
||||||
pnpm install --frozen-lockfile
|
|
||||||
pnpm type-check
|
|
||||||
playwright-tests:
|
playwright-tests:
|
||||||
name: "Playwright E2E tests"
|
name: "Playwright E2E tests"
|
||||||
runs-on: ubuntu-24.04
|
runs-on: ubuntu-24.04
|
||||||
@@ -125,19 +104,20 @@ jobs:
|
|||||||
distribution: temurin
|
distribution: temurin
|
||||||
- uses: pnpm/action-setup@v5
|
- uses: pnpm/action-setup@v5
|
||||||
with:
|
with:
|
||||||
version: 10
|
version: 11
|
||||||
- uses: actions/setup-node@v6
|
- uses: actions/setup-node@v6
|
||||||
with:
|
with:
|
||||||
cache: pnpm
|
cache: pnpm
|
||||||
cache-dependency-path: photon-client/pnpm-lock.yaml
|
cache-dependency-path: photon-client/pnpm-lock.yaml
|
||||||
node-version: 24
|
node-version: 24
|
||||||
- name: Setup tests
|
- parallel:
|
||||||
working-directory: photon-client
|
- name: Setup tests
|
||||||
run: |
|
working-directory: photon-client
|
||||||
pnpm install
|
run: |
|
||||||
pnpm test-setup
|
pnpm install
|
||||||
- name: Prebuild Gradle
|
pnpm test-setup
|
||||||
run: ./gradlew photon-targeting:build photon-core:build photon-server:build -x check
|
- name: Prebuild Gradle
|
||||||
|
run: ./gradlew photon-targeting:build photon-core:build photon-server:build -x check
|
||||||
- name: Run Playwright tests
|
- name: Run Playwright tests
|
||||||
working-directory: photon-client
|
working-directory: photon-client
|
||||||
run: pnpm test
|
run: pnpm test
|
||||||
@@ -164,7 +144,7 @@ jobs:
|
|||||||
distribution: temurin
|
distribution: temurin
|
||||||
- uses: pnpm/action-setup@v5
|
- uses: pnpm/action-setup@v5
|
||||||
with:
|
with:
|
||||||
version: 10
|
version: 11
|
||||||
- uses: actions/setup-node@v6
|
- uses: actions/setup-node@v6
|
||||||
with:
|
with:
|
||||||
cache: pnpm
|
cache: pnpm
|
||||||
@@ -174,6 +154,19 @@ jobs:
|
|||||||
run: ./gradlew photon-targeting:build photon-core:build photon-server:build -x check
|
run: ./gradlew photon-targeting:build photon-core:build photon-server:build -x check
|
||||||
- name: Gradle Tests and Coverage
|
- name: Gradle Tests and Coverage
|
||||||
run: ./gradlew test jacocoTestReport --stacktrace
|
run: ./gradlew test jacocoTestReport --stacktrace
|
||||||
|
- name: Cancel on failure
|
||||||
|
if: failure()
|
||||||
|
uses: actions/github-script@v6
|
||||||
|
with:
|
||||||
|
script: |
|
||||||
|
const { owner, repo } = context.repo;
|
||||||
|
const runId = context.runId;
|
||||||
|
|
||||||
|
await github.rest.actions.cancelWorkflowRun({
|
||||||
|
owner,
|
||||||
|
repo,
|
||||||
|
run_id: runId
|
||||||
|
});
|
||||||
build-offline-docs:
|
build-offline-docs:
|
||||||
name: "Build Offline Docs"
|
name: "Build Offline Docs"
|
||||||
runs-on: ubuntu-24.04
|
runs-on: ubuntu-24.04
|
||||||
@@ -337,7 +330,7 @@ jobs:
|
|||||||
path: output/*.zip
|
path: output/*.zip
|
||||||
|
|
||||||
build-package-linux:
|
build-package-linux:
|
||||||
needs: [build-gradle, build-offline-docs]
|
needs: [build-offline-docs]
|
||||||
|
|
||||||
strategy:
|
strategy:
|
||||||
fail-fast: false
|
fail-fast: false
|
||||||
@@ -363,7 +356,7 @@ jobs:
|
|||||||
distribution: temurin
|
distribution: temurin
|
||||||
- uses: pnpm/action-setup@v5
|
- uses: pnpm/action-setup@v5
|
||||||
with:
|
with:
|
||||||
version: 10
|
version: 11
|
||||||
- uses: actions/setup-node@v6
|
- uses: actions/setup-node@v6
|
||||||
with:
|
with:
|
||||||
node-version: 24
|
node-version: 24
|
||||||
@@ -390,7 +383,7 @@ jobs:
|
|||||||
path: photon-targeting/build/libs
|
path: photon-targeting/build/libs
|
||||||
|
|
||||||
build-package-macos:
|
build-package-macos:
|
||||||
needs: [build-gradle, build-offline-docs]
|
needs: [build-offline-docs]
|
||||||
|
|
||||||
strategy:
|
strategy:
|
||||||
fail-fast: false
|
fail-fast: false
|
||||||
@@ -409,13 +402,13 @@ jobs:
|
|||||||
steps: *build-package-steps
|
steps: *build-package-steps
|
||||||
|
|
||||||
build-package-windows:
|
build-package-windows:
|
||||||
needs: [build-gradle, build-offline-docs]
|
needs: [build-offline-docs]
|
||||||
|
|
||||||
strategy:
|
strategy:
|
||||||
fail-fast: false
|
fail-fast: false
|
||||||
matrix:
|
matrix:
|
||||||
include:
|
include:
|
||||||
- os: windows-latest
|
- os: windows-2022
|
||||||
artifact-name: Win
|
artifact-name: Win
|
||||||
arch-override: winx86-64
|
arch-override: winx86-64
|
||||||
|
|
||||||
@@ -434,7 +427,7 @@ jobs:
|
|||||||
- os: ubuntu-24.04
|
- os: ubuntu-24.04
|
||||||
artifact-name: photonvision-*-linuxx86-64.jar
|
artifact-name: photonvision-*-linuxx86-64.jar
|
||||||
extraOpts: -Djdk.lang.Process.launchMechanism=vfork
|
extraOpts: -Djdk.lang.Process.launchMechanism=vfork
|
||||||
- os: windows-latest
|
- os: windows-2022
|
||||||
artifact-name: photonvision-*-winx86-64.jar
|
artifact-name: photonvision-*-winx86-64.jar
|
||||||
- os: macos-latest
|
- os: macos-latest
|
||||||
artifact-name: photonvision-*-macarm64.jar
|
artifact-name: photonvision-*-macarm64.jar
|
||||||
@@ -474,11 +467,11 @@ jobs:
|
|||||||
fi
|
fi
|
||||||
echo "=== Second run ==="
|
echo "=== Second run ==="
|
||||||
java -jar ${{ matrix.extraOpts }} *.jar --smoketest
|
java -jar ${{ matrix.extraOpts }} *.jar --smoketest
|
||||||
if: ${{ (matrix.os) != 'windows-latest' }}
|
if: ${{ (matrix.os) != 'windows-2022' }}
|
||||||
- run: |
|
- run: |
|
||||||
ls *.jar | %{ Write-Host "Running $($_.Name)"; Start-Process "java" -ArgumentList "-jar `"$($_.FullName)`" --smoketest" -NoNewWindow -Wait; break }
|
ls *.jar | %{ Write-Host "Running $($_.Name)"; Start-Process "java" -ArgumentList "-jar `"$($_.FullName)`" --smoketest" -NoNewWindow -Wait; break }
|
||||||
ls *.jar | %{ Write-Host "Running $($_.Name)"; Start-Process "java" -ArgumentList "-jar `"$($_.FullName)`" --smoketest" -NoNewWindow -Wait; break }
|
ls *.jar | %{ Write-Host "Running $($_.Name)"; Start-Process "java" -ArgumentList "-jar `"$($_.FullName)`" --smoketest" -NoNewWindow -Wait; break }
|
||||||
if: ${{ (matrix.os) == 'windows-latest' }}
|
if: ${{ (matrix.os) == 'windows-2022' }}
|
||||||
|
|
||||||
build-image:
|
build-image:
|
||||||
needs: [build-package-linux]
|
needs: [build-package-linux]
|
||||||
@@ -490,67 +483,68 @@ jobs:
|
|||||||
- os: ubuntu-24.04-arm
|
- os: ubuntu-24.04-arm
|
||||||
image_suffix: RaspberryPi
|
image_suffix: RaspberryPi
|
||||||
plat_override: LINUX_RASPBIAN64
|
plat_override: LINUX_RASPBIAN64
|
||||||
image_url: https://github.com/PhotonVision/photon-image-modifier/releases/download/$IMAGE_VERSION/photonvision_raspi.img.xz
|
image_name: photonvision_raspi.img.xz
|
||||||
minimum_free_mb: 100
|
minimum_free_mb: 100
|
||||||
- os: ubuntu-24.04-arm
|
- os: ubuntu-24.04-arm
|
||||||
image_suffix: limelight2
|
image_suffix: limelight2
|
||||||
plat_override: LINUX_RASPBIAN64
|
plat_override: LINUX_RASPBIAN64
|
||||||
image_url: https://github.com/PhotonVision/photon-image-modifier/releases/download/$IMAGE_VERSION/photonvision_limelight.img.xz
|
image_name: photonvision_limelight.img.xz
|
||||||
minimum_free_mb: 100
|
minimum_free_mb: 100
|
||||||
- os: ubuntu-24.04-arm
|
- os: ubuntu-24.04-arm
|
||||||
image_suffix: limelight3
|
image_suffix: limelight3
|
||||||
plat_override: LINUX_RASPBIAN64
|
plat_override: LINUX_RASPBIAN64
|
||||||
image_url: https://github.com/PhotonVision/photon-image-modifier/releases/download/$IMAGE_VERSION/photonvision_limelight3.img.xz
|
image_name: photonvision_limelight3.img.xz
|
||||||
minimum_free_mb: 100
|
minimum_free_mb: 100
|
||||||
- os: ubuntu-24.04-arm
|
- os: ubuntu-24.04-arm
|
||||||
image_suffix: limelight3G
|
image_suffix: limelight3G
|
||||||
plat_override: LINUX_RASPBIAN64
|
plat_override: LINUX_RASPBIAN64
|
||||||
image_url: https://github.com/PhotonVision/photon-image-modifier/releases/download/$IMAGE_VERSION/photonvision_limelight3g.img.xz
|
image_name: photonvision_limelight3g.img.xz
|
||||||
minimum_free_mb: 100
|
minimum_free_mb: 100
|
||||||
- os: ubuntu-24.04-arm
|
- os: ubuntu-24.04-arm
|
||||||
image_suffix: limelight4
|
image_suffix: limelight4
|
||||||
plat_override: LINUX_RASPBIAN64
|
plat_override: LINUX_RASPBIAN64
|
||||||
image_url: https://github.com/PhotonVision/photon-image-modifier/releases/download/$IMAGE_VERSION/photonvision_limelight4.img.xz
|
image_name: photonvision_limelight4.img.xz
|
||||||
minimum_free_mb: 100
|
minimum_free_mb: 100
|
||||||
- os: ubuntu-24.04-arm
|
- os: ubuntu-24.04-arm
|
||||||
image_suffix: luma_p1
|
image_suffix: luma_p1
|
||||||
plat_override: LINUX_RASPBIAN64
|
plat_override: LINUX_RASPBIAN64
|
||||||
image_url: https://github.com/PhotonVision/photon-image-modifier/releases/download/$IMAGE_VERSION/photonvision_luma_p1.img.xz
|
image_name: photonvision_luma_p1.img.xz
|
||||||
minimum_free_mb: 100
|
minimum_free_mb: 100
|
||||||
- os: ubuntu-24.04-arm
|
- os: ubuntu-24.04-arm
|
||||||
image_suffix: orangepi5
|
image_suffix: orangepi5
|
||||||
plat_override: LINUX_RK3588_64
|
plat_override: LINUX_RK3588_64
|
||||||
image_url: https://github.com/PhotonVision/photon-image-modifier/releases/download/$IMAGE_VERSION/photonvision_opi5.img.xz
|
image_name: photonvision_opi5.img.xz
|
||||||
minimum_free_mb: 1024
|
minimum_free_mb: 1024
|
||||||
- os: ubuntu-24.04-arm
|
- os: ubuntu-24.04-arm
|
||||||
image_suffix: orangepi5b
|
image_suffix: orangepi5b
|
||||||
plat_override: LINUX_RK3588_64
|
plat_override: LINUX_RK3588_64
|
||||||
image_url: https://github.com/PhotonVision/photon-image-modifier/releases/download/$IMAGE_VERSION/photonvision_opi5b.img.xz
|
image_name: photonvision_opi5b.img.xz
|
||||||
minimum_free_mb: 1024
|
minimum_free_mb: 1024
|
||||||
- os: ubuntu-24.04-arm
|
- os: ubuntu-24.04-arm
|
||||||
image_suffix: orangepi5plus
|
image_suffix: orangepi5plus
|
||||||
plat_override: LINUX_RK3588_64
|
plat_override: LINUX_RK3588_64
|
||||||
image_url: https://github.com/PhotonVision/photon-image-modifier/releases/download/$IMAGE_VERSION/photonvision_opi5plus.img.xz
|
image_name: photonvision_opi5plus.img.xz
|
||||||
minimum_free_mb: 1024
|
minimum_free_mb: 1024
|
||||||
- os: ubuntu-24.04-arm
|
- os: ubuntu-24.04-arm
|
||||||
image_suffix: orangepi5pro
|
image_suffix: orangepi5pro
|
||||||
plat_override: LINUX_RK3588_64
|
plat_override: LINUX_RK3588_64
|
||||||
image_url: https://github.com/PhotonVision/photon-image-modifier/releases/download/$IMAGE_VERSION/photonvision_opi5pro.img.xz
|
image_name: photonvision_opi5pro.img.xz
|
||||||
minimum_free_mb: 1024
|
minimum_free_mb: 1024
|
||||||
- os: ubuntu-24.04-arm
|
- os: ubuntu-24.04-arm
|
||||||
image_suffix: orangepi5max
|
image_suffix: orangepi5max
|
||||||
plat_override: LINUX_RK3588_64
|
plat_override: LINUX_RK3588_64
|
||||||
image_url: https://github.com/PhotonVision/photon-image-modifier/releases/download/$IMAGE_VERSION/photonvision_opi5max.img.xz
|
image_name: photonvision_opi5max.img.xz
|
||||||
minimum_free_mb: 1024
|
minimum_free_mb: 1024
|
||||||
- os: ubuntu-24.04-arm
|
- os: ubuntu-24.04-arm
|
||||||
image_suffix: rock5c
|
image_suffix: rock5c
|
||||||
plat_override: LINUX_RK3588_64
|
plat_override: LINUX_RK3588_64
|
||||||
image_url: https://github.com/PhotonVision/photon-image-modifier/releases/download/$IMAGE_VERSION/photonvision_rock5c.img.xz
|
image_name: photonvision_rock5c.img.xz
|
||||||
minimum_free_mb: 1024
|
minimum_free_mb: 1024
|
||||||
- os: ubuntu-24.04-arm
|
- os: ubuntu-24.04-arm
|
||||||
image_suffix: rubikpi3
|
image_suffix: rubikpi3
|
||||||
|
cache: 'yes'
|
||||||
plat_override: LINUX_QCS6490
|
plat_override: LINUX_QCS6490
|
||||||
image_url: https://github.com/PhotonVision/photon-image-modifier/releases/download/$IMAGE_VERSION/photonvision_rubikpi3.tar.xz
|
image_name: photonvision_rubikpi3.tar.xz
|
||||||
minimum_free_mb: 1024
|
minimum_free_mb: 1024
|
||||||
root_location: 'offset=569376768'
|
root_location: 'offset=569376768'
|
||||||
shrink_image: 'no'
|
shrink_image: 'no'
|
||||||
@@ -566,11 +560,12 @@ jobs:
|
|||||||
- uses: actions/download-artifact@v8
|
- uses: actions/download-artifact@v8
|
||||||
with:
|
with:
|
||||||
pattern: photonvision-*-linuxarm64.jar
|
pattern: photonvision-*-linuxarm64.jar
|
||||||
- uses: photonvision/photon-image-runner@HEAD
|
- uses: photonvision/photon-image-runner@v2.0.0
|
||||||
name: Generate image
|
name: Generate image
|
||||||
id: generate_image
|
id: generate_image
|
||||||
with:
|
with:
|
||||||
image_url: ${{ matrix.image_url }}
|
image_url: "https://github.com/PhotonVision/photon-image-modifier/releases/download/${{ env.IMAGE_VERSION }}/${{ matrix.image_name }}"
|
||||||
|
use_cache: ${{ matrix.cache || 'no' }}
|
||||||
minimum_free_mb: ${{ matrix.minimum_free_mb }}
|
minimum_free_mb: ${{ matrix.minimum_free_mb }}
|
||||||
root_location: ${{ matrix.root_location || 'partition=2' }}
|
root_location: ${{ matrix.root_location || 'partition=2' }}
|
||||||
shrink_image: ${{ matrix.shrink_image || 'yes' }}
|
shrink_image: ${{ matrix.shrink_image || 'yes' }}
|
||||||
|
|||||||
9
.github/workflows/lint-format.yml
vendored
9
.github/workflows/lint-format.yml
vendored
@@ -109,3 +109,12 @@ jobs:
|
|||||||
echo "::error ::Linting failed. See https://docs.photonvision.org/en/latest/docs/contributing/linting.html"
|
echo "::error ::Linting failed. See https://docs.photonvision.org/en/latest/docs/contributing/linting.html"
|
||||||
exit $exit_code
|
exit $exit_code
|
||||||
fi
|
fi
|
||||||
|
- name: Run Typechecking
|
||||||
|
run: |
|
||||||
|
set +e
|
||||||
|
pnpm run type-check
|
||||||
|
exit_code=$?
|
||||||
|
if test "$exit_code" -ne "0"; then
|
||||||
|
echo "::error ::Linting failed. See https://docs.photonvision.org/en/latest/docs/contributing/linting.html"
|
||||||
|
exit $exit_code
|
||||||
|
fi
|
||||||
|
|||||||
@@ -34,7 +34,7 @@ ext {
|
|||||||
wpilibVersion = "2027.0.0-alpha-6"
|
wpilibVersion = "2027.0.0-alpha-6"
|
||||||
openCVversion = "2027-4.13.0-3"
|
openCVversion = "2027-4.13.0-3"
|
||||||
ejmlVersion = "0.43.1";
|
ejmlVersion = "0.43.1";
|
||||||
avajeJsonbVersion = "3.14-RC4";
|
avajeJsonbVersion = "3.14";
|
||||||
msgpackVersion = "0.9.0";
|
msgpackVersion = "0.9.0";
|
||||||
quickbufVersion = "1.3.3";
|
quickbufVersion = "1.3.3";
|
||||||
jacocoVersion = "0.8.14";
|
jacocoVersion = "0.8.14";
|
||||||
|
|||||||
@@ -21,6 +21,7 @@
|
|||||||
"type-check": "vue-tsc --noEmit"
|
"type-check": "vue-tsc --noEmit"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
|
"@adam-rocska/units-and-measurement": "^1.2.0",
|
||||||
"@fontsource/prompt": "^5.2.6",
|
"@fontsource/prompt": "^5.2.6",
|
||||||
"@mdi/font": "^7.4.47",
|
"@mdi/font": "^7.4.47",
|
||||||
"@msgpack/msgpack": "^3.1.2",
|
"@msgpack/msgpack": "^3.1.2",
|
||||||
@@ -36,11 +37,10 @@
|
|||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@eslint/js": "^9.31.0",
|
"@eslint/js": "^9.31.0",
|
||||||
"@playwright/test": "^1.56.1",
|
"@playwright/test": "^1.61.1",
|
||||||
"@types/node": "^24.0.0",
|
"@types/node": "^24.0.0",
|
||||||
"@types/three": "^0.178.0",
|
"@types/three": "^0.178.0",
|
||||||
"@vitejs/plugin-vue": "^6.0.6",
|
"@vitejs/plugin-vue": "^6.0.6",
|
||||||
"vue-tsc": "^3.2.5",
|
|
||||||
"@vue/eslint-config-prettier": "^10.2.0",
|
"@vue/eslint-config-prettier": "^10.2.0",
|
||||||
"@vue/eslint-config-typescript": "^14.5.0",
|
"@vue/eslint-config-typescript": "^14.5.0",
|
||||||
"@vue/tsconfig": "^0.7.0",
|
"@vue/tsconfig": "^0.7.0",
|
||||||
@@ -50,6 +50,7 @@
|
|||||||
"sass": "^1.89.2",
|
"sass": "^1.89.2",
|
||||||
"typescript": "^5.8.3",
|
"typescript": "^5.8.3",
|
||||||
"vite": "^8.0.10",
|
"vite": "^8.0.10",
|
||||||
"vite-plugin-vuetify": "^2.1.1"
|
"vite-plugin-vuetify": "^2.1.1",
|
||||||
|
"vue-tsc": "^3.2.5"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
35
photon-client/pnpm-lock.yaml
generated
35
photon-client/pnpm-lock.yaml
generated
@@ -8,6 +8,9 @@ importers:
|
|||||||
|
|
||||||
.:
|
.:
|
||||||
dependencies:
|
dependencies:
|
||||||
|
'@adam-rocska/units-and-measurement':
|
||||||
|
specifier: ^1.2.0
|
||||||
|
version: 1.2.0
|
||||||
'@fontsource/prompt':
|
'@fontsource/prompt':
|
||||||
specifier: ^5.2.6
|
specifier: ^5.2.6
|
||||||
version: 5.2.6
|
version: 5.2.6
|
||||||
@@ -49,8 +52,8 @@ importers:
|
|||||||
specifier: ^9.31.0
|
specifier: ^9.31.0
|
||||||
version: 9.31.0
|
version: 9.31.0
|
||||||
'@playwright/test':
|
'@playwright/test':
|
||||||
specifier: ^1.56.1
|
specifier: ^1.61.1
|
||||||
version: 1.56.1
|
version: 1.61.1
|
||||||
'@types/node':
|
'@types/node':
|
||||||
specifier: ^24.0.0
|
specifier: ^24.0.0
|
||||||
version: 24.12.2
|
version: 24.12.2
|
||||||
@@ -96,6 +99,10 @@ importers:
|
|||||||
|
|
||||||
packages:
|
packages:
|
||||||
|
|
||||||
|
'@adam-rocska/units-and-measurement@1.2.0':
|
||||||
|
resolution: {integrity: sha512-mBnZ8/STbztVec+Mz9DH932z0gny52SebtSJ/y3n+IVtuF7KqbtQ3t1u1lpFSkLFU1msaNGzFgqsW7Emj0lrXA==}
|
||||||
|
engines: {node: '>=20.0.0'}
|
||||||
|
|
||||||
'@babel/helper-string-parser@7.27.1':
|
'@babel/helper-string-parser@7.27.1':
|
||||||
resolution: {integrity: sha512-qMlSxKbpRlAridDExk92nSobyDdpPijUq2DW6oDnUqd0iOGxmQjyqhMIihI9+zv4LPyZdRje2cavWPbCbWm3eA==}
|
resolution: {integrity: sha512-qMlSxKbpRlAridDExk92nSobyDdpPijUq2DW6oDnUqd0iOGxmQjyqhMIihI9+zv4LPyZdRje2cavWPbCbWm3eA==}
|
||||||
engines: {node: '>=6.9.0'}
|
engines: {node: '>=6.9.0'}
|
||||||
@@ -313,8 +320,8 @@ packages:
|
|||||||
resolution: {integrity: sha512-ROFF39F6ZrnzSUEmQQZUar0Jt4xVoP9WnDRdWwF4NNcXs3xBTLgBUDoOwW141y1jP+S8nahIbdxbFC7IShw9Iw==}
|
resolution: {integrity: sha512-ROFF39F6ZrnzSUEmQQZUar0Jt4xVoP9WnDRdWwF4NNcXs3xBTLgBUDoOwW141y1jP+S8nahIbdxbFC7IShw9Iw==}
|
||||||
engines: {node: ^12.20.0 || ^14.18.0 || >=16.0.0}
|
engines: {node: ^12.20.0 || ^14.18.0 || >=16.0.0}
|
||||||
|
|
||||||
'@playwright/test@1.56.1':
|
'@playwright/test@1.61.1':
|
||||||
resolution: {integrity: sha512-vSMYtL/zOcFpvJCW71Q/OEGQb7KYBPAdKh35WNSkaZA75JlAO8ED8UN6GUNTm3drWomcbcqRPFqQbLae8yBTdg==}
|
resolution: {integrity: sha512-8nKv6+0RJSL9FE4jYOEGXnPeM/Hg12qZpmqzZjRh3qM0Y7c3z1mrOTfFLids72RDQYVh9WpLEfR5WdpNX4fkig==}
|
||||||
engines: {node: '>=18'}
|
engines: {node: '>=18'}
|
||||||
hasBin: true
|
hasBin: true
|
||||||
|
|
||||||
@@ -1242,13 +1249,13 @@ packages:
|
|||||||
typescript:
|
typescript:
|
||||||
optional: true
|
optional: true
|
||||||
|
|
||||||
playwright-core@1.56.1:
|
playwright-core@1.61.1:
|
||||||
resolution: {integrity: sha512-hutraynyn31F+Bifme+Ps9Vq59hKuUCz7H1kDOcBs+2oGguKkWTU50bBWrtz34OUWmIwpBTWDxaRPXrIXkgvmQ==}
|
resolution: {integrity: sha512-h7Qlt6m4REp25qvIdvbDtVmD4LqVXfpRxhORv9L0jzETM05p4fuPJ3dKyuSXQxDSbXnmS79HAgi9589lGSpLkg==}
|
||||||
engines: {node: '>=18'}
|
engines: {node: '>=18'}
|
||||||
hasBin: true
|
hasBin: true
|
||||||
|
|
||||||
playwright@1.56.1:
|
playwright@1.61.1:
|
||||||
resolution: {integrity: sha512-aFi5B0WovBHTEvpM3DzXTUaeN6eN0qWnTkKx4NQaH4Wvcmc153PdaY2UBdSYKaGYw+UyWXSVyxDUg5DoPEttjw==}
|
resolution: {integrity: sha512-DWnY5o3YbLWK4GovuAVwpqL+1VwGNdUGrRr++8j8PtQQzvAVZUIMjKQ90fY689sEJZJBbZVw1rXaOKSTitkzPQ==}
|
||||||
engines: {node: '>=18'}
|
engines: {node: '>=18'}
|
||||||
hasBin: true
|
hasBin: true
|
||||||
|
|
||||||
@@ -1550,6 +1557,8 @@ packages:
|
|||||||
|
|
||||||
snapshots:
|
snapshots:
|
||||||
|
|
||||||
|
'@adam-rocska/units-and-measurement@1.2.0': {}
|
||||||
|
|
||||||
'@babel/helper-string-parser@7.27.1': {}
|
'@babel/helper-string-parser@7.27.1': {}
|
||||||
|
|
||||||
'@babel/helper-validator-identifier@7.27.1': {}
|
'@babel/helper-validator-identifier@7.27.1': {}
|
||||||
@@ -1732,9 +1741,9 @@ snapshots:
|
|||||||
|
|
||||||
'@pkgr/core@0.2.4': {}
|
'@pkgr/core@0.2.4': {}
|
||||||
|
|
||||||
'@playwright/test@1.56.1':
|
'@playwright/test@1.61.1':
|
||||||
dependencies:
|
dependencies:
|
||||||
playwright: 1.56.1
|
playwright: 1.61.1
|
||||||
|
|
||||||
'@rolldown/binding-android-arm64@1.0.0-rc.17':
|
'@rolldown/binding-android-arm64@1.0.0-rc.17':
|
||||||
optional: true
|
optional: true
|
||||||
@@ -2637,11 +2646,11 @@ snapshots:
|
|||||||
optionalDependencies:
|
optionalDependencies:
|
||||||
typescript: 5.8.3
|
typescript: 5.8.3
|
||||||
|
|
||||||
playwright-core@1.56.1: {}
|
playwright-core@1.61.1: {}
|
||||||
|
|
||||||
playwright@1.56.1:
|
playwright@1.61.1:
|
||||||
dependencies:
|
dependencies:
|
||||||
playwright-core: 1.56.1
|
playwright-core: 1.61.1
|
||||||
optionalDependencies:
|
optionalDependencies:
|
||||||
fsevents: 2.3.2
|
fsevents: 2.3.2
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { computed, ref, watchEffect } from "vue";
|
import { computed, ref, watch, watchEffect } from "vue";
|
||||||
import { useCameraSettingsStore } from "@/stores/settings/CameraSettingsStore";
|
import { useCameraSettingsStore } from "@/stores/settings/CameraSettingsStore";
|
||||||
import { CalibrationBoardTypes, CalibrationTagFamilies, type VideoFormat } from "@/types/SettingTypes";
|
import { CalibrationBoardTypes, CalibrationTagFamilies, type VideoFormat } from "@/types/SettingTypes";
|
||||||
import MonoLogo from "@/assets/images/logoMono.png";
|
import MonoLogo from "@/assets/images/logoMono.png";
|
||||||
@@ -15,12 +15,12 @@ import CameraCalibrationInfoCard from "@/components/cameras/CameraCalibrationInf
|
|||||||
import { useSettingsStore } from "@/stores/settings/GeneralSettingsStore";
|
import { useSettingsStore } from "@/stores/settings/GeneralSettingsStore";
|
||||||
import { useTheme } from "vuetify";
|
import { useTheme } from "vuetify";
|
||||||
import TooltippedLabel from "@/components/common/pv-tooltipped-label.vue";
|
import TooltippedLabel from "@/components/common/pv-tooltipped-label.vue";
|
||||||
|
import { length } from "@adam-rocska/units-and-measurement/length";
|
||||||
|
|
||||||
const PromptRegular = import("@/assets/fonts/PromptRegular");
|
const PromptRegular = import("@/assets/fonts/PromptRegular");
|
||||||
const jspdf = import("jspdf");
|
const jspdf = import("jspdf");
|
||||||
|
|
||||||
const theme = useTheme();
|
const theme = useTheme();
|
||||||
const MM_PER_INCH = 25.4;
|
|
||||||
|
|
||||||
const settingsValid = ref(true);
|
const settingsValid = ref(true);
|
||||||
|
|
||||||
@@ -110,8 +110,8 @@ watchEffect(() => {
|
|||||||
uniqueVideoResolutionIndex.value = currentIndex;
|
uniqueVideoResolutionIndex.value = currentIndex;
|
||||||
});
|
});
|
||||||
const dimensionUnit = ref<"in" | "mm">("in");
|
const dimensionUnit = ref<"in" | "mm">("in");
|
||||||
const squareSizeIn = ref(1);
|
const squareSize = ref(30);
|
||||||
const markerSizeIn = ref(0.75);
|
const markerSize = ref(22);
|
||||||
const patternWidth = ref(8);
|
const patternWidth = ref(8);
|
||||||
const patternHeight = ref(8);
|
const patternHeight = ref(8);
|
||||||
const boardType = ref<CalibrationBoardTypes>(CalibrationBoardTypes.Charuco);
|
const boardType = ref<CalibrationBoardTypes>(CalibrationBoardTypes.Charuco);
|
||||||
@@ -119,24 +119,9 @@ const useOldPattern = ref(false);
|
|||||||
const tagFamily = ref<CalibrationTagFamilies>(CalibrationTagFamilies.Dict_4X4_1000);
|
const tagFamily = ref<CalibrationTagFamilies>(CalibrationTagFamilies.Dict_4X4_1000);
|
||||||
const requestedVideoFormatIndex = ref(0);
|
const requestedVideoFormatIndex = ref(0);
|
||||||
|
|
||||||
const convertInchesToDisplay = (valueInInches: number) =>
|
watch(dimensionUnit, (value, oldValue) => {
|
||||||
dimensionUnit.value === "mm" ? valueInInches * MM_PER_INCH : valueInInches;
|
squareSize.value = length[oldValue](squareSize.value)[value].value;
|
||||||
|
markerSize.value = length[oldValue](markerSize.value)[value].value;
|
||||||
const convertDisplayToInches = (displayValue: number) =>
|
|
||||||
dimensionUnit.value === "mm" ? displayValue / MM_PER_INCH : displayValue;
|
|
||||||
|
|
||||||
const squareSize = computed({
|
|
||||||
get: () => convertInchesToDisplay(squareSizeIn.value),
|
|
||||||
set(value) {
|
|
||||||
squareSizeIn.value = convertDisplayToInches(value);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
const markerSize = computed({
|
|
||||||
get: () => convertInchesToDisplay(markerSizeIn.value),
|
|
||||||
set(value) {
|
|
||||||
markerSizeIn.value = convertDisplayToInches(value);
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
|
|
||||||
const dimensionStep = computed(() => (dimensionUnit.value === "mm" ? 0.1 : 0.01));
|
const dimensionStep = computed(() => (dimensionUnit.value === "mm" ? 0.1 : 0.01));
|
||||||
@@ -161,25 +146,31 @@ const downloadCalibBoard = async () => {
|
|||||||
|
|
||||||
switch (boardType.value) {
|
switch (boardType.value) {
|
||||||
case CalibrationBoardTypes.Chessboard:
|
case CalibrationBoardTypes.Chessboard:
|
||||||
const chessboardStartX = (paperWidth - patternWidth.value * squareSizeIn.value) / 2;
|
const squareSizeIn = length[dimensionUnit.value](squareSize.value).in.value;
|
||||||
|
const chessboardStartX = (paperWidth - patternWidth.value * squareSizeIn) / 2;
|
||||||
|
|
||||||
const chessboardStartY = (paperHeight - patternWidth.value * squareSizeIn.value) / 2;
|
const chessboardStartY = (paperHeight - patternHeight.value * squareSizeIn) / 2;
|
||||||
|
|
||||||
for (let squareY = 0; squareY < patternHeight.value; squareY++) {
|
for (let squareY = 0; squareY < patternHeight.value; squareY++) {
|
||||||
for (let squareX = 0; squareX < patternWidth.value; squareX++) {
|
for (let squareX = 0; squareX < patternWidth.value; squareX++) {
|
||||||
const xPos = chessboardStartX + squareX * squareSizeIn.value;
|
const xPos = chessboardStartX + squareX * squareSizeIn;
|
||||||
const yPos = chessboardStartY + squareY * squareSizeIn.value;
|
const yPos = chessboardStartY + squareY * squareSizeIn;
|
||||||
|
|
||||||
// Only draw the odd squares to create the chessboard pattern
|
// Only draw the odd squares to create the chessboard pattern
|
||||||
if (squareY % 2 !== squareX % 2) {
|
if (squareY % 2 !== squareX % 2) {
|
||||||
doc.rect(xPos, yPos, squareSizeIn.value, squareSizeIn.value, "F");
|
doc.rect(xPos, yPos, squareSizeIn, squareSizeIn, "F");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
doc.text(`${patternWidth.value} x ${patternHeight.value} | ${squareSizeIn.value}in`, paperWidth - 1, 1.0, {
|
doc.text(
|
||||||
maxWidth: (paperWidth - 2.0) / 2,
|
`${patternWidth.value} x ${patternHeight.value} | ${squareSize.value}${dimensionUnit.value}`,
|
||||||
align: "right"
|
paperWidth - 1,
|
||||||
});
|
1.0,
|
||||||
|
{
|
||||||
|
maxWidth: (paperWidth - 2.0) / 2,
|
||||||
|
align: "right"
|
||||||
|
}
|
||||||
|
);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case CalibrationBoardTypes.Charuco:
|
case CalibrationBoardTypes.Charuco:
|
||||||
@@ -220,8 +211,8 @@ const isCalibrating = computed(
|
|||||||
|
|
||||||
const startCalibration = () => {
|
const startCalibration = () => {
|
||||||
useCameraSettingsStore().startPnPCalibration({
|
useCameraSettingsStore().startPnPCalibration({
|
||||||
squareSizeIn: squareSizeIn.value,
|
squareSizeMeters: length[dimensionUnit.value](squareSize.value).m.value,
|
||||||
markerSizeIn: markerSizeIn.value,
|
markerSizeMeters: length[dimensionUnit.value](markerSize.value).m.value,
|
||||||
patternHeight: patternHeight.value,
|
patternHeight: patternHeight.value,
|
||||||
patternWidth: patternWidth.value,
|
patternWidth: patternWidth.value,
|
||||||
boardType: boardType.value,
|
boardType: boardType.value,
|
||||||
|
|||||||
@@ -368,8 +368,8 @@ export const useCameraSettingsStore = defineStore("cameraSettings", {
|
|||||||
*/
|
*/
|
||||||
startPnPCalibration(
|
startPnPCalibration(
|
||||||
calibrationInitData: {
|
calibrationInitData: {
|
||||||
squareSizeIn: number;
|
squareSizeMeters: number;
|
||||||
markerSizeIn: number;
|
markerSizeMeters: number;
|
||||||
patternWidth: number;
|
patternWidth: number;
|
||||||
patternHeight: number;
|
patternHeight: number;
|
||||||
boardType: CalibrationBoardTypes;
|
boardType: CalibrationBoardTypes;
|
||||||
|
|||||||
@@ -87,8 +87,8 @@ export interface WebsocketCalibrationData {
|
|||||||
minCount: number;
|
minCount: number;
|
||||||
videoModeIndex: number;
|
videoModeIndex: number;
|
||||||
patternHeight: number;
|
patternHeight: number;
|
||||||
squareSizeIn: number;
|
squareSizeMm: number;
|
||||||
markerSizeIn: number;
|
markerSizeMm: number;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface IncomingWebsocketData {
|
export interface IncomingWebsocketData {
|
||||||
|
|||||||
@@ -38,9 +38,10 @@ import org.photonvision.common.configuration.NeuralNetworkModelsSettings.ModelPr
|
|||||||
import org.photonvision.common.hardware.Platform;
|
import org.photonvision.common.hardware.Platform;
|
||||||
import org.photonvision.common.logging.LogGroup;
|
import org.photonvision.common.logging.LogGroup;
|
||||||
import org.photonvision.common.logging.Logger;
|
import org.photonvision.common.logging.Logger;
|
||||||
|
import org.photonvision.tflite.TFLiteJNI.TFLiteSource;
|
||||||
import org.photonvision.vision.objects.Model;
|
import org.photonvision.vision.objects.Model;
|
||||||
import org.photonvision.vision.objects.RknnModel;
|
import org.photonvision.vision.objects.RknnModel;
|
||||||
import org.photonvision.vision.objects.RubikModel;
|
import org.photonvision.vision.objects.TFLiteModel;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Manages the loading of neural network models.
|
* Manages the loading of neural network models.
|
||||||
@@ -280,10 +281,10 @@ public class NeuralNetworkModelManager {
|
|||||||
*
|
*
|
||||||
* <p>If this method returns `Optional.of(..)` then the model should be safe to load.
|
* <p>If this method returns `Optional.of(..)` then the model should be safe to load.
|
||||||
*
|
*
|
||||||
* @param modelUID the unique identifier of the model to retrieve
|
* @param modelPath the unique identifier of the model to retrieve
|
||||||
* @return an Optional containing the model if found, or an empty Optional if not found
|
* @return an Optional containing the model if found, or an empty Optional if not found
|
||||||
*/
|
*/
|
||||||
public Optional<Model> getModel(String modelUID) {
|
public Optional<Model> getModel(Path modelPath) {
|
||||||
if (models == null) {
|
if (models == null) {
|
||||||
return Optional.empty();
|
return Optional.empty();
|
||||||
}
|
}
|
||||||
@@ -292,7 +293,7 @@ public class NeuralNetworkModelManager {
|
|||||||
for (Family backend : supportedBackends) {
|
for (Family backend : supportedBackends) {
|
||||||
if (models.containsKey(backend)) {
|
if (models.containsKey(backend)) {
|
||||||
Optional<Model> model =
|
Optional<Model> model =
|
||||||
models.get(backend).stream().filter(m -> m.getUID().equals(modelUID)).findFirst();
|
models.get(backend).stream().filter(m -> m.getPath().equals(modelPath)).findFirst();
|
||||||
if (model.isPresent()) {
|
if (model.isPresent()) {
|
||||||
return model;
|
return model;
|
||||||
}
|
}
|
||||||
@@ -360,7 +361,7 @@ public class NeuralNetworkModelManager {
|
|||||||
models.get(properties.family()).add(new RknnModel(properties));
|
models.get(properties.family()).add(new RknnModel(properties));
|
||||||
}
|
}
|
||||||
case RUBIK -> {
|
case RUBIK -> {
|
||||||
models.get(properties.family()).add(new RubikModel(properties));
|
models.get(properties.family()).add(new TFLiteModel(properties, TFLiteSource.RUBIK));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
logger.info(
|
logger.info(
|
||||||
@@ -406,7 +407,8 @@ public class NeuralNetworkModelManager {
|
|||||||
// After loading all of the models, sort them by name to ensure a consistent
|
// After loading all of the models, sort them by name to ensure a consistent
|
||||||
// ordering
|
// ordering
|
||||||
models.forEach(
|
models.forEach(
|
||||||
(backend, backendModels) -> backendModels.sort((a, b) -> a.getUID().compareTo(b.getUID())));
|
(backend, backendModels) ->
|
||||||
|
backendModels.sort((a, b) -> a.getPath().compareTo(b.getPath())));
|
||||||
|
|
||||||
// Log
|
// Log
|
||||||
StringBuilder sb = new StringBuilder();
|
StringBuilder sb = new StringBuilder();
|
||||||
@@ -414,7 +416,7 @@ public class NeuralNetworkModelManager {
|
|||||||
models.forEach(
|
models.forEach(
|
||||||
(backend, backendModels) -> {
|
(backend, backendModels) -> {
|
||||||
sb.append(backend).append(" [");
|
sb.append(backend).append(" [");
|
||||||
backendModels.forEach(model -> sb.append(model.getUID()).append(", "));
|
backendModels.forEach(model -> sb.append(model.getPath()).append(", "));
|
||||||
sb.append("] ");
|
sb.append("] ");
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -17,13 +17,19 @@
|
|||||||
|
|
||||||
package org.photonvision.vision.objects;
|
package org.photonvision.vision.objects;
|
||||||
|
|
||||||
|
import java.nio.file.Path;
|
||||||
import org.photonvision.common.configuration.NeuralNetworkModelManager.Family;
|
import org.photonvision.common.configuration.NeuralNetworkModelManager.Family;
|
||||||
import org.photonvision.common.configuration.NeuralNetworkModelsSettings.ModelProperties;
|
import org.photonvision.common.configuration.NeuralNetworkModelsSettings.ModelProperties;
|
||||||
|
|
||||||
public interface Model {
|
public interface Model {
|
||||||
public ObjectDetector load();
|
public ObjectDetector load();
|
||||||
|
|
||||||
public String getUID();
|
/**
|
||||||
|
* Gets the path to the model file. This is being used as a UID.
|
||||||
|
*
|
||||||
|
* @return the path to the model file (for use as a UID)
|
||||||
|
*/
|
||||||
|
public Path getPath();
|
||||||
|
|
||||||
public String getNickname();
|
public String getNickname();
|
||||||
|
|
||||||
|
|||||||
@@ -17,6 +17,7 @@
|
|||||||
|
|
||||||
package org.photonvision.vision.objects;
|
package org.photonvision.vision.objects;
|
||||||
|
|
||||||
|
import java.nio.file.Path;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import org.opencv.core.Mat;
|
import org.opencv.core.Mat;
|
||||||
import org.photonvision.common.configuration.NeuralNetworkModelManager.Family;
|
import org.photonvision.common.configuration.NeuralNetworkModelManager.Family;
|
||||||
@@ -43,8 +44,8 @@ public class NullModel implements Model, ObjectDetector {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String getUID() {
|
public Path getPath() {
|
||||||
return "NullModel";
|
return Path.of("null");
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|||||||
@@ -18,7 +18,7 @@
|
|||||||
package org.photonvision.vision.objects;
|
package org.photonvision.vision.objects;
|
||||||
|
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
import org.opencv.core.Size;
|
import java.nio.file.Path;
|
||||||
import org.photonvision.common.configuration.NeuralNetworkModelManager.Family;
|
import org.photonvision.common.configuration.NeuralNetworkModelManager.Family;
|
||||||
import org.photonvision.common.configuration.NeuralNetworkModelManager.Version;
|
import org.photonvision.common.configuration.NeuralNetworkModelManager.Version;
|
||||||
import org.photonvision.common.configuration.NeuralNetworkModelsSettings.ModelProperties;
|
import org.photonvision.common.configuration.NeuralNetworkModelsSettings.ModelProperties;
|
||||||
@@ -61,8 +61,8 @@ public class RknnModel implements Model {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/** Return the unique identifier for the model. In this case, it's the model's path. */
|
/** Return the unique identifier for the model. In this case, it's the model's path. */
|
||||||
public String getUID() {
|
public Path getPath() {
|
||||||
return properties.modelPath().toString();
|
return properties.modelPath();
|
||||||
}
|
}
|
||||||
|
|
||||||
public String getNickname() {
|
public String getNickname() {
|
||||||
@@ -78,8 +78,7 @@ public class RknnModel implements Model {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public ObjectDetector load() {
|
public ObjectDetector load() {
|
||||||
return new RknnObjectDetector(
|
return new RknnObjectDetector(this);
|
||||||
this, new Size(properties.resolutionWidth(), properties.resolutionHeight()));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public String toString() {
|
public String toString() {
|
||||||
|
|||||||
@@ -61,9 +61,10 @@ public class RknnObjectDetector implements ObjectDetector {
|
|||||||
* @param inputSize The required image dimensions for the model. Images will be {@link
|
* @param inputSize The required image dimensions for the model. Images will be {@link
|
||||||
* Letterbox}ed to this shape.
|
* Letterbox}ed to this shape.
|
||||||
*/
|
*/
|
||||||
public RknnObjectDetector(RknnModel model, Size inputSize) {
|
public RknnObjectDetector(RknnModel model) {
|
||||||
this.model = model;
|
this.model = model;
|
||||||
this.inputSize = inputSize;
|
this.inputSize =
|
||||||
|
new Size(model.properties.resolutionWidth(), model.properties.resolutionHeight());
|
||||||
|
|
||||||
// Create the detector
|
// Create the detector
|
||||||
objPointer =
|
objPointer =
|
||||||
|
|||||||
@@ -18,22 +18,27 @@
|
|||||||
package org.photonvision.vision.objects;
|
package org.photonvision.vision.objects;
|
||||||
|
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
import org.opencv.core.Size;
|
import java.nio.file.Path;
|
||||||
import org.photonvision.common.configuration.NeuralNetworkModelManager.Family;
|
import org.photonvision.common.configuration.NeuralNetworkModelManager.Family;
|
||||||
import org.photonvision.common.configuration.NeuralNetworkModelManager.Version;
|
import org.photonvision.common.configuration.NeuralNetworkModelManager.Version;
|
||||||
import org.photonvision.common.configuration.NeuralNetworkModelsSettings.ModelProperties;
|
import org.photonvision.common.configuration.NeuralNetworkModelsSettings.ModelProperties;
|
||||||
|
import org.photonvision.tflite.TFLiteJNI.TFLiteSource;
|
||||||
|
|
||||||
public class RubikModel implements Model {
|
public class TFLiteModel implements Model {
|
||||||
public final File modelFile;
|
public final File modelFile;
|
||||||
public final ModelProperties properties;
|
public final ModelProperties properties;
|
||||||
|
public final TFLiteSource backend;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Rubik model constructor.
|
* TFLite model constructor.
|
||||||
*
|
*
|
||||||
* @param properties The properties of the model.
|
* @param properties The properties of the model.
|
||||||
|
* @param backend The backend of the model should run on.
|
||||||
* @throws IllegalArgumentException
|
* @throws IllegalArgumentException
|
||||||
*/
|
*/
|
||||||
public RubikModel(ModelProperties properties) throws IllegalArgumentException {
|
public TFLiteModel(ModelProperties properties, TFLiteSource backend)
|
||||||
|
throws IllegalArgumentException {
|
||||||
|
this.backend = backend;
|
||||||
modelFile = new File(properties.modelPath().toString());
|
modelFile = new File(properties.modelPath().toString());
|
||||||
if (!modelFile.exists()) {
|
if (!modelFile.exists()) {
|
||||||
throw new IllegalArgumentException("Model file does not exist: " + modelFile);
|
throw new IllegalArgumentException("Model file does not exist: " + modelFile);
|
||||||
@@ -59,8 +64,8 @@ public class RubikModel implements Model {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/** Return the unique identifier for the model. In this case, it's the model's path. */
|
/** Return the unique identifier for the model. In this case, it's the model's path. */
|
||||||
public String getUID() {
|
public Path getPath() {
|
||||||
return properties.modelPath().toString();
|
return properties.modelPath();
|
||||||
}
|
}
|
||||||
|
|
||||||
public String getNickname() {
|
public String getNickname() {
|
||||||
@@ -76,11 +81,10 @@ public class RubikModel implements Model {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public ObjectDetector load() {
|
public ObjectDetector load() {
|
||||||
return new RubikObjectDetector(
|
return new TFLiteObjectDetector(this, backend);
|
||||||
this, new Size(this.properties.resolutionWidth(), this.properties.resolutionHeight()));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public String toString() {
|
public String toString() {
|
||||||
return "RubikModel{" + "modelFile=" + modelFile + ", properties=" + properties + '}';
|
return "TFLiteModel{" + "modelFile=" + modelFile + ", properties=" + properties + '}';
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -30,9 +30,9 @@ import org.photonvision.tflite.TFLiteJNI;
|
|||||||
import org.photonvision.tflite.TFLiteJNI.TFLiteSource;
|
import org.photonvision.tflite.TFLiteJNI.TFLiteSource;
|
||||||
import org.photonvision.vision.pipe.impl.NeuralNetworkPipeResult;
|
import org.photonvision.vision.pipe.impl.NeuralNetworkPipeResult;
|
||||||
|
|
||||||
/** Manages an object detector using the rubik backend. */
|
/** Manages an object detector using the TFLite backend. */
|
||||||
public class RubikObjectDetector implements ObjectDetector {
|
public class TFLiteObjectDetector implements ObjectDetector {
|
||||||
private static final Logger logger = new Logger(RubikObjectDetector.class, LogGroup.General);
|
private static final Logger logger = new Logger(TFLiteObjectDetector.class, LogGroup.General);
|
||||||
|
|
||||||
private static final Cleaner cleaner = Cleaner.create();
|
private static final Cleaner cleaner = Cleaner.create();
|
||||||
|
|
||||||
@@ -45,26 +45,26 @@ public class RubikObjectDetector implements ObjectDetector {
|
|||||||
/** Pointer to the native object */
|
/** Pointer to the native object */
|
||||||
private final long ptr;
|
private final long ptr;
|
||||||
|
|
||||||
private final RubikModel model;
|
private final TFLiteModel model;
|
||||||
|
|
||||||
private final Size inputSize;
|
private final Size inputSize;
|
||||||
|
|
||||||
/** Returns the model in use by this detector. */
|
/** Returns the model in use by this detector. */
|
||||||
@Override
|
@Override
|
||||||
public RubikModel getModel() {
|
public TFLiteModel getModel() {
|
||||||
return model;
|
return model;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates a new rubikObjectDetector from the given model.
|
* Creates a new TFLite detector from the given model.
|
||||||
*
|
*
|
||||||
* @param model The model to create the detector from.
|
* @param model The model to create the detector from.
|
||||||
* @param inputSize The required image dimensions for the model. Images will be {@link
|
* @param source The backend to run the detector on.
|
||||||
* Letterbox}ed to this shape.
|
|
||||||
*/
|
*/
|
||||||
public RubikObjectDetector(RubikModel model, Size inputSize) {
|
public TFLiteObjectDetector(TFLiteModel model, TFLiteSource backend) {
|
||||||
this.model = model;
|
this.model = model;
|
||||||
this.inputSize = inputSize;
|
this.inputSize =
|
||||||
|
new Size(model.properties.resolutionWidth(), model.properties.resolutionHeight());
|
||||||
|
|
||||||
// Create the detector
|
// Create the detector
|
||||||
try {
|
try {
|
||||||
@@ -72,7 +72,7 @@ public class RubikObjectDetector implements ObjectDetector {
|
|||||||
TFLiteJNI.create(
|
TFLiteJNI.create(
|
||||||
model.modelFile.getPath().toString(),
|
model.modelFile.getPath().toString(),
|
||||||
model.properties.version().ordinal(),
|
model.properties.version().ordinal(),
|
||||||
TFLiteSource.RUBIK.value());
|
backend.value());
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
logger.error("Failed to create detector from path " + model.modelFile.getPath(), e);
|
logger.error("Failed to create detector from path " + model.modelFile.getPath(), e);
|
||||||
throw new RuntimeException(
|
throw new RuntimeException(
|
||||||
@@ -83,7 +83,7 @@ public class RubikObjectDetector implements ObjectDetector {
|
|||||||
logger.error(
|
logger.error(
|
||||||
"Failed to create detector from path "
|
"Failed to create detector from path "
|
||||||
+ model.modelFile.getPath()
|
+ model.modelFile.getPath()
|
||||||
+ ". Please ensure the model is valid and compatible with the Rubik backend.");
|
+ ". Please ensure the model is valid and compatible with the TFLite backend.");
|
||||||
throw new RuntimeException(
|
throw new RuntimeException(
|
||||||
"Failed to create detector from path " + model.modelFile.getPath());
|
"Failed to create detector from path " + model.modelFile.getPath());
|
||||||
} else if (!TFLiteJNI.isQuantized(ptr)) {
|
} else if (!TFLiteJNI.isQuantized(ptr)) {
|
||||||
@@ -107,7 +107,7 @@ public class RubikObjectDetector implements ObjectDetector {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Detects objects in the given input image using the rubikDetector.
|
* Detects objects in the given input image using the TFLite detector.
|
||||||
*
|
*
|
||||||
* @param in The input image to perform object detection on.
|
* @param in The input image to perform object detection on.
|
||||||
* @param nmsThresh The threshold value for non-maximum suppression.
|
* @param nmsThresh The threshold value for non-maximum suppression.
|
||||||
@@ -57,8 +57,7 @@ public class ObjectDetectionPipeline
|
|||||||
protected void setPipeParamsImpl() {
|
protected void setPipeParamsImpl() {
|
||||||
Optional<Model> selectedModel =
|
Optional<Model> selectedModel =
|
||||||
settings.model != null
|
settings.model != null
|
||||||
? NeuralNetworkModelManager.getInstance()
|
? NeuralNetworkModelManager.getInstance().getModel(settings.model.modelPath())
|
||||||
.getModel(settings.model.modelPath().toString())
|
|
||||||
: Optional.empty();
|
: Optional.empty();
|
||||||
|
|
||||||
// If the desired model couldn't be found, log an error and try to use the default model
|
// If the desired model couldn't be found, log an error and try to use the default model
|
||||||
|
|||||||
@@ -24,11 +24,11 @@ import org.opencv.objdetect.Objdetect;
|
|||||||
public class UICalibrationData {
|
public class UICalibrationData {
|
||||||
public int videoModeIndex;
|
public int videoModeIndex;
|
||||||
public int count;
|
public int count;
|
||||||
public double squareSizeIn;
|
public double squareSizeMeters;
|
||||||
public int patternWidth;
|
public int patternWidth;
|
||||||
public int patternHeight;
|
public int patternHeight;
|
||||||
public BoardType boardType;
|
public BoardType boardType;
|
||||||
public double markerSizeIn;
|
public double markerSizeMeters;
|
||||||
public boolean useOldPattern;
|
public boolean useOldPattern;
|
||||||
public TagFamily tagFamily;
|
public TagFamily tagFamily;
|
||||||
|
|
||||||
@@ -37,8 +37,8 @@ public class UICalibrationData {
|
|||||||
public UICalibrationData(
|
public UICalibrationData(
|
||||||
int count,
|
int count,
|
||||||
int videoModeIndex,
|
int videoModeIndex,
|
||||||
double squareSizeIn,
|
double squareSizeMeters,
|
||||||
double markerSizeIn,
|
double markerSizeMeters,
|
||||||
int patternWidth,
|
int patternWidth,
|
||||||
int patternHeight,
|
int patternHeight,
|
||||||
BoardType boardType,
|
BoardType boardType,
|
||||||
@@ -46,8 +46,8 @@ public class UICalibrationData {
|
|||||||
TagFamily tagFamily) {
|
TagFamily tagFamily) {
|
||||||
this.count = count;
|
this.count = count;
|
||||||
this.videoModeIndex = videoModeIndex;
|
this.videoModeIndex = videoModeIndex;
|
||||||
this.squareSizeIn = squareSizeIn;
|
this.squareSizeMeters = squareSizeMeters;
|
||||||
this.markerSizeIn = markerSizeIn;
|
this.markerSizeMeters = markerSizeMeters;
|
||||||
this.patternWidth = patternWidth;
|
this.patternWidth = patternWidth;
|
||||||
this.patternHeight = patternHeight;
|
this.patternHeight = patternHeight;
|
||||||
this.boardType = boardType;
|
this.boardType = boardType;
|
||||||
@@ -98,10 +98,10 @@ public class UICalibrationData {
|
|||||||
+ videoModeIndex
|
+ videoModeIndex
|
||||||
+ ", count="
|
+ ", count="
|
||||||
+ count
|
+ count
|
||||||
+ ", squareSizeIn="
|
+ ", squareSizeMeters="
|
||||||
+ squareSizeIn
|
+ squareSizeMeters
|
||||||
+ ", markerSizeIn="
|
+ ", markerSizeMeters="
|
||||||
+ markerSizeIn
|
+ markerSizeMeters
|
||||||
+ ", patternWidth="
|
+ ", patternWidth="
|
||||||
+ patternWidth
|
+ patternWidth
|
||||||
+ ", patternHeight="
|
+ ", patternHeight="
|
||||||
|
|||||||
@@ -55,7 +55,6 @@ import org.photonvision.vision.pipeline.UICalibrationData;
|
|||||||
import org.photonvision.vision.pipeline.result.CVPipelineResult;
|
import org.photonvision.vision.pipeline.result.CVPipelineResult;
|
||||||
import org.photonvision.vision.target.TargetModel;
|
import org.photonvision.vision.target.TargetModel;
|
||||||
import org.photonvision.vision.target.TrackedTarget;
|
import org.photonvision.vision.target.TrackedTarget;
|
||||||
import org.wpilib.math.util.Units;
|
|
||||||
import org.wpilib.vision.camera.CameraServerJNI;
|
import org.wpilib.vision.camera.CameraServerJNI;
|
||||||
import org.wpilib.vision.camera.VideoException;
|
import org.wpilib.vision.camera.VideoException;
|
||||||
|
|
||||||
@@ -391,8 +390,8 @@ public class VisionModule {
|
|||||||
+ data.videoModeIndex
|
+ data.videoModeIndex
|
||||||
+ " and settings "
|
+ " and settings "
|
||||||
+ data);
|
+ data);
|
||||||
settings.gridSize = Units.inchesToMeters(data.squareSizeIn);
|
settings.gridSize = data.squareSizeMeters;
|
||||||
settings.markerSize = Units.inchesToMeters(data.markerSizeIn);
|
settings.markerSize = data.markerSizeMeters;
|
||||||
settings.boardHeight = data.patternHeight;
|
settings.boardHeight = data.patternHeight;
|
||||||
settings.boardWidth = data.patternWidth;
|
settings.boardWidth = data.patternWidth;
|
||||||
settings.boardType = data.boardType;
|
settings.boardType = data.boardType;
|
||||||
|
|||||||
@@ -69,97 +69,28 @@ public enum TargetModel implements Releasable {
|
|||||||
new Point3(Units.inchesToMeters(-19.625), Units.inchesToMeters(-8.5), 0),
|
new Point3(Units.inchesToMeters(-19.625), Units.inchesToMeters(-8.5), 0),
|
||||||
new Point3(Units.inchesToMeters(19.625), Units.inchesToMeters(-8.5), 0)),
|
new Point3(Units.inchesToMeters(19.625), Units.inchesToMeters(-8.5), 0)),
|
||||||
Units.inchesToMeters(12)),
|
Units.inchesToMeters(12)),
|
||||||
kCircularPowerCell7in(
|
kCircularPowerCell7in(circleTargetCorners(Units.inchesToMeters(7)), 0),
|
||||||
List.of(
|
k2022CircularCargoBall(circleTargetCorners(Units.inchesToMeters(9.5)), 0),
|
||||||
new Point3(
|
k2025Algae(circleTargetCorners(Units.inchesToMeters(16.25)), 0),
|
||||||
-Units.inchesToMeters(7) / 2,
|
|
||||||
-Units.inchesToMeters(7) / 2,
|
|
||||||
-Units.inchesToMeters(7) / 2),
|
|
||||||
new Point3(
|
|
||||||
-Units.inchesToMeters(7) / 2,
|
|
||||||
Units.inchesToMeters(7) / 2,
|
|
||||||
-Units.inchesToMeters(7) / 2),
|
|
||||||
new Point3(
|
|
||||||
Units.inchesToMeters(7) / 2,
|
|
||||||
Units.inchesToMeters(7) / 2,
|
|
||||||
-Units.inchesToMeters(7) / 2),
|
|
||||||
new Point3(
|
|
||||||
Units.inchesToMeters(7) / 2,
|
|
||||||
-Units.inchesToMeters(7) / 2,
|
|
||||||
-Units.inchesToMeters(7) / 2)),
|
|
||||||
0),
|
|
||||||
k2022CircularCargoBall(
|
|
||||||
List.of(
|
|
||||||
new Point3(
|
|
||||||
-Units.inchesToMeters(9.5) / 2,
|
|
||||||
-Units.inchesToMeters(9.5) / 2,
|
|
||||||
-Units.inchesToMeters(9.5) / 2),
|
|
||||||
new Point3(
|
|
||||||
-Units.inchesToMeters(9.5) / 2,
|
|
||||||
Units.inchesToMeters(9.5) / 2,
|
|
||||||
-Units.inchesToMeters(9.5) / 2),
|
|
||||||
new Point3(
|
|
||||||
Units.inchesToMeters(9.5) / 2,
|
|
||||||
Units.inchesToMeters(9.5) / 2,
|
|
||||||
-Units.inchesToMeters(9.5) / 2),
|
|
||||||
new Point3(
|
|
||||||
Units.inchesToMeters(9.5) / 2,
|
|
||||||
-Units.inchesToMeters(9.5) / 2,
|
|
||||||
-Units.inchesToMeters(9.5) / 2)),
|
|
||||||
0),
|
|
||||||
k2025Algae(
|
|
||||||
List.of(
|
|
||||||
new Point3(
|
|
||||||
-Units.inchesToMeters(16.25) / 2,
|
|
||||||
-Units.inchesToMeters(16.25) / 2,
|
|
||||||
-Units.inchesToMeters(16.25) / 2),
|
|
||||||
new Point3(
|
|
||||||
-Units.inchesToMeters(16.25) / 2,
|
|
||||||
Units.inchesToMeters(16.25) / 2,
|
|
||||||
-Units.inchesToMeters(16.25) / 2),
|
|
||||||
new Point3(
|
|
||||||
Units.inchesToMeters(16.25) / 2,
|
|
||||||
Units.inchesToMeters(16.25) / 2,
|
|
||||||
-Units.inchesToMeters(16.25) / 2),
|
|
||||||
new Point3(
|
|
||||||
Units.inchesToMeters(16.25) / 2,
|
|
||||||
-Units.inchesToMeters(16.25) / 2,
|
|
||||||
-Units.inchesToMeters(16.25) / 2)),
|
|
||||||
0),
|
|
||||||
// 2023 AprilTag, with 6 inch marker width (inner black square).
|
// 2023 AprilTag, with 6 inch marker width (inner black square).
|
||||||
// MIGRATION: 2023
|
// MIGRATION: 2023
|
||||||
@Json.Alias({"k6in_16h5"})
|
@Json.Alias({"k6in_16h5"})
|
||||||
kAprilTag6in_16h5(
|
kAprilTag6in_16h5(
|
||||||
// Corners of the tag's inner black square (excluding white border)
|
// Corners of the tag's inner black square (excluding white border)
|
||||||
List.of(
|
squareTargetCorners(Units.inchesToMeters(6)), Units.inchesToMeters(6)),
|
||||||
new Point3(Units.inchesToMeters(3), Units.inchesToMeters(3), 0),
|
|
||||||
new Point3(-Units.inchesToMeters(3), Units.inchesToMeters(3), 0),
|
|
||||||
new Point3(-Units.inchesToMeters(3), -Units.inchesToMeters(3), 0),
|
|
||||||
new Point3(Units.inchesToMeters(3), -Units.inchesToMeters(3), 0)),
|
|
||||||
Units.inchesToMeters(3 * 2)),
|
|
||||||
// 2024 AprilTag, with 6.5 inch marker width (inner black square).
|
// 2024 AprilTag, with 6.5 inch marker width (inner black square).
|
||||||
// MIGRATION: 2023
|
// MIGRATION: 2023
|
||||||
@Json.Alias({"k6p5in_36h11", "k200mmAprilTag", "kAruco6p5in_36h11"})
|
@Json.Alias({"k6p5in_36h11", "k200mmAprilTag", "kAruco6p5in_36h11"})
|
||||||
kAprilTag6p5in_36h11(
|
kAprilTag6p5in_36h11(
|
||||||
// Corners of the tag's inner black square (excluding white border)
|
// Corners of the tag's inner black square (excluding white border)
|
||||||
List.of(
|
squareTargetCorners(Units.inchesToMeters(6.5)), Units.inchesToMeters(6.5));
|
||||||
new Point3(-Units.inchesToMeters(6.5 / 2.0), Units.inchesToMeters(6.5 / 2.0), 0),
|
|
||||||
new Point3(Units.inchesToMeters(6.5 / 2.0), Units.inchesToMeters(6.5 / 2.0), 0),
|
|
||||||
new Point3(Units.inchesToMeters(6.5 / 2.0), -Units.inchesToMeters(6.5 / 2.0), 0),
|
|
||||||
new Point3(-Units.inchesToMeters(6.5 / 2.0), -Units.inchesToMeters(6.5 / 2.0), 0)),
|
|
||||||
Units.inchesToMeters(6.5));
|
|
||||||
|
|
||||||
@Json.Ignore private final MatOfPoint3f realWorldTargetCoordinates;
|
@Json.Ignore private final MatOfPoint3f realWorldTargetCoordinates;
|
||||||
@Json.Ignore private final MatOfPoint3f visualizationBoxBottom = new MatOfPoint3f();
|
@Json.Ignore private final MatOfPoint3f visualizationBoxBottom = new MatOfPoint3f();
|
||||||
@Json.Ignore private final MatOfPoint3f visualizationBoxTop = new MatOfPoint3f();
|
@Json.Ignore private final MatOfPoint3f visualizationBoxTop = new MatOfPoint3f();
|
||||||
|
|
||||||
private List<Point3> realWorldCoordinatesArray;
|
|
||||||
private double boxHeight;
|
|
||||||
|
|
||||||
TargetModel(MatOfPoint3f realWorldTargetCoordinates, double boxHeight) {
|
TargetModel(MatOfPoint3f realWorldTargetCoordinates, double boxHeight) {
|
||||||
this.realWorldTargetCoordinates = realWorldTargetCoordinates;
|
this.realWorldTargetCoordinates = realWorldTargetCoordinates;
|
||||||
this.realWorldCoordinatesArray = realWorldTargetCoordinates.toList();
|
|
||||||
this.boxHeight = boxHeight;
|
|
||||||
|
|
||||||
var bottomList = realWorldTargetCoordinates.toList();
|
var bottomList = realWorldTargetCoordinates.toList();
|
||||||
var topList = new ArrayList<Point3>();
|
var topList = new ArrayList<Point3>();
|
||||||
@@ -175,22 +106,6 @@ public enum TargetModel implements Releasable {
|
|||||||
this(listToMat(realWorldCoordinatesArray), boxHeight);
|
this(listToMat(realWorldCoordinatesArray), boxHeight);
|
||||||
}
|
}
|
||||||
|
|
||||||
public List<Point3> getRealWorldCoordinatesArray() {
|
|
||||||
return this.realWorldCoordinatesArray;
|
|
||||||
}
|
|
||||||
|
|
||||||
public double getBoxHeight() {
|
|
||||||
return boxHeight;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setRealWorldCoordinatesArray(List<Point3> realWorldCoordinatesArray) {
|
|
||||||
this.realWorldCoordinatesArray = realWorldCoordinatesArray;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setBoxHeight(double boxHeight) {
|
|
||||||
this.boxHeight = boxHeight;
|
|
||||||
}
|
|
||||||
|
|
||||||
private static MatOfPoint3f listToMat(List<Point3> points) {
|
private static MatOfPoint3f listToMat(List<Point3> points) {
|
||||||
var mat = new MatOfPoint3f();
|
var mat = new MatOfPoint3f();
|
||||||
mat.fromList(points);
|
mat.fromList(points);
|
||||||
@@ -209,15 +124,23 @@ public enum TargetModel implements Releasable {
|
|||||||
return visualizationBoxTop;
|
return visualizationBoxTop;
|
||||||
}
|
}
|
||||||
|
|
||||||
// public static TargetModel getCircleTarget(double Units.inchesToMeters(7)) {
|
private static List<Point3> circleTargetCorners(double diameter) {
|
||||||
// var corners =
|
double radius = diameter / 2;
|
||||||
// List.of(
|
return List.of(
|
||||||
// new Point3(-Units.inchesToMeters(7) / 2, -radius / 2, -radius / 2),
|
new Point3(-radius, -radius, -radius),
|
||||||
// new Point3(-Units.inchesToMeters(7) / 2, radius / 2, -radius / 2),
|
new Point3(-radius, radius, -radius),
|
||||||
// new Point3(Units.inchesToMeters(7) / 2, radius / 2, -radius / 2),
|
new Point3(radius, radius, -radius),
|
||||||
// new Point3(Units.inchesToMeters(7) / 2, -radius / 2, -radius / 2));
|
new Point3(radius, -radius, -radius));
|
||||||
// return new TargetModel(corners, 0);
|
}
|
||||||
// }
|
|
||||||
|
private static List<Point3> squareTargetCorners(double edgeLength) {
|
||||||
|
double radius = edgeLength / 2;
|
||||||
|
return List.of(
|
||||||
|
new Point3(-radius, -radius, 0),
|
||||||
|
new Point3(-radius, radius, 0),
|
||||||
|
new Point3(radius, radius, 0),
|
||||||
|
new Point3(radius, -radius, 0));
|
||||||
|
}
|
||||||
|
|
||||||
@Json.Value
|
@Json.Value
|
||||||
@Override
|
@Override
|
||||||
|
|||||||
@@ -62,7 +62,7 @@ public class TargetCalculationsTest {
|
|||||||
null);
|
null);
|
||||||
|
|
||||||
@BeforeAll
|
@BeforeAll
|
||||||
public static void setup() {
|
public static void init() {
|
||||||
LoadJNI.loadLibraries();
|
LoadJNI.loadLibraries();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,79 @@
|
|||||||
|
/*
|
||||||
|
* 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.vision.target;
|
||||||
|
|
||||||
|
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
import org.junit.jupiter.api.BeforeAll;
|
||||||
|
import org.junit.jupiter.api.Test;
|
||||||
|
import org.opencv.core.Point3;
|
||||||
|
import org.photonvision.common.LoadJNI;
|
||||||
|
import org.wpilib.math.util.Units;
|
||||||
|
|
||||||
|
public class TargetModelTest {
|
||||||
|
@BeforeAll
|
||||||
|
public static void init() {
|
||||||
|
LoadJNI.loadLibraries();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void testCircleTargetGeneration() {
|
||||||
|
assertApproxEquals(
|
||||||
|
List.of(
|
||||||
|
new Point3(
|
||||||
|
-Units.inchesToMeters(7) / 2,
|
||||||
|
-Units.inchesToMeters(7) / 2,
|
||||||
|
-Units.inchesToMeters(7) / 2),
|
||||||
|
new Point3(
|
||||||
|
-Units.inchesToMeters(7) / 2,
|
||||||
|
Units.inchesToMeters(7) / 2,
|
||||||
|
-Units.inchesToMeters(7) / 2),
|
||||||
|
new Point3(
|
||||||
|
Units.inchesToMeters(7) / 2,
|
||||||
|
Units.inchesToMeters(7) / 2,
|
||||||
|
-Units.inchesToMeters(7) / 2),
|
||||||
|
new Point3(
|
||||||
|
Units.inchesToMeters(7) / 2,
|
||||||
|
-Units.inchesToMeters(7) / 2,
|
||||||
|
-Units.inchesToMeters(7) / 2)),
|
||||||
|
TargetModel.kCircularPowerCell7in.getRealWorldTargetCoordinates().toList(),
|
||||||
|
1E-6);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void testSquareTargetGeneration() {
|
||||||
|
assertApproxEquals(
|
||||||
|
List.of(
|
||||||
|
new Point3(-Units.inchesToMeters(6.5 / 2.0), -Units.inchesToMeters(6.5 / 2.0), 0),
|
||||||
|
new Point3(-Units.inchesToMeters(6.5 / 2.0), Units.inchesToMeters(6.5 / 2.0), 0),
|
||||||
|
new Point3(Units.inchesToMeters(6.5 / 2.0), Units.inchesToMeters(6.5 / 2.0), 0),
|
||||||
|
new Point3(Units.inchesToMeters(6.5 / 2.0), -Units.inchesToMeters(6.5 / 2.0), 0)),
|
||||||
|
TargetModel.kAprilTag6p5in_36h11.getRealWorldTargetCoordinates().toList(),
|
||||||
|
1E-6);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void assertApproxEquals(List<Point3> expected, List<Point3> actual, double delta) {
|
||||||
|
assertEquals(expected.size(), actual.size());
|
||||||
|
for (int i = 0; i < actual.size(); i++) {
|
||||||
|
assertEquals(expected.get(i).x, actual.get(i).x, delta, "Bad x for point %d".formatted(i));
|
||||||
|
assertEquals(expected.get(i).y, actual.get(i).y, delta, "Bad y for point %d".formatted(i));
|
||||||
|
assertEquals(expected.get(i).z, actual.get(i).z, delta, "Bad z for point %d".formatted(i));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -20,7 +20,7 @@ package org.photonvision.vision.target;
|
|||||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import org.junit.jupiter.api.BeforeEach;
|
import org.junit.jupiter.api.BeforeAll;
|
||||||
import org.junit.jupiter.api.Test;
|
import org.junit.jupiter.api.Test;
|
||||||
import org.opencv.core.MatOfPoint;
|
import org.opencv.core.MatOfPoint;
|
||||||
import org.opencv.core.Point;
|
import org.opencv.core.Point;
|
||||||
@@ -30,8 +30,8 @@ import org.photonvision.vision.opencv.Contour;
|
|||||||
import org.photonvision.vision.opencv.DualOffsetValues;
|
import org.photonvision.vision.opencv.DualOffsetValues;
|
||||||
|
|
||||||
public class TrackedTargetTest {
|
public class TrackedTargetTest {
|
||||||
@BeforeEach
|
@BeforeAll
|
||||||
public void Init() {
|
public static void init() {
|
||||||
LoadJNI.loadLibraries();
|
LoadJNI.loadLibraries();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -17,6 +17,10 @@ dependencies {
|
|||||||
|
|
||||||
// Needed for Javalin Runtime Logging
|
// Needed for Javalin Runtime Logging
|
||||||
implementation "org.slf4j:slf4j-simple:2.0.7"
|
implementation "org.slf4j:slf4j-simple:2.0.7"
|
||||||
|
|
||||||
|
implementation("org.photonvision:tflite_jni-java:$tfliteVersion") {
|
||||||
|
transitive = false
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
group = 'org.photonvision'
|
group = 'org.photonvision'
|
||||||
|
|||||||
@@ -55,12 +55,13 @@ import org.photonvision.common.networking.NetworkManager;
|
|||||||
import org.photonvision.common.util.ShellExec;
|
import org.photonvision.common.util.ShellExec;
|
||||||
import org.photonvision.common.util.TimedTaskManager;
|
import org.photonvision.common.util.TimedTaskManager;
|
||||||
import org.photonvision.common.util.file.ProgramDirectoryUtilities;
|
import org.photonvision.common.util.file.ProgramDirectoryUtilities;
|
||||||
|
import org.photonvision.tflite.TFLiteJNI.TFLiteSource;
|
||||||
import org.photonvision.vision.calibration.CameraCalibrationCoefficients;
|
import org.photonvision.vision.calibration.CameraCalibrationCoefficients;
|
||||||
import org.photonvision.vision.camera.CameraQuirk;
|
import org.photonvision.vision.camera.CameraQuirk;
|
||||||
import org.photonvision.vision.camera.PVCameraInfo;
|
import org.photonvision.vision.camera.PVCameraInfo;
|
||||||
import org.photonvision.vision.objects.ObjectDetector;
|
import org.photonvision.vision.objects.ObjectDetector;
|
||||||
import org.photonvision.vision.objects.RknnModel;
|
import org.photonvision.vision.objects.RknnModel;
|
||||||
import org.photonvision.vision.objects.RubikModel;
|
import org.photonvision.vision.objects.TFLiteModel;
|
||||||
import org.photonvision.vision.processes.VisionSourceManager;
|
import org.photonvision.vision.processes.VisionSourceManager;
|
||||||
import org.zeroturnaround.zip.ZipUtil;
|
import org.zeroturnaround.zip.ZipUtil;
|
||||||
|
|
||||||
@@ -679,7 +680,7 @@ public class RequestHandler {
|
|||||||
try {
|
try {
|
||||||
objDetector =
|
objDetector =
|
||||||
switch (family) {
|
switch (family) {
|
||||||
case RUBIK -> new RubikModel(modelProperties).load();
|
case RUBIK -> new TFLiteModel(modelProperties, TFLiteSource.RUBIK).load();
|
||||||
case RKNN -> new RknnModel(modelProperties).load();
|
case RKNN -> new RknnModel(modelProperties).load();
|
||||||
};
|
};
|
||||||
} catch (RuntimeException e) {
|
} catch (RuntimeException e) {
|
||||||
|
|||||||
@@ -17,8 +17,10 @@
|
|||||||
|
|
||||||
package org.photonvision.server;
|
package org.photonvision.server;
|
||||||
|
|
||||||
|
import io.avaje.jsonb.javalin.JavalinJsonb;
|
||||||
import io.javalin.Javalin;
|
import io.javalin.Javalin;
|
||||||
import io.javalin.plugin.bundled.CorsPlugin;
|
import io.javalin.plugin.bundled.CorsPlugin;
|
||||||
|
import io.javalin.plugin.bundled.CorsPluginConfig.CorsRule;
|
||||||
import java.net.InetSocketAddress;
|
import java.net.InetSocketAddress;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.StringJoiner;
|
import java.util.StringJoiner;
|
||||||
@@ -60,14 +62,7 @@ public class Server {
|
|||||||
javalinConfig -> {
|
javalinConfig -> {
|
||||||
javalinConfig.showJavalinBanner = false;
|
javalinConfig.showJavalinBanner = false;
|
||||||
javalinConfig.staticFiles.add("web");
|
javalinConfig.staticFiles.add("web");
|
||||||
javalinConfig.registerPlugin(
|
javalinConfig.registerPlugin(new CorsPlugin(cors -> cors.addRule(CorsRule::anyHost)));
|
||||||
new CorsPlugin(
|
|
||||||
cors -> {
|
|
||||||
cors.addRule(
|
|
||||||
it -> {
|
|
||||||
it.anyHost();
|
|
||||||
});
|
|
||||||
}));
|
|
||||||
javalinConfig.requestLogger.http(
|
javalinConfig.requestLogger.http(
|
||||||
(ctx, ms) -> {
|
(ctx, ms) -> {
|
||||||
StringJoiner joiner =
|
StringJoiner joiner =
|
||||||
@@ -103,6 +98,7 @@ public class Server {
|
|||||||
return "Got WebSockets binary message from host: " + host;
|
return "Got WebSockets binary message from host: " + host;
|
||||||
}));
|
}));
|
||||||
});
|
});
|
||||||
|
javalinConfig.jsonMapper(new JavalinJsonb());
|
||||||
});
|
});
|
||||||
|
|
||||||
/* Web Socket Events for Data Exchange */
|
/* Web Socket Events for Data Exchange */
|
||||||
|
|||||||
@@ -37,6 +37,7 @@ dependencies {
|
|||||||
implementation group: "io.avaje", name: "avaje-jsonb", version: avajeJsonbVersion
|
implementation group: "io.avaje", name: "avaje-jsonb", version: avajeJsonbVersion
|
||||||
annotationProcessor group: "io.avaje", name: "avaje-jsonb-generator", version: avajeJsonbVersion
|
annotationProcessor group: "io.avaje", name: "avaje-jsonb-generator", version: avajeJsonbVersion
|
||||||
implementation group: "io.avaje", name: "avaje-jsonb-jackson", version: avajeJsonbVersion
|
implementation group: "io.avaje", name: "avaje-jsonb-jackson", version: avajeJsonbVersion
|
||||||
|
implementation group: "io.avaje", name: "avaje-jsonb-javalin-mapper", version: avajeJsonbVersion
|
||||||
|
|
||||||
implementation group: "org.ejml", name: "ejml-simple", version: ejmlVersion
|
implementation group: "org.ejml", name: "ejml-simple", version: ejmlVersion
|
||||||
implementation group: "us.hebi.quickbuf", name: "quickbuf-runtime", version: quickbufVersion;
|
implementation group: "us.hebi.quickbuf", name: "quickbuf-runtime", version: quickbufVersion;
|
||||||
|
|||||||
Reference in New Issue
Block a user