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