-
-
Notifications
You must be signed in to change notification settings - Fork 16
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Resolve #289 Find similar students #316
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -314,15 +314,29 @@ private File createAvatarFileFromStudentImage(StudentImage studentImage, Student | |
|
||
/** | ||
* Find similar students | ||
* Case 1: Student was added during fallback but in the meantime the same person has an existing StudentImageCollectionEvent and a new Student entry | ||
* | ||
* | ||
*/ | ||
public synchronized void findAndMergeSimilarStudents(){ | ||
Log.i(getClass().getName(), "findAndMergeSimilarStudents"); | ||
PreProcessorFactory ppF = new PreProcessorFactory(context); | ||
TensorFlow tensorFlow = getInitializedTensorFlow(); | ||
findSimilarStudentsUsingAvatarImages(ppF, tensorFlow); | ||
findSimilarStudentsUsingMeanFeatureVector(ppF, tensorFlow); | ||
} | ||
|
||
/** | ||
* Find similar students | ||
* Case 1: Student was added during fallback but in the meantime the same person has an existing StudentImageCollectionEvent and a new Student entry | ||
* ---> Use the avatar image as input for the recognition | ||
* @param ppF | ||
* @param tensorFlow | ||
*/ | ||
private synchronized void findSimilarStudentsUsingAvatarImages(PreProcessorFactory ppF, TensorFlow tensorFlow){ | ||
// Iterate through all Students | ||
List<Student> students = studentDao.loadAll(); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Add logging here so that we can see if the method was triggered
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. done |
||
// Iterate through all students | ||
for (Student student : students){ | ||
// Take the avatar image of the student | ||
// Take the avatar image of the Student | ||
Mat avatarImage = Imgcodecs.imread(student.getAvatar()); | ||
// Search for faces in the avatar image | ||
List<Mat> faceImages = ppF.getCroppedImage(avatarImage); | ||
|
@@ -334,26 +348,60 @@ public synchronized void findAndMergeSimilarStudents(){ | |
Rect[] faces = ppF.getFacesForRecognition(); | ||
if (faces != null && faces.length == 1) { | ||
// Proceed if exactly one face rectangle exists | ||
RecognitionThread recognitionThread = new RecognitionThread(getInitializedTensorFlow(), studentImageCollectionEventDao); | ||
RecognitionThread recognitionThread = new RecognitionThread(tensorFlow, studentImageCollectionEventDao); | ||
recognitionThread.setImg(faceImage); | ||
Log.i(getClass().getName(), "findAndMergeSimilarStudents: recognitionThread will be started to recognize student: " + student.getUniqueId()); | ||
Log.i(getClass().getName(), "findSimilarStudentsUsingAvatarImages: recognitionThread will be started to recognize student: " + student.getUniqueId()); | ||
recognitionThread.start(); | ||
try { | ||
recognitionThread.join(); | ||
Student recognizedStudent = recognitionThread.getStudent(); | ||
if (recognizedStudent != null){ | ||
Log.i(getClass().getName(), "findAndMergeSimilarStudents: The student " + student.getUniqueId() + " has been recognized as " + recognizedStudent.getUniqueId()); | ||
Log.i(getClass().getName(), "findSimilarStudentsUsingAvatarImages: The student " + student.getUniqueId() + " has been recognized as " + recognizedStudent.getUniqueId()); | ||
mergeSimilarStudents(student, recognizedStudent); | ||
} else { | ||
Log.i(getClass().getName(), "findAndMergeSimilarStudents: The student " + student.getUniqueId() + " was not recognized"); | ||
Log.i(getClass().getName(), "findSimilarStudentsUsingAvatarImages: The student " + student.getUniqueId() + " was not recognized"); | ||
} | ||
} catch (InterruptedException e) { | ||
e.printStackTrace(); | ||
} | ||
|
||
} | ||
} | ||
} | ||
} | ||
} | ||
|
||
/** | ||
* Find similar students | ||
* Case 2: Student was added regularly but maybe on another tablet or due to some reason the authentication didn't recognize the student correctly in the numberOfTries | ||
* ---> Use the meanFeatureVector as input for the cosineSimilarityScore calculation | ||
* @param ppF | ||
* @param tensorFlow | ||
*/ | ||
private synchronized void findSimilarStudentsUsingMeanFeatureVector(PreProcessorFactory ppF, TensorFlow tensorFlow){ | ||
// Iterate through all StudentImageCollectionEvents | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Add There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. done |
||
List<StudentImageCollectionEvent> studentImageCollectionEvents = studentImageCollectionEventDao.loadAll(); | ||
for (StudentImageCollectionEvent studentImageCollectionEvent : studentImageCollectionEvents){ | ||
// Take the meanFeatureVector of the StudentImageCollectionEvent | ||
List<Float> meanFeatureVectorList = gson.fromJson(studentImageCollectionEvent.getMeanFeatureVector(), new TypeToken<List<Float>>(){}.getType()); | ||
Mat meanFeatureVector = Converters.vector_float_to_Mat(meanFeatureVectorList); | ||
RecognitionThread recognitionThread = new RecognitionThread(tensorFlow, studentImageCollectionEventDao); | ||
recognitionThread.setImg(meanFeatureVector); | ||
// To indicate, that this Mat object contains the already extracted features and therefore this step can be skipped in the RecognitionThread | ||
recognitionThread.setFeaturesAlreadyExtracted(true); | ||
Student student = studentImageCollectionEvent.getStudent(); | ||
Log.i(getClass().getName(), "findSimilarStudentsUsingMeanFeatureVector: recognitionThread will be started to recognize student: " + student.getUniqueId()); | ||
recognitionThread.start(); | ||
try { | ||
recognitionThread.join(); | ||
Student recognizedStudent = recognitionThread.getStudent(); | ||
if (recognizedStudent != null){ | ||
Log.i(getClass().getName(), "findSimilarStudentsUsingMeanFeatureVector: The student " + student.getUniqueId() + " has been recognized as " + recognizedStudent.getUniqueId()); | ||
mergeSimilarStudents(student, recognizedStudent); | ||
} else { | ||
Log.i(getClass().getName(), "findSimilarStudentsUsingMeanFeatureVector: The student " + student.getUniqueId() + " was not recognized"); | ||
} | ||
} catch (InterruptedException e) { | ||
e.printStackTrace(); | ||
} | ||
} | ||
} | ||
|
@@ -365,5 +413,6 @@ public synchronized void findAndMergeSimilarStudents(){ | |
*/ | ||
private synchronized void mergeSimilarStudents(Student student1, Student student2){ | ||
Log.i(getClass().getName(), "mergeSimilarStudents: student1: " + student1.getUniqueId() + " student2: " + student2.getUniqueId()); | ||
// TODO Implement merging of students (maybe in another class like StudentMergeHelper) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This will be implemented in #314 |
||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,30 @@ | ||
package org.literacyapp.service.synchronization; | ||
|
||
import android.app.Service; | ||
import android.app.job.JobParameters; | ||
import android.app.job.JobService; | ||
import android.content.Intent; | ||
import android.os.IBinder; | ||
import android.util.Log; | ||
|
||
import org.literacyapp.authentication.TrainingHelper; | ||
|
||
public class MergeSimilarStudentsJobService extends JobService { | ||
public static boolean isRunning = false; | ||
|
||
@Override | ||
public boolean onStartJob(JobParameters jobParameters) { | ||
Log.i(getClass().getName(), "onStartJob"); | ||
isRunning = true; | ||
TrainingHelper trainingHelper = new TrainingHelper(getApplicationContext()); | ||
trainingHelper.findAndMergeSimilarStudents(); | ||
isRunning = false; | ||
return false; | ||
} | ||
|
||
@Override | ||
public boolean onStopJob(JobParameters jobParameters) { | ||
Log.i(getClass().getName(), "onStopJob"); | ||
return false; | ||
} | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Does an avatar image also include those taken manually in the fall-back registration activity? If so, you currently get a mix between 180px and 224px images. Will this inconsistency in image size/format cause problems?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
No, because our library uses the default value 224 for resizing the image to 224 x 224 if no sharedPreference with the key "key_faceSize" exists (this key doesn't exist in our app because we don't have the Settings from the library included)