Package com.warelogic.simplelpr — package overview
VideoSource.TrackedPlateCandidate.PlateCandidateTracker: temporal behavior and
thumbnail sizing.ProcessorPool.ProcessorPool.pollNextTrackingResult(int, int) —
the tracking-oriented sibling of PoolResult.PlateCandidateTracker
(or of PlateCandidateTracker.flush()).VideoSource.VideoSource.Counterpart of ICandidate in the .NET wrapper. Following the same
policy as .NET, all candidate data is copied out of the native result as soon
as an analyze* call returns, and the native handles are released
immediately — so this class needs no close() and cannot dangle.
A candidate carries zero or more CountryMatch interpretations.
The last entry in the list corresponds to the raw text before syntax
validation — it carries an empty country/ISO code, and is the reason a plate
usually appears twice in simple listings.
float-1 when the plate region
detection feature is not enabled on the processor
(see Processor.setPlateRegionDetectionEnabled(boolean)).booleantoString()-1 when the plate region
detection feature is not enabled on the processor
(see Processor.setPlateRegionDetectionEnabled(boolean)).getPlateRegionDetectionConfidence()
is greater than 0; otherwise all coordinates are set to -1.Counterpart of ICountryMatch in the .NET wrapper. All data is copied
out of the native result at analysis time, so instances carry no native
resources and never need disposing — they can be stored, logged or passed
between threads freely.
floatElement.getConfidence()).getText()toString()Candidate.getMatches()).Element.getConfidence()). A ranking value in [0, 1], not a
probability.Java note: the returned list is unmodifiable — calling add or
remove on it throws UnsupportedOperationException. This is
the standard Java way of exposing read-only collections (the analog of
IReadOnlyList<T> in .NET).
Counterpart of SIMPLELPR_Element / the .NET Element struct.
Elements are listed by CountryMatch.getElements() in the same order as
they appear in the plate text; to know the physical layout, use each element's
bounding box.
Java counterpart of EngineSetupParms in the .NET wrapper. When a
CUDA-compatible GPU is available it can be selected to off-load computation
intensive tasks from the CPU; image processing and text candidate
classification can be moved to the GPU independently. Since some of the image
processing algorithms are memory consuming, the maximum number of concurrent
image processing operations can also be capped. Defaults select CPU-only
operation with the recommended concurrency.
EngineSetupParams params = new EngineSetupParams(); // CPU, recommended settings
try (SimpleLPR lpr = SimpleLPR.setup(params)) {
...
}
int-1: use the CPU (default).intbooleanbooleansetCudaDeviceId(int cudaDeviceId) setEnableClassificationWithGPU(boolean value) setEnableImageProcessingWithGPU(boolean value) setMaxConcurrentImageProcessingOps(int value) -1: use the CPU (default). Otherwise: the CUDA device identifier —
usually 0 corresponds to the default device.0 (default) selects the recommended
value for each case.Serializable, Comparable<FrameFormat>VideoSource.
Counterpart of SIMPLELPR_FrameFormat.static FrameFormatstatic FrameFormat[]values()name - the name of the enum constant to be returned.IllegalArgumentException - if this enum type has no constant with the specified nameNullPointerException - if the argument is nullAutoCloseableTrackedPlateCandidate.
The temporal correlation is resistant to OCR misreadings and partial
detections — occasional bad frames are absorbed into the track instead of
producing spurious reads.
Counterpart of IPlateCandidateTracker in the .NET wrapper. Create
instances with SimpleLPR.createPlateCandidateTracker(com.warelogic.simplelpr.PlateCandidateTrackerSetupParams). Feed it every
analyzed frame's result in presentation order via
processFrameCandidates(PoolTrackingResult, VideoFrame), and call
flush() at end of stream to close whatever is still being tracked.
The tracker is single-stream and not thread-safe: feed it from one thread
(typically the same loop that polls the pool).
voidclose()flush()processFrameCandidates(long frameId,
double timestampInSec,
PoolTrackingResult result) processFrameCandidates(PoolTrackingResult result,
VideoFrame frame) result - the tracking-oriented pool result (must be successful and
still open — pass it here before closing it)frame - the frame the result was computed from (still open)close in interface AutoCloseablePlateCandidateTracker: temporal behavior and
thumbnail sizing. Counterpart of PlateCandidateTrackerSetupParms in
the .NET wrapper, with the same defaults.floatintintintfloatsetMaxIdleTimeInSec(float value) setMinTriggerFrameCount(int value) setThumbnailHeight(int value) setThumbnailWidth(int value) setTriggerWindowInSec(float value) Counterpart of SIMPLELPR_Point. Defined here rather than reusing
java.awt.Point to keep the wrapper free of the desktop (AWT) module,
which matters for server deployments.
ProcessorPool.
Immutable snapshot: all data is copied out of the native result at poll time
and the native handles are released before pollNextResult returns.
Counterpart of IProcessorPoolResult in the .NET wrapper. A result is
either a success — getCandidates() holds the recognition outcome — or a
failure — getError() describes what went wrong for that request (for
example, an unreadable image file). Per-request failures are reported here
rather than thrown, so one bad image does not abort a batch.
getError()null on success.longintlaunchAnalyze*).doublebooleantoString()launchAnalyze*).launchAnalyze* calls; the request id is what correlates
results across streams and back to their inputs.
Java note: exposed as long because the native type is an
unsigned 32-bit integer and Java has no unsigned int;
values above 2³¹−1 would otherwise print as negative numbers.
null on success. Not thrown — inspect it.AutoCloseableProcessorPool.pollNextTrackingResult(int, int) —
the tracking-oriented sibling of PoolResult.
Why two result types? The PlateCandidateTracker consumes recognition
results natively, so this result must keep the native candidates
handle alive until it has been fed to the tracker. That makes it the mirror
of the .NET IProcessorPoolResult (which is IDisposable for the
same reason), and it is why this class — unlike PoolResult — is
AutoCloseable: close it after passing it to the tracker,
ideally with try-with-resources. When no tracking is involved, use the plain
pollNextResult and never think about disposal.
voidclose()getError()null on success.longPoolResult.getRequestId() on why long).intdoublebooleanPoolResult.getRequestId() on why long).null on success. Not thrown — inspect it.close in interface AutoCloseableAutoCloseableCounterpart of IProcessor in the .NET wrapper. Create instances with
SimpleLPR.createProcessor(); each processor analyzes one image at a time,
so use one processor per thread (or, in a later increment, a processor pool).
Like the engine, a processor owns a native handle: release it with
close(), ideally via try-with-resources (the Java analog of C#'s
using block):
try (Processor proc = lpr.createProcessor()) {
List<Candidate> candidates = proc.analyzeFile(Paths.get("car.jpg"));
for (Candidate c : candidates)
for (CountryMatch m : c.getMatches())
System.out.println(m.getText() + " [" + m.getCountryISO() + "]");
}
Results are returned as immutable Candidate snapshots: every value is
copied out of the native result and the native handles are released before the
analyze* method returns (same eager-release policy as the .NET wrapper),
so result objects never require disposal.
Disposal ordering note: the native layer is ordering-tolerant as of 3.6.4, so closing the engine before its processors is safe, though closing children first remains the tidy pattern the samples demonstrate.
analyzeC3(byte[] pixels,
int widthStep,
int width,
int height,
float weight0,
float weight1,
float weight2) analyzeC3(ByteBuffer, int, int, int, float, float, float) for heap arrays.analyzeC3(ByteBuffer pixels,
int widthStep,
int width,
int height,
float weight0,
float weight1,
float weight2) analyzeC4(byte[] pixels,
int widthStep,
int width,
int height,
float weight0,
float weight1,
float weight2) analyzeC4(ByteBuffer, int, int, int, float, float, float) for heap arrays.analyzeC4(ByteBuffer pixels,
int widthStep,
int width,
int height,
float weight0,
float weight1,
float weight2) analyzeEncodedImage(byte[] encodedImage) analyzeFile(Path imagePath) analyzeGray8(byte[] pixels,
int widthStep,
int width,
int height) analyzeGray8(ByteBuffer, int, int, int) for heap arrays.analyzeGray8(ByteBuffer pixels,
int widthStep,
int width,
int height) analyzeVideoFrame(VideoFrame frame) analyzeVideoFrame(VideoFrame frame,
Rect regionOfInterest) null region
analyzes the whole frame.voidclose()floatfloatgetCountryWeight(String countryCode) booleanbooleanvoidvoidsetContrastSensitivityFactor(float factor) voidsetCountryWeight(String countryCode,
float weight) voidsetCropToPlateRegionEnabled(boolean enabled) voidsetPlateRegionDetectionEnabled(boolean enabled) countryCode - the country string identifier
(see SimpleLPR.getSupportedCountries())realizeCountryWeights() once configuration is complete.weight - the desired weight, ≥ 0; a zero weight effectively disables
the countryanalyze* method.Candidate.getPlateRegionDetectionConfidence() and region vertices.This is the Java analog of the .NET IntPtr overloads: a
direct ByteBuffer (e.g. obtained from a camera SDK,
OpenCV, or VideoFrame.getDataBuffer()) is passed to the native
side by address, with zero copying. Array-backed buffers work too. Pixels
are read starting at the buffer's current position (widthStep ×
height bytes); the position itself is not modified.
The image must be top-down: the top row of the image is the first row in memory, followed by the next row down.
pixels - the first image row, one byte per pixelwidthStep - distance in bytes between starts of consecutive rows
(≥ width; allows padded rows)analyzeGray8(ByteBuffer, int, int, int) for heap arrays.L = weight0*C0 + weight1*C1 + weight2*C2:
for RGB data use (0.299f, 0.587f, 0.114f), for BGR data
(0.114f, 0.587f, 0.299f). Direct buffers are passed zero-copy;
see analyzeGray8(ByteBuffer, int, int, int).analyzeC3(ByteBuffer, int, int, int, float, float, float) for heap arrays.analyzeC3(ByteBuffer, int, int, int, float, float, float).
Direct buffers are passed zero-copy.analyzeC4(ByteBuffer, int, int, int, float, float, float) for heap arrays.null region
analyzes the whole frame.close in interface AutoCloseableAutoCloseableCounterpart of IProcessorPool in the .NET wrapper. Create instances
with SimpleLPR.createProcessorPool(int). Requests are submitted with the
launchAnalyze* methods and results collected with
pollNextResult(int, int); results may arrive in any order, so callers
correlate them through the request id they supplied at launch. The canonical
batch pattern (identical to the .NET samples):
try (ProcessorPool pool = lpr.createProcessorPool(poolSize)) {
long requestId = 0;
for (Path image : images) {
pool.launchAnalyzeFile(0, requestId++, 0.0, ProcessorPool.TIMEOUT_INFINITE, image);
// Drain whatever is already done, without blocking:
for (PoolResult r; (r = pool.pollNextResult(0, ProcessorPool.TIMEOUT_IMMEDIATE)) != null; )
handle(r);
}
// All submitted; wait for the stragglers:
while (pool.getOngoingRequestCount(0) > 0)
handle(pool.pollNextResult(0, ProcessorPool.TIMEOUT_INFINITE));
}
Stream ids partition the pool's queues: requests and results with different stream ids never mix, which lets independent producers (e.g. two cameras) share one pool. Single-source applications simply use stream 0 throughout.
static final intpollNextResult(int, int),
pollNextTrackingResult(int, int) or getOngoingRequestCount(int),
results/requests from ALL streams are considered.static final intstatic final intvoidclose()floatfloatgetCountryWeight(String countryCode) intgetOngoingRequestCount(int streamId) booleanbooleanbooleanlaunchAnalyzeC3(int streamId,
long requestId,
double timestampInSec,
int timeoutInMs,
byte[] pixels,
int widthStep,
int width,
int height,
float weight0,
float weight1,
float weight2) booleanlaunchAnalyzeC3(int streamId,
long requestId,
double timestampInSec,
int timeoutInMs,
ByteBuffer pixels,
int widthStep,
int width,
int height,
float weight0,
float weight1,
float weight2) booleanlaunchAnalyzeC4(int streamId,
long requestId,
double timestampInSec,
int timeoutInMs,
byte[] pixels,
int widthStep,
int width,
int height,
float weight0,
float weight1,
float weight2) booleanlaunchAnalyzeC4(int streamId,
long requestId,
double timestampInSec,
int timeoutInMs,
ByteBuffer pixels,
int widthStep,
int width,
int height,
float weight0,
float weight1,
float weight2) booleanlaunchAnalyzeEncodedImage(int streamId,
long requestId,
double timestampInSec,
int timeoutInMs,
byte[] encodedImage) booleanlaunchAnalyzeFile(int streamId,
long requestId,
double timestampInSec,
int timeoutInMs,
Path imagePath) booleanlaunchAnalyzeGray8(int streamId,
long requestId,
double timestampInSec,
int timeoutInMs,
byte[] pixels,
int widthStep,
int width,
int height) launchAnalyzeGray8(int, long, double, int, ByteBuffer, int, int, int) for heap arrays.booleanlaunchAnalyzeGray8(int streamId,
long requestId,
double timestampInSec,
int timeoutInMs,
ByteBuffer pixels,
int widthStep,
int width,
int height) widthStep bytes).booleanlaunchAnalyzeVideoFrame(int streamId,
long requestId,
int timeoutInMs,
VideoFrame frame,
Rect regionOfInterest) pollNextResult(int streamId,
int timeoutInMs) pollNextTrackingResult(int streamId,
int timeoutInMs) pollNextResult(int, int): the returned result
retains the native candidates handle so it can be fed to a
PlateCandidateTracker, and must therefore be closed after use —
see PoolTrackingResult.voidvoidsetContrastSensitivityFactor(float factor) voidsetCountryWeight(String countryCode,
float weight) voidsetCropToPlateRegionEnabled(boolean enabled) voidsetPlateRegionDetectionEnabled(boolean enabled) pollNextResult(int, int),
pollNextTrackingResult(int, int) or getOngoingRequestCount(int),
results/requests from ALL streams are considered.realizeCountryWeights() afterwards.streamId - stream identifier grouping related requestsrequestId - caller-chosen identifier returned with the result;
keep it unique among in-flight requests of a streamtimestampInSec - timestamp of the image, in secondstimeoutInMs - how long to wait for a free processor:
TIMEOUT_IMMEDIATE, TIMEOUT_INFINITE,
or a maximum wait in millisecondsencodedImage - the encoded image byteswidthStep bytes).
The native side reads the pixels when a worker thread processes the
request, not during this call. A direct ByteBuffer is
passed by address, zero-copy (the Java analog of the .NET IntPtr
overloads); the wrapper retains a reference until the matching result is
polled, so the buffer cannot be reclaimed early — but its contents must
not be modified until then. Heap and wrapped buffers are copied at launch
into wrapper-owned native memory and may be reused immediately.
streamId - stream identifier grouping related requestsrequestId - caller-chosen identifier returned with the result;
keep it unique among in-flight requests of a streamtimestampInSec - timestamp of the image, in secondstimeoutInMs - how long to wait for a free processor:
TIMEOUT_IMMEDIATE, TIMEOUT_INFINITE,
or a maximum wait in millisecondspixels - the first image row, one byte per pixel, read from
the buffer's current position (position unchanged)widthStep - distance in bytes between starts of consecutive rowswidth - image width in pixelsheight - image height in pixelslaunchAnalyzeGray8(int, long, double, int, ByteBuffer, int, int, int) for heap arrays.L = weight0*C0 + weight1*C1 + weight2*C2: for RGB data use
(0.299f, 0.587f, 0.114f), for BGR data
(0.114f, 0.587f, 0.299f). Buffer lifetime works as in
launchAnalyzeGray8(int, long, double, int, ByteBuffer, int, int, int):
direct buffers are zero-copy and must stay unmodified until the result is
polled; other buffers are copied at launch.weight0 - weight of the first color channelweight1 - weight of the second color channelweight2 - weight of the third color channellaunchAnalyzeC3(int, long, double, int, ByteBuffer, int, int, int, float, float, float).VideoFrame as usual once the launch returns.
A null region of interest analyzes the whole frame.Within each stream, results are returned in the same order as their
corresponding launchAnalyze* calls.
streamId - the stream to poll, or STREAM_ID_ANY to
retrieve results from any streamtimeoutInMs - TIMEOUT_IMMEDIATE, TIMEOUT_INFINITE,
or a maximum wait in millisecondsnull when no result became
available within the timeout.pollNextResult(int, int): the returned result
retains the native candidates handle so it can be fed to a
PlateCandidateTracker, and must therefore be closed after use —
see PoolTrackingResult. Returns null on timeout.streamId - the stream to count, or STREAM_ID_ANY for the
total across all streamsclose in interface AutoCloseableCounterpart of SIMPLELPR_Rect / the .NET wrapper's rectangle type.
AutoCloseableJava counterpart of ISimpleLPR / SimpleLPRImpl in the .NET
wrapper. Instances are created through the static setup(EngineSetupParams)
factory methods and own a native engine handle; release it deterministically with
close(), ideally through try-with-resources:
try (SimpleLPR lpr = SimpleLPR.setup(new EngineSetupParams())) {
System.out.println("SimpleLPR version " + lpr.getVersionNumber());
}
A Cleaner releases the native handle as a safety net if close()
is never invoked, but — as with the .NET wrapper's finalizers — deterministic
disposal is the supported pattern.
voidclose()createProcessorPool(0).createProcessorPool(int processorCount) getCountryCode(int id) floatgetCountryWeight(String countryCode) intopenVideoSource(String uri,
FrameFormat format,
int maxWidthCap,
int maxHeightCap) voidvoidsetCountryWeight(String countryCode,
float weight) voidsetProductKey(Path productKeyPath) static SimpleLPRsetup(EngineSetupParams params) static SimpleLPRsetup(EngineSetupParams params,
Path nativeFolderPath) ISimpleLPR.Setup(sNativeFolderPath, parms)
in the .NET wrapper.nativeFolderPath - folder containing the SimpleLPR native library
(either directly or under runtimes/<rid>/native).countryCode - the country string identifier
(see getSupportedCountries())realizeCountryWeights() once configuration is complete.weight - the desired weight, ≥ 0; a zero weight effectively disables
the countryanalyze* method.The processor inherits the engine's current country weights; per-processor
overrides are possible through Processor.setCountryWeight(java.lang.String, float). Close it
when done (try-with-resources).
createProcessorPool(0).processorCount - number of concurrent processors; 0 sizes the
pool automatically from the available CPU cores.uri - e.g. "traffic.mp4" or "rtsp://camera/stream"format - pixel format frames will be delivered in; FrameFormat.GRAY8
is cheapest when frames are only analyzedmaxWidthCap - maximum delivered frame width, or -1 for uncapped
(larger frames are isotropically downscaled)maxHeightCap - maximum delivered frame height, or -1 for uncappedclose in interface AutoCloseableSerializableCarries the native SIMPLELPR_HRESULT error code when one is available
(see IErrorInfo in the C API); hasErrorCode() tells whether
getErrorCode() is meaningful.
SimpleLPRException(int errorCode,
String message) SimpleLPRException(String message) inthasErrorCode().booleanaddSuppressed, fillInStackTrace, getCause, getLocalizedMessage, getMessage, getStackTrace, getSuppressed, initCause, printStackTrace, printStackTrace, printStackTrace, setStackTrace, toStringhasErrorCode().AutoCloseableCounterpart of ITrackedPlateCandidate in the .NET wrapper. All scalar
data and the representative Candidate are eager snapshots; the one live
resource is getRepresentativeThumbnail() — a VideoFrame holding
the cropped plate image — which is why this class is AutoCloseable
(closing it closes the thumbnail). Save or copy
the thumbnail before closing if you need it afterwards.
voidclose()null — a convenience.longdoublelongdoublelongnull.doublenull.
Owned by this object: valid until close(). Use
VideoFrame.saveAsJPEG(java.nio.file.Path, int) or VideoFrame.copyData() to keep it.null — a convenience.close in interface AutoCloseableAutoCloseablePlateCandidateTracker
(or of PlateCandidateTracker.flush()).
Counterpart of IPlateCandidateTrackerResult in the .NET wrapper.
getNewTracks() lists plates whose trigger conditions were just met;
getClosedTracks() lists tracks that just ended. Both are usually empty
— results with content are the events an application reacts to.
AutoCloseable because each contained TrackedPlateCandidate
owns a live thumbnail frame; closing the result closes them all (individually
idempotent, so closing a track twice is harmless).
close in interface AutoCloseableJava counterpart of VersionNumber in the .NET wrapper. (A plain class
rather than a record: the wrapper targets Java 11.)
AutoCloseableVideoSource.
Counterpart of IVideoFrame in the .NET wrapper — and, deliberately,
the one object in this wrapper that is not an eager snapshot: a frame
wraps the native pixel buffer directly, because copying every frame of a video
stream would be prohibitively expensive.
Each open frame pins megabytes of native memory that the Java
garbage collector cannot see: unlike .NET (whose wrapper calls
GC.AddMemoryPressure), the JVM offers no way to report native
allocations, so nothing nudges the GC to collect forgotten frames. Always
close each frame as soon as it has been used — the standard shape is a
try-with-resources around every frame, as the video samples demonstrate:
for (VideoFrame frame; (frame = source.nextFrame()) != null; ) {
try (VideoFrame f = frame) { // guarantees close, even on exceptions
process(proc.analyzeVideoFrame(f));
}
}
A Cleaner releases leaked frames eventually, but only when the GC
happens to run — treat it strictly as a safety net.
voidclose()byte[]copyData()close().getWidthStep() × getHeight() bytes, row-major).getDataBuffer().intlongdoubleintgetWidth()intvoidsaveAsJPEG(Path imagePath,
int quality) getDataBuffer().getWidthStep() × getHeight() bytes, row-major).
The view is valid only while this frame is open. It
points straight into native memory; touching it after close()
is undefined behavior (at best garbage, at worst a JVM crash). Copy what
you need — e.g. with copyData() — if it must outlive the frame.
close().quality - JPEG quality: either -1 (default quality) or a value in
the 0..100 rangeclose in interface AutoCloseableAutoCloseableCounterpart of IVideoSource in the .NET wrapper. Create instances
with SimpleLPR.openVideoSource(java.lang.String, com.warelogic.simplelpr.FrameFormat, int, int); pull frames with nextFrame()
until it returns null, then consult getState() to distinguish
a normal end of stream (VideoSourceState.EOF) from an error. Live
sources that hit an I/O error can be revived with reconnect().
Every frame returned by nextFrame() is owned by the caller and
must be closed promptly — see the class comment of VideoFrame for why
this matters more in Java than it did in .NET.
voidclose()getState()nextFrame() returns null.booleannull when none is available — end of stream or
error; use getState() to tell which.booleanVideoSourceState.EOF or VideoSourceState.IO_ERROR state.nextFrame() returns null.null when none is available — end of stream or
error; use getState() to tell which. The returned frame is owned
by the caller: close it as soon as it has been used.VideoSourceState.EOF or VideoSourceState.IO_ERROR state.
Has no effect for file-based sources. Returns true on success.close in interface AutoCloseableSerializable, Comparable<VideoSourceState>VideoSource.
Counterpart of SimpleLPR_VideoSourceState.static VideoSourceStatestatic VideoSourceState[]values()reconnected).name - the name of the enum constant to be returned.IllegalArgumentException - if this enum type has no constant with the specified nameNullPointerException - if the argument is null