Commit 6474e8dc authored by ben.coxford's avatar ben.coxford

Initial commit

parents
File added
#Ben Coxford
#------------
#Lines 6-34
#------------
#Import frameworks and libraries
import cv2
import matplotlib.pyplot as plt
import numpy as np
import statistics
import sys
import os, os.path
class _Camera(object): #Camera subsystem (2 subsystems created)
def __init__(self, cameraNumber):
#Initialise cameras instance variables
self.camera = None
self.cameraNumber = cameraNumber
self.focus = 80
self.ret = None
self.img = None
def start(self):
#Start the video capture and set the focus
self.camera = cv2.VideoCapture(self.cameraNumber)
self.camera.set(cv2.CAP_PROP_FOCUS, self.focus)
def adjustFocus(self, focus):
#Adjust the focus
self.focus = focus
self.camera.set(cv2.CAP_PROP_FOCUS, self.focus)
def readImg(self):
#Read the current frame as an image
self.ret, self.img = self.camera.read()
return self.ret, self.img
def stop(self):
#Stop the and release the camera
self.camera.release()
#Ben Coxford
#------------
#Lines 11-65 (excluding 22-46)
#------------
#Joel Guest
#------------
#Lines 22-46
#------------
#Import frameworks
import pytesseract
import datetime
class _DateValidation(object):
#Initialise date verification
def __init__(self):
self.text = []
self.endRead = False #Have three distinct dates been found?
def checkDate(self):
#stores current date in date format
currentDate = datetime.date.today()
currentDate = currentDate.strftime("%d.%m.%Y")
#Sets all dates to false
validDOB = False
validIssue = False
validExpiry = False
#sorts the dates in reverse order
sortedDates = sorted(self.text, reverse=True)
#If all dates are valid and in date the variables are changed to true
if (datetime.datetime.strptime(sortedDates[0], "%d.%m.%Y") < datetime.datetime.strptime(currentDate, "%d.%m.%Y")):
validDOB = True
if (datetime.datetime.strptime(sortedDates[1], "%d.%m.%Y") < datetime.datetime.strptime(currentDate, "%d.%m.%Y")):
validIssue = True
if (datetime.datetime.strptime(sortedDates[2], "%d.%m.%Y") > datetime.datetime.strptime(currentDate, "%d.%m.%Y")):
validExpiry = True
#Variables are returned
return validDOB, validIssue, validExpiry
def readText(self, imgID):
#If three dates have not been found
if self.endRead == False:
#Read the text from the image
pytesseract.pytesseract.tesseract_cmd = '/usr/local/Cellar/tesseract/4.1.1/bin/tesseract'
text = pytesseract.image_to_string(imgID)
#Split the text by spaces
data = text.split()
for i in data:
#For each item in the array
try:
#Attempt to test if its in the correct format
datetime.datetime.strptime(i, '%d.%m.%Y')
if(i not in self.text): #If the same date is not in the array
#Split the date and extract its year
x = i.split(".")
date = datetime.datetime.now()
#If the year is within 30 years of the current date
if(int(x[2]) > (int(date.year)-30) and int(x[2]) < (int(date.year)+30)):
#Append it to the array of dates
self.text.append(i)
except:
continue
if(self.text): #If the array is initialised
if(len(self.text) == 3): #If the array length is equal to three
self.endRead = True #Set value to true as all three dates are collected
return self.checkDate() #Return if the date are valid
return False, False, False #Return false if three dates are not found
#Ben Coxford
#------------
#Lines 7-47
#------------
#Import the frameworks and libraries
import cv2
import matplotlib.pyplot as plt
import numpy as np
import statistics
import sys
import os, os.path
import face_recognition
class _FaceDetection(object):
#Initialise the face detection object variables
def __init__(self):
self.minSize = 250; #Minimum size in pixels for a face to be detected. (Avoids smaller object being recognised)
self.faceCascade = cv2.CascadeClassifier("haarcascade_frontalface_default.xml")
self.bf = cv2.BFMatcher(cv2.NORM_L1, crossCheck=True)
def compareFaces(self, img1, img2):
try:
#Try to compare and match the faces on the two images
encodedImage0 = face_recognition.face_encodings(img1)[0]
encodedImage1 = face_recognition.face_encodings(img2)[0]
result = face_recognition.compare_faces([encodedImage0], encodedImage1)
return result[0] #Return the result
except: #If error return -1
return -1
def detectSingleFace(self, img, minSize):
#Detect a single face and return true or false if so.
face = self.faceCascade.detectMultiScale(img, scaleFactor=1.1, minNeighbors=5,minSize=(minSize, minSize),flags=cv2.CASCADE_SCALE_IMAGE)
numberFace = len(face) #Number of faces
if(numberFace==1):
return True
else:
return False
def rectangleFaceDetect(self, img, minSize):
#For testing purposes, this function places a green rectangle around the faces of an image.
face = self.faceCascade.detectMultiScale(img, scaleFactor=1.1, minNeighbors=5,minSize=(minSize, minSize),flags=cv2.CASCADE_SCALE_IMAGE)
for (x, y, w, h) in face:
cv2.rectangle(img, (x, y), (x+w, y+h), (0, 255, 0), 2)
return img
#Ben Coxford
#------------
#Lines 7-31
#------------
#Import frameworks and libraries
import cv2
import matplotlib.pyplot as plt
import numpy as np
import sys
import os, os.path
class _FeatureMatching(object):
def __init__(self):
self.matches = 0;
#Match the images and produce a number
def Match(self, img1, img2):
bf = cv2.BFMatcher(cv2.NORM_HAMMING, crossCheck=True)
sift = cv2.xfeatures2d.SIFT_create() #Sift descriptor
#Detect and calculate the matches
kp1, des1 = sift.detectAndCompute(img1,None)
kp2, des2 = sift.detectAndCompute(img2,None)
bf = cv2.BFMatcher() #Brute force method
matches = bf.knnMatch(des1,des2, k=2)
self.matches = len(matches) #Set the number of matches
def getMatch(self): #Return the number of matches
return self.matches
#Joel Guest Code Lines
#-----------------
#Lines 7-50
#-----------------
#imports libraries
import os, os.path
import cv2
import numpy as np
import matplotlib.pyplot as plt
#Inage directory
path = "/images"
#inmage pool class initialised
class _ImagePool(object):
def __init__(self):
#initialises 3 reusable objects
self._reusables = [Reusable() for _ in range(3)]
#function sets image number and returns the image
def acquire(self, number):
img = self._reusables.pop()
img.setImage(number)
return img
#Releases object back into the pool
def release(self, reusable):
reusable.reset()
self._reusables.append(reusable)
#initialises reusable class
class Reusable:
def __init__(self):
self._img = None
#Opens the image
def setImage(self, number):
imgPath = "images/img_" + str(number) + ".png"
self._img = cv2.imread(imgPath, 0)
#Resets the object
def reset(self):
self.__img = None
#Returns the image
def getImage(self):
return self._img
#Ben Coxford
#------------
#Lines 6-27
#------------
import cv2
import matplotlib.pyplot as plt
import numpy as np
import statistics
import sys
import os, os.path
class _ImageProcessing(object):
def __init__(self):
self.lastImg = None;
#Converts the image to its grayscale version and returns the image
def convertToGrayScale(self, img):
img = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
self.lastImg = img
return img
#Converts the image to its black and white binary self using the binary thresholding
#This produced better results that that of otsu's thresholding
def convertToBinary(self, img):
return cv2.threshold(img,60,255,cv2.THRESH_BINARY)
#Ben Coxford Code Lines
#-----------------
#Lines 14-212 (excluding joel's code lines 51, 108-127, 164-188)
#-----------------
#Joel Guest Code Lines
#-----------------
#Lines 51, 108-127, 164-188
#-----------------
#Import all relevant frameworks and classes
import cv2 #Image Processing Library
import matplotlib.pyplot as plt
import numpy as np
import statistics
import sys
import os, os.path
import face_recognition #Face matching library
import pytesseract #Text detection library
import datetime
#Subsystem Classes
import DateValidation
import Camera
import ImageProcessing
import FaceDetection
import FeatureMatching
import ImagePool
import TrainingClass
class IDSystem(): #System
def __init__(self):
#Initiate system and subsystems
self.__Camera_1 = Camera._Camera(1)
self.__Camera_2 = Camera._Camera(0)
self.__FaceDetection = FaceDetection._FaceDetection()
self.__FeatureMatching = FeatureMatching._FeatureMatching()
self.__ImageProcessing = ImageProcessing._ImageProcessing()
self.__DateValidation = DateValidation._DateValidation()
self.__ImagePool = ImagePool._ImagePool()
self.__Training = TrainingClass._TrainData()
#Pipeline passes
self.passA = -1
self.passB = -1
self.passC = -1
#Indicator when button pressed
self.turnt = False
#Date boolean checks
self.ValidDOB = False
self.ValidIssue = False
self.ValidExpiry = False
#ID Verification check
self.ImagePass = False
#Start the system
def startSystem(self):
cv2.namedWindow("preview", cv2.WINDOW_NORMAL) #Create a new window named preview
cv2.setWindowProperty('preview', cv2.WND_PROP_FULLSCREEN, cv2.WINDOW_FULLSCREEN) #Set to fullscreen
self.__Camera_1.start() #Initialise camera 1
self.__Camera_2.start() #Initialise camera 2
#Loop until the algorithm breaks
while(True):
retCustomer, frameCustomer = self.__Camera_1.readImg() #Read image of customers view
retID, frameID = self.__Camera_2.readImg() #Read image of ID
if(retCustomer and retID): #If the images are accepted
#Pipeline test 1 = match face
if(self.passA == -1):
#Detect if there is one face on both the ID and customer view
error = self.__FaceDetection.detectSingleFace(frameID, 300)
error2 = self.__FaceDetection.detectSingleFace(frameCustomer, 300)
#If there is one face detected
if(error != False and error2 != False):
result = self.__FaceDetection.compareFaces(frameCustomer, frameID) #Compare faces and return the result
if(result == True): #If the faces match
self.passA = True
elif(result == False): #If the faces do match
self.passA = False
#Pipeline test 2 = test dates
if(self.passB == -1):
ret, image = self.__ImageProcessing.convertToBinary(frameID)
self.validDOB, self.validIssue, self.validExpiry = self.__DateValidation.readText(image)
if(self.validDOB != False):
self.passB = True
#Pipeline test 3 = test UV light
if(self.passB != -1 and self.passA != -1 and self.turnt == True):
if(self.passC == -1):
#Convert image to grayscale and then to binary
grayID = self.__ImageProcessing.convertToGrayScale(frameID)
binaryID = self.__ImageProcessing.convertToBinary(grayID)
#From tuple get the binary data
binaryImage = binaryID[1]
matches = [] #List of match counts
#Number of images in the directory.
numberOfImg = len(os.listdir("images/"))
#loops from 1 to number of image
for i in range(1,numberOfImg):
#retrievs an object from the object pool
img = self.__ImagePool.acquire(i)
image = img.getImage()
#matches the features of both images
self.__FeatureMatching.Match(binaryImage, image)
match = self.__FeatureMatching.getMatch()
#Append the number of matches to the list of match counts
matches.append(match)
#Releases object back to the object pool
self.__ImagePool.release(img)
matchList = self.__Training.getMean() #Gets the mean average from the data set
if(matches): #If there is any matches
meanMatches = statistics.mean(matches) #Calculate the average match count
if(meanMatches > (matchList*0.8)): #If the number of matches is above 80% of the average match count
self.__Training.saveImage(binaryID[1]) #Save the new image to the data set
self.__Training.addMatch(meanMatches) #Add the new average number of matches to the data.
self.ImagePass = True #Set image pass to true (ID verified)
self.passC = True #Image has been processed
#Set borders for ID image
borderType = cv2.BORDER_CONSTANT
top = bottom = int(0.01 * frameID.shape[0])
left = right = int(0.005 * frameID.shape[1])
borderColour = [0,0,0]
frameID = cv2.copyMakeBorder(frameID, top, bottom, left, right, borderType, None, borderColour)
#Flips the ID image
frameCustomer = cv2.flip(frameCustomer, 1)
#Gets the height and width of the window.
x, y, width, height = cv2.getWindowImageRect("preview")
#Copies and resizes the image (width, height)
projectedImage = frameCustomer.copy()
projectedID = cv2.resize(frameID, (300, 200))
#Places the new resized ID image to the customer view. (y,y_max), (x,x_max)
projectedImage[50:250, width-525:width-225,:] = projectedID
#stores status to display when face has been recognised
status = "Recognising face and checking dates..."
if(self.passA != -1 and self.passB != -1 and self.passC != -1 and self.turnt == True): # if the algoritmn has finished
#If statements determine what message to output
if(self.passA):
if(self.passC != -1 and self.ImagePass):
if(self.validDOB):
if(self.validIssue):
if(self.validExpiry):
status = "ID Verified"
else:
status = "ID has expired."
else:
status = "ID issue date is invalid"
else:
status = "The age limit has not been reached"
else:
status = "The ID card was not validated"
else:
status = "We could not match your face to the ID card"
else:
if(self.passA != -1):
status = "Face Recongised, "
if(self.passB == True):
status = status + "Dates Found, "
if(self.passC == True):
status = "ID Verified "
#Output text and place it on the projected image.
cv2.putText(projectedImage, status, (width-525, 300), cv2.FONT_HERSHEY_SIMPLEX, 0.5, (0,0,0), 2)
#Display the projected image to the screen
cv2.imshow("preview", projectedImage)
#Key interrupts
k = cv2.waitKey(30) & 0xff
if k == 32: #If the spacebar is pressed, terminate the program
self.__Camera_1.stop()
self.__Camera_2.stop()
cv2.destroyAllWindows()
break
if k == 13: #If the enter button is pressed, set turnt to true
self.turnt = True
#Main function
def main():
system = IDSystem()
system.startSystem()
if __name__ == "__main__":
main()
#Ben Coxford
#------------
#Lines 8-40
#------------
#Used for testing the UVLightBox Feature
import cv2
import matplotlib.pyplot as plt
import numpy as np
import statistics
import sys
import os, os.path
#Creates a camera with a live feed to simulate the ID Camera
camera1 = cv2.VideoCapture(0)
focus = 80
camera1.set(cv2.CAP_PROP_FOCUS, focus)
cv2.namedWindow("preview", cv2.WINDOW_NORMAL)
result = None
while 1:
#Reads the image
ret0, img0 = camera1.read()
if (ret0):
#Converts it to grayscale
gray0 = cv2.cvtColor(img0, cv2.COLOR_BGR2GRAY)
#Returns the binary threshold of the image (black and white)
ret0, result = cv2.threshold(gray0,60,255,cv2.THRESH_BINARY)
#Displays the image to the preview
cv2.imshow("preview", result)
#Terminates when the space bar is pressed and releases the camera.
k = cv2.waitKey(30) & 0xff
if k == 32:
break
camera1.release()
#Ben Coxford
#------------
#Lines 27-29
#------------
#Joel Guest
#------------
#Lines 12-51 (excluding 27-29)
#------------
#imports library
import statistics
import sys
import os, os.path
import cv2
import matplotlib.pyplot as plt
import numpy as np
#saves training data to data files
class _TrainData(object):
def __init__(self):
self.fileName = "dataFile.txt"
self.path = "images/"
self.data = self.getMatch()
#Writes the image to the directory and sets the name to img_'image number'
def saveImage(self, image):
numberOfImg = len(os.listdir(self.path)) #Number of images in the directory
cv2.imwrite(self.path+"img_"+str(numberOfImg)+".png", image)
#Appends the number of matches plus one to the file
def addMatch(self, numberOfMatches):
file = open(self.fileName, "a")
file.write(","+str(numberOfMatches+1))
file.close()
#Reads the file and seperates the number of matches
def getMatch(self):
file = open(self.fileName, "r")
self.data = file.readline().split(",")
file.close()
self.data = [int(i) for i in self.data]
return self.data
#Gets the average number of matc hes from the file and returns value
def getMean(self):
self.data = self.getMatch()
if(self.data):
mean = statistics.mean(self.data)
return mean
return False
#Joel Guest Lines 3-92
import unittest
import cv2
import numpy as np
import Camera
import DateValidation
import TrainingClass
import FaceDetection
import FeatureMatching
import ImagePool
import ProgramCode
#Tests each subsystem with example data and the expected outcomes.
class TestSubsystems(unittest.TestCase):
#Tests if an image can be read from the camera
def testReadImg(self):
camera = Camera._Camera(0)
camera.start()
ret, img = camera.readImg()
self.assertTrue(ret)
#Tests the full camera
def testFullCamera(self):
camera = Camera._Camera(0)
camera.start()
ret, img = camera.readImg()
camera.stop()
#Tests if an ID card returns valid dates
def testDate(self):
date = DateValidation._DateValidation()
imgPath = "TestImages/TestID.jpg"
img = cv2.imread(imgPath, 0)
a, b, c = False, False, False
for i in range(0,50):
a, b, c = date.readText(img)
self.assertTrue(a)
self.assertTrue(b)
self.assertTrue(c)
#Test the training data to get the number of matches and the mean
def testTrainData(self):
train = TrainingClass._TrainData()
self.assertEqual(train.getMatch(), [1700,2848,2383,3176])
self.assertEqual(train.getMean(), 2526.75)
#Test if two faces can be matched
def testFaceDetection(self):
imgPath = "TestImages/TestFace.jpg"
img = cv2.imread(imgPath, 0)
imgPath = "TestImages/TestFace2.jpg"
img2 = cv2.imread(imgPath, 0)
face = FaceDetection._FaceDetection()
self.assertTrue(face.detectSingleFace(img,300))
self.assertTrue(face.compareFaces(img,img2))
#Tests if the number of matches returned on the test data is between the given range
#Any errors matching or using invalid images will produce a lower number of matches.
def testFeatureMatching(self):
imgPath = "TestImages/TestBlob.png"
img = cv2.imread(imgPath, 0)
imgPath = "TestImages/TestBlob2.png"
img2 = cv2.imread(imgPath, 0)
match = FeatureMatching._FeatureMatching()
match.Match(img,img2)
self.assertTrue(400 <= match.getMatch() <= 4000)
#Tests if the image pool can aquire an image and return the correct image
def testImagePool(self):
imgPath = "images/img_1.png"
img = cv2.imread(imgPath, 0)
pool = ImagePool._ImagePool()
image = pool.acquire(1)
np.testing.assert_array_almost_equal(image.getImage(), img, 2)
image.reset()
pool.release(image)
if __name__ == '__main__':
unittest.main()
1700,2848,2383,3176,2025,2156
\ No newline at end of file
This source diff could not be displayed because it is too large. You can view the blob instead.
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment