trainingsample 0.3.1__tar.gz → 0.3.2__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {trainingsample-0.3.1 → trainingsample-0.3.2}/.github/workflows/ci.yml +2 -3
- {trainingsample-0.3.1 → trainingsample-0.3.2}/.github/workflows/publish.yml +30 -8
- {trainingsample-0.3.1 → trainingsample-0.3.2}/Cargo.lock +45 -46
- {trainingsample-0.3.1 → trainingsample-0.3.2}/Cargo.toml +4 -4
- {trainingsample-0.3.1 → trainingsample-0.3.2}/PKG-INFO +3 -2
- {trainingsample-0.3.1 → trainingsample-0.3.2}/pyproject.toml +5 -4
- {trainingsample-0.3.1 → trainingsample-0.3.2}/src/python_bindings.rs +33 -33
- trainingsample-0.3.2/tests/coverage_tests.rs +427 -0
- {trainingsample-0.3.1 → trainingsample-0.3.2}/.cargo/config.toml +0 -0
- {trainingsample-0.3.1 → trainingsample-0.3.2}/.envrc +0 -0
- {trainingsample-0.3.1 → trainingsample-0.3.2}/.gitignore +0 -0
- {trainingsample-0.3.1 → trainingsample-0.3.2}/.pre-commit-config.yaml +0 -0
- {trainingsample-0.3.1 → trainingsample-0.3.2}/.rustfmt.toml +0 -0
- {trainingsample-0.3.1 → trainingsample-0.3.2}/BENCHMARKS.md +0 -0
- {trainingsample-0.3.1 → trainingsample-0.3.2}/Dockerfile +0 -0
- {trainingsample-0.3.1 → trainingsample-0.3.2}/LICENSE +0 -0
- {trainingsample-0.3.1 → trainingsample-0.3.2}/README.md +0 -0
- {trainingsample-0.3.1 → trainingsample-0.3.2}/clippy.toml +0 -0
- {trainingsample-0.3.1 → trainingsample-0.3.2}/docs/API_COMPAT_CV2.md +0 -0
- {trainingsample-0.3.1 → trainingsample-0.3.2}/docs/BUILDING_STATIC_OPENCV.md +0 -0
- {trainingsample-0.3.1 → trainingsample-0.3.2}/rust-toolchain.toml +0 -0
- {trainingsample-0.3.1 → trainingsample-0.3.2}/scripts/build-opencv-static.sh +0 -0
- {trainingsample-0.3.1 → trainingsample-0.3.2}/scripts/repair-wheel.sh +0 -0
- {trainingsample-0.3.1 → trainingsample-0.3.2}/scripts/run_competitive_benchmarks.sh +0 -0
- {trainingsample-0.3.1 → trainingsample-0.3.2}/setup-env.sh +0 -0
- {trainingsample-0.3.1 → trainingsample-0.3.2}/src/core.rs +0 -0
- {trainingsample-0.3.1 → trainingsample-0.3.2}/src/cropping.rs +0 -0
- {trainingsample-0.3.1 → trainingsample-0.3.2}/src/cv_batch_ops.rs +0 -0
- {trainingsample-0.3.1 → trainingsample-0.3.2}/src/cv_batch_ops_optimized.rs +0 -0
- {trainingsample-0.3.1 → trainingsample-0.3.2}/src/cv_compat.rs +0 -0
- {trainingsample-0.3.1 → trainingsample-0.3.2}/src/format_conversion_simd.rs +0 -0
- {trainingsample-0.3.1 → trainingsample-0.3.2}/src/lib.rs +0 -0
- {trainingsample-0.3.1 → trainingsample-0.3.2}/src/loading.rs +0 -0
- {trainingsample-0.3.1 → trainingsample-0.3.2}/src/luminance.rs +0 -0
- {trainingsample-0.3.1 → trainingsample-0.3.2}/src/luminance_simd.rs +0 -0
- {trainingsample-0.3.1 → trainingsample-0.3.2}/src/opencv_ops.rs +0 -0
- {trainingsample-0.3.1 → trainingsample-0.3.2}/src/tests.rs +0 -0
- {trainingsample-0.3.1 → trainingsample-0.3.2}/src/true_batch_ops.rs +0 -0
- {trainingsample-0.3.1 → trainingsample-0.3.2}/tests/__init__.py +0 -0
- {trainingsample-0.3.1 → trainingsample-0.3.2}/tests/comprehensive_tests.rs +0 -0
- {trainingsample-0.3.1 → trainingsample-0.3.2}/tests/test_comprehensive.py +0 -0
- {trainingsample-0.3.1 → trainingsample-0.3.2}/tests/test_performance_benchmarks.py +0 -0
- {trainingsample-0.3.1 → trainingsample-0.3.2}/tests/test_python_bindings.py +0 -0
|
@@ -108,7 +108,7 @@ jobs:
|
|
|
108
108
|
runs-on: ubuntu-latest
|
|
109
109
|
strategy:
|
|
110
110
|
matrix:
|
|
111
|
-
python-version: ["3.11", "3.12", "3.13"]
|
|
111
|
+
python-version: ["3.11", "3.12", "3.13", "3.14"]
|
|
112
112
|
|
|
113
113
|
steps:
|
|
114
114
|
- uses: actions/checkout@v4
|
|
@@ -387,7 +387,7 @@ jobs:
|
|
|
387
387
|
runs-on: ubuntu-24.04-arm
|
|
388
388
|
strategy:
|
|
389
389
|
matrix:
|
|
390
|
-
python: ["3.11", "3.12", "3.13"]
|
|
390
|
+
python: ["3.11", "3.12", "3.13", "3.14"]
|
|
391
391
|
|
|
392
392
|
steps:
|
|
393
393
|
- uses: actions/checkout@v4
|
|
@@ -434,7 +434,6 @@ jobs:
|
|
|
434
434
|
container: off
|
|
435
435
|
manylinux: manylinux_2_39
|
|
436
436
|
env:
|
|
437
|
-
PYO3_USE_ABI3_FORWARD_COMPATIBILITY: '1'
|
|
438
437
|
LIBCLANG_PATH: ${{ env.LIBCLANG_PATH }}
|
|
439
438
|
LLVM_CONFIG_PATH: ${{ env.LLVM_CONFIG_PATH }}
|
|
440
439
|
OPENCV_INCLUDE_PATHS: ${{ github.workspace }}/third_party/opencv-static/include/opencv4
|
|
@@ -25,6 +25,10 @@ jobs:
|
|
|
25
25
|
target: x86_64
|
|
26
26
|
manylinux: manylinux_2_35
|
|
27
27
|
python: '3.13'
|
|
28
|
+
- os: ubuntu-22.04
|
|
29
|
+
target: x86_64
|
|
30
|
+
manylinux: manylinux_2_35
|
|
31
|
+
python: '3.14'
|
|
28
32
|
# Ubuntu 24.04 (libc 2.39)
|
|
29
33
|
- os: ubuntu-24.04
|
|
30
34
|
target: x86_64
|
|
@@ -38,6 +42,10 @@ jobs:
|
|
|
38
42
|
target: x86_64
|
|
39
43
|
manylinux: manylinux_2_39
|
|
40
44
|
python: '3.13'
|
|
45
|
+
- os: ubuntu-24.04
|
|
46
|
+
target: x86_64
|
|
47
|
+
manylinux: manylinux_2_39
|
|
48
|
+
python: '3.14'
|
|
41
49
|
steps:
|
|
42
50
|
- uses: actions/checkout@v4
|
|
43
51
|
- uses: actions/setup-python@v5
|
|
@@ -104,8 +112,6 @@ jobs:
|
|
|
104
112
|
container: off
|
|
105
113
|
manylinux: ${{ matrix.manylinux }}
|
|
106
114
|
env:
|
|
107
|
-
# Use stable ABI for forward compatibility
|
|
108
|
-
PYO3_USE_ABI3_FORWARD_COMPATIBILITY: '1'
|
|
109
115
|
# LLVM for opencv-rust bindings (from earlier install step)
|
|
110
116
|
LIBCLANG_PATH: ${{ env.LIBCLANG_PATH }}
|
|
111
117
|
LLVM_CONFIG_PATH: ${{ env.LLVM_CONFIG_PATH }}
|
|
@@ -135,7 +141,7 @@ jobs:
|
|
|
135
141
|
runs-on: ubuntu-24.04-arm
|
|
136
142
|
strategy:
|
|
137
143
|
matrix:
|
|
138
|
-
python: ['3.11', '3.12', '3.13']
|
|
144
|
+
python: ['3.11', '3.12', '3.13', '3.14']
|
|
139
145
|
steps:
|
|
140
146
|
- uses: actions/checkout@v4
|
|
141
147
|
- uses: actions/setup-python@v5
|
|
@@ -186,8 +192,6 @@ jobs:
|
|
|
186
192
|
container: off
|
|
187
193
|
manylinux: manylinux_2_39
|
|
188
194
|
env:
|
|
189
|
-
# Use stable ABI for forward compatibility
|
|
190
|
-
PYO3_USE_ABI3_FORWARD_COMPATIBILITY: '1'
|
|
191
195
|
# LLVM for opencv-rust bindings (from earlier install step)
|
|
192
196
|
LIBCLANG_PATH: ${{ env.LIBCLANG_PATH }}
|
|
193
197
|
LLVM_CONFIG_PATH: ${{ env.LLVM_CONFIG_PATH }}
|
|
@@ -217,7 +221,7 @@ jobs:
|
|
|
217
221
|
strategy:
|
|
218
222
|
matrix:
|
|
219
223
|
target: [aarch64]
|
|
220
|
-
python: ['3.11', '3.12', '3.13']
|
|
224
|
+
python: ['3.11', '3.12', '3.13', '3.14']
|
|
221
225
|
steps:
|
|
222
226
|
- uses: actions/checkout@v4
|
|
223
227
|
- uses: actions/setup-python@v5
|
|
@@ -251,8 +255,6 @@ jobs:
|
|
|
251
255
|
args: --release --out dist -i python --no-default-features --features python-bindings,simd,opencv,metal
|
|
252
256
|
sccache: 'false'
|
|
253
257
|
env:
|
|
254
|
-
# Use stable ABI for forward compatibility
|
|
255
|
-
PYO3_USE_ABI3_FORWARD_COMPATIBILITY: '1'
|
|
256
258
|
# OpenCV static linking configuration
|
|
257
259
|
OPENCV_INCLUDE_PATHS: ${{ github.workspace }}/third_party/opencv-static/include/opencv4
|
|
258
260
|
OPENCV_LINK_PATHS: ${{ github.workspace }}/third_party/opencv-static/lib
|
|
@@ -306,6 +308,11 @@ jobs:
|
|
|
306
308
|
manylinux: manylinux_2_35
|
|
307
309
|
python: '3.13'
|
|
308
310
|
artifact_name: wheels-ubuntu-22.04-x86_64-py3.13
|
|
311
|
+
- os: ubuntu-22.04
|
|
312
|
+
target: x86_64
|
|
313
|
+
manylinux: manylinux_2_35
|
|
314
|
+
python: '3.14'
|
|
315
|
+
artifact_name: wheels-ubuntu-22.04-x86_64-py3.14
|
|
309
316
|
# Ubuntu 24.04 (libc 2.39)
|
|
310
317
|
- os: ubuntu-24.04
|
|
311
318
|
target: x86_64
|
|
@@ -322,6 +329,11 @@ jobs:
|
|
|
322
329
|
manylinux: manylinux_2_39
|
|
323
330
|
python: '3.13'
|
|
324
331
|
artifact_name: wheels-ubuntu-24.04-x86_64-py3.13
|
|
332
|
+
- os: ubuntu-24.04
|
|
333
|
+
target: x86_64
|
|
334
|
+
manylinux: manylinux_2_39
|
|
335
|
+
python: '3.14'
|
|
336
|
+
artifact_name: wheels-ubuntu-24.04-x86_64-py3.14
|
|
325
337
|
# Linux aarch64 (DGX Spark / GB10)
|
|
326
338
|
- os: ubuntu-24.04-arm
|
|
327
339
|
target: aarch64
|
|
@@ -338,6 +350,11 @@ jobs:
|
|
|
338
350
|
manylinux: manylinux_2_39
|
|
339
351
|
python: '3.13'
|
|
340
352
|
artifact_name: wheels-linux-aarch64-py3.13
|
|
353
|
+
- os: ubuntu-24.04-arm
|
|
354
|
+
target: aarch64
|
|
355
|
+
manylinux: manylinux_2_39
|
|
356
|
+
python: '3.14'
|
|
357
|
+
artifact_name: wheels-linux-aarch64-py3.14
|
|
341
358
|
# macOS aarch64
|
|
342
359
|
- os: macos-latest
|
|
343
360
|
target: aarch64
|
|
@@ -354,6 +371,11 @@ jobs:
|
|
|
354
371
|
manylinux: ''
|
|
355
372
|
python: '3.13'
|
|
356
373
|
artifact_name: wheels-macos-latest-aarch64-py3.13
|
|
374
|
+
- os: macos-latest
|
|
375
|
+
target: aarch64
|
|
376
|
+
manylinux: ''
|
|
377
|
+
python: '3.14'
|
|
378
|
+
artifact_name: wheels-macos-latest-aarch64-py3.14
|
|
357
379
|
steps:
|
|
358
380
|
- uses: actions/download-artifact@v4
|
|
359
381
|
with:
|
|
@@ -224,9 +224,9 @@ checksum = "37b2a672a2cb129a2e41c10b1224bb368f9f37a2b16b612598138befd7b37eb5"
|
|
|
224
224
|
|
|
225
225
|
[[package]]
|
|
226
226
|
name = "cc"
|
|
227
|
-
version = "1.4.
|
|
227
|
+
version = "1.4.4"
|
|
228
228
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
229
|
-
checksum = "
|
|
229
|
+
checksum = "0ad534f4357a5264cce5019c989cf66a4f0dc4e0d1b1d15f8aacec0ff7360273"
|
|
230
230
|
dependencies = [
|
|
231
231
|
"find-msvc-tools",
|
|
232
232
|
"jobserver",
|
|
@@ -348,9 +348,9 @@ dependencies = [
|
|
|
348
348
|
|
|
349
349
|
[[package]]
|
|
350
350
|
name = "crc32fast"
|
|
351
|
-
version = "1.5.
|
|
351
|
+
version = "1.5.1"
|
|
352
352
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
353
|
-
checksum = "
|
|
353
|
+
checksum = "8498c871161e1742aaa9d52551b2d6ebdd4c3d45a3be423e3728f33b955be550"
|
|
354
354
|
dependencies = [
|
|
355
355
|
"cfg-if",
|
|
356
356
|
]
|
|
@@ -430,9 +430,9 @@ checksum = "92773504d58c093f6de2459af4af33faa518c13451eb8f2b5698ed3d36e7c813"
|
|
|
430
430
|
|
|
431
431
|
[[package]]
|
|
432
432
|
name = "either"
|
|
433
|
-
version = "1.
|
|
433
|
+
version = "1.18.0"
|
|
434
434
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
435
|
-
checksum = "
|
|
435
|
+
checksum = "252afb9ae5eaa683babdc6a068b3f5726eb19e05070c731f9b2a23a7c3e8ed34"
|
|
436
436
|
|
|
437
437
|
[[package]]
|
|
438
438
|
name = "equator"
|
|
@@ -504,9 +504,9 @@ dependencies = [
|
|
|
504
504
|
|
|
505
505
|
[[package]]
|
|
506
506
|
name = "find-msvc-tools"
|
|
507
|
-
version = "0.1.
|
|
507
|
+
version = "0.1.11"
|
|
508
508
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
509
|
-
checksum = "
|
|
509
|
+
checksum = "d45db016d36b838f563236e9193d0ee6ce38f3f68b6c94e914b4929c96bbb890"
|
|
510
510
|
|
|
511
511
|
[[package]]
|
|
512
512
|
name = "flate2"
|
|
@@ -536,7 +536,7 @@ checksum = "ea5190182e6915eb873ddbc16e23b711b6eb1f9c00a0d0a3a91b5f6228475225"
|
|
|
536
536
|
dependencies = [
|
|
537
537
|
"proc-macro2",
|
|
538
538
|
"quote",
|
|
539
|
-
"syn 3.0.
|
|
539
|
+
"syn 3.0.4",
|
|
540
540
|
]
|
|
541
541
|
|
|
542
542
|
[[package]]
|
|
@@ -547,21 +547,21 @@ checksum = "aa9a19cbb55df58761df49b23516a86d432839add4af60fc256da840f66ed35b"
|
|
|
547
547
|
|
|
548
548
|
[[package]]
|
|
549
549
|
name = "futures-core"
|
|
550
|
-
version = "0.3.
|
|
550
|
+
version = "0.3.34"
|
|
551
551
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
552
|
-
checksum = "
|
|
552
|
+
checksum = "92d699e522242e69e3003b94ecc1f960f3a5e015aa7c5d7486e65ad01dd94f5e"
|
|
553
553
|
|
|
554
554
|
[[package]]
|
|
555
555
|
name = "futures-task"
|
|
556
|
-
version = "0.3.
|
|
556
|
+
version = "0.3.34"
|
|
557
557
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
558
|
-
checksum = "
|
|
558
|
+
checksum = "cd417de3d1d015fc3bfd2b1ea46dfc7bab72ef86f1cc7cc9c78e728b34a6d1fd"
|
|
559
559
|
|
|
560
560
|
[[package]]
|
|
561
561
|
name = "futures-util"
|
|
562
|
-
version = "0.3.
|
|
562
|
+
version = "0.3.34"
|
|
563
563
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
564
|
-
checksum = "
|
|
564
|
+
checksum = "0d50a92467f8ba5dd6e3ee5d4bd04d73ab2e4e1c44474a0674821dfce14b79bc"
|
|
565
565
|
dependencies = [
|
|
566
566
|
"futures-core",
|
|
567
567
|
"futures-task",
|
|
@@ -833,9 +833,9 @@ checksum = "32a66949e030da00e8c7d4434b251670a91556f4144941d37452769c25d58a53"
|
|
|
833
833
|
|
|
834
834
|
[[package]]
|
|
835
835
|
name = "log"
|
|
836
|
-
version = "0.4.
|
|
836
|
+
version = "0.4.34"
|
|
837
837
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
838
|
-
checksum = "
|
|
838
|
+
checksum = "f9f8bd3e56ce4dfc153cf470fffbfa98c7620958b312ca5c3a4b8d5181fd13c6"
|
|
839
839
|
|
|
840
840
|
[[package]]
|
|
841
841
|
name = "loop9"
|
|
@@ -942,9 +942,9 @@ dependencies = [
|
|
|
942
942
|
|
|
943
943
|
[[package]]
|
|
944
944
|
name = "ndarray"
|
|
945
|
-
version = "0.
|
|
945
|
+
version = "0.17.2"
|
|
946
946
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
947
|
-
checksum = "
|
|
947
|
+
checksum = "520080814a7a6b4a6e9070823bb24b4531daac8c4627e08ba5de8c5ef2f2752d"
|
|
948
948
|
dependencies = [
|
|
949
949
|
"matrixmultiply",
|
|
950
950
|
"num-complex",
|
|
@@ -1032,9 +1032,9 @@ dependencies = [
|
|
|
1032
1032
|
|
|
1033
1033
|
[[package]]
|
|
1034
1034
|
name = "num-integer"
|
|
1035
|
-
version = "0.1.
|
|
1035
|
+
version = "0.1.47"
|
|
1036
1036
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
1037
|
-
checksum = "
|
|
1037
|
+
checksum = "7ce2d95d4b3734dc35aa2f45e1aa22cd416814592a4f9d9205e11affd5b8e10b"
|
|
1038
1038
|
dependencies = [
|
|
1039
1039
|
"num-traits",
|
|
1040
1040
|
]
|
|
@@ -1082,9 +1082,9 @@ dependencies = [
|
|
|
1082
1082
|
|
|
1083
1083
|
[[package]]
|
|
1084
1084
|
name = "numpy"
|
|
1085
|
-
version = "0.
|
|
1085
|
+
version = "0.27.1"
|
|
1086
1086
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
1087
|
-
checksum = "
|
|
1087
|
+
checksum = "7aac2e6a6e4468ffa092ad43c39b81c79196c2bb773b8db4085f695efe3bba17"
|
|
1088
1088
|
dependencies = [
|
|
1089
1089
|
"libc",
|
|
1090
1090
|
"ndarray",
|
|
@@ -1092,6 +1092,7 @@ dependencies = [
|
|
|
1092
1092
|
"num-integer",
|
|
1093
1093
|
"num-traits",
|
|
1094
1094
|
"pyo3",
|
|
1095
|
+
"pyo3-build-config",
|
|
1095
1096
|
"rustc-hash",
|
|
1096
1097
|
]
|
|
1097
1098
|
|
|
@@ -1196,9 +1197,9 @@ checksum = "a89322df9ebe1c1578d689c92318e070967d1042b512afbe49518723f4e6d5cd"
|
|
|
1196
1197
|
|
|
1197
1198
|
[[package]]
|
|
1198
1199
|
name = "pkg-config"
|
|
1199
|
-
version = "0.3.
|
|
1200
|
+
version = "0.3.34"
|
|
1200
1201
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
1201
|
-
checksum = "
|
|
1202
|
+
checksum = "f6b464fbc74e149a392436b17d523f769e057cb6877f6a5c4618bc6f11800548"
|
|
1202
1203
|
|
|
1203
1204
|
[[package]]
|
|
1204
1205
|
name = "plotters"
|
|
@@ -1324,11 +1325,10 @@ checksum = "d55d956fa96f5ec02be2e13af0e20391a5aa83d6a074e3ad368959d0fab299ea"
|
|
|
1324
1325
|
|
|
1325
1326
|
[[package]]
|
|
1326
1327
|
name = "pyo3"
|
|
1327
|
-
version = "0.
|
|
1328
|
+
version = "0.27.2"
|
|
1328
1329
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
1329
|
-
checksum = "
|
|
1330
|
+
checksum = "ab53c047fcd1a1d2a8820fe84f05d6be69e9526be40cb03b73f86b6b03e6d87d"
|
|
1330
1331
|
dependencies = [
|
|
1331
|
-
"cfg-if",
|
|
1332
1332
|
"indoc",
|
|
1333
1333
|
"libc",
|
|
1334
1334
|
"memoffset",
|
|
@@ -1342,19 +1342,18 @@ dependencies = [
|
|
|
1342
1342
|
|
|
1343
1343
|
[[package]]
|
|
1344
1344
|
name = "pyo3-build-config"
|
|
1345
|
-
version = "0.
|
|
1345
|
+
version = "0.27.2"
|
|
1346
1346
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
1347
|
-
checksum = "
|
|
1347
|
+
checksum = "b455933107de8642b4487ed26d912c2d899dec6114884214a0b3bb3be9261ea6"
|
|
1348
1348
|
dependencies = [
|
|
1349
|
-
"once_cell",
|
|
1350
1349
|
"target-lexicon",
|
|
1351
1350
|
]
|
|
1352
1351
|
|
|
1353
1352
|
[[package]]
|
|
1354
1353
|
name = "pyo3-ffi"
|
|
1355
|
-
version = "0.
|
|
1354
|
+
version = "0.27.2"
|
|
1356
1355
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
1357
|
-
checksum = "
|
|
1356
|
+
checksum = "1c85c9cbfaddf651b1221594209aed57e9e5cff63c4d11d1feead529b872a089"
|
|
1358
1357
|
dependencies = [
|
|
1359
1358
|
"libc",
|
|
1360
1359
|
"pyo3-build-config",
|
|
@@ -1362,9 +1361,9 @@ dependencies = [
|
|
|
1362
1361
|
|
|
1363
1362
|
[[package]]
|
|
1364
1363
|
name = "pyo3-macros"
|
|
1365
|
-
version = "0.
|
|
1364
|
+
version = "0.27.2"
|
|
1366
1365
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
1367
|
-
checksum = "
|
|
1366
|
+
checksum = "0a5b10c9bf9888125d917fb4d2ca2d25c8df94c7ab5a52e13313a07e050a3b02"
|
|
1368
1367
|
dependencies = [
|
|
1369
1368
|
"proc-macro2",
|
|
1370
1369
|
"pyo3-macros-backend",
|
|
@@ -1374,9 +1373,9 @@ dependencies = [
|
|
|
1374
1373
|
|
|
1375
1374
|
[[package]]
|
|
1376
1375
|
name = "pyo3-macros-backend"
|
|
1377
|
-
version = "0.
|
|
1376
|
+
version = "0.27.2"
|
|
1378
1377
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
1379
|
-
checksum = "
|
|
1378
|
+
checksum = "03b51720d314836e53327f5871d4c0cfb4fb37cc2c4a11cc71907a86342c40f9"
|
|
1380
1379
|
dependencies = [
|
|
1381
1380
|
"heck",
|
|
1382
1381
|
"proc-macro2",
|
|
@@ -1618,9 +1617,9 @@ checksum = "47b34b781b31e5d73e9fbc8689c70551fd1ade9a19e3e28cfec8580a79290cc4"
|
|
|
1618
1617
|
|
|
1619
1618
|
[[package]]
|
|
1620
1619
|
name = "rustc-hash"
|
|
1621
|
-
version = "
|
|
1620
|
+
version = "2.1.3"
|
|
1622
1621
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
1623
|
-
checksum = "
|
|
1622
|
+
checksum = "6b1e7f9a428571be2dc5bc0505c13fb6bf936822b894ec87abf8a08a4e51742d"
|
|
1624
1623
|
|
|
1625
1624
|
[[package]]
|
|
1626
1625
|
name = "rustix"
|
|
@@ -1692,7 +1691,7 @@ checksum = "e7a5d71263a5a7d47b41f6b3f06ba276f10cc18b0931f1799f710578e2309348"
|
|
|
1692
1691
|
dependencies = [
|
|
1693
1692
|
"proc-macro2",
|
|
1694
1693
|
"quote",
|
|
1695
|
-
"syn 3.0.
|
|
1694
|
+
"syn 3.0.4",
|
|
1696
1695
|
]
|
|
1697
1696
|
|
|
1698
1697
|
[[package]]
|
|
@@ -1773,9 +1772,9 @@ dependencies = [
|
|
|
1773
1772
|
|
|
1774
1773
|
[[package]]
|
|
1775
1774
|
name = "syn"
|
|
1776
|
-
version = "3.0.
|
|
1775
|
+
version = "3.0.4"
|
|
1777
1776
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
1778
|
-
checksum = "
|
|
1777
|
+
checksum = "e6275cddf4610d1775e6d1fe9469b2e77d0f39fd98fb7450901b821e0c53649f"
|
|
1779
1778
|
dependencies = [
|
|
1780
1779
|
"proc-macro2",
|
|
1781
1780
|
"quote",
|
|
@@ -1784,9 +1783,9 @@ dependencies = [
|
|
|
1784
1783
|
|
|
1785
1784
|
[[package]]
|
|
1786
1785
|
name = "target-lexicon"
|
|
1787
|
-
version = "0.
|
|
1786
|
+
version = "0.13.5"
|
|
1788
1787
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
1789
|
-
checksum = "
|
|
1788
|
+
checksum = "adb6935a6f5c20170eeceb1a3835a49e12e19d792f6dd344ccc76a985ca5a6ca"
|
|
1790
1789
|
|
|
1791
1790
|
[[package]]
|
|
1792
1791
|
name = "tempfile"
|
|
@@ -1818,7 +1817,7 @@ checksum = "bc04cd3e1236dd4a98afca4569f2deb3f120e5422a4023be2cb683f8486292af"
|
|
|
1818
1817
|
dependencies = [
|
|
1819
1818
|
"proc-macro2",
|
|
1820
1819
|
"quote",
|
|
1821
|
-
"syn 3.0.
|
|
1820
|
+
"syn 3.0.4",
|
|
1822
1821
|
]
|
|
1823
1822
|
|
|
1824
1823
|
[[package]]
|
|
@@ -1847,7 +1846,7 @@ dependencies = [
|
|
|
1847
1846
|
|
|
1848
1847
|
[[package]]
|
|
1849
1848
|
name = "trainingsample"
|
|
1850
|
-
version = "0.3.
|
|
1849
|
+
version = "0.3.2"
|
|
1851
1850
|
dependencies = [
|
|
1852
1851
|
"anyhow",
|
|
1853
1852
|
"criterion",
|
|
@@ -5,15 +5,15 @@ image = {version = "0.25", features = ["png", "jpeg", "webp"]}
|
|
|
5
5
|
imageproc = "0.25"
|
|
6
6
|
# Metal GPU acceleration
|
|
7
7
|
metal = {version = "0.27", optional = true}
|
|
8
|
-
ndarray = "0.
|
|
8
|
+
ndarray = "0.17"
|
|
9
9
|
num_cpus = "1.16"
|
|
10
|
-
numpy = {version = "0.
|
|
10
|
+
numpy = {version = "0.27", optional = true}
|
|
11
11
|
objc = {version = "0.2", optional = true}
|
|
12
12
|
# OpenCV bindings for performance parity
|
|
13
13
|
# Limit binding generation to the modules this crate actually uses.
|
|
14
14
|
opencv = {version = "0.99", optional = true, default-features = false, features = ["clang-runtime", "imgproc", "videoio"]}
|
|
15
15
|
# Python bindings (optional)
|
|
16
|
-
pyo3 = {version = "0.
|
|
16
|
+
pyo3 = {version = "0.27", features = ["extension-module"], optional = true}
|
|
17
17
|
rayon = "1.8"
|
|
18
18
|
tempfile = {version = "3.10", optional = true}
|
|
19
19
|
# SIMD optimizations
|
|
@@ -39,7 +39,7 @@ description = "High-performance Rust reimplementation of GIL-blocking video/imag
|
|
|
39
39
|
edition = "2021"
|
|
40
40
|
license = "MIT"
|
|
41
41
|
name = "trainingsample"
|
|
42
|
-
version = "0.3.
|
|
42
|
+
version = "0.3.2"
|
|
43
43
|
readme = "README.md"
|
|
44
44
|
|
|
45
45
|
[profile.release]
|
|
@@ -1,17 +1,18 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: trainingsample
|
|
3
|
-
Version: 0.3.
|
|
3
|
+
Version: 0.3.2
|
|
4
4
|
Classifier: Programming Language :: Rust
|
|
5
5
|
Classifier: Programming Language :: Python :: Implementation :: CPython
|
|
6
6
|
Classifier: Programming Language :: Python :: Implementation :: PyPy
|
|
7
7
|
Classifier: Programming Language :: Python :: 3.11
|
|
8
8
|
Classifier: Programming Language :: Python :: 3.12
|
|
9
9
|
Classifier: Programming Language :: Python :: 3.13
|
|
10
|
+
Classifier: Programming Language :: Python :: 3.14
|
|
10
11
|
Requires-Dist: numpy>=1.21.0
|
|
11
12
|
Requires-Dist: pillow>=8.0.0
|
|
12
13
|
Requires-Dist: pytest>=6.0 ; extra == 'dev'
|
|
13
14
|
Requires-Dist: pytest-benchmark ; extra == 'dev'
|
|
14
|
-
Requires-Dist: maturin>=1.
|
|
15
|
+
Requires-Dist: maturin>=1.9.5,<2.0 ; extra == 'dev'
|
|
15
16
|
Requires-Dist: pre-commit ; extra == 'dev'
|
|
16
17
|
Provides-Extra: dev
|
|
17
18
|
License-File: LICENSE
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
[build-system]
|
|
2
2
|
build-backend = "maturin"
|
|
3
|
-
requires = ["maturin>=1.
|
|
3
|
+
requires = ["maturin>=1.9.5,<2.0"]
|
|
4
4
|
|
|
5
5
|
[project]
|
|
6
6
|
authors = [{name = "bghira", email = "bghira@users.noreply.github.com"}]
|
|
@@ -10,17 +10,18 @@ classifiers = [
|
|
|
10
10
|
"Programming Language :: Python :: Implementation :: PyPy",
|
|
11
11
|
"Programming Language :: Python :: 3.11",
|
|
12
12
|
"Programming Language :: Python :: 3.12",
|
|
13
|
-
"Programming Language :: Python :: 3.13"
|
|
13
|
+
"Programming Language :: Python :: 3.13",
|
|
14
|
+
"Programming Language :: Python :: 3.14"
|
|
14
15
|
]
|
|
15
16
|
dependencies = ["numpy>=1.21.0", "pillow>=8.0.0"]
|
|
16
17
|
description = "High-performance Rust reimplementation of GIL-blocking video/image operations"
|
|
17
18
|
license = {text = "MIT"}
|
|
18
19
|
name = "trainingsample"
|
|
19
20
|
requires-python = ">=3.11"
|
|
20
|
-
version = "0.3.
|
|
21
|
+
version = "0.3.2"
|
|
21
22
|
|
|
22
23
|
[project.optional-dependencies]
|
|
23
|
-
dev = ["pytest>=6.0", "pytest-benchmark", "maturin>=1.
|
|
24
|
+
dev = ["pytest>=6.0", "pytest-benchmark", "maturin>=1.9.5,<2.0", "pre-commit"]
|
|
24
25
|
|
|
25
26
|
[tool.black]
|
|
26
27
|
extend-exclude = '''
|
|
@@ -88,7 +88,7 @@ impl BufferPool {
|
|
|
88
88
|
|
|
89
89
|
#[cfg(feature = "python-bindings")]
|
|
90
90
|
#[pyfunction]
|
|
91
|
-
pub fn load_image_batch(py: Python, image_paths: Vec<String>) -> PyResult<Vec<
|
|
91
|
+
pub fn load_image_batch(py: Python, image_paths: Vec<String>) -> PyResult<Vec<Py<PyAny>>> {
|
|
92
92
|
use rayon::prelude::*;
|
|
93
93
|
|
|
94
94
|
let results: Vec<_> = image_paths
|
|
@@ -100,7 +100,7 @@ pub fn load_image_batch(py: Python, image_paths: Vec<String>) -> PyResult<Vec<Py
|
|
|
100
100
|
for result in results {
|
|
101
101
|
match result {
|
|
102
102
|
Ok(image_data) => {
|
|
103
|
-
let py_bytes = PyBytes::
|
|
103
|
+
let py_bytes = PyBytes::new(py, &image_data);
|
|
104
104
|
py_results.push(py_bytes.into_any().unbind());
|
|
105
105
|
}
|
|
106
106
|
Err(_) => {
|
|
@@ -155,7 +155,7 @@ pub unsafe fn batch_crop_images_zero_copy<'py>(
|
|
|
155
155
|
|
|
156
156
|
let array = ndarray::Array3::from_shape_vec((height, width, channels), output_buffer)
|
|
157
157
|
.map_err(|e| pyo3::exceptions::PyValueError::new_err(format!("Shape error: {}", e)))?;
|
|
158
|
-
let py_array = PyArray3::
|
|
158
|
+
let py_array = PyArray3::from_owned_array(py, array);
|
|
159
159
|
py_results.push(py_array);
|
|
160
160
|
}
|
|
161
161
|
|
|
@@ -206,7 +206,7 @@ pub unsafe fn batch_center_crop_images_zero_copy<'py>(
|
|
|
206
206
|
.map_err(|e| {
|
|
207
207
|
pyo3::exceptions::PyValueError::new_err(format!("Shape error: {}", e))
|
|
208
208
|
})?;
|
|
209
|
-
let py_array = PyArray3::
|
|
209
|
+
let py_array = PyArray3::from_owned_array(py, array);
|
|
210
210
|
py_results.push(py_array);
|
|
211
211
|
}
|
|
212
212
|
|
|
@@ -390,10 +390,10 @@ pub fn batch_resize_images_zero_copy<'py>(
|
|
|
390
390
|
// Convert to PyArray3 and return as Python list
|
|
391
391
|
let py_results: Vec<Bound<'py, PyArray3<u8>>> = results
|
|
392
392
|
.into_iter()
|
|
393
|
-
.map(|array| PyArray3::
|
|
393
|
+
.map(|array| PyArray3::from_owned_array(py, array))
|
|
394
394
|
.collect();
|
|
395
395
|
|
|
396
|
-
Ok(PyList::
|
|
396
|
+
Ok(PyList::new(py, py_results)?.into_any())
|
|
397
397
|
}
|
|
398
398
|
|
|
399
399
|
/// Ultra-fast OpenCV-powered resize using zero-copy Mat headers
|
|
@@ -552,7 +552,7 @@ fn resize_single_image_direct<'py>(
|
|
|
552
552
|
})?;
|
|
553
553
|
|
|
554
554
|
// DIRECT return - no Vec wrapper overhead!
|
|
555
|
-
Ok(PyArray3::
|
|
555
|
+
Ok(PyArray3::from_owned_array(py, result))
|
|
556
556
|
}
|
|
557
557
|
|
|
558
558
|
#[cfg(not(feature = "opencv"))]
|
|
@@ -578,12 +578,12 @@ fn is_tuple_or_list_of_two(obj: &Bound<PyAny>) -> bool {
|
|
|
578
578
|
use pyo3::types::{PyList, PyTuple};
|
|
579
579
|
|
|
580
580
|
// Check if it's a tuple of length 2
|
|
581
|
-
if let Ok(tuple) = obj.
|
|
581
|
+
if let Ok(tuple) = obj.cast::<PyTuple>() {
|
|
582
582
|
return tuple.len() == 2;
|
|
583
583
|
}
|
|
584
584
|
|
|
585
585
|
// Check if it's a list of length 2 containing numbers (not nested lists)
|
|
586
|
-
if let Ok(list) = obj.
|
|
586
|
+
if let Ok(list) = obj.cast::<PyList>() {
|
|
587
587
|
if list.len() == 2 {
|
|
588
588
|
// Check if first element is a number (not a nested list/tuple)
|
|
589
589
|
if let Ok(first) = list.get_item(0) {
|
|
@@ -616,7 +616,7 @@ impl ResizeIterator {
|
|
|
616
616
|
// Transfer the completed allocation directly into the ndarray instead
|
|
617
617
|
// of cloning the full resized image during iteration.
|
|
618
618
|
match ndarray::Array3::from_shape_vec((height, width, channels), buffer) {
|
|
619
|
-
Ok(array) => Some(PyArray3::
|
|
619
|
+
Ok(array) => Some(PyArray3::from_owned_array(py, array)),
|
|
620
620
|
Err(_) => None, // Malformed buffer; end iteration (StopIteration)
|
|
621
621
|
}
|
|
622
622
|
}
|
|
@@ -872,7 +872,7 @@ pub fn batch_crop_images<'py>(
|
|
|
872
872
|
let img_view = image.as_array();
|
|
873
873
|
match crop_image_array(&img_view, x, y, width, height) {
|
|
874
874
|
Ok(cropped) => {
|
|
875
|
-
let py_array = PyArray3::
|
|
875
|
+
let py_array = PyArray3::from_owned_array(py, cropped);
|
|
876
876
|
py_results.push(py_array);
|
|
877
877
|
}
|
|
878
878
|
Err(e) => {
|
|
@@ -905,7 +905,7 @@ pub fn batch_center_crop_images<'py>(
|
|
|
905
905
|
let img_view = image.as_array();
|
|
906
906
|
match crate::cropping::center_crop_image_array(&img_view, target_width, target_height) {
|
|
907
907
|
Ok(cropped) => {
|
|
908
|
-
let py_array = PyArray3::
|
|
908
|
+
let py_array = PyArray3::from_owned_array(py, cropped);
|
|
909
909
|
py_results.push(py_array);
|
|
910
910
|
}
|
|
911
911
|
Err(e) => {
|
|
@@ -932,7 +932,7 @@ pub fn batch_random_crop_images<'py>(
|
|
|
932
932
|
let img_view = image.as_array();
|
|
933
933
|
match random_crop_image_array(&img_view, target_width, target_height) {
|
|
934
934
|
Ok(cropped) => {
|
|
935
|
-
let py_array = PyArray3::
|
|
935
|
+
let py_array = PyArray3::from_owned_array(py, cropped);
|
|
936
936
|
py_results.push(py_array);
|
|
937
937
|
}
|
|
938
938
|
Err(e) => {
|
|
@@ -958,7 +958,7 @@ pub fn batch_calculate_luminance(
|
|
|
958
958
|
|
|
959
959
|
let image_views: Vec<_> = images.iter().map(|image| image.as_array()).collect();
|
|
960
960
|
|
|
961
|
-
Ok(py.
|
|
961
|
+
Ok(py.detach(|| {
|
|
962
962
|
image_views
|
|
963
963
|
.par_iter()
|
|
964
964
|
.map(crate::luminance::calculate_luminance_array_sequential)
|
|
@@ -984,7 +984,7 @@ pub fn rgb_to_rgba_optimized<'py>(
|
|
|
984
984
|
let rgba_array = ndarray::Array3::from_shape_vec((height, width, 4), rgba_data)
|
|
985
985
|
.map_err(|e| pyo3::exceptions::PyValueError::new_err(format!("Shape error: {}", e)))?;
|
|
986
986
|
|
|
987
|
-
let py_array = PyArray3::
|
|
987
|
+
let py_array = PyArray3::from_owned_array(py, rgba_array);
|
|
988
988
|
Ok((py_array, metrics.throughput_mpixels_per_sec))
|
|
989
989
|
}
|
|
990
990
|
|
|
@@ -1013,7 +1013,7 @@ pub fn rgba_to_rgb_optimized<'py>(
|
|
|
1013
1013
|
let rgb_array = ndarray::Array3::from_shape_vec((height, width, 3), rgb_data)
|
|
1014
1014
|
.map_err(|e| pyo3::exceptions::PyValueError::new_err(format!("Shape error: {}", e)))?;
|
|
1015
1015
|
|
|
1016
|
-
let py_array = PyArray3::
|
|
1016
|
+
let py_array = PyArray3::from_owned_array(py, rgb_array);
|
|
1017
1017
|
Ok((py_array, metrics.throughput_mpixels_per_sec))
|
|
1018
1018
|
}
|
|
1019
1019
|
|
|
@@ -1057,7 +1057,7 @@ pub fn batch_resize_images<'py>(
|
|
|
1057
1057
|
Ok(resized_images) => {
|
|
1058
1058
|
let py_results: Vec<_> = resized_images
|
|
1059
1059
|
.into_iter()
|
|
1060
|
-
.map(|resized| PyArray3::
|
|
1060
|
+
.map(|resized| PyArray3::from_owned_array(py, resized))
|
|
1061
1061
|
.collect();
|
|
1062
1062
|
Ok(py_results)
|
|
1063
1063
|
}
|
|
@@ -1095,7 +1095,7 @@ pub fn batch_resize_videos<'py>(
|
|
|
1095
1095
|
Ok(resized_videos) => {
|
|
1096
1096
|
let py_results: Vec<_> = resized_videos
|
|
1097
1097
|
.into_iter()
|
|
1098
|
-
.map(|resized| PyArray4::
|
|
1098
|
+
.map(|resized| PyArray4::from_owned_array(py, resized))
|
|
1099
1099
|
.collect();
|
|
1100
1100
|
Ok(py_results)
|
|
1101
1101
|
}
|
|
@@ -1134,7 +1134,7 @@ pub fn resize_bilinear_opencv<'py>(
|
|
|
1134
1134
|
|
|
1135
1135
|
match resize_bilinear_opencv(&image_array, target_width, target_height) {
|
|
1136
1136
|
Ok(resized) => {
|
|
1137
|
-
let py_array = PyArray3::
|
|
1137
|
+
let py_array = PyArray3::from_owned_array(py, resized);
|
|
1138
1138
|
Ok(py_array)
|
|
1139
1139
|
}
|
|
1140
1140
|
Err(e) => Err(pyo3::exceptions::PyRuntimeError::new_err(format!(
|
|
@@ -1158,7 +1158,7 @@ pub fn resize_lanczos4_opencv<'py>(
|
|
|
1158
1158
|
|
|
1159
1159
|
match resize_lanczos4_opencv(&image_array, target_width, target_height) {
|
|
1160
1160
|
Ok(resized) => {
|
|
1161
|
-
let py_array = PyArray3::
|
|
1161
|
+
let py_array = PyArray3::from_owned_array(py, resized);
|
|
1162
1162
|
Ok(py_array)
|
|
1163
1163
|
}
|
|
1164
1164
|
Err(e) => Err(pyo3::exceptions::PyRuntimeError::new_err(format!(
|
|
@@ -1218,11 +1218,11 @@ pub fn imdecode_py<'py>(
|
|
|
1218
1218
|
}
|
|
1219
1219
|
};
|
|
1220
1220
|
|
|
1221
|
-
let decoded = py.
|
|
1221
|
+
let decoded = py.detach(move || imdecode(&buf, imread_flags));
|
|
1222
1222
|
|
|
1223
1223
|
match decoded {
|
|
1224
1224
|
Ok(image) => {
|
|
1225
|
-
let py_array = PyArray3::
|
|
1225
|
+
let py_array = PyArray3::from_owned_array(py, image);
|
|
1226
1226
|
Ok(py_array)
|
|
1227
1227
|
}
|
|
1228
1228
|
Err(e) => Err(pyo3::exceptions::PyRuntimeError::new_err(format!(
|
|
@@ -1258,7 +1258,7 @@ pub fn cvt_color_py<'py>(
|
|
|
1258
1258
|
let src_array = src.as_array();
|
|
1259
1259
|
match cvt_color(&src_array, color_code) {
|
|
1260
1260
|
Ok(converted) => {
|
|
1261
|
-
let py_array = PyArray3::
|
|
1261
|
+
let py_array = PyArray3::from_owned_array(py, converted);
|
|
1262
1262
|
Ok(py_array)
|
|
1263
1263
|
}
|
|
1264
1264
|
Err(e) => Err(pyo3::exceptions::PyRuntimeError::new_err(format!(
|
|
@@ -1281,7 +1281,7 @@ pub fn canny_py<'py>(
|
|
|
1281
1281
|
let image_array = image.as_array();
|
|
1282
1282
|
match canny(&image_array, threshold1, threshold2) {
|
|
1283
1283
|
Ok(edges) => {
|
|
1284
|
-
let py_array = PyArray3::
|
|
1284
|
+
let py_array = PyArray3::from_owned_array(py, edges);
|
|
1285
1285
|
Ok(py_array)
|
|
1286
1286
|
}
|
|
1287
1287
|
Err(e) => Err(pyo3::exceptions::PyRuntimeError::new_err(format!(
|
|
@@ -1317,7 +1317,7 @@ pub fn resize_py<'py>(
|
|
|
1317
1317
|
let src_array = src.as_array();
|
|
1318
1318
|
match resize(&src_array, dsize, interp) {
|
|
1319
1319
|
Ok(resized) => {
|
|
1320
|
-
let py_array = PyArray3::
|
|
1320
|
+
let py_array = PyArray3::from_owned_array(py, resized);
|
|
1321
1321
|
Ok(py_array)
|
|
1322
1322
|
}
|
|
1323
1323
|
Err(e) => Err(pyo3::exceptions::PyRuntimeError::new_err(format!(
|
|
@@ -1328,7 +1328,7 @@ pub fn resize_py<'py>(
|
|
|
1328
1328
|
}
|
|
1329
1329
|
|
|
1330
1330
|
#[cfg(feature = "python-bindings")]
|
|
1331
|
-
#[pyclass]
|
|
1331
|
+
#[pyclass(unsendable)]
|
|
1332
1332
|
pub struct PyVideoCapture {
|
|
1333
1333
|
inner: VideoCapture,
|
|
1334
1334
|
temp_path: Option<TempPath>,
|
|
@@ -1419,7 +1419,7 @@ impl PyVideoCapture {
|
|
|
1419
1419
|
fn read<'py>(&mut self, py: Python<'py>) -> PyResult<(bool, Option<Bound<'py, PyArray3<u8>>>)> {
|
|
1420
1420
|
let (ret, frame) = self.inner.read();
|
|
1421
1421
|
if let Some(frame_data) = frame {
|
|
1422
|
-
let py_array = PyArray3::
|
|
1422
|
+
let py_array = PyArray3::from_owned_array(py, frame_data);
|
|
1423
1423
|
Ok((ret, Some(py_array)))
|
|
1424
1424
|
} else {
|
|
1425
1425
|
Ok((ret, None))
|
|
@@ -1639,7 +1639,7 @@ impl PyBatchProcessor {
|
|
|
1639
1639
|
Ok(results) => {
|
|
1640
1640
|
let py_results: Vec<_> = results
|
|
1641
1641
|
.into_iter()
|
|
1642
|
-
.map(|result| PyArray3::
|
|
1642
|
+
.map(|result| PyArray3::from_owned_array(py, result))
|
|
1643
1643
|
.collect();
|
|
1644
1644
|
Ok(py_results)
|
|
1645
1645
|
}
|
|
@@ -1679,7 +1679,7 @@ impl PyBatchProcessor {
|
|
|
1679
1679
|
Ok(results) => {
|
|
1680
1680
|
let py_results: Vec<_> = results
|
|
1681
1681
|
.into_iter()
|
|
1682
|
-
.map(|result| PyArray3::
|
|
1682
|
+
.map(|result| PyArray3::from_owned_array(py, result))
|
|
1683
1683
|
.collect();
|
|
1684
1684
|
Ok(py_results)
|
|
1685
1685
|
}
|
|
@@ -1704,7 +1704,7 @@ impl PyBatchProcessor {
|
|
|
1704
1704
|
Ok(results) => {
|
|
1705
1705
|
let py_results: Vec<_> = results
|
|
1706
1706
|
.into_iter()
|
|
1707
|
-
.map(|result| PyArray3::
|
|
1707
|
+
.map(|result| PyArray3::from_owned_array(py, result))
|
|
1708
1708
|
.collect();
|
|
1709
1709
|
Ok(py_results)
|
|
1710
1710
|
}
|
|
@@ -1782,7 +1782,7 @@ impl PyBatchProcessor {
|
|
|
1782
1782
|
Ok(results) => {
|
|
1783
1783
|
let py_results: Vec<_> = results
|
|
1784
1784
|
.into_iter()
|
|
1785
|
-
.map(|result| PyArray3::
|
|
1785
|
+
.map(|result| PyArray3::from_owned_array(py, result))
|
|
1786
1786
|
.collect();
|
|
1787
1787
|
Ok(py_results)
|
|
1788
1788
|
}
|
|
@@ -1903,7 +1903,7 @@ impl PyTrueBatchProcessor {
|
|
|
1903
1903
|
Ok(results) => {
|
|
1904
1904
|
let py_results: Vec<_> = results
|
|
1905
1905
|
.into_iter()
|
|
1906
|
-
.map(|result| PyArray3::
|
|
1906
|
+
.map(|result| PyArray3::from_owned_array(py, result))
|
|
1907
1907
|
.collect();
|
|
1908
1908
|
Ok(py_results)
|
|
1909
1909
|
}
|
|
@@ -1939,7 +1939,7 @@ impl PyTrueBatchProcessor {
|
|
|
1939
1939
|
Ok(results) => {
|
|
1940
1940
|
let py_results: Vec<_> = results
|
|
1941
1941
|
.into_iter()
|
|
1942
|
-
.map(|result| PyArray3::
|
|
1942
|
+
.map(|result| PyArray3::from_owned_array(py, result))
|
|
1943
1943
|
.collect();
|
|
1944
1944
|
Ok(py_results)
|
|
1945
1945
|
}
|
|
@@ -0,0 +1,427 @@
|
|
|
1
|
+
use image::{DynamicImage, ImageFormat, RgbImage};
|
|
2
|
+
use ndarray::{Array3, Array4};
|
|
3
|
+
use std::io::Cursor;
|
|
4
|
+
use std::path::PathBuf;
|
|
5
|
+
use std::time::{SystemTime, UNIX_EPOCH};
|
|
6
|
+
use trainingsample::{
|
|
7
|
+
batch_load_images, fourcc, load_and_decode_image, load_image_from_path, BatchProcessor,
|
|
8
|
+
CascadeClassifier, ColorConversion, ColorConversionCode, ImreadFlags, OptimizedBatchProcessor,
|
|
9
|
+
ResizeInterpolation, TrueBatchProcessor, VideoCapture, VideoCaptureProperties, VideoOperation,
|
|
10
|
+
VideoWriter,
|
|
11
|
+
};
|
|
12
|
+
|
|
13
|
+
#[cfg(feature = "simd")]
|
|
14
|
+
use trainingsample::{
|
|
15
|
+
rgb_to_rgba_optimized, rgb_to_rgba_scalar, rgba_to_rgb_optimized, rgba_to_rgb_scalar,
|
|
16
|
+
FormatConversionMetrics,
|
|
17
|
+
};
|
|
18
|
+
|
|
19
|
+
fn sample_rgb(height: usize, width: usize) -> Array3<u8> {
|
|
20
|
+
Array3::from_shape_fn((height, width, 3), |(y, x, channel)| {
|
|
21
|
+
((y * 37 + x * 19 + channel * 71) % 256) as u8
|
|
22
|
+
})
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
fn encode_png(image: &Array3<u8>) -> Vec<u8> {
|
|
26
|
+
let (height, width, channels) = image.dim();
|
|
27
|
+
assert_eq!(channels, 3);
|
|
28
|
+
|
|
29
|
+
let rgb = RgbImage::from_raw(width as u32, height as u32, image.iter().copied().collect())
|
|
30
|
+
.expect("test image dimensions should match its data");
|
|
31
|
+
let mut encoded = Cursor::new(Vec::new());
|
|
32
|
+
DynamicImage::ImageRgb8(rgb)
|
|
33
|
+
.write_to(&mut encoded, ImageFormat::Png)
|
|
34
|
+
.expect("test image should encode");
|
|
35
|
+
encoded.into_inner()
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
fn temporary_path(extension: &str) -> PathBuf {
|
|
39
|
+
let nonce = SystemTime::now()
|
|
40
|
+
.duration_since(UNIX_EPOCH)
|
|
41
|
+
.expect("system clock should follow the Unix epoch")
|
|
42
|
+
.as_nanos();
|
|
43
|
+
std::env::temp_dir().join(format!(
|
|
44
|
+
"trainingsample-coverage-{}-{nonce}.{extension}",
|
|
45
|
+
std::process::id()
|
|
46
|
+
))
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
struct TemporaryImage(PathBuf);
|
|
50
|
+
|
|
51
|
+
impl TemporaryImage {
|
|
52
|
+
fn create(contents: &[u8]) -> Self {
|
|
53
|
+
let path = temporary_path("png");
|
|
54
|
+
std::fs::write(&path, contents).expect("temporary image should be writable");
|
|
55
|
+
Self(path)
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
impl Drop for TemporaryImage {
|
|
60
|
+
fn drop(&mut self) {
|
|
61
|
+
let _ = std::fs::remove_file(&self.0);
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
#[test]
|
|
66
|
+
#[cfg(feature = "simd")]
|
|
67
|
+
fn format_conversion_implementations_preserve_pixels() {
|
|
68
|
+
let image = sample_rgb(2, 8);
|
|
69
|
+
|
|
70
|
+
let (scalar_rgba, scalar_metrics) = rgb_to_rgba_scalar(&image.view(), 173);
|
|
71
|
+
let (optimized_rgba, optimized_metrics) = rgb_to_rgba_optimized(&image.view(), 173);
|
|
72
|
+
assert_eq!(optimized_rgba, scalar_rgba);
|
|
73
|
+
assert!(scalar_rgba.chunks_exact(4).all(|pixel| pixel[3] == 173));
|
|
74
|
+
assert_eq!(scalar_metrics.pixels_processed, 16);
|
|
75
|
+
assert_eq!(scalar_metrics.simd_width, 1);
|
|
76
|
+
assert_eq!(scalar_metrics.implementation, "scalar_rgb_to_rgba");
|
|
77
|
+
assert_eq!(optimized_metrics.pixels_processed, 16);
|
|
78
|
+
assert_eq!(optimized_metrics.simd_width, 8);
|
|
79
|
+
assert_eq!(optimized_metrics.implementation, "simd_rgb_to_rgba");
|
|
80
|
+
|
|
81
|
+
let (scalar_rgb, _) = rgba_to_rgb_scalar(&scalar_rgba, 8, 2);
|
|
82
|
+
let (optimized_rgb, optimized_reverse_metrics) = rgba_to_rgb_optimized(&scalar_rgba, 8, 2);
|
|
83
|
+
assert_eq!(optimized_rgb, scalar_rgb);
|
|
84
|
+
assert_eq!(scalar_rgb, image.iter().copied().collect::<Vec<_>>());
|
|
85
|
+
assert_eq!(optimized_reverse_metrics.pixels_processed, 16);
|
|
86
|
+
|
|
87
|
+
let metrics = FormatConversionMetrics::new(1_000_000, 1_000_000_000, 4, "test");
|
|
88
|
+
assert_eq!(metrics.throughput_mpixels_per_sec, 1.0);
|
|
89
|
+
assert_eq!(metrics.simd_width, 4);
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
#[test]
|
|
93
|
+
fn loading_functions_return_raw_and_decoded_images() {
|
|
94
|
+
let image = sample_rgb(3, 5);
|
|
95
|
+
let encoded = encode_png(&image);
|
|
96
|
+
let temporary = TemporaryImage::create(&encoded);
|
|
97
|
+
let path = temporary
|
|
98
|
+
.0
|
|
99
|
+
.to_str()
|
|
100
|
+
.expect("temporary test path should be valid UTF-8");
|
|
101
|
+
|
|
102
|
+
assert_eq!(load_image_from_path(path).unwrap(), encoded);
|
|
103
|
+
assert_eq!(
|
|
104
|
+
load_and_decode_image(path).unwrap().to_rgb8().dimensions(),
|
|
105
|
+
(5, 3)
|
|
106
|
+
);
|
|
107
|
+
|
|
108
|
+
let missing = temporary.0.with_extension("missing");
|
|
109
|
+
let results = batch_load_images(&[temporary.0.as_path(), missing.as_path()]);
|
|
110
|
+
assert_eq!(results.len(), 2);
|
|
111
|
+
assert_eq!(results[0].as_ref().unwrap(), &encoded);
|
|
112
|
+
assert!(results[1].is_err());
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
#[test]
|
|
116
|
+
fn batch_processor_covers_sequential_pipelines_and_validation() {
|
|
117
|
+
let processor = BatchProcessor::with_config(false, 2);
|
|
118
|
+
let image = sample_rgb(8, 8);
|
|
119
|
+
let second = sample_rgb(6, 10);
|
|
120
|
+
let views = [image.view(), second.view()];
|
|
121
|
+
let encoded = encode_png(&image);
|
|
122
|
+
|
|
123
|
+
let decoded = processor.batch_imdecode(&[encoded.as_slice()], ImreadFlags::ImreadColor);
|
|
124
|
+
assert_eq!(decoded[0].as_ref().unwrap().dim(), image.dim());
|
|
125
|
+
assert!(processor.batch_imdecode(&[b"not an image"], ImreadFlags::ImreadColor)[0].is_err());
|
|
126
|
+
|
|
127
|
+
assert!(processor
|
|
128
|
+
.batch_cvt_color(&[], ColorConversionCode::ColorBgr2Rgb)
|
|
129
|
+
.unwrap()
|
|
130
|
+
.is_empty());
|
|
131
|
+
let swapped = processor
|
|
132
|
+
.batch_cvt_color(&views, ColorConversionCode::ColorBgr2Rgb)
|
|
133
|
+
.unwrap();
|
|
134
|
+
assert_eq!(swapped[0][[0, 0, 0]], image[[0, 0, 2]]);
|
|
135
|
+
assert_eq!(swapped[0][[0, 0, 2]], image[[0, 0, 0]]);
|
|
136
|
+
|
|
137
|
+
assert!(processor
|
|
138
|
+
.batch_resize(&views, &[(4, 4)], ResizeInterpolation::InterLinear)
|
|
139
|
+
.is_err());
|
|
140
|
+
assert!(processor
|
|
141
|
+
.batch_resize(&[], &[], ResizeInterpolation::InterLinear)
|
|
142
|
+
.unwrap()
|
|
143
|
+
.is_empty());
|
|
144
|
+
let resized = processor
|
|
145
|
+
.batch_resize(&views, &[(4, 4), (5, 3)], ResizeInterpolation::InterNearest)
|
|
146
|
+
.unwrap();
|
|
147
|
+
assert_eq!(resized[0].dim(), (4, 4, 3));
|
|
148
|
+
assert_eq!(resized[1].dim(), (3, 5, 3));
|
|
149
|
+
|
|
150
|
+
assert!(processor.batch_canny(&[], 25.0, 50.0).unwrap().is_empty());
|
|
151
|
+
let edges = processor.batch_canny(&views, 25.0, 50.0).unwrap();
|
|
152
|
+
assert_eq!(edges[0].dim(), (8, 8, 1));
|
|
153
|
+
assert_eq!(edges[1].dim(), (6, 10, 1));
|
|
154
|
+
|
|
155
|
+
assert!(processor
|
|
156
|
+
.batch_preprocess_pipeline(
|
|
157
|
+
&[encoded.as_slice()],
|
|
158
|
+
&[],
|
|
159
|
+
None,
|
|
160
|
+
ImreadFlags::ImreadColor,
|
|
161
|
+
ResizeInterpolation::InterLinear,
|
|
162
|
+
)
|
|
163
|
+
.is_err());
|
|
164
|
+
let preprocessed = processor
|
|
165
|
+
.batch_preprocess_pipeline(
|
|
166
|
+
&[encoded.as_slice()],
|
|
167
|
+
&[(5, 5)],
|
|
168
|
+
Some(ColorConversionCode::ColorRgb2Gray),
|
|
169
|
+
ImreadFlags::ImreadColor,
|
|
170
|
+
ResizeInterpolation::InterCubic,
|
|
171
|
+
)
|
|
172
|
+
.unwrap();
|
|
173
|
+
assert_eq!(preprocessed[0].dim(), (5, 5, 1));
|
|
174
|
+
|
|
175
|
+
let detections = processor
|
|
176
|
+
.batch_face_detection_pipeline(&views, 1.1, 3)
|
|
177
|
+
.unwrap();
|
|
178
|
+
assert_eq!(detections, vec![Vec::new(), Vec::new()]);
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
#[test]
|
|
182
|
+
fn batch_processor_covers_parallel_and_video_paths() {
|
|
183
|
+
let processor = BatchProcessor::with_config(true, 1);
|
|
184
|
+
let images = [sample_rgb(5, 6), sample_rgb(5, 6), sample_rgb(5, 6)];
|
|
185
|
+
let views: Vec<_> = images.iter().map(|image| image.view()).collect();
|
|
186
|
+
let buffers: Vec<_> = images.iter().map(encode_png).collect();
|
|
187
|
+
let buffer_views: Vec<_> = buffers.iter().map(Vec::as_slice).collect();
|
|
188
|
+
|
|
189
|
+
assert_eq!(
|
|
190
|
+
processor
|
|
191
|
+
.batch_imdecode(&buffer_views, ImreadFlags::ImreadColor)
|
|
192
|
+
.len(),
|
|
193
|
+
3
|
|
194
|
+
);
|
|
195
|
+
assert_eq!(
|
|
196
|
+
processor
|
|
197
|
+
.batch_cvt_color(&views, ColorConversionCode::ColorRgb2Gray)
|
|
198
|
+
.unwrap()
|
|
199
|
+
.len(),
|
|
200
|
+
3
|
|
201
|
+
);
|
|
202
|
+
let resized = processor
|
|
203
|
+
.batch_resize(
|
|
204
|
+
&views,
|
|
205
|
+
&[(12, 10), (6, 5), (12, 10)],
|
|
206
|
+
ResizeInterpolation::InterLanczos4,
|
|
207
|
+
)
|
|
208
|
+
.unwrap();
|
|
209
|
+
assert_eq!(resized[0].dim(), (10, 12, 3));
|
|
210
|
+
assert_eq!(resized[1].dim(), (5, 6, 3));
|
|
211
|
+
assert_eq!(processor.batch_canny(&views, 10.0, 20.0).unwrap().len(), 3);
|
|
212
|
+
|
|
213
|
+
let video = Array4::from_shape_fn((2, 5, 6, 3), |(frame, y, x, channel)| {
|
|
214
|
+
((frame * 43 + y * 17 + x * 11 + channel * 67) % 256) as u8
|
|
215
|
+
});
|
|
216
|
+
let processed = processor
|
|
217
|
+
.batch_video_frame_processing(
|
|
218
|
+
&[video.view()],
|
|
219
|
+
(12, 10),
|
|
220
|
+
&[
|
|
221
|
+
VideoOperation::Resize(ResizeInterpolation::InterLinear),
|
|
222
|
+
VideoOperation::ColorConvert(ColorConversionCode::ColorBgr2Rgb),
|
|
223
|
+
VideoOperation::EdgeDetection(10.0, 20.0),
|
|
224
|
+
],
|
|
225
|
+
)
|
|
226
|
+
.unwrap();
|
|
227
|
+
assert_eq!(processed[0].dim(), (2, 10, 12, 1));
|
|
228
|
+
|
|
229
|
+
let empty_video = Array4::<u8>::zeros((0, 5, 6, 3));
|
|
230
|
+
let empty_processed = processor
|
|
231
|
+
.batch_video_frame_processing(&[empty_video.view()], (4, 3), &[])
|
|
232
|
+
.unwrap();
|
|
233
|
+
assert_eq!(empty_processed[0].dim(), empty_video.dim());
|
|
234
|
+
}
|
|
235
|
+
|
|
236
|
+
#[test]
|
|
237
|
+
fn optimized_batch_processor_covers_conversion_and_resize_paths() {
|
|
238
|
+
let sequential = OptimizedBatchProcessor {
|
|
239
|
+
use_parallel: false,
|
|
240
|
+
chunk_size: 8,
|
|
241
|
+
};
|
|
242
|
+
let image = sample_rgb(2, 4);
|
|
243
|
+
let views = [image.view()];
|
|
244
|
+
|
|
245
|
+
assert!(sequential
|
|
246
|
+
.batch_cvt_color_optimized(&[], ColorConversionCode::ColorBgr2Rgb)
|
|
247
|
+
.unwrap()
|
|
248
|
+
.is_empty());
|
|
249
|
+
let swapped = sequential
|
|
250
|
+
.batch_cvt_color_optimized(&views, ColorConversionCode::ColorBgr2Rgb)
|
|
251
|
+
.unwrap();
|
|
252
|
+
assert_eq!(swapped[0][[1, 3, 0]], image[[1, 3, 2]]);
|
|
253
|
+
assert_eq!(swapped[0][[1, 3, 2]], image[[1, 3, 0]]);
|
|
254
|
+
|
|
255
|
+
let grayscale = sequential
|
|
256
|
+
.batch_cvt_color_optimized(&views, ColorConversionCode::ColorRgb2Gray)
|
|
257
|
+
.unwrap();
|
|
258
|
+
assert_eq!(grayscale[0].dim(), (2, 4, 1));
|
|
259
|
+
|
|
260
|
+
let single_channel = Array3::from_shape_vec((1, 2, 1), vec![25, 200]).unwrap();
|
|
261
|
+
let expanded = sequential
|
|
262
|
+
.batch_cvt_color_optimized(&[single_channel.view()], ColorConversionCode::ColorGray2Rgb)
|
|
263
|
+
.unwrap();
|
|
264
|
+
assert_eq!(expanded[0].dim(), (1, 2, 3));
|
|
265
|
+
assert_eq!(expanded[0][[0, 1, 0]], 200);
|
|
266
|
+
assert!(sequential
|
|
267
|
+
.batch_cvt_color_optimized(&[single_channel.view()], ColorConversionCode::ColorRgb2Gray,)
|
|
268
|
+
.is_err());
|
|
269
|
+
|
|
270
|
+
assert!(sequential
|
|
271
|
+
.batch_resize_optimized(&views, &[], ResizeInterpolation::InterLinear)
|
|
272
|
+
.is_err());
|
|
273
|
+
let resized = sequential
|
|
274
|
+
.batch_resize_optimized(&views, &[(2, 1)], ResizeInterpolation::InterNearest)
|
|
275
|
+
.unwrap();
|
|
276
|
+
assert_eq!(resized[0].dim(), (1, 2, 3));
|
|
277
|
+
|
|
278
|
+
let parallel = OptimizedBatchProcessor {
|
|
279
|
+
use_parallel: true,
|
|
280
|
+
chunk_size: 1,
|
|
281
|
+
};
|
|
282
|
+
let parallel_images = [sample_rgb(4, 4), sample_rgb(4, 4), sample_rgb(4, 4)];
|
|
283
|
+
let parallel_views: Vec<_> = parallel_images.iter().map(|image| image.view()).collect();
|
|
284
|
+
assert_eq!(
|
|
285
|
+
parallel
|
|
286
|
+
.batch_cvt_color_optimized(¶llel_views, ColorConversionCode::ColorRgb2Gray)
|
|
287
|
+
.unwrap()
|
|
288
|
+
.len(),
|
|
289
|
+
3
|
|
290
|
+
);
|
|
291
|
+
let parallel_resized = parallel
|
|
292
|
+
.batch_resize_optimized(
|
|
293
|
+
¶llel_views,
|
|
294
|
+
&[(2, 2), (3, 3), (2, 2)],
|
|
295
|
+
ResizeInterpolation::InterCubic,
|
|
296
|
+
)
|
|
297
|
+
.unwrap();
|
|
298
|
+
assert_eq!(parallel_resized[0].dim(), (2, 2, 3));
|
|
299
|
+
assert_eq!(parallel_resized[1].dim(), (3, 3, 3));
|
|
300
|
+
}
|
|
301
|
+
|
|
302
|
+
#[test]
|
|
303
|
+
fn true_batch_processor_covers_resize_color_and_luminance_paths() {
|
|
304
|
+
let sequential = TrueBatchProcessor {
|
|
305
|
+
use_parallel: false,
|
|
306
|
+
chunk_size: 8,
|
|
307
|
+
simd_threshold: 4,
|
|
308
|
+
};
|
|
309
|
+
let image = sample_rgb(4, 5);
|
|
310
|
+
let views = [image.view()];
|
|
311
|
+
|
|
312
|
+
assert!(sequential
|
|
313
|
+
.true_batch_resize(&[], &[], ResizeInterpolation::InterLinear)
|
|
314
|
+
.unwrap()
|
|
315
|
+
.is_empty());
|
|
316
|
+
#[cfg(feature = "opencv")]
|
|
317
|
+
assert!(sequential
|
|
318
|
+
.true_batch_resize(&views, &[], ResizeInterpolation::InterLinear)
|
|
319
|
+
.is_err());
|
|
320
|
+
|
|
321
|
+
for interpolation in [
|
|
322
|
+
ResizeInterpolation::InterNearest,
|
|
323
|
+
ResizeInterpolation::InterLinear,
|
|
324
|
+
ResizeInterpolation::InterCubic,
|
|
325
|
+
ResizeInterpolation::InterLanczos4,
|
|
326
|
+
] {
|
|
327
|
+
let resized = sequential
|
|
328
|
+
.true_batch_resize(&views, &[(3, 2)], interpolation)
|
|
329
|
+
.unwrap();
|
|
330
|
+
assert_eq!(resized[0].dim(), (2, 3, 3));
|
|
331
|
+
}
|
|
332
|
+
|
|
333
|
+
assert!(sequential
|
|
334
|
+
.true_batch_cvt_color(&[], ColorConversion::BgrToRgb)
|
|
335
|
+
.unwrap()
|
|
336
|
+
.is_empty());
|
|
337
|
+
let swapped = sequential
|
|
338
|
+
.true_batch_cvt_color(&views, ColorConversion::BgrToRgb)
|
|
339
|
+
.unwrap();
|
|
340
|
+
assert_eq!(swapped[0][[0, 0, 0]], image[[0, 0, 2]]);
|
|
341
|
+
assert_eq!(swapped[0][[0, 0, 2]], image[[0, 0, 0]]);
|
|
342
|
+
assert_eq!(
|
|
343
|
+
sequential
|
|
344
|
+
.true_batch_cvt_color(&views, ColorConversion::RgbToBgr)
|
|
345
|
+
.unwrap()[0]
|
|
346
|
+
.dim(),
|
|
347
|
+
image.dim()
|
|
348
|
+
);
|
|
349
|
+
assert_eq!(
|
|
350
|
+
sequential
|
|
351
|
+
.true_batch_cvt_color(&views, ColorConversion::RgbToGray)
|
|
352
|
+
.unwrap()[0]
|
|
353
|
+
.dim(),
|
|
354
|
+
(4, 5, 1)
|
|
355
|
+
);
|
|
356
|
+
assert!(sequential
|
|
357
|
+
.true_batch_cvt_color(&views, ColorConversion::GrayToRgb)
|
|
358
|
+
.is_err());
|
|
359
|
+
|
|
360
|
+
let luminance = sequential.strided_luminance(&views, 0).unwrap();
|
|
361
|
+
assert_eq!(luminance.len(), 1);
|
|
362
|
+
assert!((0.0..=255.0).contains(&luminance[0]));
|
|
363
|
+
let empty_image = Array3::<u8>::zeros((0, 0, 3));
|
|
364
|
+
assert_eq!(
|
|
365
|
+
sequential
|
|
366
|
+
.strided_luminance(&[empty_image.view()], 3)
|
|
367
|
+
.unwrap(),
|
|
368
|
+
vec![0.0]
|
|
369
|
+
);
|
|
370
|
+
let invalid_image = Array3::<u8>::zeros((2, 2, 1));
|
|
371
|
+
assert!(sequential
|
|
372
|
+
.strided_luminance(&[invalid_image.view()], 1)
|
|
373
|
+
.is_err());
|
|
374
|
+
|
|
375
|
+
let parallel = TrueBatchProcessor {
|
|
376
|
+
use_parallel: true,
|
|
377
|
+
chunk_size: 1,
|
|
378
|
+
simd_threshold: 1,
|
|
379
|
+
};
|
|
380
|
+
let parallel_images = [sample_rgb(4, 5), sample_rgb(4, 5)];
|
|
381
|
+
let parallel_views: Vec<_> = parallel_images.iter().map(|image| image.view()).collect();
|
|
382
|
+
assert_eq!(
|
|
383
|
+
parallel
|
|
384
|
+
.strided_luminance(¶llel_views, 2)
|
|
385
|
+
.unwrap()
|
|
386
|
+
.len(),
|
|
387
|
+
2
|
|
388
|
+
);
|
|
389
|
+
}
|
|
390
|
+
|
|
391
|
+
#[test]
|
|
392
|
+
fn compatibility_objects_cover_success_and_error_states() {
|
|
393
|
+
assert_eq!(fourcc('M', 'J', 'P', 'G'), "MJPG");
|
|
394
|
+
|
|
395
|
+
let missing_video = temporary_path("avi");
|
|
396
|
+
let mut capture = VideoCapture::new(missing_video.to_str().unwrap()).unwrap();
|
|
397
|
+
assert!(!capture.is_opened());
|
|
398
|
+
assert_eq!(capture.get(VideoCaptureProperties::CapPropFps), 0.0);
|
|
399
|
+
assert_eq!(capture.get(VideoCaptureProperties::CapPropFrameWidth), 0.0);
|
|
400
|
+
assert_eq!(capture.get(VideoCaptureProperties::CapPropFrameHeight), 0.0);
|
|
401
|
+
assert_eq!(capture.get(VideoCaptureProperties::CapPropFrameCount), 0.0);
|
|
402
|
+
assert_eq!(capture.read(), (false, None));
|
|
403
|
+
capture.release();
|
|
404
|
+
|
|
405
|
+
let image = sample_rgb(2, 3);
|
|
406
|
+
let mut writer = VideoWriter::new("unused.avi", "MJPG", 24.0, (3, 2)).unwrap();
|
|
407
|
+
assert!(writer.is_opened());
|
|
408
|
+
writer.write(&image.view()).unwrap();
|
|
409
|
+
assert!(writer
|
|
410
|
+
.write(&Array3::<u8>::zeros((2, 3, 1)).view())
|
|
411
|
+
.is_err());
|
|
412
|
+
assert!(writer
|
|
413
|
+
.write(&Array3::<u8>::zeros((3, 2, 3)).view())
|
|
414
|
+
.is_err());
|
|
415
|
+
writer.release().unwrap();
|
|
416
|
+
writer.release().unwrap();
|
|
417
|
+
assert!(!writer.is_opened());
|
|
418
|
+
assert!(writer.write(&image.view()).is_err());
|
|
419
|
+
|
|
420
|
+
let missing_cascade = temporary_path("xml");
|
|
421
|
+
let cascade = CascadeClassifier::new(missing_cascade.to_str().unwrap()).unwrap();
|
|
422
|
+
assert!(cascade.empty());
|
|
423
|
+
assert!(cascade
|
|
424
|
+
.detect_multi_scale(&image.view(), 1.1, 3)
|
|
425
|
+
.unwrap()
|
|
426
|
+
.is_empty());
|
|
427
|
+
}
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|