Skip to content

Commit 8a2fb92

Browse files
Version 1.2.4 (#126)
* fix install fail on recent python with python_version requirement * Add functions to access system timestamps for each image (#122) * fix memory usage problem for calls to capture.transformed_ir (#125) * version 1.2.4 Co-authored-by: Johan von Forstner <[email protected]>
1 parent 0554de5 commit 8a2fb92

File tree

3 files changed

+64
-22
lines changed

3 files changed

+64
-22
lines changed

pyk4a/capture.py

+37-7
Original file line numberDiff line numberDiff line change
@@ -26,12 +26,15 @@ def __init__(
2626

2727
self._color: Optional[np.ndarray] = None
2828
self._color_timestamp_usec: int = 0
29+
self._color_system_timestamp_nsec: int = 0
2930
self._color_exposure_usec: Optional[int] = None
3031
self._color_white_balance: Optional[int] = None
3132
self._depth: Optional[np.ndarray] = None
3233
self._depth_timestamp_usec: int = 0
34+
self._depth_system_timestamp_nsec: int = 0
3335
self._ir: Optional[np.ndarray] = None
3436
self._ir_timestamp_usec: int = 0
37+
self._ir_system_timestamp_nsec: int = 0
3538
self._depth_point_cloud: Optional[np.ndarray] = None
3639
self._transformed_depth: Optional[np.ndarray] = None
3740
self._transformed_depth_point_cloud: Optional[np.ndarray] = None
@@ -41,9 +44,11 @@ def __init__(
4144
@property
4245
def color(self) -> Optional[np.ndarray]:
4346
if self._color is None:
44-
self._color, self._color_timestamp_usec = k4a_module.capture_get_color_image(
45-
self._capture_handle, self.thread_safe
46-
)
47+
(
48+
self._color,
49+
self._color_timestamp_usec,
50+
self._color_system_timestamp_nsec,
51+
) = k4a_module.capture_get_color_image(self._capture_handle, self.thread_safe)
4752
return self._color
4853

4954
@property
@@ -53,6 +58,13 @@ def color_timestamp_usec(self) -> int:
5358
self.color
5459
return self._color_timestamp_usec
5560

61+
@property
62+
def color_system_timestamp_nsec(self) -> int:
63+
"""System timestamp for color image in nanoseconds. Corresponds to Python's time.perf_counter_ns()."""
64+
if self._color is None:
65+
self.color
66+
return self._color_system_timestamp_nsec
67+
5668
@property
5769
def color_exposure_usec(self) -> int:
5870
if self._color_exposure_usec is None:
@@ -74,9 +86,11 @@ def color_white_balance(self) -> int:
7486
@property
7587
def depth(self) -> Optional[np.ndarray]:
7688
if self._depth is None:
77-
self._depth, self._depth_timestamp_usec = k4a_module.capture_get_depth_image(
78-
self._capture_handle, self.thread_safe
79-
)
89+
(
90+
self._depth,
91+
self._depth_timestamp_usec,
92+
self._depth_system_timestamp_nsec,
93+
) = k4a_module.capture_get_depth_image(self._capture_handle, self.thread_safe)
8094
return self._depth
8195

8296
@property
@@ -86,11 +100,20 @@ def depth_timestamp_usec(self) -> int:
86100
self.depth
87101
return self._depth_timestamp_usec
88102

103+
@property
104+
def depth_system_timestamp_nsec(self) -> int:
105+
"""System timestamp for depth image in nanoseconds. Corresponds to Python's time.perf_counter_ns()."""
106+
if self._depth is None:
107+
self.depth
108+
return self._depth_system_timestamp_nsec
109+
89110
@property
90111
def ir(self) -> Optional[np.ndarray]:
91112
"""Device timestamp for IR image. Not equal host machine timestamp!. Like as equal depth image timestamp"""
92113
if self._ir is None:
93-
self._ir, self._ir_timestamp_usec = k4a_module.capture_get_ir_image(self._capture_handle, self.thread_safe)
114+
self._ir, self._ir_timestamp_usec, self._ir_system_timestamp_nsec = k4a_module.capture_get_ir_image(
115+
self._capture_handle, self.thread_safe
116+
)
94117
return self._ir
95118

96119
@property
@@ -99,6 +122,13 @@ def ir_timestamp_usec(self) -> int:
99122
self.ir
100123
return self._ir_timestamp_usec
101124

125+
@property
126+
def ir_system_timestamp_nsec(self) -> int:
127+
"""System timestamp for IR image in nanoseconds. Corresponds to Python's time.perf_counter_ns()."""
128+
if self._ir is None:
129+
self.ir
130+
return self._ir_system_timestamp_nsec
131+
102132
@property
103133
def transformed_depth(self) -> Optional[np.ndarray]:
104134
if self._transformed_depth is None and self.depth is not None:

pyk4a/pyk4a.cpp

+26-14
Original file line numberDiff line numberDiff line change
@@ -517,6 +517,11 @@ k4a_result_t k4a_image_to_numpy(k4a_image_t *img_src, PyArrayObject **img_dst) {
517517
dims[1] = k4a_image_get_width_pixels(*img_src);
518518
*img_dst = (PyArrayObject *)PyArray_SimpleNewFromData(2, dims, NPY_UINT16, buffer);
519519
break;
520+
case K4A_IMAGE_FORMAT_CUSTOM8:
521+
dims[0] = k4a_image_get_height_pixels(*img_src);
522+
dims[1] = k4a_image_get_width_pixels(*img_src);
523+
*img_dst = (PyArrayObject *)PyArray_SimpleNewFromData(2, dims, NPY_UINT8, buffer);
524+
break;
520525
case K4A_IMAGE_FORMAT_CUSTOM:
521526
// xyz in uint16 format
522527
dims[0] = k4a_image_get_height_pixels(*img_src);
@@ -544,13 +549,15 @@ k4a_result_t numpy_to_k4a_image(PyArrayObject *img_src, k4a_image_t *img_dst, k4
544549

545550
switch (format) {
546551
case K4A_IMAGE_FORMAT_DEPTH16:
552+
case K4A_IMAGE_FORMAT_CUSTOM16:
553+
case K4A_IMAGE_FORMAT_IR16:
547554
pixel_size = (int)sizeof(uint16_t);
548555
break;
549556
case K4A_IMAGE_FORMAT_COLOR_BGRA32:
550557
pixel_size = (int)sizeof(uint32_t);
551558
break;
552-
case K4A_IMAGE_FORMAT_CUSTOM16:
553-
pixel_size = (unsigned int)sizeof(int16_t);
559+
case K4A_IMAGE_FORMAT_CUSTOM8:
560+
pixel_size = (int)sizeof(uint8_t);
554561
break;
555562
default:
556563
// Not supported
@@ -707,8 +714,7 @@ static PyObject *transformation_depth_image_to_color_camera_custom(PyObject *sel
707714
if (K4A_RESULT_SUCCEEDED == res) {
708715
res = k4a_image_create(k4a_image_get_format(custom_image), RESOLUTION_TO_DIMS[color_resolution][0],
709716
RESOLUTION_TO_DIMS[color_resolution][1],
710-
RESOLUTION_TO_DIMS[color_resolution][0] * static_cast<int32_t>(sizeof(int16_t)),
711-
custom_image_transformed);
717+
RESOLUTION_TO_DIMS[color_resolution][0] * (int)sizeof(uint16_t), custom_image_transformed);
712718
}
713719

714720
if (K4A_RESULT_SUCCEEDED == res) {
@@ -729,7 +735,7 @@ static PyObject *transformation_depth_image_to_color_camera_custom(PyObject *sel
729735
}
730736

731737
if (K4A_RESULT_SUCCEEDED == res) {
732-
return Py_BuildValue("OO", np_custom_image, np_depth_image);
738+
return Py_BuildValue("NN", np_custom_image, np_depth_image);
733739
} else {
734740
free(depth_image_transformed);
735741
free(custom_image_transformed);
@@ -838,6 +844,7 @@ static PyObject *capture_get_color_image(PyObject *self, PyObject *args) {
838844
PyObject *capsule;
839845
int thread_safe;
840846
uint64_t device_timestamp_usec = 0;
847+
uint64_t system_timestamp_nsec = 0;
841848
PyThreadState *thread_state;
842849
k4a_result_t res = K4A_RESULT_FAILED;
843850

@@ -847,7 +854,7 @@ static PyObject *capture_get_color_image(PyObject *self, PyObject *args) {
847854
k4a_image_t *image = (k4a_image_t *)malloc(sizeof(k4a_image_t));
848855
if (image == NULL) {
849856
fprintf(stderr, "Cannot allocate memory");
850-
return Py_BuildValue("NK", Py_None, device_timestamp_usec);
857+
return Py_BuildValue("NKK", Py_None, device_timestamp_usec, system_timestamp_nsec);
851858
}
852859

853860
thread_state = _gil_release(thread_safe);
@@ -861,10 +868,11 @@ static PyObject *capture_get_color_image(PyObject *self, PyObject *args) {
861868

862869
if (K4A_RESULT_SUCCEEDED == res) {
863870
device_timestamp_usec = k4a_image_get_device_timestamp_usec(*image);
864-
return Py_BuildValue("NK", np_image, device_timestamp_usec);
871+
system_timestamp_nsec = k4a_image_get_system_timestamp_nsec(*image);
872+
return Py_BuildValue("NKK", np_image, device_timestamp_usec, system_timestamp_nsec);
865873
} else {
866874
free(image);
867-
return Py_BuildValue("NK", Py_None, device_timestamp_usec);
875+
return Py_BuildValue("NKK", Py_None, device_timestamp_usec, system_timestamp_nsec);
868876
}
869877
}
870878

@@ -873,6 +881,7 @@ static PyObject *capture_get_depth_image(PyObject *self, PyObject *args) {
873881
PyObject *capsule;
874882
int thread_safe;
875883
uint64_t device_timestamp_usec = 0;
884+
uint64_t system_timestamp_nsec = 0;
876885
PyThreadState *thread_state;
877886
k4a_result_t res = K4A_RESULT_FAILED;
878887

@@ -882,7 +891,7 @@ static PyObject *capture_get_depth_image(PyObject *self, PyObject *args) {
882891
k4a_image_t *image = (k4a_image_t *)malloc(sizeof(k4a_image_t));
883892
if (image == NULL) {
884893
fprintf(stderr, "Cannot allocate memory");
885-
return Py_BuildValue("NK", Py_None, device_timestamp_usec);
894+
return Py_BuildValue("NKK", Py_None, device_timestamp_usec, system_timestamp_nsec);
886895
}
887896

888897
thread_state = _gil_release(thread_safe);
@@ -896,10 +905,11 @@ static PyObject *capture_get_depth_image(PyObject *self, PyObject *args) {
896905

897906
if (K4A_RESULT_SUCCEEDED == res) {
898907
device_timestamp_usec = k4a_image_get_device_timestamp_usec(*image);
899-
return Py_BuildValue("NK", np_image, device_timestamp_usec);
908+
system_timestamp_nsec = k4a_image_get_system_timestamp_nsec(*image);
909+
return Py_BuildValue("NKK", np_image, device_timestamp_usec, system_timestamp_nsec);
900910
} else {
901911
free(image);
902-
return Py_BuildValue("NK", Py_None, device_timestamp_usec);
912+
return Py_BuildValue("NKK", Py_None, device_timestamp_usec, system_timestamp_nsec);
903913
}
904914
}
905915

@@ -908,6 +918,7 @@ static PyObject *capture_get_ir_image(PyObject *self, PyObject *args) {
908918
PyObject *capsule;
909919
int thread_safe;
910920
uint64_t device_timestamp_usec = 0;
921+
uint64_t system_timestamp_nsec = 0;
911922
PyThreadState *thread_state;
912923
k4a_result_t res = K4A_RESULT_FAILED;
913924

@@ -917,7 +928,7 @@ static PyObject *capture_get_ir_image(PyObject *self, PyObject *args) {
917928
k4a_image_t *image = (k4a_image_t *)malloc(sizeof(k4a_image_t));
918929
if (image == NULL) {
919930
fprintf(stderr, "Cannot allocate memory");
920-
return Py_BuildValue("NK", Py_None, device_timestamp_usec);
931+
return Py_BuildValue("NKK", Py_None, device_timestamp_usec, system_timestamp_nsec);
921932
}
922933

923934
thread_state = _gil_release(thread_safe);
@@ -931,10 +942,11 @@ static PyObject *capture_get_ir_image(PyObject *self, PyObject *args) {
931942

932943
if (K4A_RESULT_SUCCEEDED == res) {
933944
device_timestamp_usec = k4a_image_get_device_timestamp_usec(*image);
934-
return Py_BuildValue("NK", np_image, device_timestamp_usec);
945+
system_timestamp_nsec = k4a_image_get_system_timestamp_nsec(*image);
946+
return Py_BuildValue("NKK", np_image, device_timestamp_usec, system_timestamp_nsec);
935947
} else {
936948
free(image);
937-
return Py_BuildValue("NK", Py_None, device_timestamp_usec);
949+
return Py_BuildValue("NKK", Py_None, device_timestamp_usec, system_timestamp_nsec);
938950
}
939951
}
940952

setup.cfg

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
[metadata]
22
name = pyk4a
3-
version = 1.2.3
3+
version = 1.2.4
44
description-file = README.md
55
description = Python wrapper over Azure Kinect SDK
66
long_description = file: README.md

0 commit comments

Comments
 (0)