Skip to content

Commit 0fb3667

Browse files
committed
Merge pull request #253 from wiedemeyer/improved_registration
Added filtering of shadowed color regions to registration
2 parents 15b7f08 + d823f84 commit 0fb3667

File tree

4 files changed

+108
-35
lines changed

4 files changed

+108
-35
lines changed

examples/protonect/Protonect.cpp

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -124,7 +124,7 @@ int main(int argc, char *argv[])
124124

125125
libfreenect2::SyncMultiFrameListener listener(libfreenect2::Frame::Color | libfreenect2::Frame::Ir | libfreenect2::Frame::Depth);
126126
libfreenect2::FrameMap frames;
127-
libfreenect2::Frame undistorted(512, 424, 4), registered(512, 424, 3);
127+
libfreenect2::Frame undistorted(512, 424, 4), registered(512, 424, 4);
128128

129129
dev->setColorFrameListener(&listener);
130130
dev->setIrAndDepthFrameListener(&listener);
@@ -142,14 +142,14 @@ int main(int argc, char *argv[])
142142
libfreenect2::Frame *ir = frames[libfreenect2::Frame::Ir];
143143
libfreenect2::Frame *depth = frames[libfreenect2::Frame::Depth];
144144

145-
cv::imshow("rgb", cv::Mat(rgb->height, rgb->width, CV_8UC3, rgb->data));
145+
cv::imshow("rgb", cv::Mat(rgb->height, rgb->width, CV_8UC4, rgb->data));
146146
cv::imshow("ir", cv::Mat(ir->height, ir->width, CV_32FC1, ir->data) / 20000.0f);
147147
cv::imshow("depth", cv::Mat(depth->height, depth->width, CV_32FC1, depth->data) / 4500.0f);
148148

149149
registration->apply(rgb,depth,&undistorted,&registered);
150150

151151
cv::imshow("undistorted", cv::Mat(undistorted.height, undistorted.width, CV_32FC1, undistorted.data) / 4500.0f);
152-
cv::imshow("registered", cv::Mat(registered.height, registered.width, CV_8UC3, registered.data));
152+
cv::imshow("registered", cv::Mat(registered.height, registered.width, CV_8UC4, registered.data));
153153

154154
int key = cv::waitKey(1);
155155
protonect_shutdown = protonect_shutdown || (key > 0 && ((key & 0xFF) == 27)); // shutdown on escape

examples/protonect/include/libfreenect2/registration.h

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,7 @@ class LIBFREENECT2_API Registration
4444
void apply(int dx, int dy, float dz, float& cx, float &cy) const;
4545

4646
// undistort/register a whole image
47-
void apply(const Frame* rgb, const Frame* depth, Frame* undistorted, Frame* registered) const;
47+
void apply(const Frame* rgb, const Frame* depth, Frame* undistorted, Frame* registered, const bool enable_filter = true) const;
4848

4949
private:
5050
void distort(int mx, int my, float& dx, float& dy) const;
@@ -57,6 +57,10 @@ class LIBFREENECT2_API Registration
5757
float depth_to_color_map_x[512 * 424];
5858
float depth_to_color_map_y[512 * 424];
5959
int depth_to_color_map_yi[512 * 424];
60+
61+
const int filter_width_half;
62+
const int filter_height_half;
63+
const float filter_tolerance;
6064
};
6165

6266
} /* namespace libfreenect2 */

examples/protonect/src/registration.cpp

Lines changed: 98 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -84,80 +84,149 @@ void Registration::apply( int dx, int dy, float dz, float& cx, float &cy) const
8484
cx = rx * color.fx + color.cx;
8585
}
8686

87-
void Registration::apply(const Frame *rgb, const Frame *depth, Frame *undistorted, Frame *registered) const
87+
void Registration::apply(const Frame *rgb, const Frame *depth, Frame *undistorted, Frame *registered, const bool enable_filter) const
8888
{
8989
// Check if all frames are valid and have the correct size
9090
if (!undistorted || !rgb || !registered ||
91-
rgb->width != 1920 || rgb->height != 1080 || rgb->bytes_per_pixel != 3 ||
91+
rgb->width != 1920 || rgb->height != 1080 || rgb->bytes_per_pixel != 4 ||
9292
depth->width != 512 || depth->height != 424 || depth->bytes_per_pixel != 4 ||
9393
undistorted->width != 512 || undistorted->height != 424 || undistorted->bytes_per_pixel != 4 ||
94-
registered->width != 512 || registered->height != 424 || registered->bytes_per_pixel != 3)
94+
registered->width != 512 || registered->height != 424 || registered->bytes_per_pixel != 4)
9595
return;
9696

9797
const float *depth_data = (float*)depth->data;
98+
const unsigned int *rgb_data = (unsigned int*)rgb->data;
9899
float *undistorted_data = (float*)undistorted->data;
99-
unsigned char *registered_data = registered->data;
100+
unsigned int *registered_data = (unsigned int*)registered->data;
100101
const int *map_dist = distort_map;
101102
const float *map_x = depth_to_color_map_x;
102103
const int *map_yi = depth_to_color_map_yi;
104+
103105
const int size_depth = 512 * 424;
104-
const int size_color = 1920 * 1080 * 3;
106+
const int size_color = 1920 * 1080;
105107
const float color_cx = color.cx + 0.5f; // 0.5f added for later rounding
106108

109+
// size of filter map with a border of filter_height_half on top and bottom so that no check for borders is needed.
110+
// since the color image is wide angle no border to the sides is needed.
111+
const int size_filter_map = size_color + 1920 * filter_height_half * 2;
112+
// offset to the important data
113+
const int offset_filter_map = 1920 * filter_height_half;
114+
115+
// map for storing the min z values used for each color pixel
116+
float *filter_map = NULL;
117+
// pointer to the beginning of the important data
118+
float *p_filter_map = NULL;
119+
120+
// map for storing the color offest for each depth pixel
121+
int *depth_to_c_off = new int[size_depth];
122+
int *map_c_off = depth_to_c_off;
123+
124+
// initializing the depth_map with values outside of the Kinect2 range
125+
if(enable_filter){
126+
filter_map = new float[size_filter_map];
127+
p_filter_map = filter_map + offset_filter_map;
128+
129+
for(float *it = filter_map, *end = filter_map + size_filter_map; it != end; ++it){
130+
*it = 65536.0f;
131+
}
132+
}
133+
107134
// iterating over all pixels from undistorted depth and registered color image
108-
// the three maps have the same structure as the images, so their pointers are increased each iteration as well
109-
for (int i = 0; i < size_depth; ++i, ++registered_data, ++undistorted_data, ++map_dist, ++map_x, ++map_yi) {
135+
// the four maps have the same structure as the images, so their pointers are increased each iteration as well
136+
for(int i = 0; i < size_depth; ++i, ++undistorted_data, ++map_dist, ++map_x, ++map_yi, ++map_c_off){
110137
// getting index of distorted depth pixel
111138
const int index = *map_dist;
112139

113140
// check if distorted depth pixel is outside of the depth image
114141
if(index < 0){
142+
*map_c_off = -1;
115143
*undistorted_data = 0;
116-
*registered_data = 0;
117-
*++registered_data = 0;
118-
*++registered_data = 0;
119144
continue;
120145
}
121146

122147
// getting depth value for current pixel
123-
const float z_raw = depth_data[index];
124-
*undistorted_data = z_raw;
148+
const float z = depth_data[index];
149+
*undistorted_data = z;
125150

126151
// checking for invalid depth value
127-
if (z_raw <= 0.0f) {
128-
*registered_data = 0;
129-
*++registered_data = 0;
130-
*++registered_data = 0;
152+
if(z <= 0.0f){
153+
*map_c_off = -1;
131154
continue;
132155
}
133156

134157
// calculating x offset for rgb image based on depth value
135-
const float rx = (*map_x + (color.shift_m / z_raw)) * color.fx + color_cx;
158+
const float rx = (*map_x + (color.shift_m / z)) * color.fx + color_cx;
136159
const int cx = rx; // same as round for positive numbers (0.5f was already added to color_cx)
137160
// getting y offset for depth image
138161
const int cy = *map_yi;
139162
// combining offsets
140-
const int c_off = cx * 3 + cy;
163+
const int c_off = cx + cy * 1920;
141164

142165
// check if c_off is outside of rgb image
143166
// checking rx/cx is not needed because the color image is much wider then the depth image
144-
if (c_off < 0 || c_off >= size_color) {
145-
*registered_data = 0;
146-
*++registered_data = 0;
147-
*++registered_data = 0;
167+
if(c_off < 0 || c_off >= size_color){
168+
*map_c_off = -1;
148169
continue;
149170
}
150171

151-
// Setting RGB or registered image
152-
const unsigned char *rgb_data = rgb->data + c_off;
153-
*registered_data = *rgb_data;
154-
*++registered_data = *++rgb_data;
155-
*++registered_data = *++rgb_data;
172+
// saving the offset for later
173+
*map_c_off = c_off;
174+
175+
if(enable_filter){
176+
// setting a window around the filter map pixel corresponding to the color pixel with the current z value
177+
int yi = (cy - filter_height_half) * 1920 + cx - filter_width_half; // index of first pixel to set
178+
for(int r = -filter_height_half; r <= filter_height_half; ++r, yi += 1920) // index increased by a full row each iteration
179+
{
180+
float *it = p_filter_map + yi;
181+
for(int c = -filter_width_half; c <= filter_width_half; ++c, ++it)
182+
{
183+
// only set if the current z is smaller
184+
if(z < *it)
185+
*it = z;
186+
}
187+
}
188+
}
189+
}
190+
191+
// reseting the pointers to the beginning
192+
map_c_off = depth_to_c_off;
193+
undistorted_data = (float*)undistorted->data;
194+
195+
if(enable_filter){
196+
// run through all registered color pixels and set them based on filter results
197+
for(int i = 0; i < size_depth; ++i, ++map_c_off, ++undistorted_data, ++registered_data){
198+
const int c_off = *map_c_off;
199+
200+
// check if offset is out of image
201+
if(c_off < 0){
202+
*registered_data = 0;
203+
continue;
204+
}
205+
206+
const float min_z = p_filter_map[c_off];
207+
const float z = *undistorted_data;
208+
209+
// check for allowed depth noise
210+
*registered_data = (z - min_z) / z > filter_tolerance ? 0 : *(rgb_data + c_off);
211+
}
212+
213+
delete[] filter_map;
214+
}
215+
else
216+
{
217+
// run through all registered color pixels and set them based on c_off
218+
for(int i = 0; i < size_depth; ++i, ++map_c_off, ++registered_data){
219+
const int c_off = *map_c_off;
220+
221+
// check if offset is out of image
222+
*registered_data = c_off < 0 ? 0 : *(rgb_data + c_off);
223+
}
156224
}
225+
delete[] depth_to_c_off;
157226
}
158227

159228
Registration::Registration(Freenect2Device::IrCameraParams depth_p, Freenect2Device::ColorCameraParams rgb_p):
160-
depth(depth_p), color(rgb_p)
229+
depth(depth_p), color(rgb_p), filter_width_half(2), filter_height_half(1), filter_tolerance(0.01f)
161230
{
162231
float mx, my;
163232
int ix, iy, index;
@@ -186,7 +255,7 @@ Registration::Registration(Freenect2Device::IrCameraParams depth_p, Freenect2Dev
186255
*map_x++ = rx;
187256
*map_y++ = ry;
188257
// compute the y offset to minimize later computations
189-
*map_yi++ = roundf(ry) * 1920 * 3;
258+
*map_yi++ = roundf(ry);
190259
}
191260
}
192261
}

examples/protonect/src/turbo_jpeg_rgb_packet_processor.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -73,7 +73,7 @@ class TurboJpegRgbPacketProcessorImpl
7373

7474
void newFrame()
7575
{
76-
frame = new Frame(1920, 1080, tjPixelSize[TJPF_BGR]);
76+
frame = new Frame(1920, 1080, tjPixelSize[TJPF_BGRX]);
7777
}
7878

7979
void startTiming()
@@ -115,7 +115,7 @@ void TurboJpegRgbPacketProcessor::process(const RgbPacket &packet)
115115
impl_->frame->timestamp = packet.timestamp;
116116
impl_->frame->sequence = packet.sequence;
117117

118-
int r = tjDecompress2(impl_->decompressor, packet.jpeg_buffer, packet.jpeg_buffer_length, impl_->frame->data, 1920, 1920 * tjPixelSize[TJPF_BGR], 1080, TJPF_BGR, 0);
118+
int r = tjDecompress2(impl_->decompressor, packet.jpeg_buffer, packet.jpeg_buffer_length, impl_->frame->data, 1920, 1920 * tjPixelSize[TJPF_BGRX], 1080, TJPF_BGRX, 0);
119119

120120
if(r == 0)
121121
{

0 commit comments

Comments
 (0)