Repository navigation
[java_api] byte[] Tensor, PreProcessSteps normalization ops, indexed output getter + Android CheckJNI fix - #1124
Merged
Conversation
…xed output getter Additions needed to run inference from Kotlin/Java without OpenCV: - Tensor(ElementType, int[] dims, byte[] data): feed a u8 buffer (e.g. an NHWC camera frame) directly, without a native Mat pointer. JNI TensorByte validates the element type (u8/i8) and length. - PreProcessSteps.scale(float|float[]), mean(float|float[]), convert_layout(Layout), convert_element_type(ElementType): push /255 normalization and NHWC->NCHW into the compiled model via PrePostProcessor, so callers supply raw u8 pixels. - InferRequest.get_output_tensor(int index): read multi-output models (e.g. detection + mask prototypes) by index. JNI + hpp declarations included. Tests: TensorTests (byte[] ctor, wrong length/type), PrePostProcessorTests (convert_element_type + scale + convert_layout; per-channel mean/scale), InferRequestTests (indexed getter matches the no-arg getter; bad index). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…oid CheckJNI abort) ArrayList.add returns boolean, but the JNI helpers called it via CallObjectMethod. Desktop JVMs tolerate the mismatch; Android's CheckJNI (default for debuggable apps) aborts: 'JNI DETECTED ERROR IN APPLICATION: the return type of CallObjectMethodV does not match boolean java.util.ArrayList.add'. It triggers as soon as a list-returning API is used on-device (Core.get_available_devices, CompiledModel.inputs/outputs, Model.outputs, Any.asList). Switch all six call sites to CallBooleanMethod. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
- TensorTests.testGetTensorFromByte: a u8 tensor is not int/float pointer- representable, so as_int() throws; verify the byte-array constructor via shape/size/element-type instead (wrong-length/wrong-type cases still cover validation). - PrePostProcessorTests.testScaleAndConvertLayout: derive the NHWC user-tensor spatial size from the model's actual input (net.input().get_shape() = [1,3,32,32]) so set_spatial_static_shape matches; the old hard-coded 2x2 was incompatible with the test model and failed the PrePostProcessor build. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Fix the Code Style (google-java-format) CI check: two javadoc comments in the new Tensor byte[] ctor and PreProcessSteps.scale needed rewrapping per the formatter the CI uses.
…yte, strengthen tests - GetOutputTensor1: allocate the wrapper only after the (throwing) lookup succeeds, so an out-of-range index no longer leaks an ov::Tensor while the exception unwinds through JNI_METHOD (TensorByte already followed this rule). - Add Tensor.as_byte() (Java + JNI, mirroring asInt) so u8/i8 tensors, which are not readable via data()/as_int(), can be round-tripped; guarded to byte-wide element types. - testGetTensorFromByte now round-trips the bytes via as_byte() instead of only checking metadata; add signed-i8 round-trip and as_byte wrong-type tests. - testPerChannelMeanScale now runs inference and asserts the result differs from a no-preprocessing baseline, so a dropped/no-op mean/scale is caught. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Two failures in the Build and Test job: 1. Core.java and PreProcessSteps.java had en/em-dash (U+2013 / U+2014) characters in javadoc. javac runs with -encoding US-ASCII in CI, so these raised "unmappable character" and compilation failed. Replace them with ASCII '-'. 2. testPerChannelMeanScale compared the model output with and without a folded per-channel mean/scale and required them to differ. The test model ends in a saturated one-hot classifier whose result is invariant to input normalization, so the outputs are identical and the assert always failed. Verify the steps are accepted and fused (successful build + infer, correct input element type and shape) instead, matching the approach of testScaleAndConvertLayout. Verified on Windows against a real OpenVINO build: PrePostProcessorTests and the full java_api suite pass. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Contributor
Author
|
@aobolensk please review |
aobolensk
approved these changes
Aug 10, 2026
| * @param model Model object acquired from {@link Core#read_model}. | ||
| * @param device Name of a device to load a model to. | ||
| * @param properties properties – Map of pairs: (property name, property value) relevant only | ||
| * @param properties properties - Map of pairs: (property name, property value) relevant only |
allnes
enabled auto-merge (squash)
August 10, 2026 10:39
alvoron
approved these changes
Aug 10, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Details:
Small additions to the OpenVINO Java bindings so inference can be driven from Kotlin/Java without OpenCV, plus one correctness fix that Android's CheckJNI exposes. Each has JNI + a unit test.
Tensor(ElementType, int[] dims, byte[] data)— feed au8buffer (e.g. an NHWC camera frame) directly; previously only a native pointer (long) orfloat[]/int[]/long[]were accepted, so au8frame needed OpenCV'sMat.dataAddr()or a wasteful float copy. JNITensorBytevalidates element type (u8/i8) and length.PreProcessSteps.scale(float|float[]),mean(float|float[]),convert_layout(Layout),convert_element_type(ElementType)— previously onlyresizewas exposed. Lets/255normalization and NHWC→NCHW be fused into the compiled model viaPrePostProcessor, so callers pass rawu8pixels.InferRequest.get_output_tensor(int index)— read multi-output models (e.g. detection + mask prototypes) by index; the API only had the single-output getter andget_tensor(String).ArrayList.add(returnsboolean) was called viaCallObjectMethodin six JNI helpers. Desktop JVMs tolerate it; Android's CheckJNI aborts the process (the return type of CallObjectMethodV does not match boolean java.util.ArrayList.add) the moment a list-returning API is used (Core.get_available_devices,CompiledModel.inputs/outputs,Model.outputs,Any.asList). Switched toCallBooleanMethod.Tests added/updated under
src/test/java/org/intel/openvino/:TensorTests,PrePostProcessorTests,InferRequestTests.Motivated by a new Android YOLO demo (submitted separately) that uses these APIs, but they are general and useful on their own.