49 #include <opencv2/imgproc/imgproc_c.h>
65 threads_.interrupt_all();
67 delete face_go_mutex_;
68 face_go_mutex_ = NULL;
70 for (
int i = list_.size(); i > 0; i--)
84 void Faces::initFaceDetectionDisparity(uint num_cascades, std::string haar_classifier_filename,
double face_size_min_m,
85 double face_size_max_m,
double max_face_z_m,
double face_sep_dist_m)
89 face_size_min_m_ = face_size_min_m;
90 face_size_max_m_ = face_size_max_m;
91 max_face_z_m_ = max_face_z_m;
92 face_sep_dist_m_ = face_sep_dist_m;
94 face_go_mutex_ =
new boost::mutex();
95 bool cascade_ok = cascade_.load(haar_classifier_filename);
99 ROS_ERROR_STREAM(
"Cascade file " << haar_classifier_filename <<
" doesn't exist.");
102 threads_.create_thread(boost::bind(&Faces::faceDetectionThreadDisparity,
this, 0));
106 std::vector<Box2D3D> Faces::detectAllFacesDisparity(
const cv::Mat &image,
double threshold,
107 const cv::Mat &disparity_image,
113 if (image.channels() == 1)
115 cv_image_gray_.create(image.size(), CV_8UC1);
116 image.copyTo(cv_image_gray_);
118 else if (image.channels() == 3)
120 cv_image_gray_.create(image.size(), CV_8UC1);
121 cv::cvtColor(image, cv_image_gray_, CV_BGR2GRAY);
125 std::cerr <<
"Unknown image type" << std::endl;
129 disparity_image_ = &disparity_image;
130 cam_model_ = cam_model;
133 num_threads_to_wait_for_ = threads_.size();
134 boost::mutex::scoped_lock fgmlock(*(face_go_mutex_));
138 face_detection_ready_cond_.notify_all();
140 boost::mutex::scoped_lock fdmlock(face_done_mutex_);
141 while (num_threads_to_wait_for_ > 0)
143 face_detection_done_cond_.wait(fdmlock);
150 void Faces::faceDetectionThreadDisparity(uint i)
154 boost::mutex::scoped_lock fgmlock(*(face_go_mutex_));
155 boost::mutex::scoped_lock tlock(t_mutex_, boost::defer_lock);
166 face_detection_ready_cond_.wait(fgmlock);
170 cv::Point3d p3_1(0, 0, max_face_z_m_);
171 cv::Point3d p3_2(face_size_min_m_, 0, max_face_z_m_);
172 cv::Point2d p2_1 = (cam_model_->left()).project3dToPixel(p3_1);
173 cv::Point2d p2_2 = (cam_model_->left()).project3dToPixel(p3_2);
174 int this_min_face_size =
static_cast<int>(floor(fabs(p2_2.x - p2_1.x)));
176 std::vector<cv::Rect> faces_vec;
177 cascade_.detectMultiScale(cv_image_gray_, faces_vec, 1.2, 2, cv::CASCADE_DO_CANNY_PRUNING,
178 cv::Size(this_min_face_size, this_min_face_size));
182 cv::Scalar color(0, 255, 0);
184 double avg_disp = 0.0;
185 cv::Mat uvd(1, 3, CV_32FC1);
186 cv::Mat xyz(1, 3, CV_32FC1);
188 for (uint iface = 0; iface < faces_vec.size(); iface++)
190 one_face.status =
"good";
192 one_face.box2d = faces_vec[iface];
196 cv::Mat disp_roi_shallow(*disparity_image_,
197 cv::Rect(floor(one_face.box2d.x + 0.25 * one_face.box2d.width),
198 floor(one_face.box2d.y + 0.25 * one_face.box2d.height),
199 floor(one_face.box2d.x + 0.75 * one_face.box2d.width) -
200 floor(one_face.box2d.x + 0.25 * one_face.box2d.width) + 1,
201 floor(one_face.box2d.y + 0.75 * one_face.box2d.height) -
202 floor(one_face.box2d.y + 0.25 * one_face.box2d.height) + 1));
203 cv::Mat disp_roi = disp_roi_shallow.clone();
204 cv::Mat tmat = disp_roi.reshape(1, disp_roi.rows * disp_roi.cols);
206 cv::sort(tmat, tmat_sorted, CV_SORT_EVERY_COLUMN + CV_SORT_DESCENDING);
209 avg_disp = tmat_sorted.at<
float>(floor(cv::countNonZero(tmat_sorted >= 0.0) / 2.0));
212 one_face.center2d = cv::Point2d(one_face.box2d.x + one_face.box2d.width / 2.0,
213 one_face.box2d.y + one_face.box2d.height / 2.0);
214 one_face.width2d = one_face.box2d.width;
221 cam_model_->projectDisparityTo3d(cv::Point2d(0.0, 0.0), avg_disp, p3_1);
222 cam_model_->projectDisparityTo3d(cv::Point2d(one_face.box2d.width, 0.0), avg_disp, p3_2);
223 one_face.width3d = fabs(p3_2.x - p3_1.x);
224 cam_model_->projectDisparityTo3d(one_face.center2d, avg_disp, one_face.center3d);
225 if (one_face.center3d.z > max_face_z_m_ ||
226 one_face.width3d < face_size_min_m_ ||
227 one_face.width3d > face_size_max_m_)
229 one_face.status =
"bad";
234 one_face.width3d = 0.0;
235 one_face.center3d = cv::Point3d(0.0, 0.0, 0.0);
236 one_face.status =
"unknown";
241 boost::mutex::scoped_lock lock(face_mutex_);
242 faces_.push_back(one_face);
246 boost::mutex::scoped_lock fdmlock(face_done_mutex_);
247 num_threads_to_wait_for_--;
249 face_detection_done_cond_.notify_one();
254 void Faces::initFaceDetectionDepth(uint num_cascades, std::string haar_classifier_filename,
double face_size_min_m,
255 double face_size_max_m,
double max_face_z_m,
double face_sep_dist_m)
259 face_size_min_m_ = face_size_min_m;
260 face_size_max_m_ = face_size_max_m;
261 max_face_z_m_ = max_face_z_m;
262 face_sep_dist_m_ = face_sep_dist_m;
264 face_go_mutex_ =
new boost::mutex();
265 bool cascade_ok = cascade_.load(haar_classifier_filename);
269 ROS_ERROR_STREAM(
"Cascade file " << haar_classifier_filename <<
" doesn't exist.");
272 threads_.create_thread(boost::bind(&Faces::faceDetectionThreadDepth,
this, 0));
276 std::vector<Box2D3D> Faces::detectAllFacesDepth(
const cv::Mat &image,
double threshold,
const cv::Mat &dimage,
283 if (image.channels() == 1)
285 cv_image_gray_.create(image.size(), CV_8UC1);
286 image.copyTo(cv_image_gray_);
288 else if (image.channels() == 3)
290 cv_image_gray_.create(image.size(), CV_8UC1);
291 cv::cvtColor(image, cv_image_gray_, CV_BGR2GRAY);
295 std::cerr <<
"Unknown image type" << std::endl;
299 depth_image_ = &dimage;
300 cam_model_ = cam_model;
303 num_threads_to_wait_for_ = threads_.size();
304 boost::mutex::scoped_lock fgmlock(*(face_go_mutex_));
308 face_detection_ready_cond_.notify_all();
310 boost::mutex::scoped_lock fdmlock(face_done_mutex_);
311 while (num_threads_to_wait_for_ > 0)
313 face_detection_done_cond_.wait(fdmlock);
320 void Faces::faceDetectionThreadDepth(uint i)
324 boost::mutex::scoped_lock fgmlock(*(face_go_mutex_));
325 boost::mutex::scoped_lock tlock(t_mutex_, boost::defer_lock);
336 face_detection_ready_cond_.wait(fgmlock);
340 cv::Point3d p3_1(0, 0, max_face_z_m_);
341 cv::Point3d p3_2(face_size_min_m_, 0, max_face_z_m_);
342 cv::Point2d p2_1 = (cam_model_->left()).project3dToPixel(p3_1);
343 cv::Point2d p2_2 = (cam_model_->left()).project3dToPixel(p3_2);
344 int this_min_face_size =
static_cast<int>(floor(fabs(p2_2.x - p2_1.x)));
346 std::vector<cv::Rect> faces_vec;
347 cascade_.detectMultiScale(cv_image_gray_, faces_vec, 1.2, 2, cv::CASCADE_DO_CANNY_PRUNING,
348 cv::Size(this_min_face_size, this_min_face_size));
352 cv::Scalar color(0, 255, 0);
355 cv::Mat uvd(1, 3, CV_32FC1);
356 cv::Mat xyz(1, 3, CV_32FC1);
358 for (uint iface = 0; iface < faces_vec.size(); iface++)
360 one_face.status =
"good";
362 one_face.box2d = faces_vec[iface];
366 cv::Mat depth_roi_shallow(*depth_image_,
367 cv::Rect(floor(one_face.box2d.x + 0.25 * one_face.box2d.width),
368 floor(one_face.box2d.y + 0.25 * one_face.box2d.height),
369 floor(one_face.box2d.x + 0.75 * one_face.box2d.width) -
370 floor(one_face.box2d.x + 0.25 * one_face.box2d.width) + 1,
371 floor(one_face.box2d.y + 0.75 * one_face.box2d.height) -
372 floor(one_face.box2d.y + 0.25 * one_face.box2d.height) + 1));
375 one_face.center2d = cv::Point2d(one_face.box2d.x + one_face.box2d.width / 2.0,
376 one_face.box2d.y + one_face.box2d.height / 2.0);
377 one_face.width2d = one_face.box2d.width;
383 std::vector<float> depths;
385 for (
int i = 0; i < depth_roi_shallow.rows; i++)
387 const float* dptr = depth_roi_shallow.ptr<
float>(i);
388 for (
int j = 0; j < depth_roi_shallow.cols; j++)
390 if (dptr[j] == dptr[j])
392 depths.push_back(dptr[j]);
397 std::vector<float>::iterator dbegin = depths.begin();
398 std::vector<float>::iterator dend = depths.end();
400 if (depths.size() > 0)
402 std::sort(dbegin, dend);
403 avg_d = depths[floor(depths.size() / 2.0)];
405 one_face.width3d = fabs((cam_model_->left()).getDeltaX(one_face.box2d.width, avg_d));
406 one_face.center3d = (cam_model_->left()).projectPixelTo3dRay(one_face.center2d);
408 one_face.center3d = (avg_d / one_face.center3d.z) * one_face.center3d;
409 if (one_face.center3d.z > max_face_z_m_ ||
410 one_face.width3d < face_size_min_m_ ||
411 one_face.width3d > face_size_max_m_)
413 one_face.status =
"bad";
418 one_face.width3d = 0.0;
419 one_face.center3d = cv::Point3d(0.0, 0.0, 0.0);
420 one_face.status =
"unknown";
425 boost::mutex::scoped_lock lock(face_mutex_);
426 faces_.push_back(one_face);
430 boost::mutex::scoped_lock fdmlock(face_done_mutex_);
431 num_threads_to_wait_for_--;
433 face_detection_done_cond_.notify_one();