rocket-welder-sdk 1.1.46__tar.gz → 1.2.0__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.
Files changed (83) hide show
  1. {rocket_welder_sdk-1.1.46 → rocket_welder_sdk-1.2.0}/PKG-INFO +1 -1
  2. rocket_welder_sdk-1.2.0/VERSION +1 -0
  3. {rocket_welder_sdk-1.1.46 → rocket_welder_sdk-1.2.0}/rocket_welder_sdk/high_level/data_context.py +4 -1
  4. {rocket_welder_sdk-1.1.46 → rocket_welder_sdk-1.2.0}/rocket_welder_sdk/rocket_welder_client.py +84 -1
  5. {rocket_welder_sdk-1.1.46 → rocket_welder_sdk-1.2.0}/rocket_welder_sdk/segmentation_result.py +42 -8
  6. {rocket_welder_sdk-1.1.46 → rocket_welder_sdk-1.2.0}/rocket_welder_sdk.egg-info/PKG-INFO +1 -1
  7. {rocket_welder_sdk-1.1.46 → rocket_welder_sdk-1.2.0}/tests/test_segmentation_cross_platform.py +2 -2
  8. {rocket_welder_sdk-1.1.46 → rocket_welder_sdk-1.2.0}/tests/test_segmentation_result.py +43 -42
  9. {rocket_welder_sdk-1.1.46 → rocket_welder_sdk-1.2.0}/tests/test_transport_cross_platform.py +1 -1
  10. rocket_welder_sdk-1.1.46/VERSION +0 -1
  11. {rocket_welder_sdk-1.1.46 → rocket_welder_sdk-1.2.0}/MANIFEST.in +0 -0
  12. {rocket_welder_sdk-1.1.46 → rocket_welder_sdk-1.2.0}/README.md +0 -0
  13. {rocket_welder_sdk-1.1.46 → rocket_welder_sdk-1.2.0}/logo.png +0 -0
  14. {rocket_welder_sdk-1.1.46 → rocket_welder_sdk-1.2.0}/pyproject.toml +0 -0
  15. {rocket_welder_sdk-1.1.46 → rocket_welder_sdk-1.2.0}/rocket_welder_sdk/__init__.py +0 -0
  16. {rocket_welder_sdk-1.1.46 → rocket_welder_sdk-1.2.0}/rocket_welder_sdk/binary_frame_reader.py +0 -0
  17. {rocket_welder_sdk-1.1.46 → rocket_welder_sdk-1.2.0}/rocket_welder_sdk/binary_frame_writer.py +0 -0
  18. {rocket_welder_sdk-1.1.46 → rocket_welder_sdk-1.2.0}/rocket_welder_sdk/bytes_size.py +0 -0
  19. {rocket_welder_sdk-1.1.46 → rocket_welder_sdk-1.2.0}/rocket_welder_sdk/confidence.py +0 -0
  20. {rocket_welder_sdk-1.1.46 → rocket_welder_sdk-1.2.0}/rocket_welder_sdk/connection_string.py +0 -0
  21. {rocket_welder_sdk-1.1.46 → rocket_welder_sdk-1.2.0}/rocket_welder_sdk/controllers.py +0 -0
  22. {rocket_welder_sdk-1.1.46 → rocket_welder_sdk-1.2.0}/rocket_welder_sdk/delta_frame.py +0 -0
  23. {rocket_welder_sdk-1.1.46 → rocket_welder_sdk-1.2.0}/rocket_welder_sdk/external_controls/__init__.py +0 -0
  24. {rocket_welder_sdk-1.1.46 → rocket_welder_sdk-1.2.0}/rocket_welder_sdk/external_controls/contracts.py +0 -0
  25. {rocket_welder_sdk-1.1.46 → rocket_welder_sdk-1.2.0}/rocket_welder_sdk/external_controls/contracts_old.py +0 -0
  26. {rocket_welder_sdk-1.1.46 → rocket_welder_sdk-1.2.0}/rocket_welder_sdk/frame_metadata.py +0 -0
  27. {rocket_welder_sdk-1.1.46 → rocket_welder_sdk-1.2.0}/rocket_welder_sdk/graphics/__init__.py +0 -0
  28. {rocket_welder_sdk-1.1.46 → rocket_welder_sdk-1.2.0}/rocket_welder_sdk/graphics/layer_canvas.py +0 -0
  29. {rocket_welder_sdk-1.1.46 → rocket_welder_sdk-1.2.0}/rocket_welder_sdk/graphics/protocol.py +0 -0
  30. {rocket_welder_sdk-1.1.46 → rocket_welder_sdk-1.2.0}/rocket_welder_sdk/graphics/rgb_color.py +0 -0
  31. {rocket_welder_sdk-1.1.46 → rocket_welder_sdk-1.2.0}/rocket_welder_sdk/graphics/stage.py +0 -0
  32. {rocket_welder_sdk-1.1.46 → rocket_welder_sdk-1.2.0}/rocket_welder_sdk/graphics/vector_graphics_encoder.py +0 -0
  33. {rocket_welder_sdk-1.1.46 → rocket_welder_sdk-1.2.0}/rocket_welder_sdk/gst_metadata.py +0 -0
  34. {rocket_welder_sdk-1.1.46 → rocket_welder_sdk-1.2.0}/rocket_welder_sdk/high_level/__init__.py +0 -0
  35. {rocket_welder_sdk-1.1.46 → rocket_welder_sdk-1.2.0}/rocket_welder_sdk/high_level/client.py +0 -0
  36. {rocket_welder_sdk-1.1.46 → rocket_welder_sdk-1.2.0}/rocket_welder_sdk/high_level/connection_strings.py +0 -0
  37. {rocket_welder_sdk-1.1.46 → rocket_welder_sdk-1.2.0}/rocket_welder_sdk/high_level/frame_sink_factory.py +0 -0
  38. {rocket_welder_sdk-1.1.46 → rocket_welder_sdk-1.2.0}/rocket_welder_sdk/high_level/schema.py +0 -0
  39. {rocket_welder_sdk-1.1.46 → rocket_welder_sdk-1.2.0}/rocket_welder_sdk/high_level/transport_protocol.py +0 -0
  40. {rocket_welder_sdk-1.1.46 → rocket_welder_sdk-1.2.0}/rocket_welder_sdk/keypoints_protocol.py +0 -0
  41. {rocket_welder_sdk-1.1.46 → rocket_welder_sdk-1.2.0}/rocket_welder_sdk/opencv_controller.py +0 -0
  42. {rocket_welder_sdk-1.1.46 → rocket_welder_sdk-1.2.0}/rocket_welder_sdk/periodic_timer.py +0 -0
  43. {rocket_welder_sdk-1.1.46 → rocket_welder_sdk-1.2.0}/rocket_welder_sdk/py.typed +0 -0
  44. {rocket_welder_sdk-1.1.46 → rocket_welder_sdk-1.2.0}/rocket_welder_sdk/session_id.py +0 -0
  45. {rocket_welder_sdk-1.1.46 → rocket_welder_sdk-1.2.0}/rocket_welder_sdk/transport/__init__.py +0 -0
  46. {rocket_welder_sdk-1.1.46 → rocket_welder_sdk-1.2.0}/rocket_welder_sdk/transport/frame_sink.py +0 -0
  47. {rocket_welder_sdk-1.1.46 → rocket_welder_sdk-1.2.0}/rocket_welder_sdk/transport/frame_source.py +0 -0
  48. {rocket_welder_sdk-1.1.46 → rocket_welder_sdk-1.2.0}/rocket_welder_sdk/transport/stream_transport.py +0 -0
  49. {rocket_welder_sdk-1.1.46 → rocket_welder_sdk-1.2.0}/rocket_welder_sdk/transport/tcp_transport.py +0 -0
  50. {rocket_welder_sdk-1.1.46 → rocket_welder_sdk-1.2.0}/rocket_welder_sdk/transport/unix_socket_transport.py +0 -0
  51. {rocket_welder_sdk-1.1.46 → rocket_welder_sdk-1.2.0}/rocket_welder_sdk/transport/websocket_transport.py +0 -0
  52. {rocket_welder_sdk-1.1.46 → rocket_welder_sdk-1.2.0}/rocket_welder_sdk/ui/__init__.py +0 -0
  53. {rocket_welder_sdk-1.1.46 → rocket_welder_sdk-1.2.0}/rocket_welder_sdk/ui/controls.py +0 -0
  54. {rocket_welder_sdk-1.1.46 → rocket_welder_sdk-1.2.0}/rocket_welder_sdk/ui/icons.py +0 -0
  55. {rocket_welder_sdk-1.1.46 → rocket_welder_sdk-1.2.0}/rocket_welder_sdk/ui/ui_events_projection.py +0 -0
  56. {rocket_welder_sdk-1.1.46 → rocket_welder_sdk-1.2.0}/rocket_welder_sdk/ui/ui_service.py +0 -0
  57. {rocket_welder_sdk-1.1.46 → rocket_welder_sdk-1.2.0}/rocket_welder_sdk/ui/value_types.py +0 -0
  58. {rocket_welder_sdk-1.1.46 → rocket_welder_sdk-1.2.0}/rocket_welder_sdk/varint.py +0 -0
  59. {rocket_welder_sdk-1.1.46 → rocket_welder_sdk-1.2.0}/rocket_welder_sdk.egg-info/SOURCES.txt +0 -0
  60. {rocket_welder_sdk-1.1.46 → rocket_welder_sdk-1.2.0}/rocket_welder_sdk.egg-info/dependency_links.txt +0 -0
  61. {rocket_welder_sdk-1.1.46 → rocket_welder_sdk-1.2.0}/rocket_welder_sdk.egg-info/requires.txt +0 -0
  62. {rocket_welder_sdk-1.1.46 → rocket_welder_sdk-1.2.0}/rocket_welder_sdk.egg-info/top_level.txt +0 -0
  63. {rocket_welder_sdk-1.1.46 → rocket_welder_sdk-1.2.0}/setup.cfg +0 -0
  64. {rocket_welder_sdk-1.1.46 → rocket_welder_sdk-1.2.0}/setup.py +0 -0
  65. {rocket_welder_sdk-1.1.46 → rocket_welder_sdk-1.2.0}/tests/test_binary_frame.py +0 -0
  66. {rocket_welder_sdk-1.1.46 → rocket_welder_sdk-1.2.0}/tests/test_bytes_size.py +0 -0
  67. {rocket_welder_sdk-1.1.46 → rocket_welder_sdk-1.2.0}/tests/test_confidence.py +0 -0
  68. {rocket_welder_sdk-1.1.46 → rocket_welder_sdk-1.2.0}/tests/test_connection_string.py +0 -0
  69. {rocket_welder_sdk-1.1.46 → rocket_welder_sdk-1.2.0}/tests/test_controllers.py +0 -0
  70. {rocket_welder_sdk-1.1.46 → rocket_welder_sdk-1.2.0}/tests/test_delta_frame.py +0 -0
  71. {rocket_welder_sdk-1.1.46 → rocket_welder_sdk-1.2.0}/tests/test_external_controls_serialization.py +0 -0
  72. {rocket_welder_sdk-1.1.46 → rocket_welder_sdk-1.2.0}/tests/test_external_controls_serialization_v2.py +0 -0
  73. {rocket_welder_sdk-1.1.46 → rocket_welder_sdk-1.2.0}/tests/test_frame_metadata.py +0 -0
  74. {rocket_welder_sdk-1.1.46 → rocket_welder_sdk-1.2.0}/tests/test_gst_metadata.py +0 -0
  75. {rocket_welder_sdk-1.1.46 → rocket_welder_sdk-1.2.0}/tests/test_high_level_api.py +0 -0
  76. {rocket_welder_sdk-1.1.46 → rocket_welder_sdk-1.2.0}/tests/test_icons.py +0 -0
  77. {rocket_welder_sdk-1.1.46 → rocket_welder_sdk-1.2.0}/tests/test_keypoints_cross_platform.py +0 -0
  78. {rocket_welder_sdk-1.1.46 → rocket_welder_sdk-1.2.0}/tests/test_keypoints_protocol.py +0 -0
  79. {rocket_welder_sdk-1.1.46 → rocket_welder_sdk-1.2.0}/tests/test_rocket_welder_client.py +0 -0
  80. {rocket_welder_sdk-1.1.46 → rocket_welder_sdk-1.2.0}/tests/test_session_id.py +0 -0
  81. {rocket_welder_sdk-1.1.46 → rocket_welder_sdk-1.2.0}/tests/test_ui_controls.py +0 -0
  82. {rocket_welder_sdk-1.1.46 → rocket_welder_sdk-1.2.0}/tests/test_ui_service_happy_path.py +0 -0
  83. {rocket_welder_sdk-1.1.46 → rocket_welder_sdk-1.2.0}/tests/test_websocket_transport.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: rocket-welder-sdk
3
- Version: 1.1.46
3
+ Version: 1.2.0
4
4
  Summary: High-performance video streaming SDK for RocketWelder services using ZeroBuffer IPC
5
5
  Home-page: https://github.com/modelingevolution/rocket-welder-sdk
6
6
  Author: ModelingEvolution
@@ -0,0 +1 @@
1
+ 1.2.0
@@ -85,6 +85,7 @@ class ISegmentationDataContext(ABC):
85
85
  self,
86
86
  segment_class: SegmentClass,
87
87
  instance_id: int,
88
+ confidence: float,
88
89
  points: Union[Sequence[Point], npt.NDArray[np.int32]],
89
90
  ) -> None:
90
91
  """
@@ -93,6 +94,7 @@ class ISegmentationDataContext(ABC):
93
94
  Args:
94
95
  segment_class: SegmentClass from schema definition
95
96
  instance_id: Instance ID (for multiple instances of same class, 0-255)
97
+ confidence: Detection confidence score (0.0-1.0)
96
98
  points: Contour points defining the instance boundary
97
99
  """
98
100
  pass
@@ -150,6 +152,7 @@ class SegmentationDataContext(ISegmentationDataContext):
150
152
  self,
151
153
  segment_class: SegmentClass,
152
154
  instance_id: int,
155
+ confidence: float,
153
156
  points: Union[Sequence[Point], npt.NDArray[np.int32]],
154
157
  ) -> None:
155
158
  """Add a segmentation instance for this frame."""
@@ -162,7 +165,7 @@ class SegmentationDataContext(ISegmentationDataContext):
162
165
  else:
163
166
  points_array = np.array(points, dtype=np.int32)
164
167
 
165
- self._writer.append(segment_class.class_id, instance_id, points_array)
168
+ self._writer.append(segment_class.class_id, instance_id, confidence, points_array)
166
169
 
167
170
  def commit(self) -> None:
168
171
  """Commit the context (called automatically when delegate returns)."""
@@ -85,6 +85,42 @@ class RocketWelderClient:
85
85
  with self._lock:
86
86
  return self._controller is not None and self._controller.is_running
87
87
 
88
+ @property
89
+ def ml_model_path(self) -> Optional[str]:
90
+ """
91
+ Path to the ML model file mounted in the container.
92
+
93
+ Reads from ML_MODEL_PATH environment variable set by RocketWelder
94
+ when a model is mapped to this container's pipeline element.
95
+
96
+ Returns:
97
+ The path to the model file (e.g., /var/models/model.hef),
98
+ or None if no model is configured.
99
+ """
100
+ import os
101
+
102
+ return os.environ.get("ML_MODEL_PATH")
103
+
104
+ @property
105
+ def ml_model_version(self) -> Optional[int]:
106
+ """
107
+ Version of the ML model.
108
+
109
+ Reads from ML_MODEL_VERSION environment variable set by RocketWelder.
110
+
111
+ Returns:
112
+ The model version as integer, or None if not set or not a valid number.
113
+ """
114
+ import os
115
+
116
+ value = os.environ.get("ML_MODEL_VERSION")
117
+ if value is None:
118
+ return None
119
+ try:
120
+ return int(value)
121
+ except ValueError:
122
+ return None
123
+
88
124
  def get_metadata(self) -> Optional[GstMetadata]:
89
125
  """
90
126
  Get the current GStreamer metadata.
@@ -577,6 +613,47 @@ class RocketWelderClient:
577
613
  """Context manager exit."""
578
614
  self.stop()
579
615
 
616
+ @staticmethod
617
+ def get_ml_model_path() -> Optional[str]:
618
+ """
619
+ Get the ML model path from environment (static method).
620
+
621
+ Convenience method to get the model path without creating a client instance.
622
+ Useful during initialization before the client is created.
623
+
624
+ Returns:
625
+ The path to the model file (e.g., /var/models/model.hef),
626
+ or None if no model is configured.
627
+
628
+ Example:
629
+ model_path = RocketWelderClient.get_ml_model_path()
630
+ if model_path:
631
+ model = load_model(model_path)
632
+ else:
633
+ raise RuntimeError("No ML model configured")
634
+ """
635
+ import os
636
+
637
+ return os.environ.get("ML_MODEL_PATH")
638
+
639
+ @staticmethod
640
+ def get_ml_model_version() -> Optional[int]:
641
+ """
642
+ Get the ML model version from environment (static method).
643
+
644
+ Returns:
645
+ The model version as integer, or None if not set or not a valid number.
646
+ """
647
+ import os
648
+
649
+ value = os.environ.get("ML_MODEL_VERSION")
650
+ if value is None:
651
+ return None
652
+ try:
653
+ return int(value)
654
+ except ValueError:
655
+ return None
656
+
580
657
  @classmethod
581
658
  def from_connection_string(cls, connection_string: str) -> RocketWelderClient:
582
659
  """
@@ -750,7 +827,13 @@ class _NoOpKeyPointsWriter(IKeyPointsWriter):
750
827
  class _NoOpSegmentationWriter(ISegmentationResultWriter):
751
828
  """No-op segmentation writer that discards all data."""
752
829
 
753
- def append(self, class_id: int, instance_id: int, points: Any) -> None:
830
+ def append(
831
+ self,
832
+ class_id: int,
833
+ instance_id: int,
834
+ confidence: float,
835
+ points: Any,
836
+ ) -> None:
754
837
  """Discard segmentation data."""
755
838
  pass
756
839
 
@@ -6,8 +6,8 @@ Compatible with C# implementation for cross-platform interoperability.
6
6
 
7
7
  Protocol (per frame):
8
8
  [FrameId: 8B little-endian][Width: varint][Height: varint]
9
- [classId: 1B][instanceId: 1B][pointCount: varint][points: delta+varint...]
10
- [classId: 1B][instanceId: 1B][pointCount: varint][points: delta+varint...]
9
+ [classId: 1B][instanceId: 1B][confidence: 2B LE][pointCount: varint][points: delta+varint...]
10
+ [classId: 1B][instanceId: 1B][confidence: 2B LE][pointCount: varint][points: delta+varint...]
11
11
  ...
12
12
 
13
13
  Features:
@@ -104,6 +104,7 @@ class SegmentationInstance:
104
104
 
105
105
  class_id: int
106
106
  instance_id: int
107
+ confidence: float # Detection confidence score (0.0-1.0)
107
108
  points: PointArray # NumPy array of shape (N, 2) with dtype int32
108
109
 
109
110
  def to_normalized(self, width: int, height: int) -> npt.NDArray[np.float32]:
@@ -237,6 +238,7 @@ class SegmentationResultWriter:
237
238
  self,
238
239
  class_id: int,
239
240
  instance_id: int,
241
+ confidence: float,
240
242
  points: Union[List[Point], PointArray],
241
243
  ) -> None:
242
244
  """
@@ -245,6 +247,7 @@ class SegmentationResultWriter:
245
247
  Args:
246
248
  class_id: Object class ID (0-255)
247
249
  instance_id: Instance ID within class (0-255)
250
+ confidence: Detection confidence score (0.0-1.0)
248
251
  points: List of (x, y) tuples or NumPy array of shape (N, 2)
249
252
  """
250
253
  if class_id < 0 or class_id > 255:
@@ -266,6 +269,11 @@ class SegmentationResultWriter:
266
269
  # Write class_id and instance_id
267
270
  self._buffer.write(bytes([class_id, instance_id]))
268
271
 
272
+ # Write confidence as 2 bytes little-endian (ushort 0-65535)
273
+ confidence_clamped = max(0.0, min(1.0, confidence))
274
+ confidence_raw = int(confidence_clamped * 65535)
275
+ self._buffer.write(struct.pack("<H", confidence_raw))
276
+
269
277
  # Write point count
270
278
  point_count = len(points_array)
271
279
  _write_varint(self._buffer, point_count)
@@ -402,6 +410,13 @@ class SegmentationResultReader:
402
410
  class_id = header[0]
403
411
  instance_id = header[1]
404
412
 
413
+ # Read confidence (2 bytes little-endian)
414
+ confidence_bytes = self._stream.read(2)
415
+ if len(confidence_bytes) != 2:
416
+ raise EOFError("Unexpected end of stream reading confidence")
417
+ confidence_raw = struct.unpack("<H", confidence_bytes)[0]
418
+ confidence = confidence_raw / 65535.0
419
+
405
420
  # Read point count with validation
406
421
  point_count = _read_varint(self._stream)
407
422
  if point_count > self._max_points_per_instance:
@@ -412,7 +427,7 @@ class SegmentationResultReader:
412
427
  if point_count == 0:
413
428
  # Empty points array
414
429
  points = np.empty((0, 2), dtype=np.int32)
415
- return SegmentationInstance(class_id, instance_id, points)
430
+ return SegmentationInstance(class_id, instance_id, confidence, points)
416
431
 
417
432
  # Allocate NumPy array for points
418
433
  points = np.empty((point_count, 2), dtype=np.int32)
@@ -430,7 +445,7 @@ class SegmentationResultReader:
430
445
  y += delta_y
431
446
  points[i] = [x, y]
432
447
 
433
- return SegmentationInstance(class_id, instance_id, points)
448
+ return SegmentationInstance(class_id, instance_id, confidence, points)
434
449
 
435
450
  def read_all(self) -> List[SegmentationInstance]:
436
451
  """
@@ -472,6 +487,7 @@ class ISegmentationResultWriter(ABC):
472
487
  self,
473
488
  class_id: int,
474
489
  instance_id: int,
490
+ confidence: float,
475
491
  points: Union[List[Point], PointArray],
476
492
  ) -> None:
477
493
  """
@@ -480,6 +496,7 @@ class ISegmentationResultWriter(ABC):
480
496
  Args:
481
497
  class_id: Object class ID (0-255)
482
498
  instance_id: Instance ID within class (0-255)
499
+ confidence: Detection confidence score (0.0-1.0)
483
500
  points: List of (x, y) tuples or NumPy array of shape (N, 2)
484
501
  """
485
502
  pass
@@ -741,6 +758,7 @@ class SegmentationProtocol:
741
758
  Instance Format:
742
759
  [ClassId: 1 byte]
743
760
  [InstanceId: 1 byte]
761
+ [Confidence: 2 bytes, little-endian uint16]
744
762
  [PointCount: varint]
745
763
  [Point0: X zigzag-varint, Y zigzag-varint] (absolute)
746
764
  [Point1+: deltaX zigzag-varint, deltaY zigzag-varint]
@@ -777,6 +795,12 @@ class SegmentationProtocol:
777
795
  def _write_instance_core(stream: BinaryIO, instance: SegmentationInstance) -> None:
778
796
  """Write a single instance to the stream."""
779
797
  stream.write(bytes([instance.class_id, instance.instance_id]))
798
+
799
+ # Write confidence as 2 bytes little-endian (ushort 0-65535)
800
+ confidence_clamped = max(0.0, min(1.0, instance.confidence))
801
+ confidence_raw = int(confidence_clamped * 65535)
802
+ stream.write(struct.pack("<H", confidence_raw))
803
+
780
804
  point_count = len(instance.points)
781
805
  _write_varint(stream, point_count)
782
806
 
@@ -823,6 +847,7 @@ class SegmentationProtocol:
823
847
  buffer: bytearray,
824
848
  class_id: int,
825
849
  instance_id: int,
850
+ confidence: float,
826
851
  points: Union[List[Point], PointArray],
827
852
  ) -> int:
828
853
  """
@@ -834,6 +859,7 @@ class SegmentationProtocol:
834
859
  buffer: Pre-allocated buffer to write to.
835
860
  class_id: Class identifier (0-255).
836
861
  instance_id: Instance identifier (0-255).
862
+ confidence: Detection confidence score (0.0-1.0).
837
863
  points: Polygon points.
838
864
 
839
865
  Returns:
@@ -845,7 +871,7 @@ class SegmentationProtocol:
845
871
  else:
846
872
  points_array = points.astype(np.int32)
847
873
 
848
- instance = SegmentationInstance(class_id, instance_id, points_array)
874
+ instance = SegmentationInstance(class_id, instance_id, confidence, points_array)
849
875
 
850
876
  stream = io.BytesIO()
851
877
  SegmentationProtocol._write_instance_core(stream, instance)
@@ -864,8 +890,8 @@ class SegmentationProtocol:
864
890
  Returns:
865
891
  Maximum bytes needed.
866
892
  """
867
- # classId(1) + instanceId(1) + pointCount(varint, max 5) + points(max 10 bytes each)
868
- return 1 + 1 + 5 + (point_count * 10)
893
+ # classId(1) + instanceId(1) + confidence(2) + pointCount(varint, max 5) + points(max 10 bytes each)
894
+ return 1 + 1 + 2 + 5 + (point_count * 10)
869
895
 
870
896
  @staticmethod
871
897
  def read(data: bytes) -> SegmentationFrame:
@@ -899,6 +925,14 @@ class SegmentationProtocol:
899
925
 
900
926
  class_id = header[0]
901
927
  instance_id = header[1]
928
+
929
+ # Read confidence (2 bytes little-endian)
930
+ confidence_bytes = stream.read(2)
931
+ if len(confidence_bytes) != 2:
932
+ raise EOFError("Unexpected end of stream reading confidence")
933
+ confidence_raw = struct.unpack("<H", confidence_bytes)[0]
934
+ confidence = confidence_raw / 65535.0
935
+
902
936
  point_count = _read_varint(stream)
903
937
 
904
938
  if point_count == 0:
@@ -916,7 +950,7 @@ class SegmentationProtocol:
916
950
  points[i] = [x, y]
917
951
  prev_x, prev_y = x, y
918
952
 
919
- instances.append(SegmentationInstance(class_id, instance_id, points))
953
+ instances.append(SegmentationInstance(class_id, instance_id, confidence, points))
920
954
 
921
955
  return SegmentationFrame(frame_id, width, height, instances)
922
956
 
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: rocket-welder-sdk
3
- Version: 1.1.46
3
+ Version: 1.2.0
4
4
  Summary: High-performance video streaming SDK for RocketWelder services using ZeroBuffer IPC
5
5
  Home-page: https://github.com/modelingevolution/rocket-welder-sdk
6
6
  Author: ModelingEvolution
@@ -96,7 +96,7 @@ class TestCrossPlatform:
96
96
  frame_id, width, height, f
97
97
  ) as writer:
98
98
  for class_id, instance_id, points in instances:
99
- writer.append(class_id, instance_id, points)
99
+ writer.append(class_id, instance_id, 0.95, points)
100
100
 
101
101
  # Verify file exists and has data
102
102
  assert test_file.exists()
@@ -129,7 +129,7 @@ class TestCrossPlatform:
129
129
  frame_id, width, height, f
130
130
  ) as writer:
131
131
  for class_id, instance_id, points in instances:
132
- writer.append(class_id, instance_id, points)
132
+ writer.append(class_id, instance_id, 0.95, points)
133
133
 
134
134
  # Act - Read (via transport layer for framing)
135
135
  with open(test_file, "rb") as f:
@@ -45,7 +45,7 @@ class TestRoundTrip:
45
45
 
46
46
  # Act - Write
47
47
  with SegmentationResultWriter(frame_id, width, height, stream) as writer:
48
- writer.append(class_id, instance_id, points)
48
+ writer.append(class_id, instance_id, 0.95, points)
49
49
 
50
50
  # Act - Read via transport layer
51
51
  with _read_frame_via_transport(stream) as reader:
@@ -82,7 +82,7 @@ class TestRoundTrip:
82
82
  # Act - Write
83
83
  with SegmentationResultWriter(frame_id, width, height, stream) as writer:
84
84
  for class_id, instance_id, points in instances:
85
- writer.append(class_id, instance_id, points)
85
+ writer.append(class_id, instance_id, 0.95, points)
86
86
 
87
87
  # Act - Read via transport layer
88
88
  # Via transport layer
@@ -104,7 +104,7 @@ class TestRoundTrip:
104
104
  stream = io.BytesIO()
105
105
 
106
106
  with SegmentationResultWriter(1, 100, 100, stream) as writer:
107
- writer.append(1, 1, np.empty((0, 2), dtype=np.int32))
107
+ writer.append(1, 1, 0.95, np.empty((0, 2), dtype=np.int32))
108
108
 
109
109
  # Via transport layer
110
110
  with _read_frame_via_transport(stream) as reader:
@@ -128,7 +128,7 @@ class TestRoundTrip:
128
128
  stream = io.BytesIO()
129
129
 
130
130
  with SegmentationResultWriter(999, 3840, 2160, stream) as writer:
131
- writer.append(10, 5, points)
131
+ writer.append(10, 5, 0.95, points)
132
132
 
133
133
  # Via transport layer
134
134
  with _read_frame_via_transport(stream) as reader:
@@ -153,7 +153,7 @@ class TestRoundTrip:
153
153
  stream = io.BytesIO()
154
154
 
155
155
  with SegmentationResultWriter(1, 200, 200, stream) as writer:
156
- writer.append(1, 1, points)
156
+ writer.append(1, 1, 0.95, points)
157
157
 
158
158
  # Via transport layer
159
159
  with _read_frame_via_transport(stream) as reader:
@@ -174,7 +174,7 @@ class TestRoundTrip:
174
174
  1, 640, 480, frame_sink=StreamFrameSink(stream, leave_open=True)
175
175
  ) as writer:
176
176
  for class_id, instance_id, points in frame1_points:
177
- writer.append(class_id, instance_id, points)
177
+ writer.append(class_id, instance_id, 0.95, points)
178
178
 
179
179
  # Frame 2
180
180
  frame2_points = [
@@ -186,7 +186,7 @@ class TestRoundTrip:
186
186
  2, 1920, 1080, frame_sink=StreamFrameSink(stream, leave_open=True)
187
187
  ) as writer:
188
188
  for class_id, instance_id, points in frame2_points:
189
- writer.append(class_id, instance_id, points)
189
+ writer.append(class_id, instance_id, 0.95, points)
190
190
 
191
191
  # Read both frames via transport layer
192
192
  stream.seek(0)
@@ -235,7 +235,7 @@ class TestNormalization:
235
235
  def test_to_normalized_converts_to_float_range(self) -> None:
236
236
  """Test normalization to [0-1] range."""
237
237
  points = np.array([[0, 0], [1920, 1080], [960, 540]], dtype=np.int32)
238
- instance = SegmentationInstance(1, 1, points)
238
+ instance = SegmentationInstance(1, 1, 0.95, points)
239
239
 
240
240
  normalized = instance.to_normalized(1920, 1080)
241
241
 
@@ -247,7 +247,7 @@ class TestNormalization:
247
247
  def test_to_normalized_raises_on_zero_dimensions(self) -> None:
248
248
  """Test that normalization raises on zero width/height."""
249
249
  points = np.array([[10, 20]], dtype=np.int32)
250
- instance = SegmentationInstance(1, 1, points)
250
+ instance = SegmentationInstance(1, 1, 0.95, points)
251
251
 
252
252
  with pytest.raises(ValueError, match="must be positive"):
253
253
  instance.to_normalized(0, 1080)
@@ -271,7 +271,7 @@ class TestIterator:
271
271
 
272
272
  with SegmentationResultWriter(1, 100, 100, stream) as writer:
273
273
  for class_id, instance_id, points in instances_data:
274
- writer.append(class_id, instance_id, points)
274
+ writer.append(class_id, instance_id, 0.95, points)
275
275
 
276
276
  # Via transport layer
277
277
  with _read_frame_via_transport(stream) as reader:
@@ -287,8 +287,8 @@ class TestIterator:
287
287
  stream = io.BytesIO()
288
288
 
289
289
  with SegmentationResultWriter(1, 100, 100, stream) as writer:
290
- writer.append(1, 1, np.array([[10, 20]], dtype=np.int32))
291
- writer.append(2, 1, np.array([[30, 40]], dtype=np.int32))
290
+ writer.append(1, 1, 0.95, np.array([[10, 20]], dtype=np.int32))
291
+ writer.append(2, 1, 0.95, np.array([[30, 40]], dtype=np.int32))
292
292
 
293
293
  # Via transport layer
294
294
  with _read_frame_via_transport(stream) as reader:
@@ -306,14 +306,14 @@ class TestFlush:
306
306
  stream = io.BytesIO()
307
307
  writer = SegmentationResultWriter(1, 100, 100, stream)
308
308
 
309
- writer.append(1, 1, np.array([[10, 20]], dtype=np.int32))
309
+ writer.append(1, 1, 0.95, np.array([[10, 20]], dtype=np.int32))
310
310
  writer.flush()
311
311
 
312
312
  # Should have data
313
313
  assert stream.tell() > 0
314
314
 
315
315
  # Can still write more
316
- writer.append(2, 1, np.array([[30, 40]], dtype=np.int32))
316
+ writer.append(2, 1, 0.95, np.array([[30, 40]], dtype=np.int32))
317
317
  writer.close()
318
318
 
319
319
 
@@ -328,9 +328,9 @@ class TestValidation:
328
328
  points = np.array([[10, 20]], dtype=np.int32)
329
329
 
330
330
  # 255 is now valid (no end-marker)
331
- writer.append(255, 1, points)
332
- writer.append(1, 255, points)
333
- writer.append(255, 255, points)
331
+ writer.append(255, 1, 0.95, points)
332
+ writer.append(1, 255, 0.95, points)
333
+ writer.append(255, 255, 0.95, points)
334
334
  writer.close()
335
335
 
336
336
  # Read back and verify via transport layer
@@ -361,6 +361,7 @@ class TestValidation:
361
361
 
362
362
  # Write instance with huge point count
363
363
  stream.write(bytes([1, 1])) # class_id, instance_id
364
+ stream.write(struct.pack("<H", 32767)) # confidence = 0.5 (2 bytes LE)
364
365
  # Write varint for > 10M points (will fail validation)
365
366
  # 20M = 0x1312D00
366
367
  stream.write(b"\x80\xba\xc8\x89\x01") # varint encoding of 20000000
@@ -379,7 +380,7 @@ class TestListConversion:
379
380
  def test_to_list_converts_numpy_to_tuples(self) -> None:
380
381
  """Test conversion from NumPy array to list of tuples."""
381
382
  points = np.array([[10, 20], [30, 40]], dtype=np.int32)
382
- instance = SegmentationInstance(1, 1, points)
383
+ instance = SegmentationInstance(1, 1, 0.95, points)
383
384
 
384
385
  points_list = instance.to_list()
385
386
 
@@ -396,7 +397,7 @@ class TestListInput:
396
397
  points_list: List[Tuple[int, int]] = [(10, 20), (30, 40), (50, 60)]
397
398
 
398
399
  with SegmentationResultWriter(1, 100, 100, stream) as writer:
399
- writer.append(1, 1, points_list)
400
+ writer.append(1, 1, 0.95, points_list)
400
401
 
401
402
  # Via transport layer
402
403
  with _read_frame_via_transport(stream) as reader:
@@ -439,8 +440,8 @@ class TestSegmentationFrame:
439
440
  def test_frame_properties(self) -> None:
440
441
  """Test basic frame properties."""
441
442
  instances = [
442
- SegmentationInstance(1, 1, np.array([[10, 20]], dtype=np.int32)),
443
- SegmentationInstance(2, 1, np.array([[30, 40], [50, 60]], dtype=np.int32)),
443
+ SegmentationInstance(1, 1, 0.95, np.array([[10, 20]], dtype=np.int32)),
444
+ SegmentationInstance(2, 1, 0.95, np.array([[30, 40], [50, 60]], dtype=np.int32)),
444
445
  ]
445
446
  frame = SegmentationFrame(frame_id=42, width=1920, height=1080, instances=instances)
446
447
 
@@ -452,9 +453,9 @@ class TestSegmentationFrame:
452
453
  def test_find_by_class(self) -> None:
453
454
  """Test finding instances by class ID."""
454
455
  instances = [
455
- SegmentationInstance(1, 1, np.array([[10, 20]], dtype=np.int32)),
456
- SegmentationInstance(2, 1, np.array([[30, 40]], dtype=np.int32)),
457
- SegmentationInstance(1, 2, np.array([[50, 60]], dtype=np.int32)),
456
+ SegmentationInstance(1, 1, 0.95, np.array([[10, 20]], dtype=np.int32)),
457
+ SegmentationInstance(2, 1, 0.95, np.array([[30, 40]], dtype=np.int32)),
458
+ SegmentationInstance(1, 2, 0.95, np.array([[50, 60]], dtype=np.int32)),
458
459
  ]
459
460
  frame = SegmentationFrame(frame_id=1, width=100, height=100, instances=instances)
460
461
 
@@ -472,9 +473,9 @@ class TestSegmentationFrame:
472
473
  def test_find_by_instance(self) -> None:
473
474
  """Test finding instances by instance ID."""
474
475
  instances = [
475
- SegmentationInstance(1, 1, np.array([[10, 20]], dtype=np.int32)),
476
- SegmentationInstance(2, 1, np.array([[30, 40]], dtype=np.int32)),
477
- SegmentationInstance(1, 2, np.array([[50, 60]], dtype=np.int32)),
476
+ SegmentationInstance(1, 1, 0.95, np.array([[10, 20]], dtype=np.int32)),
477
+ SegmentationInstance(2, 1, 0.95, np.array([[30, 40]], dtype=np.int32)),
478
+ SegmentationInstance(1, 2, 0.95, np.array([[50, 60]], dtype=np.int32)),
478
479
  ]
479
480
  frame = SegmentationFrame(frame_id=1, width=100, height=100, instances=instances)
480
481
 
@@ -491,8 +492,8 @@ class TestSegmentationProtocol:
491
492
  def test_write_read_roundtrip(self) -> None:
492
493
  """Test write/read roundtrip through protocol."""
493
494
  instances = [
494
- SegmentationInstance(1, 1, np.array([[10, 20], [30, 40]], dtype=np.int32)),
495
- SegmentationInstance(2, 1, np.array([[100, 200], [101, 201]], dtype=np.int32)),
495
+ SegmentationInstance(1, 1, 0.95, np.array([[10, 20], [30, 40]], dtype=np.int32)),
496
+ SegmentationInstance(2, 1, 0.95, np.array([[100, 200], [101, 201]], dtype=np.int32)),
496
497
  ]
497
498
  original = SegmentationFrame(frame_id=42, width=1920, height=1080, instances=instances)
498
499
 
@@ -528,20 +529,20 @@ class TestSegmentationProtocol:
528
529
  """Test writing a single instance."""
529
530
  points: List[Tuple[int, int]] = [(10, 20), (30, 40)]
530
531
  buffer = bytearray(100)
531
- written = SegmentationProtocol.write_instance(buffer, 5, 3, points)
532
+ written = SegmentationProtocol.write_instance(buffer, 5, 3, 0.95, points)
532
533
 
533
- # Should have classId(1) + instanceId(1) + pointCount varint + points
534
- assert written > 4
534
+ # Should have classId(1) + instanceId(1) + confidence(2) + pointCount varint + points
535
+ assert written > 6
535
536
 
536
537
  def test_calculate_instance_size(self) -> None:
537
538
  """Test size calculation."""
538
539
  size = SegmentationProtocol.calculate_instance_size(10)
539
- # classId(1) + instanceId(1) + pointCount(max 5) + points(max 10 each)
540
- assert size == 1 + 1 + 5 + (10 * 10)
540
+ # classId(1) + instanceId(1) + confidence(2) + pointCount(max 5) + points(max 10 each)
541
+ assert size == 1 + 1 + 2 + 5 + (10 * 10)
541
542
 
542
543
  def test_try_read_success(self) -> None:
543
544
  """Test try_read with valid data."""
544
- instances = [SegmentationInstance(1, 1, np.array([[10, 20]], dtype=np.int32))]
545
+ instances = [SegmentationInstance(1, 1, 0.95, np.array([[10, 20]], dtype=np.int32))]
545
546
  original = SegmentationFrame(frame_id=1, width=100, height=100, instances=instances)
546
547
 
547
548
  buffer = bytearray(100)
@@ -571,7 +572,7 @@ class TestSegmentationProtocol:
571
572
 
572
573
  def test_empty_points(self) -> None:
573
574
  """Test roundtrip with instance having empty points."""
574
- instances = [SegmentationInstance(1, 1, np.empty((0, 2), dtype=np.int32))]
575
+ instances = [SegmentationInstance(1, 1, 0.95, np.empty((0, 2), dtype=np.int32))]
575
576
  original = SegmentationFrame(frame_id=1, width=100, height=100, instances=instances)
576
577
 
577
578
  buffer = bytearray(100)
@@ -592,8 +593,8 @@ class TestSegmentationResultSource:
592
593
  with SegmentationResultWriter(
593
594
  42, 1920, 1080, frame_sink=StreamFrameSink(stream, leave_open=True)
594
595
  ) as writer:
595
- writer.append(1, 1, np.array([[10, 20], [30, 40]], dtype=np.int32))
596
- writer.append(2, 1, np.array([[100, 200]], dtype=np.int32))
596
+ writer.append(1, 1, 0.95, np.array([[10, 20], [30, 40]], dtype=np.int32))
597
+ writer.append(2, 1, 0.95, np.array([[100, 200]], dtype=np.int32))
597
598
 
598
599
  # Read via source
599
600
  stream.seek(0)
@@ -618,12 +619,12 @@ class TestSegmentationResultSource:
618
619
 
619
620
  # Write frame 1
620
621
  with SegmentationResultWriter(1, 640, 480, frame_sink=sink) as writer:
621
- writer.append(1, 1, np.array([[10, 20]], dtype=np.int32))
622
+ writer.append(1, 1, 0.95, np.array([[10, 20]], dtype=np.int32))
622
623
 
623
624
  # Write frame 2
624
625
  with SegmentationResultWriter(2, 1920, 1080, frame_sink=sink) as writer:
625
- writer.append(2, 1, np.array([[100, 200]], dtype=np.int32))
626
- writer.append(3, 1, np.array([[300, 400]], dtype=np.int32))
626
+ writer.append(2, 1, 0.95, np.array([[100, 200]], dtype=np.int32))
627
+ writer.append(3, 1, 0.95, np.array([[300, 400]], dtype=np.int32))
627
628
 
628
629
  # Read via source
629
630
  stream.seek(0)
@@ -645,7 +646,7 @@ class TestSegmentationResultSource:
645
646
  with SegmentationResultWriter(
646
647
  1, 100, 100, frame_sink=StreamFrameSink(stream, leave_open=True)
647
648
  ) as writer:
648
- writer.append(1, 1, np.array([[10, 20]], dtype=np.int32))
649
+ writer.append(1, 1, 0.95, np.array([[10, 20]], dtype=np.int32))
649
650
 
650
651
  stream.seek(0)
651
652
  frame_source = StreamFrameSource(stream)
@@ -167,7 +167,7 @@ class TestUnixSocketTransportRoundTrip:
167
167
  frame_id=42, width=1920, height=1080, stream=buffer
168
168
  ) as writer:
169
169
  points = np.array([[100, 200], [101, 201], [102, 199]], dtype=np.int32)
170
- writer.append(class_id=1, instance_id=1, points=points)
170
+ writer.append(class_id=1, instance_id=1, confidence=0.95, points=points)
171
171
 
172
172
  # Get frame data (with varint prefix)
173
173
  buffer.seek(0)
@@ -1 +0,0 @@
1
- 1.1.46