1
- """
2
- .. py:class:: ColorCameraParams
3
-
4
- Color camera intrinsic calibration.
5
-
6
- .. py:attribute:: fx
7
-
8
- Focal length for x-axis (pixels)
9
-
10
- .. py:attribute:: fy
11
-
12
- Focal length for y-axis (pixels)
13
-
14
- .. py:attribute:: cx
15
-
16
- Principal point for x-axis (pixels)
17
-
18
- .. py:attribute:: cy
19
-
20
- Principal point for y-axis (pixels)
21
-
22
- .. py:class:: IrCameraParams
23
-
24
- IR/depth camera intrinsic calibration.
25
-
26
- .. py:attribute:: fx
27
-
28
- Focal length for x-axis (pixels)
29
-
30
- .. py:attribute:: fy
31
-
32
- Focal length for y-axis (pixels)
33
-
34
- .. py:attribute:: cx
35
-
36
- Principal point for x-axis (pixels)
37
-
38
- .. py:attribute:: cy
39
-
40
- Principal point for y-axis (pixels)
41
-
42
- .. py:attribute:: k1
43
-
44
- Radial distortion co-efficient, 1st-order
45
-
46
- .. py:attribute:: k2
47
-
48
- Radial distortion co-efficient, 2nd-order
49
-
50
- .. py:attribute:: k3
51
-
52
- Radial distortion co-efficient, 3rd-order
53
-
54
- .. py:attribute:: p1
55
-
56
- Tangential distortion co-efficient
57
-
58
- .. py:attribute:: p2
59
-
60
- Tangential distortion co-efficient
61
-
62
- """
63
1
from __future__ import print_function
64
2
65
3
from contextlib import contextmanager
79
17
'FrameFormat' ,
80
18
'Frame' ,
81
19
'Registration' ,
20
+ 'IrCameraParams' ,
21
+ 'ColorCameraParams'
82
22
)
83
23
84
24
_FREENECT2_SINGLETON = None
@@ -160,6 +100,68 @@ def __call__(self, frame_type, frame):
160
100
def get (self , timeout = False ):
161
101
return self .queue .get (True , timeout )
162
102
103
+ class ColorCameraParams (object ):
104
+ """
105
+ Color camera intrinsic calibration.
106
+
107
+ .. py:attribute:: fx
108
+
109
+ Focal length for x-axis (pixels)
110
+
111
+ .. py:attribute:: fy
112
+
113
+ Focal length for y-axis (pixels)
114
+
115
+ .. py:attribute:: cx
116
+
117
+ Principal point for x-axis (pixels)
118
+
119
+ .. py:attribute:: cy
120
+
121
+ Principal point for y-axis (pixels)
122
+ """
123
+
124
+ class IrCameraParams (object ):
125
+ """
126
+ IR/depth camera intrinsic calibration.
127
+
128
+ .. py:attribute:: fx
129
+
130
+ Focal length for x-axis (pixels)
131
+
132
+ .. py:attribute:: fy
133
+
134
+ Focal length for y-axis (pixels)
135
+
136
+ .. py:attribute:: cx
137
+
138
+ Principal point for x-axis (pixels)
139
+
140
+ .. py:attribute:: cy
141
+
142
+ Principal point for y-axis (pixels)
143
+
144
+ .. py:attribute:: k1
145
+
146
+ Radial distortion co-efficient, 1st-order
147
+
148
+ .. py:attribute:: k2
149
+
150
+ Radial distortion co-efficient, 2nd-order
151
+
152
+ .. py:attribute:: k3
153
+
154
+ Radial distortion co-efficient, 3rd-order
155
+
156
+ .. py:attribute:: p1
157
+
158
+ Tangential distortion co-efficient
159
+
160
+ .. py:attribute:: p2
161
+
162
+ Tangential distortion co-efficient
163
+ """
164
+
163
165
class Device (object ):
164
166
"""Control a single device.
165
167
@@ -498,6 +500,8 @@ class Registration(object):
498
500
499
501
"""
500
502
def __init__ (self , depth_p , rgb_p ):
503
+ self .depth_p = depth_p
504
+ self .rgb_p = rgb_p
501
505
self ._c_object = ffi .gc (
502
506
lib .freenect2_registration_create (depth_p , rgb_p ),
503
507
lib .freenect2_registration_dispose )
@@ -573,24 +577,47 @@ def get_points_xyz(self, undistorted, rows, cols):
573
577
ffi .cast ('float*' , ys .ctypes .data ),
574
578
ffi .cast ('float*' , zs .ctypes .data )
575
579
)
576
- return xs , ys , zs
580
+ return xs , ys , - zs
577
581
578
582
def get_points_xyz_array (self , undistorted ):
579
583
"""Return a 3D array of x, y, z points for each point in an undistorted
580
584
frame. Invalid points are Nan-ed.
581
585
582
586
Args:
583
- undistorted (:py:class:`Frame`): the undistorted depth frame
587
+ undistorted (:py:class:`. Frame`): the undistorted depth frame
584
588
585
589
Returns:
586
- A 512x424x3 array of 3D points. The last dimension corresponding to
590
+ A 424x512x3 array of 3D points. The last dimension corresponding to
587
591
x, y and z.
588
592
589
593
"""
590
594
cols , rows = np .meshgrid (
591
595
np .arange (undistorted .width ), np .arange (undistorted .height ))
592
596
return np .dstack (self .get_points_xyz (undistorted , rows , cols ))
593
597
598
+ def get_big_points_xyz_array (self , big_depth ):
599
+ """Like :py:meth:`.get_points_xyz_array` but operates on the "big" depth
600
+ map which can be returned from :py:meth:`.apply`.
601
+
602
+ Args:
603
+ big_depth (:py:class:`.Frame`): big 1920x1082 frame returned from
604
+ :py:meth:`.apply`.
605
+
606
+ Returns:
607
+ A 1082x1920x3 array of 3D points. The last dimension corresponding
608
+ to x, y and z.
609
+
610
+ """
611
+ points = np .ones ((big_depth .height , big_depth .width , 3 ), dtype = np .float32 )
612
+ points [..., 2 ] = 1e-3 * big_depth .to_array ()
613
+ points [..., 0 ], points [..., 1 ] = np .meshgrid (
614
+ (np .arange (1920 ) - self .rgb_p .cx ) / self .rgb_p .fx ,
615
+ (1080 - np .arange (- 1 , 1081 ) - self .rgb_p .cy ) / self .rgb_p .fy )
616
+ points [..., 0 ] *= points [..., 2 ]
617
+ points [..., 1 ] *= points [..., 2 ]
618
+
619
+ return points
620
+
594
621
def write_pcd (self , file_object , undistorted , registered = None ):
595
622
"""Write depth map and (optionally) RGB data to libpcl-compatible PCD
596
623
format file. If the registered RGB frame is present, each point is
@@ -604,38 +631,78 @@ def write_pcd(self, file_object, undistorted, registered=None):
604
631
Args:
605
632
file_object (file): A file object to write PCD data to
606
633
undistorted (:py:class:`Frame`): the undistorted depth frame
607
- rgb (:py:class:`Frame`): if not-None, the RGB data corresponding to
634
+ registered (:py:class:`Frame`): if not-None, the RGB data corresponding to
608
635
the depth frame.
609
636
"""
610
- cols , rows = np .meshgrid (np .arange (undistorted .width ), np .arange (undistorted .height ))
611
- xs , ys , zs = self .get_points_xyz (undistorted , rows , cols )
612
- n_points = int (np .product (xs .shape ))
613
-
614
- file_object .write (b'VERSION .7\n ' )
615
-
616
- if registered is None :
617
- file_object .write (
618
- b'FIELDS x y z\n SIZE 4 4 4\n TYPE F F F\n COUNT 1 1 1\n ' )
619
- data = np .zeros ((n_points , 3 ), order = 'C' , dtype = np .float32 )
620
- data [:, 0 ] = - xs .flatten ()
621
- data [:, 1 ] = - ys .flatten ()
622
- data [:, 2 ] = - zs .flatten ()
623
- else :
624
- file_object .write (
625
- b'FIELDS x y z rgb\n SIZE 4 4 4 4\n TYPE F F F F\n COUNT 1 1 1 1\n ' )
626
- bgrx = registered .to_array ().astype (np .uint32 )
627
- rgbs = (
628
- bgrx [..., 0 ] + (bgrx [..., 1 ] << 8 ) + (bgrx [..., 2 ] << 16 )
629
- ).view (np .float32 )
630
- data = np .zeros ((n_points , 4 ), order = 'C' , dtype = np .float32 )
631
- data [:, 0 ] = - xs .flatten ()
632
- data [:, 1 ] = - ys .flatten ()
633
- data [:, 2 ] = - zs .flatten ()
634
- data [:, 3 ] = rgbs .flatten ()
635
-
636
- file_object .write ('WIDTH {}\n ' .format (undistorted .width ).encode ())
637
- file_object .write ('HEIGHT {}\n ' .format (undistorted .height ).encode ())
638
- file_object .write (b'VIEWPOINT 0 0 0 1 0 0 0\n ' )
639
- file_object .write ('POINTS {}\n ' .format (n_points ).encode ())
640
- file_object .write (b'DATA binary\n ' )
641
- file_object .write (data .tobytes ())
637
+ write_pcd (
638
+ file_object , self .get_points_xyz_array (undistorted ), registered )
639
+
640
+ def write_big_pcd (self , file_object , big_depth , rgb = None ):
641
+ """Write depth map and (optionally) RGB data to libpcl-compatible PCD
642
+ format file. Works like :py:meth:`.write_pcd` except that it works on
643
+ the "big" depth map which can be returned from :py:meth:`apply`. If the
644
+ RGB frame is present, each point is coloured according to the image
645
+ otherwise the points are left uncoloured.
646
+
647
+ .. note::
648
+
649
+ Under Python 3 the file object *must* be opened in binary mode.
650
+
651
+ Args:
652
+ file_object (file): A file object to write PCD data to
653
+ big_depth (:py:class:`Frame`): the 1920x1082 de[th frame
654
+ registered (:py:class:`Frame`): if not-None, the RGB data from the
655
+ color camera
656
+ """
657
+ write_pcd (
658
+ file_object ,
659
+ self .get_big_points_xyz_array (big_depth )[1 :- 1 , ...], rgb )
660
+
661
+ def write_pcd (file_object , points , rgb = None ):
662
+ """Write 3d points and (optionally) RGB data to libpcl-compatible PCD
663
+ format file. If the registered RGB frame is present, each point is
664
+ coloured according to the image otherwise the points are left
665
+ uncoloured.
666
+
667
+ .. note::
668
+
669
+ Under Python 3 the file object *must* be opened in binary mode.
670
+
671
+ Args:
672
+ file_object (file): A file object to write PCD data to
673
+ points (array): A NxMx3 array of 3d points.
674
+ rgb (:py:class:`Frame`): if not-None, the RGB frame corresponding to
675
+ the points array. Assumed to be NxM.
676
+ """
677
+ assert len (points .shape ) == 3
678
+ xs , ys , zs = points [..., 0 ], points [..., 1 ], points [..., 2 ]
679
+ n_points = int (np .product (points .shape [:- 1 ]))
680
+
681
+ file_object .write (b'VERSION .7\n ' )
682
+
683
+ if rgb is None :
684
+ file_object .write (
685
+ b'FIELDS x y z\n SIZE 4 4 4\n TYPE F F F\n COUNT 1 1 1\n ' )
686
+ data = np .zeros ((n_points , 3 ), order = 'C' , dtype = np .float32 )
687
+ data [:, 0 ] = xs .flatten ()
688
+ data [:, 1 ] = ys .flatten ()
689
+ data [:, 2 ] = zs .flatten ()
690
+ else :
691
+ file_object .write (
692
+ b'FIELDS x y z rgb\n SIZE 4 4 4 4\n TYPE F F F F\n COUNT 1 1 1 1\n ' )
693
+ bgrx = rgb .to_array ().astype (np .uint32 )
694
+ rgbs = (
695
+ bgrx [..., 0 ] + (bgrx [..., 1 ] << 8 ) + (bgrx [..., 2 ] << 16 )
696
+ ).view (np .float32 )
697
+ data = np .zeros ((n_points , 4 ), order = 'C' , dtype = np .float32 )
698
+ data [:, 0 ] = xs .flatten ()
699
+ data [:, 1 ] = ys .flatten ()
700
+ data [:, 2 ] = zs .flatten ()
701
+ data [:, 3 ] = rgbs .flatten ()
702
+
703
+ file_object .write ('WIDTH {}\n ' .format (points .shape [1 ]).encode ())
704
+ file_object .write ('HEIGHT {}\n ' .format (points .shape [0 ]).encode ())
705
+ file_object .write (b'VIEWPOINT 0 0 0 1 0 0 0\n ' )
706
+ file_object .write ('POINTS {}\n ' .format (n_points ).encode ())
707
+ file_object .write (b'DATA binary\n ' )
708
+ file_object .write (data .tobytes ())
0 commit comments