@jax-data-science/sci-image-visualizer 0.2.13 → 0.2.15

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.
@@ -425,6 +425,36 @@ const EYE_DEFAULTS = {
425
425
  overlapX: 0,
426
426
  overlapY: 0,
427
427
  };
428
+ /**
429
+ * The retina is an elongated band spanning the whole field, so it crosses tile
430
+ * seams wherever they fall.
431
+ *
432
+ * With no overlap the tiles butt together at fixed boundaries: a structure
433
+ * sitting across a seam is cut in half, each tile sees only a slice, and the
434
+ * slice often fails to clear the confidence threshold — so the object vanishes
435
+ * exactly where the seam lands. Observed as multi-thousand-pixel holes in the
436
+ * middle of an otherwise continuous retina, which closed once overlap was
437
+ * raised.
438
+ *
439
+ * An object of size `s` is guaranteed to sit wholly inside some tile only when
440
+ * the overlap is at least `s / tileSize`; at 60% that covers anything up to
441
+ * ~307px of a 512px tile. The server's own table uses 0 here and has the same
442
+ * blind spot — this deliberately diverges from it.
443
+ */
444
+ const RETINA_DEFAULTS = {
445
+ confidence: 0.6,
446
+ iouThreshold: 0.5,
447
+ // Cross-tile merging uses intersection-over-*smaller*, so at 0.3 a fragment is
448
+ // discarded once 30% of its own area is covered by a larger box — even when
449
+ // most of it lies outside. On a band detected as a chain of overlapping
450
+ // fragments that deletes the middle ones. Measured on one slide: 0.3 gave two
451
+ // boxes covering 75% of the band with a 3150px hole through it; 0.8 gave four
452
+ // boxes covering 100% with no hole, at the cost of two overlapping pairs.
453
+ // Matches the value jit-ui already sends the server for this checkpoint.
454
+ mergeThreshold: 0.8,
455
+ overlapX: 60,
456
+ overlapY: 60,
457
+ };
428
458
  // Embryos are large, touch each other, and are imaged at native scale — hence
429
459
  // the heavy overlap and the far looser merge thresholds.
430
460
  const EMBRYO_DEFAULTS = {
@@ -445,7 +475,7 @@ const YOLO_MODELS = [
445
475
  id: 'yolov8x-seg-retina',
446
476
  label: 'Retina',
447
477
  modelUrl: `${HF}/yolov8x-seg-retina-onnx/resolve/main/model.fp16w.onnx`,
448
- defaults: { ...EYE_DEFAULTS },
478
+ defaults: { ...RETINA_DEFAULTS },
449
479
  },
450
480
  {
451
481
  id: 'yolov8x-seg-embryo-m2',
@@ -1029,9 +1059,14 @@ class YoloDetectToolService {
1029
1059
  if (!ctx)
1030
1060
  return null;
1031
1061
  ctx.drawImage(bitmap, 0, 0);
1032
- const out = ctx.getImageData(0, 0, bitmap.width, bitmap.height);
1062
+ // Read the dimensions BEFORE close(): closing an ImageBitmap zeroes its
1063
+ // width/height, so returning them afterwards yields a 0x0 image with a
1064
+ // full pixel buffer — inference then runs on nothing and finds nothing.
1065
+ const width = bitmap.width;
1066
+ const height = bitmap.height;
1067
+ const out = ctx.getImageData(0, 0, width, height);
1033
1068
  bitmap.close?.();
1034
- return { data: out.data, width: bitmap.width, height: bitmap.height };
1069
+ return { data: out.data, width, height };
1035
1070
  }
1036
1071
  catch {
1037
1072
  return null;
@@ -8369,6 +8404,9 @@ class VisualizerComponent {
8369
8404
  mergeThreshold: def?.defaults.mergeThreshold ?? 0.3,
8370
8405
  overlapX: def?.defaults.overlapX ?? 0,
8371
8406
  overlapY: def?.defaults.overlapY ?? 0,
8407
+ // Exposed in the dialog, so it must be seeded — otherwise the scale
8408
+ // control reads as 0 and the re-crop never runs.
8409
+ downsamplingFactor: 5,
8372
8410
  withMasks: true,
8373
8411
  simplifyTolerance: 1,
8374
8412
  minArea: 0,