6
6
import pyrealsense2 as rs
7
7
from rspy import test , log
8
8
from rspy import tests_wrapper as tw
9
+ import numpy as np
9
10
import os
10
- import math
11
+ import time
11
12
12
13
# Start depth + color streams and go through the frame to make sure it is showing a depth image
13
14
# Color stream is only used to display the way the camera is facing
31
32
cfg .enable_stream (rs .stream .color , rs .format .bgr8 , 30 )
32
33
33
34
34
- def display_image (img ):
35
- """
36
- Display a given image and exits when the x button or esc key are pressed
37
- """
38
- import cv2
35
+ pipeline = rs .pipeline (ctx )
36
+ pipeline_profile = pipeline .start (cfg )
37
+ pipeline .wait_for_frames ()
38
+ time .sleep (2 )
39
39
40
- window_title = "Output Stream"
41
- cv2 .imshow (window_title , img )
42
- while cv2 .getWindowProperty (window_title , cv2 .WND_PROP_VISIBLE ) > 0 :
43
- k = cv2 .waitKey (33 )
44
- if k == 27 : # Esc key to stop
45
- cv2 .destroyAllWindows ()
46
- break
47
- elif k == - 1 : # normally -1 returned
48
- pass
49
-
50
-
51
- def frames_to_image (depth , color , save , display , laser_enabled ):
40
+ def frames_to_image (depth , color , save , display ):
52
41
"""
53
42
This function gets depth and color frames, transforms them to an image (numpy array)
54
43
and then save and/or display
55
44
56
45
If color frame is given, it will also concatenate it with the depth frame before doing the given action
57
46
"""
58
- import numpy as np
47
+
48
+ def display_image (img ):
49
+ """
50
+ Display a given image and exits when the x button or esc key are pressed
51
+ """
52
+ import cv2
53
+
54
+ window_title = "Output Stream"
55
+ cv2 .imshow (window_title , img )
56
+ while cv2 .getWindowProperty (window_title , cv2 .WND_PROP_VISIBLE ) > 0 :
57
+ k = cv2 .waitKey (33 )
58
+ if k == 27 : # Esc key to stop
59
+ cv2 .destroyAllWindows ()
60
+ break
61
+ elif k == - 1 : # normally -1 returned
62
+ pass
63
+
59
64
import cv2
60
65
61
66
colorizer = rs .colorizer ()
@@ -75,81 +80,43 @@ def frames_to_image(depth, color, save, display, laser_enabled):
75
80
img = np .concatenate ((depth_image , color_image ), axis = 1 )
76
81
77
82
if save :
78
- file_name = f"output_stream{ '_laser_on' if laser_enabled else '_laser_off' } .png"
83
+ file_name = f"output_stream.png"
79
84
log .i ("Saved image in" , os .getcwd () + "\\ " + file_name )
80
85
cv2 .imwrite (file_name , img )
81
86
if display :
82
87
display_image (img )
83
88
84
89
85
- def get_frames (config , laser_enabled ):
86
- pipeline = rs .pipeline (ctx )
87
- pipeline_profile = pipeline .start (config )
88
-
89
- sensor = pipeline_profile .get_device ().first_depth_sensor ()
90
- if laser_enabled and sensor .supports (rs .option .laser_power ):
91
- sensor .set_option (rs .option .laser_power , sensor .get_option_range (rs .option .laser_power ).max )
92
- sensor .set_option (rs .option .emitter_enabled , 1 if laser_enabled else 0 )
93
-
94
- # to get a proper image, we sometimes need to wait a few frames, like when the camera is facing a light source
95
- frames = pipeline .wait_for_frames ()
96
- for i in range (30 ):
97
- frames = pipeline .wait_for_frames ()
98
- depth = frames .get_depth_frame ()
99
- color = frames .get_color_frame ()
100
- pipeline .stop ()
101
- return depth , color
102
-
90
+ def get_distances (depth_frame ):
91
+ MAX_METERS = 10 # max distance that can be detected, in meters
103
92
104
- def round_to_units (num ):
105
- """
106
- Input: Distance of a certain point, in meters
107
- Output: Distance according to the given detail level, in cm
108
- """
109
- in_cm = round (num , 2 ) * 100 # convert to cm
110
- return math .floor (in_cm / DETAIL_LEVEL ) * DETAIL_LEVEL # rounds the distance according to the given unit
93
+ depth_m = np .asanyarray (depth_frame .get_data ()).astype (np .float32 ) * depth_frame .get_units ()
111
94
95
+ valid_mask = (depth_m < MAX_METERS )
96
+ valid_depths = depth_m [valid_mask ] # ignore invalid pixels
112
97
113
- def sort_dict (my_dict ):
114
- my_keys = list (my_dict .keys ())
115
- my_keys .sort ()
116
- sorted_dict = {i : my_dict [i ] for i in my_keys }
117
- return sorted_dict
98
+ # convert to cm and round according to DETAIL_LEVEL
99
+ rounded_depths = (np .floor (valid_depths * 100.0 / DETAIL_LEVEL ) * DETAIL_LEVEL ).astype (np .int32 )
118
100
101
+ unique_vals , counts = np .unique (rounded_depths , return_counts = True )
102
+
103
+ dists = dict (zip (unique_vals .tolist (), counts .tolist ()))
104
+ total = valid_depths .size
119
105
120
- def get_distances (depth ):
121
- MAX_METERS = 10 # max distance that can be detected, in meters
122
- dists = {}
123
- total = 0
124
- for y in range (depth .get_height ()):
125
- for x in range (depth .get_width ()):
126
- dist = depth .get_distance (x , y )
127
- if dist >= MAX_METERS : # out of bounds, assuming it is a junk value
128
- continue
129
-
130
- dist = round_to_units (dist ) # round according to DETAIL_LEVEL
131
-
132
- if dists .get (dist ) is not None :
133
- dists [dist ] += 1
134
- else :
135
- dists [dist ] = 1
136
- total += 1
137
-
138
- dists = sort_dict (dists ) # for debug convenience
139
106
log .d ("Distances detected in frame are:" , dists )
140
107
return dists , total
141
108
142
109
143
- def is_depth_meaningful (config , laser_enabled = True , save_image = False , show_image = False ):
110
+ def is_depth_meaningful (save_image = False , show_image = False ):
144
111
"""
145
112
Checks if the camera is showing a frame with a meaningful depth.
146
113
DETAIL_LEVEL is setting how close distances need to be, to be considered the same
147
114
148
115
returns true if frame shows meaningful depth
149
116
"""
150
-
151
- depth , color = get_frames ( config , laser_enabled )
152
-
117
+ frames = pipeline . wait_for_frames ()
118
+ depth = frames . get_depth_frame ( )
119
+ color = frames . get_color_frame ()
153
120
if not depth :
154
121
log .f ("Error getting depth frame" )
155
122
return False
@@ -160,32 +127,34 @@ def is_depth_meaningful(config, laser_enabled=True, save_image=False, show_image
160
127
161
128
# save or display image (only possible through manual debugging)
162
129
if save_image or show_image :
163
- frames_to_image (depth , color , save_image , show_image , laser_enabled )
164
-
165
- # Goes over the distances found, and checks if any distance is the same on more than 90% of the pixels
166
- meaningful_depth = True
167
- for key in dists :
168
- if dists [key ] > total * 0.9 :
169
- meaningful_depth = False
170
- break
130
+ frames_to_image (depth , color , save_image , show_image )
131
+
132
+ # If any distance is the same on more than 90% of the pixels, there is no meaningful depth
133
+ meaningful_depth = not any (v > total * 0.9 for v in dists .values ())
171
134
num_blank_pixels = dists [0 ]
172
135
return meaningful_depth , num_blank_pixels
173
136
174
137
175
138
################################################################################################
176
139
177
140
test .start ("Testing depth frame - laser ON -" , dev .get_info (rs .camera_info .name ))
178
- is_there_depth = False
179
- max_black_pixels = float ('inf' )
141
+ # enable laser
142
+ sensor = pipeline_profile .get_device ().first_depth_sensor ()
143
+ if sensor .supports (rs .option .laser_power ):
144
+ sensor .set_option (rs .option .laser_power , sensor .get_option_range (rs .option .laser_power ).max )
145
+ sensor .set_option (rs .option .emitter_enabled , 1 ) # should be set to 0 for laser off
146
+
147
+ has_depth = False
180
148
181
- # we perform the check on a few different frames to make sure we get the best indication if we have depth
149
+ # we check a few different frames to try and detect depth
182
150
for frame_num in range (FRAMES_TO_CHECK ):
183
- result , laser_black_pixels = is_depth_meaningful (cfg , laser_enabled = True , save_image = DEBUG_MODE , show_image = DEBUG_MODE )
184
- is_there_depth = is_there_depth or result # we check if we found depth at any frame checked
185
- max_black_pixels = min ( max_black_pixels , laser_black_pixels )
151
+ has_depth , laser_black_pixels = is_depth_meaningful (save_image = DEBUG_MODE , show_image = DEBUG_MODE )
152
+ if has_depth :
153
+ break
186
154
187
- test .check (is_there_depth is True )
155
+ test .check (has_depth is True )
188
156
test .finish ()
189
157
158
+ pipeline .stop ()
190
159
tw .stop_wrapper ( dev )
191
160
test .print_results_and_exit ()
0 commit comments