Qengineering / Face-Recognition-with-Mask-Jetson-Nano

Recognize 2000+ faces on your Jetson Nano with additional mask detection, auto-fill and anti-spoofing
https://qengineering.eu/deep-learning-examples-on-raspberry-32-64-os.html
BSD 3-Clause "New" or "Revised" License
35 stars 6 forks source link

its crashing at random intervals with cv::Exception #2

Closed rsingh2083 closed 3 years ago

rsingh2083 commented 3 years ago

I think sometimes the image descriptors are ZERO and the code is trying to access this UNINITIALIZED BUFFER,hence its crashing sometimes at 30 seconds and sometimes after 10 minutes.

rsingh2083 commented 3 years ago

So I figured out when its crashing : When someone is moving their face a bit faster, then I maybe think the frame is loosing track of the face frame and then this error is coming up

terminate called after throwing an instance of 'cv::Exception'
what (): OpenCV(4.1.2) /home/ns/opencv/modules/core/src/matrix.cpp:466: error: (-215:Assertion failed) 0 <= roi.x && 
0 <= roi.width && roi.x + roi.width <=m.cols && roi.y && 0<=roi.height <=m.rows in function 'Mat'

Aborted (core dumped)
rsingh2083 commented 3 years ago

Its also happening when someones face is detected and he moves outside of the webcam suddenly, which I think is causing issue with face frame ROI tracking.

Qengineering commented 3 years ago

The same typo frame should be result_cnn. image

rsingh2083 commented 3 years ago

Sir which variable holds the name of the recognized person ? I want to save the name of recognized person. For unrecognized the variable NewItem something but for recognized I couldn't find

Qengineering commented 3 years ago

At the very beginning a global variable is declared at line 52 at main.cpp vector<cv::String> NameFaces; This is the list of strings holding the names. The list is filled at line 285 with one call cv::glob(pattern_jpg, NameFaces); Later, on lines 297 to 302, the names are fashioned into legible names.

rsingh2083 commented 3 years ago

At the very beginning a global variable is declared at line 52 at main.cpp vector<cv::String> NameFaces; This is the list of strings holding the names. The list is filled at line 285 with one call cv::glob(pattern_jpg, NameFaces); Later, on lines 297 to 302, the names are fashioned into legible names.

Sir I tried these variables but these are the names which are there in the img folder. But I want the variable which holds the name of the recognized person in front of the camera.

Qengineering commented 3 years ago

Ah, I understand. At line 340, all found faces are placed in the list. Not the names, only their coordinates. At line 352 we run through the list. Here we only use the first item, presuming when there are more faces they will too tiny to recognize given the size of the image. At line 412 a test is done if the found face has a high probability. At line 425 one major loop runs through all stored faces in the database, looking for the best mach. At line 427 the highest score is given to the face, by filling the NameIndex element of the struct FaceObject , declared at Retina.h at line 14. This struct holds all the parameters of the found face. NameIndex is the index in the database, which you can use to get the name. This is done at line 144 for drawing purposes.

Qengineering commented 3 years ago

Crashing solved

rsingh2083 commented 3 years ago

Hi, I tried this but unable to print out the names of person. I tried this code :-

174 cv::String save_name; // INSIDE THE MAIN LOOP

Then ..

408  #endif // TEST_MASK
409                     //get centre aligned image
410                     cv::Mat aligned = Warp.Process(result_cnn,Faces[i]);
411                     Faces[i].Angle  = Warp.Angle;
412                     //features of camera image
413                     cv::Mat fc2 = ArcFace.GetFeature(aligned);
414                     //reset indicators
415                     Faces[i].NameIndex = -1;    //a stranger
416                     Faces[i].Color     =  1;
417                     //the similarity score
418                     if(FaceCnt>0){
419                         vector<double> score_;
420                         for(size_t c=0;c<FaceCnt;c++) score_.push_back(CosineDistance(fc1[c], fc2));
421                         int Pmax = max_element(score_.begin(),score_.end()) - score_.begin();
422                         Faces[i].NameIndex = Pmax;
423                         Faces[i].NameProb  = score_[Pmax];
424                         save_name=Faces[i].NameIndex;  //SAVE PERSON NAME IN SAVE_NAME
425                         cout << save_name;
426                         score_.clear();
427                         if(Faces[i].NameProb >= MinFaceThreshold){
428                             //recognize a face
429                             if(Faces[i].rect.height < MinHeightFace){
430                                 Faces[i].Color = 2; //found face in database, but too tiny
431                             }
432                             else{
433                                 Faces[i].Color = 0; //found face in database and of good size
434                                 //cout << Faces[i];
435                                 save_name=Faces[i].NameIndex;
436                                 cout << save_name;

But the output Im getting on console is random english character in capital font . For example sometime it prints BBBBBBB..sometimes KKKKKKKK etc

Ah, I understand. At line 340, all found faces are placed in the list. Not the names, only their coordinates. At line 352 we run through the list. Here we only use the first item, presuming when there are more faces they will too tiny to recognize given the size of the image. At line 412 a test is done if the found face has a high probability. At line 425 one major loop runs through all stored faces in the database, looking for the best mach. At line 427 the highest score is given to the face, by filling the NameIndex element of the struct FaceObject , declared at Retina.h at line 14. This struct holds all the parameters of the found face. NameIndex is the index in the database, which you can use to get the name. This is done at line 144 for drawing purposes.

Qengineering commented 3 years ago

dear @rsingh2083 ,

At line 340 some elements of the list are reset. (the list is used every frame, so needs to be clean first)

Next look at the bottom at line 493 DrawObjects(frame, Faces); Here all found information is placed on the screen, including the names.

At line 72 the DrawObjects routine starts. After some tests regarding the the fallibility, the name is printed with the case statement at line 139. Remember, obj is in fact Faces[i]. (Easier to write obj instead of Faces[i] every time. And it's faster code) So, the string Str at line 147 holds the same information as printed above the face.

Because Faces[i].NameIndex can be negative to flag certain exceptions. A negative index in the NameFaces list lets the app crash.

After testing NameIndex>=0 you can use it to get the name, than you can put it in a file. I would use the DrawObjects routine to fill the file.

Kind regards,

rsingh2083 commented 3 years ago

Sir one more small question. The face recognition keeps displaying a persons name. Is it possible to just display the name once for a duration of lets say 3 seconds and then if still its the same person then not display anything or display a message "Your face has been already recognized please proceed". This is to solve two purposes :- 1.] While saving the person name records in a csv file, the file wont get overflooded with same person unnecessarily 2.] The person is able to see his name for a longer period of time & hence GUI becomes more appealing lookwise.