drawdown-arcore-depth 0.1.4 → 0.1.5
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.
- package/README.md +5 -0
- package/android/src/main/java/org/drawdown/arcoredepth/DepthObservationSampler.java +105 -25
- package/android/src/main/java/org/drawdown/arcoredepth/DepthSampleResult.java +64 -0
- package/android/src/main/java/org/drawdown/arcoredepth/DrawDownArCoreDepthPlugin.java +86 -9
- package/dist/esm/definitions.d.ts +12 -0
- package/package.json +2 -2
package/README.md
CHANGED
|
@@ -188,3 +188,8 @@ No ArUco marker is required by the native ARCore workflow. The existing RFID/NFC
|
|
|
188
188
|
## v0.1.4 Raw Depth field fix
|
|
189
189
|
|
|
190
190
|
The DBH sampler now anchors front-surface range with ARCore Raw Depth plus the matching confidence image (confidence >= 128). Smoothed Depth is used only after a high-confidence foreground tree range has been established, to fill the trunk surface for multi-row boundary estimation. This prevents distant outdoor background depth from being mistaken for the trunk.
|
|
191
|
+
|
|
192
|
+
|
|
193
|
+
## 0.1.5 diagnostic sweep
|
|
194
|
+
|
|
195
|
+
Version 0.1.5 keeps the 0.1.4 Raw Depth DBH acceptance geometry unchanged and adds compact native sweep diagnostics. `captureDbhSweep()` now reports per-stage frame counts and `nativeRejectionCounts` so zero-observation field failures can be diagnosed without retaining camera or depth frames.
|
|
@@ -39,29 +39,69 @@ final class DepthObservationSampler {
|
|
|
39
39
|
private static final double MIN_TARGET_DEPTH_MM = 500.0;
|
|
40
40
|
private static final double MAX_TARGET_DEPTH_MM = 5000.0;
|
|
41
41
|
|
|
42
|
-
|
|
42
|
+
DepthSampleResult sample(Frame frame, Camera camera, int viewWidth, int viewHeight) {
|
|
43
|
+
boolean trackingFrame = false;
|
|
44
|
+
boolean rawDepthFrame = false;
|
|
45
|
+
boolean mappedCenterReached = false;
|
|
46
|
+
boolean rawAnchorReached = false;
|
|
47
|
+
boolean rawPatchReached = false;
|
|
48
|
+
boolean smoothDepthMatchReached = false;
|
|
49
|
+
boolean boundaryConsensusReached = false;
|
|
50
|
+
|
|
43
51
|
if (camera.getTrackingState() != TrackingState.TRACKING) {
|
|
44
|
-
return
|
|
52
|
+
return DepthSampleResult.failure(
|
|
53
|
+
"tracking_not_tracking",
|
|
54
|
+
false, false, false, false, false, false, false);
|
|
45
55
|
}
|
|
56
|
+
trackingFrame = true;
|
|
57
|
+
|
|
58
|
+
Image rawDepth = null;
|
|
59
|
+
Image rawConfidence = null;
|
|
60
|
+
Image smoothDepth = null;
|
|
61
|
+
try {
|
|
62
|
+
try {
|
|
63
|
+
rawDepth = frame.acquireRawDepthImage16Bits();
|
|
64
|
+
rawDepthFrame = true;
|
|
65
|
+
} catch (NotYetAvailableException e) {
|
|
66
|
+
return DepthSampleResult.failure(
|
|
67
|
+
"raw_depth_not_yet_available",
|
|
68
|
+
trackingFrame, false, false, false, false, false, false);
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
try {
|
|
72
|
+
rawConfidence = frame.acquireRawDepthConfidenceImage();
|
|
73
|
+
} catch (NotYetAvailableException e) {
|
|
74
|
+
return DepthSampleResult.failure(
|
|
75
|
+
"raw_confidence_not_available",
|
|
76
|
+
trackingFrame, rawDepthFrame, false, false, false, false, false);
|
|
77
|
+
}
|
|
46
78
|
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
79
|
+
try {
|
|
80
|
+
smoothDepth = frame.acquireDepthImage16Bits();
|
|
81
|
+
} catch (NotYetAvailableException e) {
|
|
82
|
+
return DepthSampleResult.failure(
|
|
83
|
+
"smooth_depth_not_available",
|
|
84
|
+
trackingFrame, rawDepthFrame, false, false, false, false, false);
|
|
85
|
+
}
|
|
51
86
|
|
|
52
87
|
CameraIntrinsics intrinsics = camera.getImageIntrinsics();
|
|
53
88
|
float[] focal = intrinsics.getFocalLength();
|
|
54
89
|
int[] imageDimensions = intrinsics.getImageDimensions();
|
|
55
90
|
if (focal == null || focal.length < 2 || imageDimensions == null || imageDimensions.length < 2) {
|
|
56
|
-
return
|
|
91
|
+
return DepthSampleResult.failure(
|
|
92
|
+
"image_intrinsics_missing",
|
|
93
|
+
trackingFrame, rawDepthFrame, false, false, false, false, false);
|
|
57
94
|
}
|
|
58
95
|
|
|
59
|
-
//
|
|
96
|
+
// Keep the 0.1.4 geometry assumptions unchanged; 0.1.5 only makes
|
|
97
|
+
// failures observable instead of silently returning null.
|
|
60
98
|
if (rawDepth.getWidth() != rawConfidence.getWidth()
|
|
61
99
|
|| rawDepth.getHeight() != rawConfidence.getHeight()
|
|
62
100
|
|| rawDepth.getWidth() != smoothDepth.getWidth()
|
|
63
101
|
|| rawDepth.getHeight() != smoothDepth.getHeight()) {
|
|
64
|
-
return
|
|
102
|
+
return DepthSampleResult.failure(
|
|
103
|
+
"image_size_mismatch",
|
|
104
|
+
trackingFrame, rawDepthFrame, false, false, false, false, false);
|
|
65
105
|
}
|
|
66
106
|
|
|
67
107
|
float[] viewCenter = new float[] { viewWidth / 2f, viewHeight / 2f };
|
|
@@ -74,13 +114,19 @@ final class DepthObservationSampler {
|
|
|
74
114
|
|
|
75
115
|
int[] mappedCenter = imageToDepth(frame, rawDepth, imageCenter[0], imageCenter[1]);
|
|
76
116
|
if (mappedCenter == null) {
|
|
77
|
-
return
|
|
117
|
+
return DepthSampleResult.failure(
|
|
118
|
+
"image_to_depth_mapping_failed",
|
|
119
|
+
trackingFrame, rawDepthFrame, false, false, false, false, false);
|
|
78
120
|
}
|
|
121
|
+
mappedCenterReached = true;
|
|
79
122
|
|
|
80
123
|
RawAnchor anchor = findRawAnchor(rawDepth, rawConfidence, mappedCenter[0], mappedCenter[1]);
|
|
81
124
|
if (anchor == null) {
|
|
82
|
-
return
|
|
125
|
+
return DepthSampleResult.failure(
|
|
126
|
+
"no_confident_raw_anchor",
|
|
127
|
+
trackingFrame, rawDepthFrame, mappedCenterReached, false, false, false, false);
|
|
83
128
|
}
|
|
129
|
+
rawAnchorReached = true;
|
|
84
130
|
|
|
85
131
|
double rawToleranceMm = clamp(anchor.depthMm * 0.10, 100.0, 250.0);
|
|
86
132
|
List<Integer> rawPatch = collectConfidentRawPatch(
|
|
@@ -92,13 +138,18 @@ final class DepthObservationSampler {
|
|
|
92
138
|
rawToleranceMm,
|
|
93
139
|
anchor.depthMm);
|
|
94
140
|
if (rawPatch.size() < MIN_RAW_PATCH_SAMPLES) {
|
|
95
|
-
return
|
|
141
|
+
return DepthSampleResult.failure(
|
|
142
|
+
"insufficient_raw_patch_samples",
|
|
143
|
+
trackingFrame, rawDepthFrame, mappedCenterReached, rawAnchorReached, false, false, false);
|
|
96
144
|
}
|
|
145
|
+
rawPatchReached = true;
|
|
97
146
|
|
|
98
147
|
double centerDepthMm = median(rawPatch);
|
|
99
148
|
double centerMadMm = mad(rawPatch, centerDepthMm);
|
|
100
149
|
if (centerDepthMm < MIN_TARGET_DEPTH_MM || centerDepthMm > MAX_TARGET_DEPTH_MM) {
|
|
101
|
-
return
|
|
150
|
+
return DepthSampleResult.failure(
|
|
151
|
+
"target_depth_out_of_range",
|
|
152
|
+
trackingFrame, rawDepthFrame, mappedCenterReached, rawAnchorReached, rawPatchReached, false, false);
|
|
102
153
|
}
|
|
103
154
|
|
|
104
155
|
// Locate the foreground surface in the smoothed depth image, but only
|
|
@@ -111,8 +162,11 @@ final class DepthObservationSampler {
|
|
|
111
162
|
centerDepthMm,
|
|
112
163
|
clamp(centerDepthMm * 0.10, 100.0, 250.0));
|
|
113
164
|
if (centerX < 0) {
|
|
114
|
-
return
|
|
165
|
+
return DepthSampleResult.failure(
|
|
166
|
+
"no_smooth_depth_match",
|
|
167
|
+
trackingFrame, rawDepthFrame, mappedCenterReached, rawAnchorReached, rawPatchReached, false, false);
|
|
115
168
|
}
|
|
169
|
+
smoothDepthMatchReached = true;
|
|
116
170
|
|
|
117
171
|
double toleranceMm = clamp(centerDepthMm * 0.08, 80.0, 220.0);
|
|
118
172
|
Boundary boundary = findConsensusBoundary(
|
|
@@ -122,28 +176,41 @@ final class DepthObservationSampler {
|
|
|
122
176
|
centerDepthMm,
|
|
123
177
|
toleranceMm);
|
|
124
178
|
if (boundary == null || boundary.rightX - boundary.leftX < 3) {
|
|
125
|
-
return
|
|
179
|
+
return DepthSampleResult.failure(
|
|
180
|
+
"boundary_no_consensus",
|
|
181
|
+
trackingFrame, rawDepthFrame, mappedCenterReached, rawAnchorReached, rawPatchReached, smoothDepthMatchReached, false);
|
|
126
182
|
}
|
|
183
|
+
boundaryConsensusReached = true;
|
|
127
184
|
|
|
128
185
|
int depthWidth = smoothDepth.getWidth();
|
|
129
186
|
int boundaryWidth = boundary.rightX - boundary.leftX;
|
|
130
187
|
if (boundary.leftX <= EDGE_MARGIN_PX
|
|
131
|
-
|| boundary.rightX >= depthWidth - 1 - EDGE_MARGIN_PX
|
|
132
|
-
|
|
133
|
-
|
|
188
|
+
|| boundary.rightX >= depthWidth - 1 - EDGE_MARGIN_PX) {
|
|
189
|
+
return DepthSampleResult.failure(
|
|
190
|
+
"boundary_touches_edge",
|
|
191
|
+
trackingFrame, rawDepthFrame, mappedCenterReached, rawAnchorReached, rawPatchReached, smoothDepthMatchReached, boundaryConsensusReached);
|
|
192
|
+
}
|
|
193
|
+
if (boundaryWidth > depthWidth * MAX_TRUNK_WIDTH_FRACTION) {
|
|
194
|
+
return DepthSampleResult.failure(
|
|
195
|
+
"boundary_too_wide",
|
|
196
|
+
trackingFrame, rawDepthFrame, mappedCenterReached, rawAnchorReached, rawPatchReached, smoothDepthMatchReached, boundaryConsensusReached);
|
|
134
197
|
}
|
|
135
198
|
|
|
136
199
|
float[] leftImage = depthToImage(frame, smoothDepth, boundary.leftX, anchor.y);
|
|
137
200
|
float[] rightImage = depthToImage(frame, smoothDepth, boundary.rightX, anchor.y);
|
|
138
201
|
if (leftImage == null || rightImage == null) {
|
|
139
|
-
return
|
|
202
|
+
return DepthSampleResult.failure(
|
|
203
|
+
"depth_to_image_mapping_failed",
|
|
204
|
+
trackingFrame, rawDepthFrame, mappedCenterReached, rawAnchorReached, rawPatchReached, smoothDepthMatchReached, boundaryConsensusReached);
|
|
140
205
|
}
|
|
141
206
|
|
|
142
207
|
double dx = rightImage[0] - leftImage[0];
|
|
143
208
|
double dy = rightImage[1] - leftImage[1];
|
|
144
209
|
double imageWidthPx = Math.hypot(dx, dy);
|
|
145
210
|
if (!Double.isFinite(imageWidthPx) || imageWidthPx < 8.0) {
|
|
146
|
-
return
|
|
211
|
+
return DepthSampleResult.failure(
|
|
212
|
+
"image_width_too_small",
|
|
213
|
+
trackingFrame, rawDepthFrame, mappedCenterReached, rawAnchorReached, rawPatchReached, smoothDepthMatchReached, boundaryConsensusReached);
|
|
147
214
|
}
|
|
148
215
|
|
|
149
216
|
double normalizedAngularWidth = Math.sqrt(
|
|
@@ -152,7 +219,9 @@ final class DepthObservationSampler {
|
|
|
152
219
|
if (!Double.isFinite(normalizedAngularWidth)
|
|
153
220
|
|| normalizedAngularWidth <= 0.0
|
|
154
221
|
|| normalizedAngularWidth > 0.95) {
|
|
155
|
-
return
|
|
222
|
+
return DepthSampleResult.failure(
|
|
223
|
+
"angular_width_invalid",
|
|
224
|
+
trackingFrame, rawDepthFrame, mappedCenterReached, rawAnchorReached, rawPatchReached, smoothDepthMatchReached, boundaryConsensusReached);
|
|
156
225
|
}
|
|
157
226
|
|
|
158
227
|
double effectiveFocalPx = imageWidthPx / normalizedAngularWidth;
|
|
@@ -178,7 +247,7 @@ final class DepthObservationSampler {
|
|
|
178
247
|
boundaryConfidence = "low";
|
|
179
248
|
}
|
|
180
249
|
|
|
181
|
-
|
|
250
|
+
DepthObservation observation = new DepthObservation(
|
|
182
251
|
centerDepthMm / 1000.0,
|
|
183
252
|
effectiveFocalPx,
|
|
184
253
|
imageWidthPx,
|
|
@@ -187,10 +256,21 @@ final class DepthObservationSampler {
|
|
|
187
256
|
boundaryConfidence,
|
|
188
257
|
centerMadMm / 1000.0,
|
|
189
258
|
System.currentTimeMillis());
|
|
190
|
-
|
|
191
|
-
return null;
|
|
259
|
+
return DepthSampleResult.success(observation);
|
|
192
260
|
} catch (Exception e) {
|
|
193
|
-
return
|
|
261
|
+
return DepthSampleResult.failure(
|
|
262
|
+
"unexpected_exception",
|
|
263
|
+
trackingFrame,
|
|
264
|
+
rawDepthFrame,
|
|
265
|
+
mappedCenterReached,
|
|
266
|
+
rawAnchorReached,
|
|
267
|
+
rawPatchReached,
|
|
268
|
+
smoothDepthMatchReached,
|
|
269
|
+
boundaryConsensusReached);
|
|
270
|
+
} finally {
|
|
271
|
+
if (smoothDepth != null) smoothDepth.close();
|
|
272
|
+
if (rawConfidence != null) rawConfidence.close();
|
|
273
|
+
if (rawDepth != null) rawDepth.close();
|
|
194
274
|
}
|
|
195
275
|
}
|
|
196
276
|
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
package org.drawdown.arcoredepth;
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* One attempted native ARCore sample. A failed sample carries a stable reason
|
|
5
|
+
* plus milestone flags so the sweep can explain where frames are being lost
|
|
6
|
+
* without persisting camera/depth frames.
|
|
7
|
+
*/
|
|
8
|
+
final class DepthSampleResult {
|
|
9
|
+
final DepthObservation observation;
|
|
10
|
+
final String rejectionReason;
|
|
11
|
+
final boolean trackingFrame;
|
|
12
|
+
final boolean rawDepthFrame;
|
|
13
|
+
final boolean mappedCenter;
|
|
14
|
+
final boolean rawAnchor;
|
|
15
|
+
final boolean rawPatch;
|
|
16
|
+
final boolean smoothDepthMatch;
|
|
17
|
+
final boolean boundaryConsensus;
|
|
18
|
+
|
|
19
|
+
DepthSampleResult(
|
|
20
|
+
DepthObservation observation,
|
|
21
|
+
String rejectionReason,
|
|
22
|
+
boolean trackingFrame,
|
|
23
|
+
boolean rawDepthFrame,
|
|
24
|
+
boolean mappedCenter,
|
|
25
|
+
boolean rawAnchor,
|
|
26
|
+
boolean rawPatch,
|
|
27
|
+
boolean smoothDepthMatch,
|
|
28
|
+
boolean boundaryConsensus) {
|
|
29
|
+
this.observation = observation;
|
|
30
|
+
this.rejectionReason = rejectionReason;
|
|
31
|
+
this.trackingFrame = trackingFrame;
|
|
32
|
+
this.rawDepthFrame = rawDepthFrame;
|
|
33
|
+
this.mappedCenter = mappedCenter;
|
|
34
|
+
this.rawAnchor = rawAnchor;
|
|
35
|
+
this.rawPatch = rawPatch;
|
|
36
|
+
this.smoothDepthMatch = smoothDepthMatch;
|
|
37
|
+
this.boundaryConsensus = boundaryConsensus;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
static DepthSampleResult failure(
|
|
41
|
+
String reason,
|
|
42
|
+
boolean trackingFrame,
|
|
43
|
+
boolean rawDepthFrame,
|
|
44
|
+
boolean mappedCenter,
|
|
45
|
+
boolean rawAnchor,
|
|
46
|
+
boolean rawPatch,
|
|
47
|
+
boolean smoothDepthMatch,
|
|
48
|
+
boolean boundaryConsensus) {
|
|
49
|
+
return new DepthSampleResult(
|
|
50
|
+
null,
|
|
51
|
+
reason,
|
|
52
|
+
trackingFrame,
|
|
53
|
+
rawDepthFrame,
|
|
54
|
+
mappedCenter,
|
|
55
|
+
rawAnchor,
|
|
56
|
+
rawPatch,
|
|
57
|
+
smoothDepthMatch,
|
|
58
|
+
boundaryConsensus);
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
static DepthSampleResult success(DepthObservation observation) {
|
|
62
|
+
return new DepthSampleResult(observation, null, true, true, true, true, true, true, true);
|
|
63
|
+
}
|
|
64
|
+
}
|
|
@@ -36,7 +36,9 @@ import com.google.ar.core.exceptions.UnavailableUserDeclinedInstallationExceptio
|
|
|
36
36
|
import android.opengl.GLSurfaceView;
|
|
37
37
|
|
|
38
38
|
import java.util.ArrayList;
|
|
39
|
+
import java.util.LinkedHashMap;
|
|
39
40
|
import java.util.List;
|
|
41
|
+
import java.util.Map;
|
|
40
42
|
|
|
41
43
|
@CapacitorPlugin(
|
|
42
44
|
name = "DrawDownArCoreDepth",
|
|
@@ -44,7 +46,8 @@ import java.util.List;
|
|
|
44
46
|
@Permission(alias = "camera", strings = { Manifest.permission.CAMERA })
|
|
45
47
|
})
|
|
46
48
|
public class DrawDownArCoreDepthPlugin extends Plugin {
|
|
47
|
-
private static final String PLUGIN_VERSION = "0.1.
|
|
49
|
+
private static final String PLUGIN_VERSION = "0.1.5";
|
|
50
|
+
private static final String METHOD_VERSION = "arcore-raw-depth-cylinder-v4-diagnostics";
|
|
48
51
|
private static final long WARMUP_MS = 1200L;
|
|
49
52
|
|
|
50
53
|
private final Handler mainHandler = new Handler(Looper.getMainLooper());
|
|
@@ -68,6 +71,15 @@ public class DrawDownArCoreDepthPlugin extends Plugin {
|
|
|
68
71
|
private int maxObservations = 10;
|
|
69
72
|
private int minObservations = 5;
|
|
70
73
|
private final List<DepthObservation> sweepObservations = new ArrayList<>();
|
|
74
|
+
private final Map<String, Integer> sweepRejectionCounts = new LinkedHashMap<>();
|
|
75
|
+
private int totalFrameCount = 0;
|
|
76
|
+
private int trackingFrameCount = 0;
|
|
77
|
+
private int rawDepthFrameCount = 0;
|
|
78
|
+
private int mappedCenterCount = 0;
|
|
79
|
+
private int rawAnchorCount = 0;
|
|
80
|
+
private int rawPatchCount = 0;
|
|
81
|
+
private int smoothDepthMatchCount = 0;
|
|
82
|
+
private int boundaryConsensusCount = 0;
|
|
71
83
|
|
|
72
84
|
@PluginMethod
|
|
73
85
|
public void checkSupport(PluginCall call) {
|
|
@@ -251,6 +263,15 @@ public class DrawDownArCoreDepthPlugin extends Plugin {
|
|
|
251
263
|
|
|
252
264
|
pendingSweepCall = call;
|
|
253
265
|
sweepObservations.clear();
|
|
266
|
+
sweepRejectionCounts.clear();
|
|
267
|
+
totalFrameCount = 0;
|
|
268
|
+
trackingFrameCount = 0;
|
|
269
|
+
rawDepthFrameCount = 0;
|
|
270
|
+
mappedCenterCount = 0;
|
|
271
|
+
rawAnchorCount = 0;
|
|
272
|
+
rawPatchCount = 0;
|
|
273
|
+
smoothDepthMatchCount = 0;
|
|
274
|
+
boundaryConsensusCount = 0;
|
|
254
275
|
minObservations = requestedMin;
|
|
255
276
|
maxObservations = requestedMax;
|
|
256
277
|
sampleIntervalMs = Math.max(100L, durationMs / Math.max(1, requestedMax * 2));
|
|
@@ -372,32 +393,61 @@ public class DrawDownArCoreDepthPlugin extends Plugin {
|
|
|
372
393
|
|
|
373
394
|
try {
|
|
374
395
|
Camera camera = frame.getCamera();
|
|
375
|
-
|
|
376
|
-
if (observation == null) {
|
|
377
|
-
return;
|
|
378
|
-
}
|
|
396
|
+
DepthSampleResult sampleResult = sampler.sample(frame, camera, viewWidth, viewHeight);
|
|
379
397
|
|
|
380
398
|
boolean reachedMax = false;
|
|
381
399
|
synchronized (sweepLock) {
|
|
382
400
|
if (!sweepActive || pendingSweepCall == null) {
|
|
383
401
|
return;
|
|
384
402
|
}
|
|
385
|
-
|
|
386
|
-
|
|
403
|
+
totalFrameCount += 1;
|
|
404
|
+
if (sampleResult.trackingFrame) trackingFrameCount += 1;
|
|
405
|
+
if (sampleResult.rawDepthFrame) rawDepthFrameCount += 1;
|
|
406
|
+
if (sampleResult.mappedCenter) mappedCenterCount += 1;
|
|
407
|
+
if (sampleResult.rawAnchor) rawAnchorCount += 1;
|
|
408
|
+
if (sampleResult.rawPatch) rawPatchCount += 1;
|
|
409
|
+
if (sampleResult.smoothDepthMatch) smoothDepthMatchCount += 1;
|
|
410
|
+
if (sampleResult.boundaryConsensus) boundaryConsensusCount += 1;
|
|
411
|
+
|
|
412
|
+
if (sampleResult.rejectionReason != null) {
|
|
413
|
+
int current = sweepRejectionCounts.containsKey(sampleResult.rejectionReason)
|
|
414
|
+
? sweepRejectionCounts.get(sampleResult.rejectionReason)
|
|
415
|
+
: 0;
|
|
416
|
+
sweepRejectionCounts.put(sampleResult.rejectionReason, current + 1);
|
|
417
|
+
}
|
|
418
|
+
|
|
419
|
+
if (sampleResult.observation != null) {
|
|
420
|
+
sweepObservations.add(sampleResult.observation);
|
|
421
|
+
reachedMax = sweepObservations.size() >= maxObservations;
|
|
422
|
+
}
|
|
387
423
|
}
|
|
388
424
|
|
|
389
425
|
if (reachedMax) {
|
|
390
426
|
mainHandler.post(() -> finishSweep(false));
|
|
391
427
|
}
|
|
392
428
|
} catch (Exception ignored) {
|
|
393
|
-
|
|
394
|
-
|
|
429
|
+
synchronized (sweepLock) {
|
|
430
|
+
totalFrameCount += 1;
|
|
431
|
+
int current = sweepRejectionCounts.containsKey("unexpected_exception")
|
|
432
|
+
? sweepRejectionCounts.get("unexpected_exception")
|
|
433
|
+
: 0;
|
|
434
|
+
sweepRejectionCounts.put("unexpected_exception", current + 1);
|
|
435
|
+
}
|
|
395
436
|
}
|
|
396
437
|
}
|
|
397
438
|
|
|
398
439
|
private void finishSweep(boolean stoppedByCaller) {
|
|
399
440
|
PluginCall sweepCall;
|
|
400
441
|
List<DepthObservation> observations;
|
|
442
|
+
Map<String, Integer> rejectionCounts;
|
|
443
|
+
int framesTotal;
|
|
444
|
+
int framesTracking;
|
|
445
|
+
int framesRawDepth;
|
|
446
|
+
int centersMapped;
|
|
447
|
+
int anchorsRaw;
|
|
448
|
+
int patchesRaw;
|
|
449
|
+
int matchesSmooth;
|
|
450
|
+
int boundariesConsensus;
|
|
401
451
|
synchronized (sweepLock) {
|
|
402
452
|
sweepCall = pendingSweepCall;
|
|
403
453
|
if (sweepCall == null) {
|
|
@@ -407,7 +457,17 @@ public class DrawDownArCoreDepthPlugin extends Plugin {
|
|
|
407
457
|
pendingSweepCall = null;
|
|
408
458
|
sweepActive = false;
|
|
409
459
|
observations = new ArrayList<>(sweepObservations);
|
|
460
|
+
rejectionCounts = new LinkedHashMap<>(sweepRejectionCounts);
|
|
461
|
+
framesTotal = totalFrameCount;
|
|
462
|
+
framesTracking = trackingFrameCount;
|
|
463
|
+
framesRawDepth = rawDepthFrameCount;
|
|
464
|
+
centersMapped = mappedCenterCount;
|
|
465
|
+
anchorsRaw = rawAnchorCount;
|
|
466
|
+
patchesRaw = rawPatchCount;
|
|
467
|
+
matchesSmooth = smoothDepthMatchCount;
|
|
468
|
+
boundariesConsensus = boundaryConsensusCount;
|
|
410
469
|
sweepObservations.clear();
|
|
470
|
+
sweepRejectionCounts.clear();
|
|
411
471
|
}
|
|
412
472
|
|
|
413
473
|
JSArray observationArray = new JSArray();
|
|
@@ -415,12 +475,29 @@ public class DrawDownArCoreDepthPlugin extends Plugin {
|
|
|
415
475
|
observationArray.put(observation.toJsObject());
|
|
416
476
|
}
|
|
417
477
|
|
|
478
|
+
JSObject rejectionObject = new JSObject();
|
|
479
|
+
for (Map.Entry<String, Integer> entry : rejectionCounts.entrySet()) {
|
|
480
|
+
rejectionObject.put(entry.getKey(), entry.getValue());
|
|
481
|
+
}
|
|
482
|
+
|
|
418
483
|
JSObject result = new JSObject();
|
|
419
484
|
result.put("observations", observationArray);
|
|
420
485
|
result.put("deviceModel", Build.MANUFACTURER + " " + Build.MODEL);
|
|
421
486
|
result.put("arcoreVersion", installedArcoreVersion());
|
|
487
|
+
result.put("pluginVersion", PLUGIN_VERSION);
|
|
488
|
+
result.put("methodVersion", METHOD_VERSION);
|
|
422
489
|
result.put("minimumRequested", minObservations);
|
|
423
490
|
result.put("stoppedByCaller", stoppedByCaller);
|
|
491
|
+
result.put("totalFrameCount", framesTotal);
|
|
492
|
+
result.put("trackingFrameCount", framesTracking);
|
|
493
|
+
result.put("rawDepthFrameCount", framesRawDepth);
|
|
494
|
+
result.put("mappedCenterCount", centersMapped);
|
|
495
|
+
result.put("rawAnchorCount", anchorsRaw);
|
|
496
|
+
result.put("rawPatchCount", patchesRaw);
|
|
497
|
+
result.put("smoothDepthMatchCount", matchesSmooth);
|
|
498
|
+
result.put("boundaryConsensusCount", boundariesConsensus);
|
|
499
|
+
result.put("nativeValidObservationCount", observations.size());
|
|
500
|
+
result.put("nativeRejectionCounts", rejectionObject);
|
|
424
501
|
sweepCall.resolve(result);
|
|
425
502
|
|
|
426
503
|
if (!stoppedByCaller) {
|
|
@@ -44,6 +44,18 @@ export interface CaptureDbhSweepResult {
|
|
|
44
44
|
observations: DbhObservation[];
|
|
45
45
|
deviceModel?: string;
|
|
46
46
|
arcoreVersion?: string;
|
|
47
|
+
pluginVersion?: string;
|
|
48
|
+
methodVersion?: string;
|
|
49
|
+
totalFrameCount?: number;
|
|
50
|
+
trackingFrameCount?: number;
|
|
51
|
+
rawDepthFrameCount?: number;
|
|
52
|
+
mappedCenterCount?: number;
|
|
53
|
+
rawAnchorCount?: number;
|
|
54
|
+
rawPatchCount?: number;
|
|
55
|
+
smoothDepthMatchCount?: number;
|
|
56
|
+
boundaryConsensusCount?: number;
|
|
57
|
+
nativeValidObservationCount?: number;
|
|
58
|
+
nativeRejectionCounts?: Record<string, number>;
|
|
47
59
|
}
|
|
48
60
|
export interface DrawDownArCoreDepthPlugin {
|
|
49
61
|
checkSupport(): Promise<SupportResult>;
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "drawdown-arcore-depth",
|
|
3
|
-
"version": "0.1.
|
|
4
|
-
"description": "Small Android-only Capacitor 8 bridge for ARCore Depth DBH observations.",
|
|
3
|
+
"version": "0.1.5",
|
|
4
|
+
"description": "Small Android-only Capacitor 8 bridge for ARCore Raw Depth DBH observations with native sweep diagnostics.",
|
|
5
5
|
"main": "dist/plugin.cjs.js",
|
|
6
6
|
"module": "dist/esm/index.js",
|
|
7
7
|
"types": "dist/esm/index.d.ts",
|