dmswjt
Posts: 2
Joined: Wed Sep 28, 2016 1:25 pm

Face Recognition to activate Solenoid or Relay HELP

Fri Sep 30, 2016 7:38 pm

Hi all,
I apologise in advance if this in the wrong place, or this confuses you. I'm a relative newbie to any kind of electronics.
I want to build a security system entrance to my work space using face recognition (OpenCV),
I found a tutorial by Tony DiCola which is perfect for that desire.
https://learn.adafruit.com/raspberry-pi ... x?view=all

I own picamera, push button, relay and solenoid.
I prefer to use solenoid, because I think solenoid much more promising than servo, and because I already have it. :D but ..
Small servo or lock solenoid for the locking mechanism, depending on how your box can be latched shut.

A lock solenoid can work with boxes that have a door or drawer. See this locking drawer project for information on using a lock solenoid. Note: the software for this project is written to use a servo as the locking mechanism, so if you use a lock solenoid you will need to modify the software to actuate the lock with the solenoid instead of the servo.
and in the tutorial it is not included how to modify the software ..

I do not have the ability in the python
Any help would be appreciated..
Thanks in advance,

the software for this project:
https://github.com/tdicola/pi-facerec-b ... master.zip

Box.py

Code: Select all

"""Raspberry Pi Face Recognition Treasure Box
Treasure Box Script
Copyright 2013 Tony DiCola 
"""
import cv2

import config
import face
import hardware


if __name__ == '__main__':
	# Load training data into model
	print 'Loading training data...'
	model = cv2.createEigenFaceRecognizer()
	model.load(config.TRAINING_FILE)
	print 'Training data loaded!'
	# Initialize camer and box.
	camera = config.get_camera()
	box = hardware.Box()
	# Move box to locked position.
	box.lock()
	print 'Running box...'
	print 'Press button to lock (if unlocked), or unlock if the correct face is detected.'
	print 'Press Ctrl-C to quit.'
	while True:
		# Check if capture should be made.
		# TODO: Check if button is pressed.
		if box.is_button_up():
			if not box.is_locked:
				# Lock the box if it is unlocked
				box.lock()
				print 'Box is now locked.'
			else:
				print 'Button pressed, looking for face...'
				# Check for the positive face and unlock if found.
				image = camera.read()
				# Convert image to grayscale.
				image = cv2.cvtColor(image, cv2.COLOR_RGB2GRAY)
				# Get coordinates of single face in captured image.
				result = face.detect_single(image)
				if result is None:
					print 'Could not detect single face!  Check the image in capture.pgm' \
						  ' to see what was captured and try again with only one face visible.'
					continue
				x, y, w, h = result
				# Crop and resize image to face.
				crop = face.resize(face.crop(image, x, y, w, h))
				# Test face against model.
				label, confidence = model.predict(crop)
				print 'Predicted {0} face with confidence {1} (lower is more confident).'.format(
					'POSITIVE' if label == config.POSITIVE_LABEL else 'NEGATIVE', 
					confidence)
				if label == config.POSITIVE_LABEL and confidence < config.POSITIVE_THRESHOLD:
					print 'Recognized face!'
					box.unlock()
				else:
					print 'Did not recognize face!'
Capture Positive.py

Code: Select all

"""Raspberry Pi Face Recognition Treasure Box
Positive Image Capture Script
Copyright 2013 Tony DiCola 

Run this script to capture positive images for training the face recognizer.
"""
import glob
import os
import sys
import select

import cv2

import hardware
import config
import face


# Prefix for positive training image filenames.
POSITIVE_FILE_PREFIX = 'positive_'


def is_letter_input(letter):
	# Utility function to check if a specific character is available on stdin.
	# Comparison is case insensitive.
	if select.select([sys.stdin,],[],[],0.0)[0]:
		input_char = sys.stdin.read(1)
		return input_char.lower() == letter.lower()
	return False


if __name__ == '__main__':
	camera = config.get_camera()
	box = hardware.Box()
	# Create the directory for positive training images if it doesn't exist.
	if not os.path.exists(config.POSITIVE_DIR):
		os.makedirs(config.POSITIVE_DIR)
	# Find the largest ID of existing positive images.
	# Start new images after this ID value.
	files = sorted(glob.glob(os.path.join(config.POSITIVE_DIR, 
		POSITIVE_FILE_PREFIX + '[0-9][0-9][0-9].pgm')))
	count = 0
	if len(files) > 0:
		# Grab the count from the last filename.
		count = int(files[-1][-7:-4])+1
	print 'Capturing positive training images.'
	print 'Press button or type c (and press enter) to capture an image.'
	print 'Press Ctrl-C to quit.'
	while True:
		# Check if button was pressed or 'c' was received, then capture image.
		if box.is_button_up() or is_letter_input('c'):
			print 'Capturing image...'
			image = camera.read()
			# Convert image to grayscale.
			image = cv2.cvtColor(image, cv2.COLOR_RGB2GRAY)
			# Get coordinates of single face in captured image.
			result = face.detect_single(image)
			if result is None:
				print 'Could not detect single face!  Check the image in capture.pgm' \
					  ' to see what was captured and try again with only one face visible.'
				continue
			x, y, w, h = result
			# Crop image as close as possible to desired face aspect ratio.
			# Might be smaller if face is near edge of image.
			crop = face.crop(image, x, y, w, h)
			# Save image to file.
			filename = os.path.join(config.POSITIVE_DIR, POSITIVE_FILE_PREFIX + '%03d.pgm' % count)
			cv2.imwrite(filename, crop)
			print 'Found face and wrote training image', filename
			count += 1
Config.py

Code: Select all

# Raspberry Pi Face Recognition Treasure Box Configuration
# Copyright 2013 Tony DiCola 

# Edit the values below to configure the training and usage of the
# face recognition box.

# Pi GPIO port which is connected to the lock servo signal line.
LOCK_SERVO_PIN = 18
# Pulse width value (in microseconds) for the servo at the unlocked and locked
# position.  Center should be a value of 1500, max left a value of 1000, and 
# max right a value of 2000.
LOCK_SERVO_UNLOCKED = 2000
LOCK_SERVO_LOCKED   = 1100

# Pi GPIO port which is connected to the button.
BUTTON_PIN = 25
# Down and up values for the button.  The code expects to detect a down to up
# transition as an activation of the button.  Therefore a normally open button
# should be False (low) when down and True (high) when up.
BUTTON_DOWN = False  # Low signal
BUTTON_UP   = True   # High signal

# Threshold for the confidence of a recognized face before it's considered a
# positive match.  Confidence values below this threshold will be considered
# a positive match because the lower the confidence value, or distance, the
# more confident the algorithm is that the face was correctly detected.
# Start with a value of 3000, but you might need to tweak this value down if 
# you're getting too many false positives (incorrectly recognized faces), or up
# if too many false negatives (undetected faces).
POSITIVE_THRESHOLD = 2000.0

# File to save and load face recognizer model.
TRAINING_FILE = 'training.xml'

# Directories which contain the positive and negative training image data.
POSITIVE_DIR = './training/positive'
NEGATIVE_DIR = './training/negative'

# Value for positive and negative labels passed to face recognition model.
# Can be any integer values, but must be unique from each other.
# You shouldn't have to change these values.
POSITIVE_LABEL = 1
NEGATIVE_LABEL = 2

# Size (in pixels) to resize images for training and prediction.
# Don't change this unless you also change the size of the training images.
FACE_WIDTH  = 92
FACE_HEIGHT = 112

# Face detection cascade classifier configuration.
# You don't need to modify this unless you know what you're doing.
# See: http://docs.opencv.org/modules/objdetect/doc/cascade_classification.html
HAAR_FACES         = 'haarcascade_frontalface_alt.xml'
HAAR_SCALE_FACTOR  = 1.3
HAAR_MIN_NEIGHBORS = 4
HAAR_MIN_SIZE      = (30, 30)

# Filename to use when saving the most recently captured image for debugging.
DEBUG_IMAGE = 'capture.pgm'

def get_camera():	
	# Camera to use for capturing images.
	# Use this code for capturing from the Pi camera:
	import picam
	return picam.OpenCVCapture()
	# Use this code for capturing from a webcam:
	# import webcam
	# return webcam.OpenCVCapture(device_id=0)
face.py

Code: Select all

"""Raspberry Pi Face Recognition Treasure Box
Face Detection Helper Functions
Copyright 2013 Tony DiCola 

Functions to help with the detection and cropping of faces.
"""
import cv2

import config


haar_faces = cv2.CascadeClassifier(config.HAAR_FACES)


def detect_single(image):
	"""Return bounds (x, y, width, height) of detected face in grayscale image.
	   If no face or more than one face are detected, None is returned.
	"""
	faces = haar_faces.detectMultiScale(image, 
				scaleFactor=config.HAAR_SCALE_FACTOR, 
				minNeighbors=config.HAAR_MIN_NEIGHBORS, 
				minSize=config.HAAR_MIN_SIZE, 
				flags=cv2.CASCADE_SCALE_IMAGE)
	if len(faces) != 1:
		return None
	return faces[0]

def crop(image, x, y, w, h):
	"""Crop box defined by x, y (upper left corner) and w, h (width and height)
	to an image with the same aspect ratio as the face training data.  Might
	return a smaller crop if the box is near the edge of the image.
	"""
	crop_height = int((config.FACE_HEIGHT / float(config.FACE_WIDTH)) * w)
	midy = y + h/2
	y1 = max(0, midy-crop_height/2)
	y2 = min(image.shape[0]-1, midy+crop_height/2)
	return image[y1:y2, x:x+w]

def resize(image):
	"""Resize a face image to the proper size for training and detection.
	"""
	return cv2.resize(image, 
					  (config.FACE_WIDTH, config.FACE_HEIGHT), 
					  interpolation=cv2.INTER_LANCZOS4)
hardware.py

Code: Select all

"""Raspberry Pi Face Recognition Treasure Box
Treasure Box Class
Copyright 2013 Tony DiCola 
"""
import time

import cv2
import RPIO
from RPIO import PWM

import picam
import config
import face


class Box(object):
	"""Class to represent the state and encapsulate access to the hardware of 
	the treasure box."""
	def __init__(self):
		# Initialize lock servo and button.
		self.servo = PWM.Servo()
		RPIO.setup(config.BUTTON_PIN, RPIO.IN)
		# Set initial box state.
		self.button_state = RPIO.input(config.BUTTON_PIN)
		self.is_locked = None

	def lock(self):
		"""Lock the box."""
		self.servo.set_servo(config.LOCK_SERVO_PIN, config.LOCK_SERVO_LOCKED)
		self.is_locked = True

	def unlock(self):
		"""Unlock the box."""
		self.servo.set_servo(config.LOCK_SERVO_PIN, config.LOCK_SERVO_UNLOCKED)
		self.is_locked = False

	def is_button_up(self):
		"""Return True when the box button has transitioned from down to up (i.e.
		the button was pressed)."""
		old_state = self.button_state
		self.button_state = RPIO.input(config.BUTTON_PIN)
		# Check if transition from down to up
		if old_state == config.BUTTON_DOWN and self.button_state == config.BUTTON_UP:
			# Wait 20 milliseconds and measure again to debounce switch.
			time.sleep(20.0/1000.0)
			self.button_state = RPIO.input(config.BUTTON_PIN)
			if self.button_state == config.BUTTON_UP:
				return True
		return False
picam.py

Code: Select all

"""Raspberry Pi Face Recognition Treasure Box 
Pi Camera OpenCV Capture Device
Copyright 2013 Tony DiCola 

Pi camera device capture class for OpenCV.  This class allows you to capture a
single image from the pi camera as an OpenCV image.
"""
import io
import time

import cv2
import numpy as np
import picamera

import config


class OpenCVCapture(object):
	def read(self):
		"""Read a single frame from the camera and return the data as an OpenCV
		image (which is a numpy array).
		"""
		# This code is based on the picamera example at:
		# http://picamera.readthedocs.org/en/release-1.0/recipes1.html#capturing-to-an-opencv-object
		# Capture a frame from the camera.
		data = io.BytesIO()
		with picamera.PiCamera() as camera:
			camera.capture(data, format='jpeg')
		data = np.fromstring(data.getvalue(), dtype=np.uint8)
		# Decode the image data and return an OpenCV image.
		image = cv2.imdecode(data, 1)
		# Save captured image for debugging.
		cv2.imwrite(config.DEBUG_IMAGE, image)
		# Return the captured image data.
		return image
servo.py

Code: Select all

# Raspberry Pi Face Recognition Box Servo Calibration Sketch
# Copyright 2013 Tony DiCola

from RPIO import PWM

import config

servo = PWM.Servo()

print 'Servo Calibration'
print
print 'Use this tool to find the pulsewidth values which move the'
print 'lock latch to the locked and unlocked position. Update config.py'
print 'with the locked and unlocked servo pulsewidth values.'
print
print 'Values range from 1000 to 2000 (in microseconds), with 1500 being the center.'
print
print 'Press Ctrl-C to quit'
print 

while True:
	val = raw_input('Enter servo pulsewidth (1000 to 2000):')
	try:
		val = int(val)
	except ValueError:
		print 'Invalid value, must be between 1000 and 2000!'
		continue
	if val < 1000 or val > 2000:
		print 'Invalid value, must be between 1000 and 2000!'
		continue
	servo.set_servo(config.LOCK_SERVO_PIN, val)
train.py

Code: Select all

"""Raspberry Pi Face Recognition Treasure Box
Face Recognition Training Script
Copyright 2013 Tony DiCola 

Run this script to train the face recognition system with positive and negative
training images.  The face recognition model is based on the eigen faces
algorithm implemented in OpenCV.  You can find more details on the algorithm
and face recognition here:
  http://docs.opencv.org/modules/contrib/doc/facerec/facerec_tutorial.html
"""
import fnmatch
import os

import cv2
import numpy as np

import config
import face


MEAN_FILE = 'mean.png'
POSITIVE_EIGENFACE_FILE = 'positive_eigenface.png'
NEGATIVE_EIGENFACE_FILE = 'negative_eigenface.png'


def walk_files(directory, match='*'):
	"""Generator function to iterate through all files in a directory recursively
	which match the given filename match parameter.
	"""
	for root, dirs, files in os.walk(directory):
		for filename in fnmatch.filter(files, match):
			yield os.path.join(root, filename)

def prepare_image(filename):
	"""Read an image as grayscale and resize it to the appropriate size for
	training the face recognition model.
	"""
	return face.resize(cv2.imread(filename, cv2.IMREAD_GRAYSCALE))

def normalize(X, low, high, dtype=None):
	"""Normalizes a given array in X to a value between low and high.
	Adapted from python OpenCV face recognition example at:
	  https://github.com/Itseez/opencv/blob/2.4/samples/python2/facerec_demo.py
	"""
	X = np.asarray(X)
	minX, maxX = np.min(X), np.max(X)
	# normalize to [0...1].
	X = X - float(minX)
	X = X / float((maxX - minX))
	# scale to [low...high].
	X = X * (high-low)
	X = X + low
	if dtype is None:
		return np.asarray(X)
	return np.asarray(X, dtype=dtype)

if __name__ == '__main__':
	print "Reading training images..."
	faces = []
	labels = []
	pos_count = 0
	neg_count = 0
	# Read all positive images
	for filename in walk_files(config.POSITIVE_DIR, '*.pgm'):
		faces.append(prepare_image(filename))
		labels.append(config.POSITIVE_LABEL)
		pos_count += 1
	# Read all negative images
	for filename in walk_files(config.NEGATIVE_DIR, '*.pgm'):
		faces.append(prepare_image(filename))
		labels.append(config.NEGATIVE_LABEL)
		neg_count += 1
	print 'Read', pos_count, 'positive images and', neg_count, 'negative images.'

	# Train model
	print 'Training model...'
	model = cv2.createEigenFaceRecognizer()
	model.train(np.asarray(faces), np.asarray(labels))

	# Save model results
	model.save(config.TRAINING_FILE)
	print 'Training data saved to', config.TRAINING_FILE

	# Save mean and eignface images which summarize the face recognition model.
	mean = model.getMat("mean").reshape(faces[0].shape)
	cv2.imwrite(MEAN_FILE, normalize(mean, 0, 255, dtype=np.uint8))
	eigenvectors = model.getMat("eigenvectors")
	pos_eigenvector = eigenvectors[:,0].reshape(faces[0].shape)
	cv2.imwrite(POSITIVE_EIGENFACE_FILE, normalize(pos_eigenvector, 0, 255, dtype=np.uint8))
	neg_eigenvector = eigenvectors[:,1].reshape(faces[0].shape)
	cv2.imwrite(NEGATIVE_EIGENFACE_FILE, normalize(neg_eigenvector, 0, 255, dtype=np.uint8))
webcam.py

Code: Select all

"""Raspberry Pi Face Recognition Treasure Box 
Webcam OpenCV Camera Capture Device
Copyright 2013 Tony DiCola 

Webcam device capture class using OpenCV.  This class allows you to capture a
single image from the webcam, as if it were a snapshot camera.  

This isn't used by the treasure box code out of the box, but is useful to have
if running the code on a PC where only a webcam is available.  The interface is
the same as the picam.py capture class so it can be used in the box.py code
without any changes.
"""
import threading
import time

import cv2

import config


# Rate at which the webcam will be polled for new images.
CAPTURE_HZ = 30.0


class OpenCVCapture(object):
	def __init__(self, device_id=0):
		"""Create an OpenCV capture object associated with the provided webcam
		device ID.
		"""
		# Open the camera.
		self._camera = cv2.VideoCapture(device_id)
		if not self._camera.isOpened():
			self._camera.open()
		# Start a thread to continuously capture frames.
		# This must be done because different layers of buffering in the webcam
		# and OS drivers will cause you to retrieve old frames if they aren't 
		# continuously read.
		self._capture_frame = None
		# Use a lock to prevent access concurrent access to the camera.
		self._capture_lock = threading.Lock()
		self._capture_thread = threading.Thread(target=self._grab_frames)
		self._capture_thread.daemon = True
		self._capture_thread.start()

	def _grab_frames(self):
		while True:
			retval, frame = self._camera.read()
			with self._capture_lock:
				self._capture_frame = None
				if retval:
					self._capture_frame = frame
			time.sleep(1.0/CAPTURE_HZ)

	def read(self):
		"""Read a single frame from the camera and return the data as an OpenCV
		image (which is a numpy array).
		"""
		frame = None
		with self._capture_lock:
			frame = self._capture_frame
		# If there are problems, keep retrying until an image can be read.
		while frame == None:
			time.sleep(0)
			with self._capture_lock:
				frame = self._capture_frame
		# Save captured image for debugging.
		cv2.imwrite(config.DEBUG_IMAGE, frame)
		# Return the capture image data.
		return frame

BMS Doug
Posts: 3824
Joined: Thu Mar 27, 2014 2:42 pm
Location: London, UK

Re: Face Recognition to activate Solenoid or Relay HELP

Tue Oct 11, 2016 4:47 pm

dmswjt wrote:Hi all,
I apologise in advance if this in the wrong place, or this confuses you. I'm a relative newbie to any kind of electronics.
I want to build a security system entrance to my work space using face recognition (OpenCV),
I found a tutorial by Tony DiCola which is perfect for that desire.
https://learn.adafruit.com/raspberry-pi ... x?view=all

I own picamera, push button, relay and solenoid.
I prefer to use solenoid, because I think solenoid much more promising than servo, and because I already have it. :D but ..
Small servo or lock solenoid for the locking mechanism, depending on how your box can be latched shut.

A lock solenoid can work with boxes that have a door or drawer. See this locking drawer project for information on using a lock solenoid. Note: the software for this project is written to use a servo as the locking mechanism, so if you use a lock solenoid you will need to modify the software to actuate the lock with the solenoid instead of the servo.
and in the tutorial it is not included how to modify the software ..

I do not have the ability in the python
Any help would be appreciated..
Thanks in advance.
the code you want to modify is in hardware.py, where it defines the locking and unlocking operations. Servo.py can be ignored.

A solenoid is operated by turning it on or turning it off (there are plenty of led gpio tutorials to show how to operate an output) i would suggest starting your project with an LED in place of the solenoid so that you can see it working.

You should use a transistor to switch the solenoid, adafruit's drawer tutorial won't work for the wiring of this as the voltage would destroy your pi.
please give details of the solenoid operating voltage and current.
Doug.
Building Management Systems Engineer.

Return to “Off topic discussion”