DIY Portable Face Recogniser Python Part 4

Main Program Loop

Okay, we will enter the main loop of the program in this post.

The first part of the loop has:

  • Prepare to catch keyboard interruption
  • Start the main program loop
  • Reset default values for each iteration
### Main program loop
try:
	while(endProgramCount  <  endProgramAfter):
		sleepTimer = 0
		NewSpeech = ''
		msg1 = format(WeekDay[datetime.now().weekday()]) + datetime.now().strftime(" %d-%b %H:%M")
		msg2 = 'REC          OFF'

Line 2: Prepare for KeyboardInterrupt exception
Line 3: Keep looping until the program shutdown sequence is triggered
Line 4-7: Reset variables for each iteration

Program Mode

We have different behavior for each program mode from here.

Detecting
  • Get an image from camera
  • Detect faces in the image
  • Recognise the detected faces using the face recognition model
  • Get the name of recognised face
  • Greet on LCD screen depending on the confidence level

The confidence values are:

  • 0 = 100% (Highest)
  • 100 = 0% (Lowest)
		if 'Detecting'==mode and not newTrainer:
			for i in range(5):
				ret, frame = cap.read()
			frame = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)
			faces = face_cascade.detectMultiScale(frame, 1.3, 5)
			for (x,y,w,h) in faces:
				msg1 = 'Face Detected!'
				id, confidence = recogniser.predict(frame[y:y+h, x:x+w])
				sql = '''SELECT name FROM people WHERE ROWID = ? '''
				c.execute(sql, (str(id),))
				if confidence < 55:
					if confidence < 20:
						msg1 = 'Hello'
						msg2 = c.fetchone()[0]
					elif confidence < 25:
						msg1 = 'How are you'
						msg2 = c.fetchone()[0] + '?'
					elif confidence < 30:
						msg1 = 'You must be'
						msg2 = c.fetchone()[0]
					elif confidence < 35:
						msg1 = 'How is it going'
						msg2 = c.fetchone()[0] + '?'
					elif confidence < 40:
						msg1 = 'Nice to see you'
						msg2 = c.fetchone()[0]
					elif confidence < 45:
						msg1 = 'I think you are'
						msg2 = c.fetchone()[0]
					elif confidence < 50:
						msg1 = 'You look like'
						msg2 = c.fetchone()[0]
					else:
						msg1 = 'You may be'
						msg2 = c.fetchone()[0] + '?'
					NewSpeech = msg1 + ' ' + msg2 
				elif confidence < 100:
					msg1 = str(round(100-confidence))+ '% similar to'
					msg2 = c.fetchone()[0]

Line 1: If the mode is in “Detecting” then execute lines 2-39
Line 2 & 3: Get 5th frame of captured video to avoid getting a similar image
Line 4: Converting image colour to grayscale for face detection
Line 5: Detect face within the image using detector
Line 6-8: Cut out a face from a frame of image and recognise it using the face recognition model
Line 9 & 10: Retrieve the name of the recognised face
Line 11-35: If the confidence level is more than 45% then prepare a greeting message depending on the confidence level
Line 37-39: If the confidence level is less than 46% then show a different message

Recording
  • Prepare the message to indicate process progression
		elif 'Recording' == mode:
			msg1 = indicator + ' Recording...'
			msg2 = str(len(trainingImg)) + ' Recorded'

Line 1: If the mode is in “Recording” then execute lines 2 & 3
Line 2 & 3: Prepare the message to indicate process progression

Predicting
  • Prepare a text to confirm if the suggestion is correct
  • Prepare a message to indicate button function
  • Find similar faces from the face recognition model
  • Get the names for similar faces from the database
		elif 'Predicting' == mode:
			if len(predictedIDset) == 0:
				for Img in trainingImg:
					id, confidence = recogniser.predict(Img)
					predictedIDset.add(id)
			else:
				if not (predictedID in predictedIDset):
					for i in predictedIDset:
						predictedID = i
						sql = '''SELECT name FROM people WHERE ROWID = ? '''
						c.execute(sql, (str(predictedID),))
						predictedName = c.fetchone()[0]
						break
			msg1 = 'Are you ' + predictedName + '?'
			msg2 = '   Yes    No'

Line 1: If mode is in “Predicting” then execute lines 2-15
Line 2: If prediction has not been made
Line 3-5: Find all similar faces from the face recognition model and put them in the predicted ID set
Line 6: If the prediction is has been made
Line 7: Skip lines 8-12 if the current suggestion is still in the predicted ID set
Line 8-13: If the current suggestion is already removed from the predicted ID set, then nominate the next suggestion from predicted ID set with the name retrieved from the database
Line 14: Prepare a text to confirm if the suggestion is correct
Line 15: Prepare a message to indicate button function

Updating
  • Show text on LCD screen
  • Add new face records for the existing person in the training model
  • Reset variables
  • Back to “Detecting” mode
		elif 'Updating'== mode:
			lcd.lcd_display_string('Updating...'.ljust(16), 1, 0)
			lcd.lcd_display_string('Please wait.'.ljust(16), 2, 0)
			recogniser.update(trainingImg, np_array([predictedID]*len(trainingImg)))
			recogniser.write(ScriptLocation + '/face_recogniser.yml')
			resetPrediction()
			trainingImg = []
			mode = 'Detecting'

Line 1: If the program is in “Updating” mode then execute lines 2-8
Line 2 & 3: Show “Updating…” on the top row and “Please wait.” the bottom row of the LCD screen
Line 4: Update face recognition model by passing face images and database record ID to the “update” method
Line 5: Overwrite current face recognition model into “face_recogniser.yml”
Line 6 & 7: Reset variables used to update the face recognition model
Line 8: Switch back to “Detecting” mode

Naming
  • Prepare message to show current name entered
  • Prepare message to indicate button function
		elif 'Naming' == mode:
			if NameCursorBlink:
				msg1 = 'Name:'+name
				NameCursorBlink = False
			else:
				msg1 = 'Name:'+name+alphabet[alphabet_index]
				NameCursorBlink = True
			msg2 = 'Sve <   >  E   C'

Line 1: If the mode is in “Naming” mode then execute lines 2-8
Line 2-7: Prepare a text “Name:” followed by the entred name and blink next alphabet
Line 8: Prepare a text to indicate the button functions

Saving
  • Show text on LCD screen
  • Insert record into the database
  • Save a new face into the face training model
  • Reset some variables
  • Switch back to the “Detecting” mode
		if 'Saving'==mode:
			lcd.lcd_display_string('Saving...'.ljust(16), 1, 0)
			lcd.lcd_display_string('Please wait.'.ljust(16), 2, 0)
		
			sql = '''INSERT INTO people(name, date_created) VALUES (?,?)'''
			c.execute(sql, (name, datetime.now()))
			conn.commit()
			rowid = c.lastrowid
			if newTrainer:
				recogniser.train(trainingImg, np_array([rowid]*len(trainingImg)))
			else:
				recogniser.update(trainingImg, np_array([rowid]*len(trainingImg)))
			print('write face_recogniser.yml')
			recogniser.write(ScriptLocation + '/face_recogniser.yml')
			newTrainer = False
			resetPrediction()
			trainingImg = []
			name = ''
			alphabet_index = 0
			mode = 'Detecting'

Line 1: If the program is in “Saving” mode then execute line 2-20
Line 2 & 3: Show “Saving…” on the top row and “Please wait.” the bottom row of the LCD screen
Line 5-7: Save the name into the database table called “people”
Line 8: Get the record ID for the name just entered from database
Line 9: If this is the first face to record
Line 10: Passing face images and database record ID to the “train” method to create the face recognition model
Line 11: If this isn’t the first face to record
Line 12: Passing face images and database record ID to the “update” method to add to the face recognition model
Line 14: Create or Overwrite “face_recogniser.yml” file using the current face recognition model
Line 15: Indicating that at least one face is recorded in the model
Line 16-19: Reset all variables used to save face
Line 20: Switch back to “Detecting” mode

Ending
  • Prepare a text indicating the program is shutting down
  • Prepare a text showing a number counting down
		elif 'Ending' == mode:
			msg1 = 'End Program in'
			msg2 = str(endProgramAfter - endProgramCount)

Line 1: If the mode is in “Ending” mode then execute lines 2 & 3
Line 2: Prepare a text indicating the program is shutting down
Line 3: Prepare a text showing a number counting down

Show Text on LCD Screen

		### Show message on LCD screen
		lcd.lcd_display_string(msg1.ljust(16), 1, 0)
		lcd.lcd_display_string(msg2.ljust(16), 2, 0)

Line 2: Show message on the top row of the LCD screen
Line 3: Show message on the bottom row of the LCD screen

Voice Output

  • Avoid repeating the same speech
  • Output voice
        ### Voice Output	
		if '' != NewSpeech and NewSpeech != OldSpeech:
			PicoSpeech(NewSpeech)
			OldSpeech = NewSpeech

Line 2: If there is a new speech and the new speech is different to previous speech then execute lines 3 & 4
Line 3: Output voice
Line 4: Remember what just has been said

This is the end of the main program loop.

Ending Program

The main program loop will end when:

  • User keep pressing the “OFF” button
  • Interrupted by a keyboard input such as Ctrl+C
### Out of main program loop 
	quit_program(True)
	
### Program interruption		
except KeyboardInterrupt:
	quit_program(False)

Line 2: Start quitting the program with device shutdown
Line 5-6: Start quitting the program on a keyboard interruption without device shutdown

What’s Next?

We will configure Raspberry pi to automatically start this program.