Go to the documentation of this file.00001
00061 #ifdef __LINUX__
00062 #include "cob_people_detection/face_detector.h"
00063 #include "cob_vision_utils/GlobalDefines.h"
00064 #else
00065 #include "cob_vision/cob_people_detection/common/include/cob_people_detection/PeopleDetector.h"
00066 #include "cob_common/cob_vision_utils/common/include/cob_vision_utils/GlobalDefines.h"
00067 #endif
00068
00069 #include <opencv2/opencv.hpp>
00070
00071 using namespace ipa_PeopleDetector;
00072
00073 FaceDetector::FaceDetector(void)
00074 {
00075 m_face_cascade = 0;
00076 m_initialized = false;
00077 }
00078
00079 unsigned long FaceDetector::init(std::string directory, double faces_increase_search_scale, int faces_drop_groups, int faces_min_search_scale_x, int faces_min_search_scale_y,
00080 bool reason_about_3dface_size, double face_size_max_m, double face_size_min_m, double max_face_z_m, bool debug)
00081 {
00082
00083 m_faces_increase_search_scale = faces_increase_search_scale;
00084 m_faces_drop_groups = faces_drop_groups;
00085 m_faces_min_search_scale_x = faces_min_search_scale_x;
00086 m_faces_min_search_scale_y = faces_min_search_scale_y;
00087 m_reason_about_3dface_size = reason_about_3dface_size;
00088 m_face_size_max_m = face_size_max_m;
00089 m_face_size_min_m = face_size_min_m;
00090 m_max_face_z_m = max_face_z_m;
00091 m_debug = debug;
00092
00093
00094 std::string faceCascadePath = directory + "haarcascades/haarcascade_frontalface_alt2.xml";
00095 m_face_cascade = (CvHaarClassifierCascade*)cvLoad(faceCascadePath.c_str(), 0, 0, 0 );
00096
00097
00098 m_storage = cvCreateMemStorage(0);
00099
00100 m_initialized = true;
00101
00102 return ipa_Utils::RET_OK;
00103 }
00104
00105 FaceDetector::~FaceDetector(void)
00106 {
00107
00108 cvReleaseHaarClassifierCascade(&m_face_cascade);
00109 cvReleaseMemStorage(&m_storage);
00110 }
00111
00112 unsigned long FaceDetector::detectColorFaces(std::vector<cv::Mat>& heads_color_images, const std::vector<cv::Mat>& heads_depth_images, std::vector<std::vector<cv::Rect> >& face_coordinates)
00113 {
00114 if (m_initialized == false)
00115 {
00116 std::cout << "Error: FaceDetector::DetectColorFaces: init() must be called first." << std::endl;
00117 return ipa_Utils::RET_FAILED;
00118 }
00119
00120 face_coordinates.clear();
00121 face_coordinates.resize(heads_color_images.size());
00122
00123
00124 for(unsigned int head=0; head<heads_color_images.size(); head++)
00125 {
00126
00127 IplImage imgPtr = (IplImage)heads_color_images[head];
00128 CvSeq* faces = cvHaarDetectObjects(&imgPtr, m_face_cascade, m_storage, m_faces_increase_search_scale, m_faces_drop_groups, CV_HAAR_DO_CANNY_PRUNING, cvSize(m_faces_min_search_scale_x, m_faces_min_search_scale_y));
00129
00130 cv::Size parentSize;
00131 cv::Point roiOffset;
00132 for(int i=0; i<faces->total; i++)
00133 {
00134 cv::Rect* face = (cv::Rect*)cvGetSeqElem(faces, i);
00135
00136
00137
00138
00139 if (face->width > 0.4*heads_color_images[head].cols && face->height > 0.4*heads_color_images[head].rows)
00140 face_coordinates[head].push_back(*face);
00141 }
00142 }
00143
00144 if (m_reason_about_3dface_size==true)
00145 {
00146
00147 for (uint head_index=0; head_index<face_coordinates.size(); head_index++)
00148 {
00149 double avg_depth_value = 0.0;
00150 int last_accepted_face_index = -1;
00151 double last_accepted_face_area = 0.0;
00152 for (uint face_index = 0; face_index < face_coordinates[head_index].size(); face_index++)
00153 {
00154
00155
00156 cv::Rect& face = face_coordinates[head_index][face_index];
00157
00158
00159 int uStart = floor(0.25*face.width);
00160 int uEnd = floor(0.75*face.width) + 1;
00161 int vStart = floor(0.25*face.height);
00162 int vEnd = floor(0.75*face.height) + 1;
00163 int du = abs(uEnd-uStart);
00164
00165
00166 cv::Mat face_region = heads_depth_images[head_index];
00167
00168 cv::Mat tmat(1, du*abs(vEnd-vStart), CV_32FC1);
00169 float* tmatPtr = (float*)tmat.data;
00170 for (int v=vStart; v<vEnd; v++)
00171 {
00172 float* zPtr = (float*)face_region.row(v).data;
00173 zPtr += 2+3*uStart;
00174 for (int u=uStart; u<uEnd; u++)
00175 {
00176 float depthval = *zPtr;
00177 if (!isnan(depthval)) *tmatPtr = depthval;
00178 else *tmatPtr = -1.0;
00179 tmatPtr++;
00180 zPtr += 3;
00181 }
00182 }
00183
00184
00185 cv::Mat tmat_sorted;
00186 cv::sort(tmat, tmat_sorted, CV_SORT_EVERY_ROW+CV_SORT_DESCENDING);
00187 double avg_depth = tmat_sorted.at<float>(floor(cv::countNonZero(tmat_sorted>=0.0)*0.5));
00188
00189
00190
00191
00192
00193 bool remove_face = false;
00194 if (avg_depth > 0)
00195 {
00196 double radiusX, radiusY, radius3d=1e20;
00197 cv::Vec3f a, b;
00198
00199
00200 a = heads_depth_images[head_index].at<cv::Vec3f>((int)(face.y+face.height*0.25), (int)(face.x+0.5*face.width));
00201 b = heads_depth_images[head_index].at<cv::Vec3f>((int)(face.y+face.height*0.75), (int)(face.x+0.5*face.width));
00202 if (m_debug) std::cout << "a: " << a.val[0] << " " << a.val[1] << " " << a.val[2] << " b: " << " " << b.val[0] << " " << b.val[1] << " " << b.val[2] << "\n";
00203 if (isnan(a.val[0]) || isnan(b.val[0])) radiusY = 0.0;
00204 else radiusY = cv::norm(b-a);
00205 radius3d = radiusY;
00206
00207
00208 a = heads_depth_images[head_index].at<cv::Vec3f>((int)(face.y+face.height*0.5), (int)(face.x+face.width*0.25));
00209 b = heads_depth_images[head_index].at<cv::Vec3f>((int)(face.y+face.height*0.5), (int)(face.x+face.width*0.75));
00210 if (m_debug) std::cout << "a: " << a.val[0] << " " << a.val[1] << " " << a.val[2] << " b: " << " " << b.val[0] << " " << b.val[1] << " " << b.val[2] << "\n";
00211 if (isnan(a.val[0]) || isnan(b.val[0])) radiusX = 0.0;
00212 else
00213 {
00214 radiusX = cv::norm(b-a);
00215 if (radiusY != 0.0) radius3d = (radiusX+radiusY)*0.5;
00216 else radius3d = radiusX;
00217 }
00218
00219
00220
00221
00222
00223
00224
00225
00226 if (m_debug)
00227 {
00228 std::cout << "radiusX: " << radiusX << " radiusY: " << radiusY << "\n";
00229 std::cout << "avg_depth: " << avg_depth << " > max_face_z_m: " << m_max_face_z_m << " ? 2*radius3d: " << 2.0*radius3d << " < face_size_min_m: " << m_face_size_min_m << " ? 2radius3d: " << 2.0*radius3d << " > face_size_max_m:" << m_face_size_max_m << "?\n";
00230 }
00231 if (radius3d > 0.0 && (avg_depth > m_max_face_z_m || 2.0*radius3d < m_face_size_min_m || 2.0*radius3d > m_face_size_max_m))
00232 {
00233 remove_face = true;
00234 }
00235 }
00236
00237 if (remove_face==true)
00238 {
00239
00240 face_coordinates[head_index].erase(face_coordinates[head_index].begin()+face_index);
00241 face_index--;
00242 }
00243 else
00244 {
00245
00246 double current_area = face_coordinates[head_index][face_index].height * face_coordinates[head_index][face_index].width;
00247 if (last_accepted_face_index == -1)
00248 {
00249 last_accepted_face_index = (int)face_index;
00250 last_accepted_face_area = current_area;
00251 avg_depth_value = avg_depth;
00252 }
00253 else
00254 {
00255 if (current_area > last_accepted_face_area)
00256 {
00257
00258 face_coordinates[head_index].erase(face_coordinates[head_index].begin()+last_accepted_face_index);
00259 face_index--;
00260
00261 last_accepted_face_index = face_index;
00262 last_accepted_face_area = current_area;
00263 avg_depth_value = avg_depth;
00264 }
00265 else
00266 {
00267
00268 face_coordinates[head_index].erase(face_coordinates[head_index].begin()+face_index);
00269 face_index--;
00270 }
00271 }
00272 }
00273 }
00274 assert(face_coordinates[head_index].size()==0 || face_coordinates[head_index].size()==1);
00275
00276
00277 if (avg_depth_value > 0)
00278 for (int v=0; v<heads_depth_images[head_index].rows; v++)
00279 for (int u=0; u<heads_depth_images[head_index].cols; u++)
00280 {
00281 float val = heads_depth_images[head_index].at<cv::Vec3f>(v,u)[2];
00282 if (val==0.f || fabs(heads_depth_images[head_index].at<cv::Vec3f>(v,u)[2]-avg_depth_value) > 0.18 || val!=val)
00283 heads_color_images[head_index].at<cv::Vec3b>(v,u) = cv::Vec3b(255, 255, 255);
00284 }
00285
00286
00287
00288
00289
00290 }
00291 }
00292
00293 return ipa_Utils::RET_OK;
00294 }
00295