00001
00002
00003 #ifdef __LINUX__
00004 #include "cob_people_detection/people_detector.h"
00005 #include "cob_vision_utils/GlobalDefines.h"
00006 #else
00007 #include "cob_vision/cob_people_detection/common/include/cob_people_detection/PeopleDetector.h"
00008 #include "cob_common/cob_vision_utils/common/include/cob_vision_utils/GlobalDefines.h"
00009 #endif
00010
00011 #include <opencv/cv.h>
00012 #include <opencv/cvaux.h>
00013
00014 using namespace ipa_PeopleDetector;
00015
00016 PeopleDetector::PeopleDetector(void)
00017 {
00018 m_face_cascade = 0;
00019 m_range_cascade = 0;
00020 }
00021
00022 unsigned long PeopleDetector::Init(std::string directory)
00023 {
00024
00025 std::string faceCascadePath = directory + "haarcascades/haarcascade_frontalface_alt2.xml";
00026
00027 std::string rangeCascadePath = directory + "haarcascades/haarcascade_range_multiview_5p_bg.xml";
00028
00029 m_face_cascade = (CvHaarClassifierCascade*)cvLoad(faceCascadePath.c_str(), 0, 0, 0);
00030 m_range_cascade = (CvHaarClassifierCascade*)cvLoad(rangeCascadePath.c_str(), 0, 0, 0);
00031
00032
00033 m_storage = cvCreateMemStorage(0);
00034
00035 return ipa_Utils::RET_OK;
00036 }
00037
00038 PeopleDetector::~PeopleDetector(void)
00039 {
00040
00041 cvReleaseHaarClassifierCascade(&m_face_cascade);
00042 cvReleaseHaarClassifierCascade(&m_range_cascade);
00043 cvReleaseMemStorage(&m_storage);
00044 }
00045
00046 unsigned long PeopleDetector::DetectColorFaces(cv::Mat& img, std::vector<cv::Rect>& faceCoordinates)
00047 {
00048 IplImage imgPtr = (IplImage)img;
00049 CvSeq* faces = cvHaarDetectObjects(&imgPtr, m_face_cascade, m_storage, m_faces_increase_search_scale, m_faces_drop_groups, CV_HAAR_DO_CANNY_PRUNING,
00050 cvSize(m_faces_min_search_scale_x, m_faces_min_search_scale_y));
00051
00052 cv::Size parentSize;
00053 cv::Point roiOffset;
00054 for (int i = 0; i < faces->total; i++)
00055 {
00056 cv::Rect* face = (cv::Rect*)cvGetSeqElem(faces, i);
00057 img.locateROI(parentSize, roiOffset);
00058 face->x += roiOffset.x;
00059 face->y += roiOffset.y;
00060 faceCoordinates.push_back(*face);
00061 }
00062
00063 return ipa_Utils::RET_OK;
00064 }
00065
00066 unsigned long PeopleDetector::InterpolateUnassignedPixels(cv::Mat& img)
00067 {
00068 CV_Assert( img.type() == CV_8UC3 )
00069 ;
00070
00071 cv::Mat temp = img.clone();
00072
00073 uchar* data = img.data;
00074 uchar* data2 = temp.data;
00075 int stride = img.step;
00076 for (int repetitions = 0; repetitions < 10; repetitions++)
00077 {
00078
00079 for (int v = 1; v < img.rows - 1; v++)
00080 {
00081 for (int u = 1; u < img.cols - 1; u++)
00082 {
00083
00084 int index = v * stride + 3 * u;
00085 if (data[index] != 0)
00086 {
00087 uchar val = data[index];
00088 if (data2[index - 3] == 0)
00089 for (int i = -3; i < 0; i++)
00090 data2[index + i] = val;
00091 if (data2[index + 3] == 0)
00092 for (int i = 3; i < 6; i++)
00093 data2[index + i] = val;
00094 if (data2[index - stride] == 0)
00095 for (int i = -stride; i < -stride + 3; i++)
00096 data2[index + i] = val;
00097 if (data2[index + stride] == 0)
00098 for (int i = stride; i < stride + 3; i++)
00099 data2[index + i] = val;
00100 }
00101 }
00102 }
00103
00104 for (int i = 0; i < img.rows * stride; i++)
00105 data[i] = data2[i];
00106 }
00107 return ipa_Utils::RET_OK;
00108 }
00109
00110 unsigned long PeopleDetector::DetectRangeFace(cv::Mat& img, std::vector<cv::Rect>& rangeFaceCoordinates, bool fillUnassignedDepthValues)
00111 {
00112 rangeFaceCoordinates.clear();
00113
00114 if (fillUnassignedDepthValues)
00115 InterpolateUnassignedPixels(img);
00116
00117
00118
00119 IplImage imgPtr = (IplImage)img;
00120 CvSeq* rangeFaces = cvHaarDetectObjects(&imgPtr, m_range_cascade, m_storage, m_range_increase_search_scale, m_range_drop_groups, CV_HAAR_DO_CANNY_PRUNING,
00121 cvSize(m_range_min_search_scale_x, m_range_min_search_scale_y));
00122
00123 for (int i = 0; i < rangeFaces->total; i++)
00124 {
00125 cv::Rect *rangeFace = (cv::Rect*)cvGetSeqElem(rangeFaces, i);
00126 rangeFaceCoordinates.push_back(*rangeFace);
00127 }
00128
00129 return ipa_Utils::RET_OK;
00130 }
00131
00132 unsigned long PeopleDetector::DetectFaces(cv::Mat& img, cv::Mat& rangeImg, std::vector<cv::Rect>& colorFaceCoordinates, std::vector<cv::Rect>& rangeFaceCoordinates,
00133 std::set<size_t>& colorToRangeFaceDependency, bool fillUnassignedDepthValues)
00134 {
00135 colorFaceCoordinates.clear();
00136 colorToRangeFaceDependency.clear();
00137
00138
00139 DetectRangeFace(rangeImg, rangeFaceCoordinates, fillUnassignedDepthValues);
00140 for (int i = 0; i < (int)rangeFaceCoordinates.size(); i++)
00141 {
00142 cv::Rect rangeFace = rangeFaceCoordinates[i];
00143
00144 rangeFace.y += (int)(rangeFace.height * 0.1);
00145
00146 cv::Mat areaImg = img(rangeFace);
00147
00148
00149 size_t numberColorFacesBefore = colorFaceCoordinates.size();
00150 DetectColorFaces(areaImg, colorFaceCoordinates);
00151 if ((colorFaceCoordinates.size() - numberColorFacesBefore) != 0)
00152 colorToRangeFaceDependency.insert(i);
00153 }
00154
00155
00156
00157
00158
00159
00160
00161
00162
00163
00164
00165
00166
00167
00168
00169
00170
00171
00172
00173
00174
00175
00176
00177
00178
00179
00180
00181
00182
00183
00184
00185
00186
00187
00188
00189
00190
00191
00192
00193
00194
00195
00196 return ipa_Utils::RET_OK;
00197 }
00198
00199 unsigned long PeopleDetector::AddFace(cv::Mat& img, cv::Rect& face, std::string id, std::vector<cv::Mat>& images, std::vector<std::string>& ids)
00200 {
00201
00202 cv::Mat resized_8U1(100, 100, CV_8UC1);
00203 ConvertAndResize(img, resized_8U1, face);
00204
00205
00206 images.push_back(resized_8U1);
00207 ids.push_back(id);
00208
00209 return ipa_Utils::RET_OK;
00210 }
00211
00212 unsigned long PeopleDetector::ConvertAndResize(cv::Mat& img, cv::Mat& resized, cv::Rect& face)
00213 {
00214 cv::Mat temp;
00215 cv::cvtColor(img, temp, CV_BGR2GRAY);
00216 cv::Mat roi = temp(face);
00217 cv::resize(roi, resized, resized.size());
00218
00219 return ipa_Utils::RET_OK;
00220 }
00221
00222 cv::Mat PeopleDetector::preprocessImage(cv::Mat& input_image)
00223 {
00224
00225 return input_image;
00226
00227
00228 cv::Mat output(input_image.cols, input_image.rows, input_image.type());
00229
00230
00231
00232 for (int v = 0; v < input_image.rows; v++)
00233 {
00234 uchar* srcPtr = input_image.ptr(v);
00235
00236 uchar* outPtr = output.ptr(v);
00237 for (int u = 0; u < input_image.cols; u++)
00238 {
00239 int ctOutcome = 0;
00240 int offset = -1;
00241 for (int dv = -1; dv <= 1; dv++)
00242 {
00243 for (int du = -1; du <= 1; du++)
00244 {
00245 if (dv == 0 && du == 0)
00246 continue;
00247 offset++;
00248 if (v + dv < 0 || v + dv >= input_image.rows || u + du < 0 || u + du >= input_image.cols)
00249 continue;
00250
00251 if (*srcPtr < *(srcPtr + dv * input_image.step + du))
00252 ctOutcome += 1 << offset;
00253 }
00254 }
00255 *outPtr = ctOutcome;
00256
00257 srcPtr++;
00258 outPtr++;
00259 }
00260 }
00261
00262
00263
00264
00265 return output;
00266 }
00267
00268 unsigned long PeopleDetector::PCA(int* nEigens, std::vector<cv::Mat>& eigenVectors, cv::Mat& eigenValMat, cv::Mat& avgImage, std::vector<cv::Mat>& faceImages,
00269 cv::Mat& projectedTrainFaceMat)
00270 {
00271 CvTermCriteria calcLimit;
00272
00273
00274 (*nEigens) = faceImages.size() - 1;
00275
00276
00277 cv::Size faceImgSize(faceImages[0].cols, faceImages[0].rows);
00278 eigenVectors.resize(*nEigens, cv::Mat(faceImgSize, CV_32FC1));
00279 eigenValMat.create(1, *nEigens, CV_32FC1);
00280 avgImage.create(faceImgSize, CV_32FC1);
00281
00282
00283 calcLimit = cvTermCriteria(CV_TERMCRIT_ITER, (*nEigens), 1);
00284
00285
00286 IplImage** faceImgArr = (IplImage**)cvAlloc((int)faceImages.size() * sizeof(IplImage*));
00287 for (int j = 0; j < (int)faceImages.size(); j++)
00288 {
00289
00290 cv::Mat preprocessedImage = preprocessImage(faceImages[j]);
00291 IplImage temp = (IplImage)preprocessedImage;
00292 faceImgArr[j] = cvCloneImage(&temp);
00293 }
00294
00295
00296 IplImage** eigenVectArr = (IplImage**)cvAlloc((int)eigenVectors.size() * sizeof(IplImage*));
00297 for (int j = 0; j < (int)eigenVectors.size(); j++)
00298 {
00299 IplImage temp = (IplImage)eigenVectors[j];
00300 eigenVectArr[j] = cvCloneImage(&temp);
00301 }
00302
00303
00304 IplImage avgImageIpl = (IplImage)avgImage;
00305 cvCalcEigenObjects((int)faceImages.size(), (void*)faceImgArr, (void*)eigenVectArr, CV_EIGOBJ_NO_CALLBACK, 0, 0, &calcLimit, &avgImageIpl, (float*)(eigenValMat.data));
00306
00307
00308 cv::normalize(eigenValMat, eigenValMat, 1, 0, CV_L2);
00309
00310
00311 projectedTrainFaceMat.create(faceImages.size(), *nEigens, CV_32FC1);
00312 for (int i = 0; i < (int)faceImages.size(); i++)
00313 {
00314 IplImage temp = (IplImage)faceImages[i];
00315 cvEigenDecomposite(&temp, *nEigens, eigenVectArr, 0, 0, &avgImageIpl, (float*)projectedTrainFaceMat.data + i * *nEigens);
00316 };
00317
00318
00319 int eigenVectorsCount = (int)eigenVectors.size();
00320 eigenVectors.clear();
00321 for (int i = 0; i < (int)eigenVectorsCount; i++)
00322 eigenVectors.push_back(cv::Mat(eigenVectArr[i], true));
00323
00324
00325 for (int i = 0; i < (int)faceImages.size(); i++)
00326 cvReleaseImage(&(faceImgArr[i]));
00327 for (int i = 0; i < (int)eigenVectors.size(); i++)
00328 cvReleaseImage(&(eigenVectArr[i]));
00329 cvFree(&faceImgArr);
00330 cvFree(&eigenVectArr);
00331
00332 return ipa_Utils::RET_OK;
00333 }
00334
00335 unsigned long PeopleDetector::RecognizeFace(cv::Mat& colorImage, std::vector<cv::Rect>& colorFaceCoordinates, int* nEigens, std::vector<cv::Mat>& eigenVectors, cv::Mat& avgImage,
00336 cv::Mat& faceClassAvgProjections, std::vector<int>& index, int *threshold, int *threshold_FS, cv::Mat& eigenValMat, cv::SVM* personClassifier)
00337 {
00338 float* eigenVectorWeights = 0;
00339
00340 cv::Mat resized_8U1(100, 100, CV_8UC1);
00341
00342 eigenVectorWeights = (float *)cvAlloc(*nEigens * sizeof(float));
00343
00344
00345 IplImage** eigenVectArr = (IplImage**)cvAlloc((int)eigenVectors.size() * sizeof(IplImage*));
00346 for (int j = 0; j < (int)eigenVectors.size(); j++)
00347 {
00348 IplImage temp = (IplImage)eigenVectors[j];
00349 eigenVectArr[j] = cvCloneImage(&temp);
00350 }
00351
00352 for (int i = 0; i < (int)colorFaceCoordinates.size(); i++)
00353 {
00354 cv::Rect face = colorFaceCoordinates[i];
00355 ConvertAndResize(colorImage, resized_8U1, face);
00356
00357 cv::Mat preprocessedImage = preprocessImage(resized_8U1);
00358
00359 IplImage avgImageIpl = (IplImage)avgImage;
00360
00361
00362 IplImage resized_8U1Ipl = (IplImage)resized_8U1;
00363 cvEigenDecomposite(&resized_8U1Ipl, *nEigens, eigenVectArr, 0, 0, &avgImageIpl, eigenVectorWeights);
00364
00365
00366 cv::Mat srcReconstruction = cv::Mat::zeros(eigenVectors[0].size(), eigenVectors[0].type());
00367 for (int i = 0; i < (int)eigenVectors.size(); i++)
00368 srcReconstruction += eigenVectorWeights[i] * eigenVectors[i];
00369 cv::Mat temp;
00370
00371
00372
00373
00374
00375
00376
00377
00378 resized_8U1.convertTo(temp, CV_32FC1, 1.0 / 255.0);
00379 double distance = cv::norm((temp - avgImage), srcReconstruction, cv::NORM_L2);
00380
00381
00382
00383 std::cout << "FS_Distance: " << distance << std::endl;
00384
00385
00386
00387
00388 if (distance > *threshold_FS)
00389 {
00390
00391 index.push_back(-2);
00392
00393 }
00394 else
00395 {
00396 int nearest;
00397 ClassifyFace(eigenVectorWeights, &nearest, nEigens, faceClassAvgProjections, threshold, eigenValMat, personClassifier);
00398 if (nearest < 0)
00399 index.push_back(-1);
00400 else
00401 index.push_back(nearest);
00402 }
00403 }
00404
00405
00406 for (int i = 0; i < (int)eigenVectors.size(); i++)
00407 cvReleaseImage(&(eigenVectArr[i]));
00408 cvFree(&eigenVectorWeights);
00409 cvFree(&eigenVectArr);
00410 return ipa_Utils::RET_OK;
00411 }
00412
00413 unsigned long PeopleDetector::ClassifyFace(float *eigenVectorWeights, int *nearest, int *nEigens, cv::Mat& faceClassAvgProjections, int *threshold, cv::Mat& eigenValMat,
00414 cv::SVM* personClassifier)
00415 {
00416 double leastDistSq = DBL_MAX;
00417
00418 int metric = 2;
00419
00420
00421 for (int i = 0; i < faceClassAvgProjections.rows; i++)
00422 {
00423 double distance = 0;
00424 double cos = 0;
00425 double length_sample = 0;
00426 double length_projection = 0;
00427 for (int e = 0; e < *nEigens; e++)
00428 {
00429 if (metric < 2)
00430 {
00431 float d = eigenVectorWeights[e] - ((float*)(faceClassAvgProjections.data))[i * *nEigens + e];
00432 if (metric == 0)
00433 distance += d * d;
00434 else
00435 distance += d * d / ((float*)(eigenValMat.data))[e];
00436 }
00437 else
00438 {
00439 cos += eigenVectorWeights[e] * ((float*)(faceClassAvgProjections.data))[i * *nEigens + e] / ((float*)(eigenValMat.data))[e];
00440 length_projection += ((float*)(faceClassAvgProjections.data))[i * *nEigens + e] * ((float*)(faceClassAvgProjections.data))[i * *nEigens + e]
00441 / ((float*)(eigenValMat.data))[e];
00442 length_sample += eigenVectorWeights[e] * eigenVectorWeights[e] / ((float*)(eigenValMat.data))[e];
00443 }
00444 }
00445 if (metric < 2)
00446 distance = sqrt(distance);
00447 else
00448 {
00449 length_sample = sqrt(length_sample);
00450 length_projection = sqrt(length_projection);
00451 cos /= (length_projection * length_sample);
00452 distance = -cos;
00453 }
00454
00455
00456
00457 std::cout << "Distance_FC: " << distance << std::endl;
00458
00459
00460 if (distance < leastDistSq)
00461 {
00462 leastDistSq = distance;
00463 if (leastDistSq > *threshold)
00464 *nearest = -1;
00465 else
00466 *nearest = i;
00467 }
00468 }
00469
00470
00471
00472
00473
00474
00475
00476
00477
00478 return ipa_Utils::RET_OK;
00479 }
00480
00481 unsigned long PeopleDetector::CalculateFaceClasses(cv::Mat& projectedTrainFaceMat, std::vector<std::string>& id, int *nEigens, cv::Mat& faceClassAvgProjections,
00482 std::vector<std::string>& idUnique, cv::SVM* personClassifier)
00483 {
00484 std::cout << "PeopleDetector::CalculateFaceClasses ... ";
00485
00486
00487 idUnique.clear();
00488 for (int i = 0; i < (int)id.size(); i++)
00489 {
00490 std::string face_class = id[i];
00491 bool class_exists = false;
00492
00493 for (int j = 0; j < (int)idUnique.size(); j++)
00494 {
00495 if (!idUnique[j].compare(face_class))
00496 {
00497 class_exists = true;
00498 }
00499 }
00500
00501 if (!class_exists)
00502 {
00503 idUnique.push_back(face_class);
00504 }
00505 }
00506
00507
00508
00509 cv::Mat temp = cv::Mat::zeros((int)idUnique.size(), *nEigens, projectedTrainFaceMat.type());
00510 temp.convertTo(faceClassAvgProjections, projectedTrainFaceMat.type());
00511
00512
00513
00514
00515
00516
00517
00518
00519
00520
00521
00522
00523
00524
00525
00526
00527
00528
00529
00530
00531
00532
00533
00534
00535
00536
00537
00538
00539
00540
00541 for (int i = 0; i < (int)idUnique.size(); i++)
00542 {
00543 std::string face_class = idUnique[i];
00544
00545 for (int e = 0; e < *nEigens; e++)
00546 {
00547 int count = 0;
00548 for (int j = 0; j < (int)id.size(); j++)
00549 {
00550 if (!(id[j].compare(face_class)))
00551 {
00552 ((float*)(faceClassAvgProjections.data))[i * *nEigens + e] += ((float*)(projectedTrainFaceMat.data))[j * *nEigens + e];
00553 count++;
00554 }
00555 }
00556 ((float*)(faceClassAvgProjections.data))[i * *nEigens + e] /= (float)count;
00557 }
00558 }
00559
00560
00561 if (personClassifier != 0)
00562 {
00563
00564
00565 cv::Mat data(id.size(), *nEigens, CV_32FC1);
00566 cv::Mat labels(id.size(), 1, CV_32SC1);
00567 std::ofstream fout("svm.dat", std::ios::out);
00568 for (int sample = 0; sample < (int)id.size(); sample++)
00569 {
00570
00571 for (int e = 0; e < *nEigens; e++)
00572 {
00573 data.at<float>(sample, e) = ((float*)projectedTrainFaceMat.data)[sample * *nEigens + e];
00574 fout << data.at<float>(sample, e) << "\t";
00575 }
00576
00577 for (int i = 0; i < (int)idUnique.size(); i++)
00578 if (!(id[sample].compare(idUnique[i])))
00579 labels.at<int>(sample) = i;
00580 fout << labels.at<int>(sample) << "\n";
00581 }
00582 fout.close();
00583
00584
00585 cv::SVMParams svmParams(CvSVM::NU_SVC, CvSVM::RBF, 0.0, 0.001953125, 0.0, 0.0, 0.8, 0.0, 0, cv::TermCriteria(CV_TERMCRIT_ITER + CV_TERMCRIT_EPS, 100, FLT_EPSILON));
00586
00587 personClassifier->train(data, labels, cv::Mat(), cv::Mat(), svmParams);
00588 cv::SVMParams svmParamsOptimal = personClassifier->get_params();
00589 std::cout << "Optimal SVM params: gamma=" << svmParamsOptimal.gamma << " nu=" << svmParamsOptimal.nu << "\n";
00590 }
00591
00592 std::cout << "done\n";
00593
00594 return ipa_Utils::RET_OK;
00595 }
00596