├── README.md ├── figures ├── general_flowchart_PAD.png ├── print-attack │ └── print-attack_ycrcb_luv_etc_eer.png └── replay-attack │ └── replay-attack_ycrcb_luv_etc_eer.png ├── gifs ├── example1.gif └── example2.gif ├── python_scripts ├── haarcascade_frontalface_default.xml ├── main.py └── training_script.py └── trained_models ├── print-attack_trained_models └── print-attack_ycrcb_luv_extraTreesClassifier.pkl └── replay_attack_trained_models └── replay-attack_ycrcb_luv_extraTreesClassifier.pkl /README.md: -------------------------------------------------------------------------------- 1 | # [Presentation Attack Detection](https://github.com/ee09115/spoofing_detection) 2 | 3 | ## Overview 4 | This repository is dedicated to the image-based Presentation Attack Detection - PAD - systems in two different domains: (i) cork and (ii) face PAD. The proposed PAD system relies on the combination of two different color spaces and uses only a single frame to distinguish from a bona fide image and an image attack, see Fig. 1. 5 | 6 |
7 |
Fig. 1 - General flowchart for the developed image-based PAD system.
9 | 10 | ## Contents 11 | * Trained models for the public face anti-spoofing [Print-attack](https://www.idiap.ch/dataset/printattack) database; 12 | * Trained models for the public face anti-spoofing [Replay-attack](https://www.idiap.ch/dataset/replayattack) database; 13 | * Error rate curve for the development set of the [Print-attack](https://www.idiap.ch/dataset/printattack) database 14 | * Error rate curve for the development set of the [Replay-Attack](https://www.idiap.ch/dataset/replayattack) database; 15 | * [1] - [Image-based Object Spoofing Detection](https://link.springer.com/chapter/10.1007%2F978-3-030-05288-1_15) - Conference paper 16 | 17 | ## Results 18 |Method | Print-attack | Replay-attack | 21 |||
EER(%) | HTER(%) | EER(%) | HTER(%) | 24 ||
YCRCB+LUV+ETC [1] | 1.33 | 0.00 | 0.00756 | 0.5954 | 27 |
YCRCB+LUV+SVM [1] | 0.00 | 1.76 | 4.30 | 7.86 | 30 |
35 |
36 |
40 |
41 |
Demonstrative results of the proposed face PAD system - YCRCB+LUV+ETC. The classification model used in this test was trained using the training set of the Replay-Attack database.
43 | 44 | ## How to cite 45 | If you use any part of this work please cite [1]: 46 | 47 | @InProceedings{10.1007/978-3-030-05288-1_15, 48 | author="Costa, Valter 49 | and Sousa, Armando 50 | and Reis, Ana", 51 | editor="Barneva, Reneta P. 52 | and Brimkov, Valentin E. 53 | and Tavares, Jo{\~a}o Manuel R.S.", 54 | title="Image-Based Object Spoofing Detection", 55 | booktitle="Combinatorial Image Analysis", 56 | year="2018", 57 | publisher="Springer International Publishing", 58 | address="Cham", 59 | pages="189--201", 60 | abstract="Using 2D images in authentication systems raises the question of spoof attacks: is it possible to deceive an authentication system using fake models possessing identical visual properties of the genuine one? In this work, an anti-spoofing method approach for a wine anti-counterfeiting system is presented. The proposed method relies in two different color spaces: CIE L*u*v* and {\$}{\$}YC{\_}rC{\_}b{\$}{\$}, to distinguish between a genuine instance and a spoof attack. To evaluate the proposed strategy, two databases were used: a private database, with photos/2D attacks of cork stoppers, created for this work; and the public Replay-Attack database that is used for face spoofing detection methods testing. The results on the private database show that the anti-spoofing approach is able to distinguish with high accuracy a real photo from an attack. Regarding the public database, the results were obtained with existing methods, as the best HTER results using a single frame approach.", 61 | isbn="978-3-030-05288-1" 62 | } 63 | 64 | -------------------------------------------------------------------------------- /figures/general_flowchart_PAD.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ee09115/spoofing_detection/4f330c374049332e9db16d50bb1a803e392eebeb/figures/general_flowchart_PAD.png -------------------------------------------------------------------------------- /figures/print-attack/print-attack_ycrcb_luv_etc_eer.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ee09115/spoofing_detection/4f330c374049332e9db16d50bb1a803e392eebeb/figures/print-attack/print-attack_ycrcb_luv_etc_eer.png -------------------------------------------------------------------------------- /figures/replay-attack/replay-attack_ycrcb_luv_etc_eer.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ee09115/spoofing_detection/4f330c374049332e9db16d50bb1a803e392eebeb/figures/replay-attack/replay-attack_ycrcb_luv_etc_eer.png -------------------------------------------------------------------------------- /gifs/example1.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ee09115/spoofing_detection/4f330c374049332e9db16d50bb1a803e392eebeb/gifs/example1.gif -------------------------------------------------------------------------------- /gifs/example2.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ee09115/spoofing_detection/4f330c374049332e9db16d50bb1a803e392eebeb/gifs/example2.gif -------------------------------------------------------------------------------- /python_scripts/main.py: -------------------------------------------------------------------------------- 1 | import numpy as np 2 | import cv2 3 | from sklearn.externals import joblib 4 | import argparse 5 | # from time import gmtime, strftime 6 | 7 | 8 | def detect_face(img, faceCascade): 9 | faces = faceCascade.detectMultiScale(img, scaleFactor=1.1, minNeighbors=5, minSize=(110, 110) 10 | #flags = cv2.CV_HAAR_SCALE_IMAGE 11 | ) 12 | return faces 13 | 14 | 15 | def calc_hist(img): 16 | histogram = [0] * 3 17 | for j in range(3): 18 | histr = cv2.calcHist([img], [j], None, [256], [0, 256]) 19 | histr *= 255.0 / histr.max() 20 | histogram[j] = histr 21 | return np.array(histogram) 22 | 23 | 24 | ap = argparse.ArgumentParser() 25 | ap.add_argument("-n", "--name", required=True, help="name of trained model to perform spoofing detection") 26 | ap.add_argument("-d", "--device", required=True, help="camera identifier/video to acquire the image") 27 | ap.add_argument("-t", "--threshold", required=False, help="threshold used for the classifier to decide between genuine and a spoof attack") 28 | args = vars(ap.parse_args()) 29 | 30 | if __name__ == "__main__": 31 | 32 | # # Load model 33 | clf = None 34 | try: 35 | clf = joblib.load(args["name"]) 36 | except IOError as e: 37 | print "Error loading model <"+args["name"]+">: {0}".format(e.strerror) 38 | exit(0) 39 | 40 | # # Open the camera 41 | if '.' in args["device"]: 42 | cap = cv2.VideoCapture(args["device"]) 43 | else: 44 | cap = cv2.VideoCapture(int(args["device"])) 45 | if not cap.isOpened(): 46 | print "Error opening camera" 47 | exit(0) 48 | 49 | width = 320 50 | height = 240 51 | cap.set(cv2.CAP_PROP_FRAME_HEIGHT, height) 52 | cap.set(cv2.CAP_PROP_FRAME_WIDTH, width) 53 | # cap.set(cv2.CAP_PROP_AUTOFOCUS, 1) 54 | 55 | # # Initialize face detector 56 | cascPath = "haarcascade_frontalface_default.xml" 57 | faceCascade = cv2.CascadeClassifier(cascPath) 58 | 59 | sample_number = 1 60 | count = 0 61 | measures = np.zeros(sample_number, dtype=np.float) 62 | 63 | while True: 64 | ret, img_bgr = cap.read() 65 | if ret is False: 66 | print "Error grabbing frame from camera" 67 | break 68 | 69 | img_gray = cv2.cvtColor(img_bgr, cv2.COLOR_BGR2GRAY) 70 | 71 | faces = detect_face(img_gray, faceCascade) 72 | 73 | measures[count%sample_number]=0 74 | 75 | point = (0,0) 76 | for i, (x, y, w, h) in enumerate(faces): 77 | 78 | roi = img_bgr[y:y+h, x:x+w] 79 | 80 | img_ycrcb = cv2.cvtColor(roi, cv2.COLOR_BGR2YCR_CB) 81 | img_luv = cv2.cvtColor(roi, cv2.COLOR_BGR2LUV) 82 | 83 | ycrcb_hist = calc_hist(img_ycrcb) 84 | luv_hist = calc_hist(img_luv) 85 | 86 | feature_vector = np.append(ycrcb_hist.ravel(), luv_hist.ravel()) 87 | feature_vector = feature_vector.reshape(1, len(feature_vector)) 88 | 89 | prediction = clf.predict_proba(feature_vector) 90 | prob = prediction[0][1] 91 | 92 | measures[count % sample_number] = prob 93 | 94 | cv2.rectangle(img_bgr, (x, y), (x + w, y + h), (255, 0, 0), 2) 95 | 96 | point = (x, y-5) 97 | 98 | print measures, np.mean(measures) 99 | if 0 not in measures: 100 | text = "True" 101 | if np.mean(measures) >= 0.7: 102 | text = "False" 103 | font = cv2.FONT_HERSHEY_SIMPLEX 104 | cv2.putText(img=img_bgr, text=text, org=point, fontFace=font, fontScale=0.9, color=(0, 0, 255), 105 | thickness=2, lineType=cv2.LINE_AA) 106 | else: 107 | font = cv2.FONT_HERSHEY_SIMPLEX 108 | cv2.putText(img=img_bgr, text=text, org=point, fontFace=font, fontScale=0.9, 109 | color=(0, 255, 0), thickness=2, lineType=cv2.LINE_AA) 110 | 111 | count+=1 112 | cv2.imshow('img_rgb', img_bgr) 113 | 114 | key = cv2.waitKey(1) 115 | if key & 0xFF == 27: 116 | break 117 | 118 | cap.release() 119 | cv2.destroyAllWindows() 120 | -------------------------------------------------------------------------------- /python_scripts/training_script.py: -------------------------------------------------------------------------------- 1 | import csv 2 | import sys 3 | import numpy as np 4 | import time 5 | from sklearn.externals import joblib 6 | import argparse 7 | from sklearn.ensemble import ExtraTreesClassifier 8 | 9 | csv.field_size_limit(sys.maxsize) 10 | 11 | 12 | def load_data(path_name, n_rows, n_cols): 13 | 14 | count = 0 15 | X = np.zeros((n_rows, n_cols), dtype=np.float) 16 | y = np.zeros(n_rows, dtype=np.uint8) 17 | pai_id = np.zeros(n_rows, dtype=np.uint8) 18 | 19 | with open(path_name, 'r') as csvfile: 20 | reader = csv.reader(csvfile, delimiter=',') 21 | for row in reader: 22 | x = np.fromstring(row[0], dtype=np.float, sep=' ') 23 | X[count] = x 24 | y[count] = int(row[1]) 25 | pai_id[count] = int(row[2]) 26 | count += 1 27 | if count >= N_ROWS: 28 | break 29 | 30 | return X, y, pai_id 31 | 32 | 33 | if __name__ == "__main__": 34 | 35 | ap = argparse.ArgumentParser() 36 | ap.add_argument("-n", "--name", required=True, help="name of trained model") 37 | ap.add_argument("-i", "--csv_file_to_train", required=True, help="input csv file to train the classifier") 38 | ap.add_argument("-f", "--folder_to_store_classifier", required=True, help="directory to store the trained classifier") 39 | ap.add_argument("-r", "--rows", required=True, help="total number of rows in the csv file") 40 | ap.add_argument("-c", "--cols", required=True, help="dimension of the feature vector") 41 | args = vars(ap.parse_args()) 42 | 43 | N_ROWS = int(args["rows"]) # Total number of rows in csv file 44 | N_COLS = int(args["cols"]) # Dimension of the Feature Vector 45 | training_file = args["csv_file_to_train"] # Input csv file with the training data 46 | output_folder = args["folder_to_store_classifier"] # Directory to store the trained classifier 47 | 48 | # # LOAD DATA 49 | X_train, y_train, PAI_ID = load_data(training_file, N_ROWS, N_COLS) 50 | 51 | # Random Forest CLASSIFIER 52 | print "Training data ETC" 53 | clf = ExtraTreesClassifier(n_estimators=20, min_samples_leaf=10, n_jobs=8) 54 | start_time = time.time() 55 | clf.fit(X_train, y_train) 56 | elapsed_time = time.time() - start_time 57 | print "ExtraTreesClassifier %.3f s" % elapsed_time 58 | joblib.dump(clf, output_folder + args["name"] + "_extraTreesClassifier" + '.pkl') 59 | print "Generated:", output_folder + args["name"] + "_extraTreesClassifier" + '.pkl' 60 | -------------------------------------------------------------------------------- /trained_models/print-attack_trained_models/print-attack_ycrcb_luv_extraTreesClassifier.pkl: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ee09115/spoofing_detection/4f330c374049332e9db16d50bb1a803e392eebeb/trained_models/print-attack_trained_models/print-attack_ycrcb_luv_extraTreesClassifier.pkl -------------------------------------------------------------------------------- /trained_models/replay_attack_trained_models/replay-attack_ycrcb_luv_extraTreesClassifier.pkl: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ee09115/spoofing_detection/4f330c374049332e9db16d50bb1a803e392eebeb/trained_models/replay_attack_trained_models/replay-attack_ycrcb_luv_extraTreesClassifier.pkl --------------------------------------------------------------------------------