DIY Portable Face Recogniser Python Part 2

Function Blocks

Just continuing from the previous post, we will start writing each function that will be assigned to the buttons.

The Button 1

Let’s start with the button 1. This button has the largest function block.

  • Pressed in “Detecting” mode to record
  • Released in “Recording” mode to go to next mode
  • Pressed in “Naming” mode to save the name
### Button 1
def button1_callback(channel):
	global cap
	global trainingImg
	global newTrainer
	global mode
	global name
	global indicator
	
	if mode in {'Detecting', 'Recording'}:
		if GPIO.input(Button_1):		
			if len(trainingImg) > 0:
				if newTrainer:
					mode = 'Naming'
				else:
					mode = 'Predicting'
			else:
				mode = 'Detecting'
		else:	
			while(False == GPIO.input(Button_1)):
				if '>'==indicator:
					indicator = '+'
				else:
					indicator = '>'	
				print('Recording')
				mode = 'Recording'
				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:
					trainingImg.append(frame[y:y+h, x:x+w])
					print('trainImg:', len(trainingImg))
					break
	elif 'Naming' == mode:
		print('Button 1 Naming mode')
		if len(name)>0:
			mode = 'Saving'
		else:
			trainingImg = []
			mode = 'Detecting'

Line 3-8: Making global variables available in this function
Line 10: If the program mode is either “Detecting” or “Recording” then execute the lines 11-34
Line 11: If the Button 1 is released then stop recording
Line 12 If there are recorded face images accumulated
Line 13: If nothing in the training file
Line 14: Switch to “Naming” mode to enter a new name
Line 15: If something in the training file
Line 16: Switch to “Predicting” mode to find similar faces
Line 17: If there are no face image accumulated for training
Line 18: Switch to “Detecting” mode to look for faces
Line 19: If the button 1 is pressed
Line 20: Repeat the lines 21-33 while button is pressed
Line 21-24: Alternating letter “+” & “>” to indicate process
Line 26: Switch to “Recording” mode
Line 27 & 28: Get 5th frame of captured video to avoid getting a similar image
Line 29: Converting image colour to grayscale for face detection
Line 30: Detect face within the image using detector
Line 31 – 34: Cut out one face from a frame of image and append to image array used for training later.
Line 35: If the program mode is “Naming” then “Save” execute “Save” actions lines 36-41
Line 36: If a name is given then switch to “Save” mode
Line 37: If no name is given then back to “Detecting” mode

The Button 2
  • Pressed in “Naming” mode to pick the previous alphabet
  • Pressed in “Predicting” mode to answer “Yes”
### Button 2
def button2_callback(channel):
	global mode
	global alphabet
	global alphabet_index
	
	if 'Naming' == mode:
		if not GPIO.input(Button_2):
			print('Button 2 Naming mode')
			alphabet_index-=1
			if alphabet_index  <  0:
				alphabet_index = len(alphabet) - 1
	elif mode in {'Predicting'}:
		mode = 'Updating'

Line 3-5: Making global variables available in this function
Line 7: If the program mode is “Naming” then execute lines 8-12
Line 8 -10: If the Button 2 is pressed then pick the previous alphabet
Line 11 & 12: If the alphabet already is “A” then go to “z”
Line 13: If the program mode is “Predicting” then “Yes” is pressed for the predicted name so switch to “Updating” mode

The Button 3
  • Pressed in “Naming” mode to pick the next alphabet
### Button 3
def button3_callback(channel):
	global mode
	global alphabet
	global alphabet_index

	if 'Naming' == mode:
		if not GPIO.input(Button_3):
			print('Button 3 Naming mode')
			alphabet_index+=1
			if alphabet_index >= len(alphabet):
				alphabet_index = 0

Line 3-5: Making global variables available in this function
Line 7: If the program mode is “Naming” then execute lines 8-12
Line 8 -10: If the Button 3 is pressed then pick the next alphabet
Line 11 & 12: If the alphabet already is “z” then go to “A”

The Button 4
  • Pressed in “Naming” mode to add alphabet to the name
  • Pressed in “Predicting” mode to answer “No”
### Button 4
def button4_callback(channel):  
	global mode
	global alphabet
	global name
	global alphabet_index
	if 'Naming' == mode:
		if not GPIO.input(Button_4):
			print('Button 4 Naming mode')
			if len(name)  <  11:
				name += alphabet[alphabet_index]
				alphabet_index = 0
	elif 'Predicting'== mode: #Pressed 'No' in predictedName mode
		print('Button 4 Predicting mode')
		if len(predictedIDset)==0:
			resetPrediction()
			mode = 'Naming' #Name entry mode
		else:
			predictedIDset.discard(predictedID)
			if len(predictedIDset)==0:
				resetPrediction()
				mode = 'Naming'

Line 3-6: Making global variables available in this function
Line 7: If the program mode is “Naming” then execute lines 8-12
Line 8 -10: If the Button 3 is pressed and the name isn’t too long
Line 11 & 12: Add alphabet to the name
Line 13 If the program mode is “Predicting” then execute lines 14-22
Line 15-17: If no more prediction then switch to “Naming” mode
Line 19: Remove a prediction
Line 20-22: If no more prediction then switch to “Naming” mode

The Button 5
  • Pressed in “Naming” mode to remove alphabet from the name (when the name has some characters)
  • Pressed in “Naming” mode to switch back to “Detecting” mode (when the name does not have any character)
  • Pressed in other modes to begin shutdown sequence
  • Released in other modes to stop shutdown sequence
### Button 5
def button5_callback(channel):
	global endProgramCount
	global alphabet
	global name
	global alphabet_index
	global mode
	global trainingImg
	
	if 'Naming' == mode:
		if not GPIO.input(Button_5):
			print('Button 5 Naming mode')
			if len(name)>0:
				alphabet_index = alphabet.index(name[-1:])
				name = name[:-1]
			else:
				trainingImg = []
				mode = 'Detecting'
	else:
		if GPIO.input(Button_5):
			endProgramCount = 0
			mode = 'Detecting'
		else:
			while(not GPIO.input(Button_5)):
				sleep(1)
				endProgramCount += 1
				mode = 'Ending'

Line 3-8: Making global variables available in this function
Line 10: If the program mode is “Naming” then execute lines 11-18
Line 11: If the button is pressed
Line 13-15: If the name has some characters, then remove a character from the name
Line 16-18: If the name does not have any character then clear accumulated image and go back to “Detecting” mode
Line 19: If the program mode is not in “Naming”
Line 20-22: If the button is released, then stop & shutdown sequence and back to “Detecting” mode
Line 23-24: Loop line 25-27 while the button is kept being pressed
Line 25: Pause program for a second to allow count down
Line 26: Add 1 to shutdown count
Line 27: Switch mode to “Ending”

Reset Previous Prediction

The next function just simplifies a common operation used 4 times in the program.

### Reset prediction 
def resetPrediction():
	global predictedIDset
	global predictedID
	predictedIDset.clear
	predictedID = -1

Line 3-4: Making global variables available in this function
Line 5: Clear the set of predicted IDs
Line 6: Set default value to the predicted ID

Pico Voice Output

The PicoSpeech function to make it easier to use Pico Text-to-Speech.

### Speech
def PicoSpeech(speech):
	call('pico2wave -w ' + ScriptLocation + '/voice.wav \"' + speech + '\" && paplay ' + ScriptLocation + '/voice.wav', shell=True)

Line 3: Call external command “pico2wave” to record the voice in the “voice.wav” sound file, then use another external command “paplay” (PulseAudio player) to play the “voice.wav”

Shutdown Sequence

The last function is used to shutdown the program.

### Program shutdown sequence
def quit_program(ShutDown):
	print('[INFO] Quit Program')
	cap.release()
	c.close()
	conn.close()
	lcd.lcd_clear()
	lcd.backlight(0)
	GPIO.cleanup()
	if ShutDown:
		call('sudo shutdown -h now', shell=True)
	else:
		quit()

Line 4: Release the video capturing process
Line 5 & 6: Close the database cursor and the connection
Line 7 & 8: Clear LCD screen and turn off the backlight
Line 9: Clean up GPIO settings
Line 10 & 11: If “ShutDown” is “True” then call an external command to shutdown Raspberry Pi
Line 12 & 13: If “ShutDown” is “False” the simply quit the Python program.

What’s Next?

That is all for the function blocks. The next part “Final Preparation” will be continued in the next post.