{
  "source_file": "0930",
  "source_platform": "技术平台",
  "author": "Adrian Rosebrock / PyImageSearch",
  "title_listed": "Face Recognition with OpenCV, Python, and Deep Learning",
  "keywords": "人脸识别,OpenCV,深度学习",
  "domain": "图像处理",
  "content_type": "教程",
  "is_paid_flag": "否",
  "url": "https://pyimagesearch.com/2018/06/18/face-recognition-with-opencv-python-and-deep-learning/",
  "publish_date": "2018-06",
  "corpus_stage": "预训练/SFT",
  "notes": "人脸识别实战教程",
  "id": "a8aa44ea93b7",
  "collected_at": "2026-10-02T17:19:18",
  "title": "Face recognition with OpenCV, Python, and deep learning - PyImageSearch",
  "body_markdown": "Click here to download the source code to this post\nLast updated on December 30, 2022 with content updates.\nIn today’s blog post you are going to learn how to perform\nface recognition\nin both images and video streams using:\nOpenCV\nPython\nDeep learning\nAs we’ll see, the deep learning-based facial embeddings we’ll be using here today are both (1)\nhighly accurate\nand (2) capable of being executed in\nreal-time\n.\nTo learn more about face recognition with\nOpenCV\n,\nPython\n, and\ndeep learning\n,\njust keep reading!\nHaving a face dataset is crucial for building robust face recognition systems. It allows the model to learn diverse features of human faces such as facial structure, skin tone, and expressions, which leads to improved performance in recognizing different individuals.\nRoboflow\nhas free tools for each stage of the computer vision pipeline that will streamline your workflows and supercharge your productivity.\nSign up or Log in to your\nRoboflow account\nto access state of the art dataset libaries and revolutionize your computer vision pipeline.\nYou can start by choosing your own datasets or using our\nPyimageSearch’s assorted library of useful datasets\n.\nBring data in any of 40+ formats to\nRoboflow\n, train using any state-of-the-art model architectures, deploy across multiple platforms (API, NVIDIA, browser, iOS, etc), and connect to applications or 3rd party tools.\nUpdate July 2021:\nAdded alternative face recognition methods section, including both deep learning-based and non-deep learning-based approaches.\nLooking for the source code to this post?\nJump Right To The Downloads Section\nFace recognition with OpenCV, Python, and deep learning\nInside this tutorial, you will learn how to perform facial recognition using OpenCV, Python, and deep learning.\nWe’ll start with a brief discussion of how deep learning-based facial recognition works, including the concept of “deep metric learning.”\nFrom there, I will help you install the libraries you need to actually perform face recognition.\nFinally, we’ll implement face recognition for both still images and video streams.\nAs we’ll discover, our face recognition implementation will be capable of running in real-time.\nUnderstanding deep learning face recognition embeddings\nSo, how does deep learning + face recognition work?\nThe secret is a technique called\ndeep metric learning.\nIf you have any prior experience with deep learning you know that we typically train a network to:\nAccept a single input image\nAnd output a classification/label for that image\nHowever, deep metric learning is different.\nInstead of trying to output a single label (or even the coordinates/bounding box of objects in an image),\nwe are instead outputting a real-valued feature vector.\nFor the dlib facial recognition network, the output feature vector is\n128-d\n(i.e., a list of 128 real-valued numbers) that is used to\nquantify the face\n. Training the network is done using\ntriplets\n:\nFigure 1:\nFacial recognition via deep metric learning involves a “triplet training step.” The triplet consists of 3 unique face images — 2 of the 3 are the same person. The NN generates a 128-d vector for each of the 3 face images. For the 2 face images of the same person, we tweak the neural network weights to make the vector closer via distance metric.\nImage credit:\nAdam Geitgey’s\n“Machine Learning is Fun”\nblog\nHere we provide three images to the network:\nTwo of these images are example faces of the\nsame\nperson.\nThe third image is a\nrandom\nface from our dataset and is\nnot\nthe same person as the other two images.\nAs an example, let’s again consider\nFigure 1\nwhere we provided three images: one of Chad Smith and two of Will Ferrell.\nOur network quantifies the faces, constructing the 128-d embedding (quantification) for each.\nFrom there, the general idea is that we’ll\ntweak the weights\nof our neural network so that the 128-d measurements of the two Will Ferrells will be\ncloser to each other\nand farther from the measurements for Chad Smith.\nOur network architecture for face recognition is based on ResNet-34 from the\nDeep Residual Learning for Image Recognition\npaper by He et al., but with fewer layers and the number of filters reduced by half.\nThe network itself was trained by\nDavis King\non a dataset of ≈3 million images. On the\nLabeled Faces in the Wild (LFW)\ndataset the network compares to other state-of-the-art methods, reaching\n99.38% accuracy\n.\nBoth Davis King (the creator of\ndlib\n) and\nAdam Geitgey\n(the author of the\nface_recognition module\nwe’ll be using shortly) have written detailed articles on how deep learning-based facial recognition works:\nHigh Quality Face Recognition with Deep Metric Learning\n(Davis)\nModern Face Recognition with Deep Learning\n(Adam)\nI would highly encourage you to read the above articles for more details on how deep learning facial embeddings work.\nInstall your face recognition libraries\nIn order to perform face recognition with Python and OpenCV we need to install two additional libraries:\ndlib\nface_recognition\nThe dlib library, maintained by\nDavis King\n, contains our implementation of “deep metric learning” which is used to construct our face embeddings used for the actual recognition process.\nThe\nface_recognition\nlibrary, created by\nAdam Geitgey\n, wraps\naround\ndlib’s facial recognition functionality, making it easier to work with.\nLearn from Adam Geitgey and Davis King at\nPyImageConf\n2018\nI assume that you have\nOpenCV installed on your system\n. If not, no worries — just visit my\nOpenCV install tutorials\npage and follow the guide appropriate for your system.\nFrom there, let’s install\ndlib\nand the\nface_recognition\npackages.\nNote:\nFor the following installs, ensure you are in a Python virtual environment if you’re using one. I highly recommend virtual environments for isolating your projects — it is a Python best practice. If you’ve followed my OpenCV install guides (and installed\nvirtualenv\n+\nvirtualenvwrapper\n) then you can use the\nworkon\ncommand prior to installing\ndlib\nand\nface_recognition\n.\nInstalling\ndlib\nwithout\nGPU support\nIf you do not have a GPU you can install\ndlib\nusing pip by\nfollowing this guide\n:\n$ workon # optional\n$ pip install dlib\nOr you can compile from source:\n$ workon <your env name here> # optional\n$ git clone https://github.com/davisking/dlib.git\n$ cd dlib\n$ mkdir build\n$ cd build\n$ cmake .. -DUSE_AVX_INSTRUCTIONS=1\n$ cmake --build .\n$ cd ..\n$ python setup.py install --yes USE_AVX_INSTRUCTIONS\nInstalling\ndlib\nwith\nGPU support (optional)\nIf you\ndo\nhave a CUDA compatible GPU you can install\ndlib\nwith GPU support, making facial recognition faster and more efficient.\nFor this, I recommend installing\ndlib\nfrom source as you’ll have more control over the build:\n$ workon <your env name here> # optional\n$ git clone https://github.com/davisking/dlib.git\n$ cd dlib\n$ mkdir build\n$ cd build\n$ cmake .. -DDLIB_USE_CUDA=1 -DUSE_AVX_INSTRUCTIONS=1\n$ cmake --build .\n$ cd ..\n$ python setup.py install --yes USE_AVX_INSTRUCTIONS --yes DLIB_USE_CUDA\nInstall the\nface_recognition\npackage\nThe\nface_recognition module\nis installable via a simple pip command:\n$ workon <your env name here> # optional\n$ pip install face_recognition\nInstall\nimutils\nYou’ll also need my package of convenience functions,\nimutils\n. You may install it in your Python virtual environment via pip:\n$ workon <your env name here> # optional\n$ pip install imutils\nOur face recognition dataset\nFigure 2:\nAn example face recognition dataset was created programmatically with Python and the Bing Image Search API. Shown are six of the characters from the Jurassic Park movie series.\nSince\nJurassic Park\n(1993) is my favorite movie of all time, and in honor of\nJurassic World: Fallen Kingdom\n(2018) being released this Friday in the U.S., we are going to apply face recognition to a sample of the characters in the films:\nAlan Grant\n,\npaleontologist\n(22 images)\nClaire Dearing\n,\npark operations manager\n(53 images)\nEllie Sattler\n,\npaleobotanist\n(31 images)\nIan Malcolm\n,\nmathematician\n(41 images)\nJohn Hammond\n,\nbusinessman/Jurassic Park owner\n(36 images)\nOwen Grady\n,\ndinosaur researcher\n(35 images)\nThis dataset was constructed in < 30 minutes using the method discussed in my\nHow to (quickly) build a deep learning image dataset\ntutorial\n.\nGiven this dataset of images we’ll:\nCreate the 128-d embeddings for each face in the dataset\nUse these embeddings to recognize the faces of the characters in both images and video streams\nFace recognition project structure\nOur project structure can be seen by examining the output from the\ntree\ncommand:\n$ tree --filelimit 10 --dirsfirst\n.\n├── dataset\n│   ├── alan_grant [22 entries]\n│   ├── claire_dearing [53 entries]\n│   ├── ellie_sattler [31 entries]\n│   ├── ian_malcolm [41 entries]\n│   ├── john_hammond [36 entries]\n│   └── owen_grady [35 entries]\n├── examples\n│   ├── example_01.png\n│   ├── example_02.png\n│   └── example_03.png\n├── output\n│   └── lunch_scene_output.avi\n├── videos\n│   └── lunch_scene.mp4\n├── search_bing_api.py\n├── encode_faces.py\n├── recognize_faces_image.py\n├── recognize_faces_video.py\n├── recognize_faces_video_file.py\n└── encodings.pickle\n\n10 directories, 11 files\nOur project has\n4 top-level directories:\ndataset/\n: Contains face images for six characters organized into subdirectories based on their respective names.\nexamples/\n: Has three face images for testing that are\nnot\nin the dataset.\noutput/\n: This is where you can store your processed face recognition videos. I’m leaving one of mine in the folder — the classic “lunch scene” from the original\nJurassic Park\nmovie.\nvideos/\n: Input videos should be stored in this folder. This folder also contains the “lunch scene” video but it hasn’t undergone our face recognition system yet.\nWe also have\n6 files\nin the root directory:\nsearch_bing_api.py\n: Step 1 is to build a dataset (I’ve already done this for you). To learn how to use the Bing API to build a dataset with my script, just see\nthis blog post\n.\nencode_faces.py\n: Encodings (128-d vectors) for faces are built with this script.\nrecognize_faces_image.py\n: Recognize faces in a single image (based on encodings from your dataset).\nrecognize_faces_video.py\n: Recognize faces in a live video stream from your webcam and output a video.\nrecognize_faces_video_file.py\n: Recognize faces in a video file residing on disk and output the processed video to disk. I won’t be discussing this file today as the bones are from the same skeleton as the video stream file.\nencodings.pickle\n: Facial recognition encodings are generated from your dataset via\nencode_faces.py\nand then serialized to disk.\nAfter a dataset of images is created (with\nsearch_bing_api.py\n), we’ll run\nencode_faces.py\nto build the embeddings.\nFrom there, we’ll run the recognize scripts to actually recognize the faces.\nEncoding the faces using OpenCV and deep learning\nFigure 3:\nFacial recognition via deep learning and Python using the\nface_recognition\nmodule method generates a 128-d real-valued number feature vector per face.\nBefore we can recognize faces in images and videos, we first need to quantify the faces in our training set. Keep in mind that we are not actually training a network here —\nthe network has\nalready been trained\nto create 128-d embeddings\non a dataset of\n~3\nmillion images.\nWe certainly\ncould\ntrain a network from scratch or even fine-tune the weights of an existing model but that is more than likely overkill for many projects. Furthermore, you would need a\nlot\nof images to train the network from scratch.\nInstead, it’s easier to use the pre-trained network and then use it to construct 128-d embeddings for each of the 218 faces in our dataset.\nThen, during classification, we can use a simple k-NN model + votes to make the final face classification. Other traditional machine learning models can be used here as well.\nTo construct our face embeddings open up\nencode_faces.py\nfrom the\n“Downloads”\nassociated with this blog post:\n# import the necessary packages\nfrom imutils import paths\nimport face_recognition\nimport argparse\nimport pickle\nimport cv2\nimport os\nFirst, we need to import required packages. Again, take note that this script requires\nimutils\n,\nface_recognition\n, and OpenCV installed. Scroll up to the “\nInstall your face recognition libraries”\nto make sure you have the libraries ready to go on your system.\nLet’s handle our\ncommand line arguments\nthat are processed at runtime with\nargparse\n:\n# construct the argument parser and parse the arguments\nap = argparse.ArgumentParser()\nap.add_argument(\"-i\", \"--dataset\", required=True,\n\thelp=\"path to input directory of faces + images\")\nap.add_argument(\"-e\", \"--encodings\", required=True,\n\thelp=\"path to serialized db of facial encodings\")\nap.add_argument(\"-d\", \"--detection-method\", type=str, default=\"cnn\",\n\thelp=\"face detection model to use: either `hog` or `cnn`\")\nargs = vars(ap.parse_args())\nIf you’re new to PyImageSearch, let me direct your attention to the above code block which will become familiar to you as you read more of my blog posts. We’re using\nargparse\nto parse command line arguments. When you run a Python program in your command line, you can provide additional information to the script without leaving your terminal.\nLines 10-17\ndo not need to be modified as they parse input coming from the terminal. Check out my blog post about\ncommand line arguments\nif these lines look unfamiliar.\nLet’s list out the argument flags and discuss them:\n--dataset\n: The path to our dataset (we created a dataset with\nsearch_bing_api.py\ndescribed in\nmethod #2 of last week’s blog post\n).\n--encodings\n: Our face encodings are written to the file that this argument points to.\n--detection-method\n: Before we can\nencode\nfaces in images we first need to\ndetect\nthem. Or two face detection methods include either\nhog\nor\ncnn\n. Those two flags are the only ones that will work for\n--detection-method\n.\nNow that we’ve defined our arguments, let’s grab the paths to the files in our dataset (as well as perform two initializations):\n# grab the paths to the input images in our dataset\nprint(\"[INFO] quantifying faces...\")\nimagePaths = list(paths.list_images(args[\"dataset\"]))\n\n# initialize the list of known encodings and known names\nknownEncodings = []\nknownNames = []\nLine 21\nuses the path to our input dataset directory to build a list of all\nimagePaths\ncontained therein.\nWe also need to initialize two lists before our loop,\nknownEncodings\nand\nknownNames\n, respectively. These two lists will contain the face encodings and corresponding names for each person in the dataset (\nLines 24 and 25\n).\nIt’s time to begin looping over our\nJurassic Park\ncharacter faces!\n# loop over the image paths\nfor (i, imagePath) in enumerate(imagePaths):\n\t# extract the person name from the image path\n\tprint(\"[INFO] processing image {}/{}\".format(i + 1,\n\t\tlen(imagePaths)))\n\tname = imagePath.split(os.path.sep)[-2]\n\n\t# load the input image and convert it from BGR (OpenCV ordering)\n\t# to dlib ordering (RGB)\n\timage = cv2.imread(imagePath)\n\trgb = cv2.cvtColor(image, cv2.COLOR_BGR2RGB)\nThis loop will cycle 218 times corresponding to our 218 face images in the dataset. We’re looping over the paths to each of the images on\nLine 28\n.\nFrom there, we’ll extract the\nname\nof the person from the\nimagePath\n(as our subdirectory is named appropriately) on\nLine 32\n.\nThen let’s load the\nimage\nwhile passing the\nimagePath\nto\ncv2.imread\n(\nLine 36\n).\nOpenCV orders color channels in BGR, but the\ndlib\nactually expects RGB. The\nface_recognition\nmodule uses\ndlib\n, so before we proceed, let’s swap color spaces on\nLine 37\n, naming the new image\nrgb\n.\nNext, let’s localize the face and compute encodings:\n# detect the (x, y)-coordinates of the bounding boxes\n\t# corresponding to each face in the input image\n\tboxes = face_recognition.face_locations(rgb,\n\t\tmodel=args[\"detection_method\"])\n\n\t# compute the facial embedding for the face\n\tencodings = face_recognition.face_encodings(rgb, boxes)\n\n\t# loop over the encodings\n\tfor encoding in encodings:\n\t\t# add each encoding + name to our set of known names and\n\t\t# encodings\n\t\tknownEncodings.append(encoding)\n\t\tknownNames.append(name)\nThis is the fun part of the script!\nFor each iteration of the loop, we’re going to detect a face (or possibly multiple faces and assume that it is the same person in multiple locations of the image — this assumption may or may not hold true in your own images so be careful here).\nFor example, let’s say that\nrgb\ncontains a picture (or pictures) of Ellie Sattler’s face.\nLines 41 and 42\nactually find/localize the faces of her resulting in a list of face\nboxes\n. We pass two parameters to the\nface_recognition.face_locations\nmethod:\nrgb\n: Our RGB image.\nmodel\n: Either\ncnn\nor\nhog\n(this value is contained within our command line arguments dictionary associated with the\n\"detection_method\"\nkey). The CNN method is more accurate but slower. HOG is faster but less accurate.\nThen, we’re going to turn the bounding\nboxes\nof Ellie Sattler’s face into a list of 128 numbers on\nLine 45\n. This is known as\nencoding\nthe face into a vector and the\nface_recognition.face_encodings\nmethod handles it for us.\nFrom there we just need to append the Ellie Sattler\nencoding\nand\nname\nto the appropriate list (\nknownEncodings\nand\nknownNames\n).\nWe’ll continue to do this for all 218 images in the dataset.\nWhat would be the point of encoding the images unless we could use the\nencodings\nin another script which handles the recognition?\nLet’s take care of that now:\n# dump the facial encodings + names to disk\nprint(\"[INFO] serializing encodings...\")\ndata = {\"encodings\": knownEncodings, \"names\": knownNames}\nf = open(args[\"encodings\"], \"wb\")\nf.write(pickle.dumps(data))\nf.close()\nLine 56\nconstructs a dictionary with two keys —\n\"encodings\"\nand\n\"names\"\n.\nFrom there\nLines 57-59\ndump the names and encodings to disk for future recall.\nHow should I run the\nencode_faces.py\nscript in the terminal?\nTo create our facial embeddings open up a terminal and execute the following command:\n$ python encode_faces.py --dataset dataset --encodings encodings.pickle\n[INFO] quantifying faces...\n[INFO] processing image 1/218\n[INFO] processing image 2/218\n[INFO] processing image 3/218\n...\n[INFO] processing image 216/218\n[INFO] processing image 217/218\n[INFO] processing image 218/218\n[INFO] serializing encodings...\n$ ls -lh encodings*\n-rw-r--r--@ 1 adrian  staff   234K May 29 13:03 encodings.pickle\nAs you can see from our output, we now have a file named\nencodings.pickle\n— this file contains the 128-d face embeddings for each face in our dataset.\nOn my Titan X GPU, processing the entire dataset took a little over a minute, but if you’re using a CPU,\nbe prepared to wait awhile for this script to complete!\nOn my Macbook Pro (no GPU), encoding 218 images required\n21min 20sec\n.\nYou should expect much faster speeds if you have a GPU and compiled dlib with GPU support.\nRecognizing faces in images\nFigure 4:\nJohn Hammond’s face is recognized using Adam Geitgey’s deep learning\nface_recognition\nPython module.\nNow that we have created our 128-d face embeddings for each image in our dataset, we are now ready to recognize faces in image using OpenCV, Python, and deep learning.\nOpen up\nrecognize_faces_image.py\nand insert the following code (or better yet, grab the files and image data associated with this blog post from the\n“Downloads”\nsection found at the bottom of this post, and follow along):\n# import the necessary packages\nimport face_recognition\nimport argparse\nimport pickle\nimport cv2\n\n# construct the argument parser and parse the arguments\nap = argparse.ArgumentParser()\nap.add_argument(\"-e\", \"--encodings\", required=True,\n\thelp=\"path to serialized db of facial encodings\")\nap.add_argument(\"-i\", \"--image\", required=True,\n\thelp=\"path to input image\")\nap.add_argument(\"-d\", \"--detection-method\", type=str, default=\"cnn\",\n\thelp=\"face detection model to use: either `hog` or `cnn`\")\nargs = vars(ap.parse_args())\nThis script requires just four imports on\nLines 2-5\n. The\nface_recognition\nmodule will do the heavy lifting and OpenCV will help us to load, convert, and display the processed image.\nWe’ll parse three command line arguments on\nLines 8-15:\n--encodings\n: The path to the pickle file containing our face encodings.\n--image\n: This is the image that is undergoing facial recognition.\n--detection-method\n: You should be familiar with this one by now — we’re either going to use a\nhog\nor\ncnn\nmethod depending on the capability of your system. For speed, choose\nhog\nand for accuracy, choose\ncnn\n.\nIMPORTANT!\nIf you are:\nRunning the face recognition code on a\nCPU\nOR\nyou using a\nRaspberry Pi\n…you’ll want to set the\n--detection-method\nto\nhog\nas the CNN face detector is (1) slow without a GPU and (2) the Raspberry Pi won’t have enough memory to run the CNN either.\nFrom there, let’s load the pre-computed encodings + face names and then construct the 128-d face encoding for the input image:\n# load the known faces and embeddings\nprint(\"[INFO] loading encodings...\")\ndata = pickle.loads(open(args[\"encodings\"], \"rb\").read())\n\n# load the input image and convert it from BGR to RGB\nimage = cv2.imread(args[\"image\"])\nrgb = cv2.cvtColor(image, cv2.COLOR_BGR2RGB)\n\n# detect the (x, y)-coordinates of the bounding boxes corresponding\n# to each face in the input image, then compute the facial embeddings\n# for each face\nprint(\"[INFO] recognizing faces...\")\nboxes = face_recognition.face_locations(rgb,\n\tmodel=args[\"detection_method\"])\nencodings = face_recognition.face_encodings(rgb, boxes)\n\n# initialize the list of names for each face detected\nnames = []\nLine 19\nloads our pickled encodings and face names from disk. We’ll need this data later during the actual face recognition step.\nThen, on\nLines 22 and 23\nwe load and convert the input\nimage\nto\nrgb\ncolor channel ordering (just as we did in the\nencode_faces.py\nscript).\nWe then proceed to detect all faces in the input image and compute their 128-d\nencodings\non\nLines 29-31\n(these lines should also look familiar).\nNow is a good time to initialize a list of\nnames\nfor each face that is detected — this list will be populated in the next step.\nNext, let’s loop over the facial\nencodings\n:\n# loop over the facial embeddings\nfor encoding in encodings:\n\t# attempt to match each face in the input image to our known\n\t# encodings\n\tmatches = face_recognition.compare_faces(data[\"encodings\"],\n\t\tencoding)\n\tname = \"Unknown\"\nOn\nLine 37\n, we begin to loop over the face encodings computed from our input image.\nThen the facial recognition magic happens!\nWe attempt to match each face in the input image (\nencoding\n) to our known encodings dataset (held in\ndata[\"encodings\"]\n) using\nface_recognition.compare_faces\n(\nLines 40 and 41\n).\nThis function returns a list of\nTrue\n/\nFalse\nvalues, one for each image in our dataset. For our\nJurassic Park\nexample, there are 218 images in the dataset and therefore the returned list will have 218 boolean values.\nInternally, the\ncompare_faces\nfunction is computing the Euclidean distance between the candidate embedding and all faces in our dataset:\nIf the distance is below some tolerance (the smaller the tolerance, the more strict our facial recognition system will be) then we return\nTrue\n,\nindicating the faces match.\nOtherwise, if the distance is above the tolerance threshold we return\nFalse\nas\nthe faces do not match.\nEssentially, we are utilizing a “more fancy”\nk-NN model\nfor classification. Be sure to refer to the\ncompare_faces implementation\nfor more details.\nThe\nname\nvariable will eventually hold the name string of the person — for now, we leave it as\n\"Unknown\"\nin case there are no “votes” (\nLine 42\n).\nGiven our\nmatches\nlist we can compute the number of “votes” for each name (number of\nTrue\nvalues associated with each name), tally up the votes, and select the person’s name with the most corresponding votes:\n# check to see if we have found a match\n\tif True in matches:\n\t\t# find the indexes of all matched faces then initialize a\n\t\t# dictionary to count the total number of times each face\n\t\t# was matched\n\t\tmatchedIdxs = [i for (i, b) in enumerate(matches) if b]\n\t\tcounts = {}\n\n\t\t# loop over the matched indexes and maintain a count for\n\t\t# each recognized face face\n\t\tfor i in matchedIdxs:\n\t\t\tname = data[\"names\"][i]\n\t\t\tcounts[name] = counts.get(name, 0) + 1\n\n\t\t# determine the recognized face with the largest number of\n\t\t# votes (note: in the event of an unlikely tie Python will\n\t\t# select first entry in the dictionary)\n\t\tname = max(counts, key=counts.get)\n\t\n\t# update the list of names\n\tnames.append(name)\nIf there are any\nTrue\nvotes in\nmatches\n(\nLine 45\n) we need to determine the\nindexes\nof where these\nTrue\nvalues are in\nmatches\n. We do just that on\nLine 49\nwhere we construct a simple list of\nmatchedIdxs\nwhich might look like this for\nexample_01.png\n:\n(Pdb) matchedIdxs\n[35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 71, 72, 73, 74, 75]\nWe then initialize a dictionary called\ncounts\nwhich will hold the character name as the\nkey\nand the number of votes as the\nvalue\n(\nLine 50\n).\nFrom there, let’s loop over the\nmatchedIdxs\nand set the value associated with each name while incrementing it as necessary in\ncounts\n. The\ncounts\ndictionary might look like this for a high vote score for Ian Malcolm:\n(Pdb) counts\n{'ian_malcolm': 40}\nRecall that we only have 41 pictures of Ian in the dataset, so a score of 40 with no votes for anybody else is extremely high.\nLine 61\nextracts the name with the most votes from\ncounts\n, in this case, it would be\n'ian_malcolm'\n.\nThe second iteration of our loop (as there are two faces in our example image) of the main facial encodings loop yields the following for\ncounts\n:\n(Pdb) counts\n{'alan_grant': 5}\nThat is definitely a smaller vote score, but still, there is only one name in the dictionary so we likely have found Alan Grant.\nNote:\nThe PDB Python Debugger was used to verify values of the\ncounts\ndictionary. PDB usage is outside the scope of this blog post; however, you can discover how to use it on the\nPython docs page\n.\nAs shown in\nFigure 5\nbelow, both Ian Malcolm and Alan Grant have been correctly recognized, so this part of the script is working well.\nLet’s move on and loop over the bounding boxes and labeled names for each person and draw them on our output image for visualization purposes:\n# loop over the recognized faces\nfor ((top, right, bottom, left), name) in zip(boxes, names):\n\t# draw the predicted face name on the image\n\tcv2.rectangle(image, (left, top), (right, bottom), (0, 255, 0), 2)\n\ty = top - 15 if top - 15 > 15 else top + 15\n\tcv2.putText(image, name, (left, y), cv2.FONT_HERSHEY_SIMPLEX,\n\t\t0.75, (0, 255, 0), 2)\n\n# show the output image\ncv2.imshow(\"Image\", image)\ncv2.waitKey(0)\nOn\nLine 67\n, we begin looping over the detected face bounding\nboxes\nand predicted\nnames\n. To create an iterable object so we can easily loop through the values, we call\nzip(boxes, names)\nresulting in tuples that we can extract the box coordinates and name from.\nWe use the box coordinates to draw a green rectangle on\nLine 69\n.\nWe also use the coordinates to calculate where we should draw the text for the person’s name (\nLine 70\n) followed by actually placing the name text on the image (\nLines 71 and 72\n). If the face bounding box is at the very top of the image, we need to move the text below the top of the box (handled on\nLine 70\n), otherwise, the text would be cut off.\nWe then proceed to display the image until a key is pressed (\nLines 75 and 76\n).\nHow should you run the facial recognition Python script?\nUsing your terminal, first ensure you’re in your respective Python correct virtual environment with the\nworkon\ncommand (if you are using a virtual environment, of course).\nThen run the script while providing the two\ncommand line arguments\nat a minimum. If you choose to use the HoG method, be sure to pass\n--detection-method hog\nas well (otherwise it will default to the deep learning detector).\nLet’s go for it!\nTo recognize a face using OpenCV and Python open up your terminal and execute our script:\n$ python recognize_faces_image.py --encodings encodings.pickle \\\n\t--image examples/example_01.png\n[INFO] loading encodings...\n[INFO] recognizing faces...\nFigure 5:\nAlan Grant and Ian Malcolm’s faces are recognized using our Python + OpenCV + deep learning method.\nA second face recognition example follows:\n$ python recognize_faces_image.py --encodings encodings.pickle \\\n\t--image examples/example_03.png\n[INFO] loading encodings...\n[INFO] recognizing faces...\nFigure 6:\nFace recognition with OpenCV and Python.\nRecognizing faces in video\nFigure 7:\nFace recognition for videos with OpenCV and Python.\nNow that we have applied face recognition to\nimages\nlet’s also apply face recognition to\nvideos\n(in real-time) as well.\nImportant Performance Note:\nThe CNN face recognizer should only be used in real-time if you are working with a GPU (you can use it with a CPU, but expect less than 0.5 FPS which makes for a choppy video). Alternatively (you are using a CPU), you should use the HoG method (or even OpenCV Haar cascades covered in a future blog post) and expect adequate speeds.\nThe following script draws many parallels from the previous\nrecognize_faces_image.py\nscript. Therefore I’ll be breezing past what we’ve already covered and just review the video components so that you understand what is going on.\nOnce you’ve grabbed the\n“Downloads”\n, open up\nrecognize_faces_video.py\nand follow along:\n# import the necessary packages\nfrom imutils.video import VideoStream\nimport face_recognition\nimport argparse\nimport imutils\nimport pickle\nimport time\nimport cv2\n\n# construct the argument parser and parse the arguments\nap = argparse.ArgumentParser()\nap.add_argument(\"-e\", \"--encodings\", required=True,\n\thelp=\"path to serialized db of facial encodings\")\nap.add_argument(\"-o\", \"--output\", type=str,\n\thelp=\"path to output video\")\nap.add_argument(\"-y\", \"--display\", type=int, default=1,\n\thelp=\"whether or not to display output frame to screen\")\nap.add_argument(\"-d\", \"--detection-method\", type=str, default=\"cnn\",\n\thelp=\"face detection model to use: either `hog` or `cnn`\")\nargs = vars(ap.parse_args())\nWe import packages on\nLines 2-8\nand then proceed to parse our command line arguments on\nLines 11-20\n.\nWe have four command line arguments, two of which you should recognize from above (\n--encodings\nand\n--detection-method\n). The other two arguments are:\n--output\n: The path to the output video.\n--display\n: A flag which instructs the script to display the frame to the screen. A value of\n1\ndisplays and a value of\n0\nwill not display the output frames to our screen.\nFrom there we’ll load our encodings and start our\nVideoStream\n:\n# load the known faces and embeddings\nprint(\"[INFO] loading encodings...\")\ndata = pickle.loads(open(args[\"encodings\"], \"rb\").read())\n\n# initialize the video stream and pointer to output video file, then\n# allow the camera sensor to warm up\nprint(\"[INFO] starting video stream...\")\nvs = VideoStream(src=0).start()\nwriter = None\ntime.sleep(2.0)\nTo access our camera we’re using the\nVideoStream\nclass from\nimutils\n.\nLine 29\nstarts the stream. If you have multiple cameras on your system (such as a built-in webcam and an external USB cam), you can change the\nsrc=0\nto\nsrc=1\nand so forth.\nWe’ll be optionally writing processed video frames to disk later, so we initialize\nwriter\nto\nNone\n(\nLine 30\n). Sleeping for 2 complete seconds allows our camera to warm up (\nLine 31\n).\nFrom there we’ll start a\nwhile\nloop and begin to grab and process frames:\n# loop over frames from the video file stream\nwhile True:\n\t# grab the frame from the threaded video stream\n\tframe = vs.read()\n\t\n\t# convert the input frame from BGR to RGB then resize it to have\n\t# a width of 750px (to speedup processing)\n\trgb = cv2.cvtColor(frame, cv2.COLOR_BGR2RGB)\n\trgb = imutils.resize(frame, width=750)\n\tr = frame.shape[1] / float(rgb.shape[1])\n\n\t# detect the (x, y)-coordinates of the bounding boxes\n\t# corresponding to each face in the input frame, then compute\n\t# the facial embeddings for each face\n\tboxes = face_recognition.face_locations(rgb,\n\t\tmodel=args[\"detection_method\"])\n\tencodings = face_recognition.face_encodings(rgb, boxes)\n\tnames = []\nOur loop begins on\nLine 34\nand the first step we take is to grab a\nframe\nfrom the video stream (\nLine 36\n).\nThe remaining\nLines 40-50\nin the above code block are nearly identical to the lines in the previous script with the exception being that this is a video frame and not a static image. Essentially we read the\nframe\n, preprocess, and then detect face bounding\nboxes\n+ calculate\nencodings\nfor each bounding box.\nNext, let’s loop over the facial\nencodings\nassociated with the faces we have just found:\n# loop over the facial embeddings\n\tfor encoding in encodings:\n\t\t# attempt to match each face in the input image to our known\n\t\t# encodings\n\t\tmatches = face_recognition.compare_faces(data[\"encodings\"],\n\t\t\tencoding)\n\t\tname = \"Unknown\"\n\n\t\t# check to see if we have found a match\n\t\tif True in matches:\n\t\t\t# find the indexes of all matched faces then initialize a\n\t\t\t# dictionary to count the total number of times each face\n\t\t\t# was matched\n\t\t\tmatchedIdxs = [i for (i, b) in enumerate(matches) if b]\n\t\t\tcounts = {}\n\n\t\t\t# loop over the matched indexes and maintain a count for\n\t\t\t# each recognized face face\n\t\t\tfor i in matchedIdxs:\n\t\t\t\tname = data[\"names\"][i]\n\t\t\t\tcounts[name] = counts.get(name, 0) + 1\n\n\t\t\t# determine the recognized face with the largest number\n\t\t\t# of votes (note: in the event of an unlikely tie Python\n\t\t\t# will select first entry in the dictionary)\n\t\t\tname = max(counts, key=counts.get)\n\t\t\n\t\t# update the list of names\n\t\tnames.append(name)\nIn this code block, we loop over each of the\nencodings\nand attempt to match the face. If there are matches found, we count the votes for each name in the dataset. We then extract the highest vote count and that is the name associated with the face. These lines are\nidentical\nto the previous script we reviewed, so let’s move on.\nIn this next block, we loop over the recognized faces and proceed to draw a box around the face and the display name of the person above the face:\n# loop over the recognized faces\n\tfor ((top, right, bottom, left), name) in zip(boxes, names):\n\t\t# rescale the face coordinates\n\t\ttop = int(top * r)\n\t\tright = int(right * r)\n\t\tbottom = int(bottom * r)\n\t\tleft = int(left * r)\n\n\t\t# draw the predicted face name on the image\n\t\tcv2.rectangle(frame, (left, top), (right, bottom),\n\t\t\t(0, 255, 0), 2)\n\t\ty = top - 15 if top - 15 > 15 else top + 15\n\t\tcv2.putText(frame, name, (left, y), cv2.FONT_HERSHEY_SIMPLEX,\n\t\t\t0.75, (0, 255, 0), 2)\nThose lines are identical too, so let’s focus on the video-related code.\nOptionally, we’re going to write the frame to disk, so let’s see how\nwriting video to disk with OpenCV\nworks:\n# if the video writer is None *AND* we are supposed to write\n\t# the output video to disk initialize the writer\n\tif writer is None and args[\"output\"] is not None:\n\t\tfourcc = cv2.VideoWriter_fourcc(*\"MJPG\")\n\t\twriter = cv2.VideoWriter(args[\"output\"], fourcc, 20,\n\t\t\t(frame.shape[1], frame.shape[0]), True)\n\n\t# if the writer is not None, write the frame with recognized\n\t# faces to disk\n\tif writer is not None:\n\t\twriter.write(frame)\nAssuming we have an output file path provided in the command line arguments and we haven’t already initialized a video\nwriter\n(\nLine 99\n), let’s go ahead and initialize it.\nOn\nLine 100\n, we initialize the\nVideoWriter_fourcc\n.\nFourCC\nis a 4-character code and in our case, we’re going to use the “MJPG” 4-character code.\nFrom there, we’ll pass that object into the\nVideoWriter\nalong with our output file path, frames per second target, and frame dimensions (\nLines 101 and 102\n).\nFinally, if the\nwriter\nexists, we can go ahead and write a frame to disk (\nLines 106 and 107\n).\nLet’s handle whether or not we should display the face recognition video frames on the screen:\n# check to see if we are supposed to display the output frame to\n\t# the screen\n\tif args[\"display\"] > 0:\n\t\tcv2.imshow(\"Frame\", frame)\n\t\tkey = cv2.waitKey(1) & 0xFF\n\n\t\t# if the `q` key was pressed, break from the loop\n\t\tif key == ord(\"q\"):\n\t\t\tbreak\nIf our display command line argument is set, we go ahead and display the frame (\nLine 112\n) and check if the quit key (\n\"q\"\n) has been pressed (\nLines 113-116\n), at which point we’d\nbreak\nout of the loop (\nLine 117\n).\nLastly, let’s perform our housekeeping duties:\n# do a bit of cleanup\ncv2.destroyAllWindows()\nvs.stop()\n\n# check to see if the video writer point needs to be released\nif writer is not None:\n\twriter.release()\nIn\nLines 120-125\n, we clean up and release the display, video stream, and video writer.\nAre you ready to see the script in action?\nTo demonstrate\nreal-time face recognition with OpenCV and Python\nin action, open up a terminal and execute the following command:\n$ python recognize_faces_video.py --encodings encodings.pickle \\\n\t--output output/webcam_face_recognition_output.avi --display 1\n[INFO] loading encodings...\n[INFO] starting video stream...\nBelow you can find an output example video that I recorded demonstrating the face recognition system in action:\nFace recognition in video files\nAs I mentioned in our\n“Face recognition project structure”\nsection, there’s an additional script included in the\n“Downloads”\nfor this blog post —\nrecognize_faces_video_file.py\n.\nThis file is essentially the same as the one we just reviewed for the webcam except it will take an input video file and generate an output video file if you’d like.\nI applied our face recognition code to the popular “lunch scene” from the original\nJurassic Park\nmovie where the cast is sitting around a table sharing their concerns with the park:\n$ python recognize_faces_video_file.py --encodings encodings.pickle \\\n\t--input videos/lunch_scene.mp4 --output output/lunch_scene_output.avi \\\n\t--display 0\nHere’s the result:\nNote:\nRecall that our model was trained on four members of the original cast: Alan Grant, Ellie Sattler, Ian Malcolm, and John Hammond. The model was\nnot\ntrained on Donald Gennaro (the lawyer) which is why his face is labeled as “Unknown”. This behavior was by design (not an accident) to show that our face recognition system can recognize faces it was trained on while leaving faces it cannot recognize as “Unknown”.\nAnd in the following video I have put together a “highlight reel” of\nJurassic Park\nand\nJurassic World\nclips, mainly from the trailers:\nAs we can see, our face recognition and OpenCV code works quite well!\nCan I use this face recognizer code on the Raspberry Pi?\nKinda, sorta. There are a few limitations though:\nThe Raspberry Pi does not have enough memory to utilize the more accurate CNN-based face detector…\n…so we are limited to HOG instead\nExcept that HOG is far too slow on the Pi for real-time face detection…\n…so we need to utilize OpenCV’s Haar cascades\nAnd once you get it running you can expect only 1-2 FPS, and even reaching that level of FPS takes a few tricks.\nThe good news is that I’ll be back next week to discuss how to run our face recognizer on the Raspberry Pi, so stay tuned!\nAlternative face recognition methods\nThe face recognition method we used inside this tutorial was based on a combination of\nDavis King’s dlib library\nand\nAdam Geitgey’s face_recognition module\n.\nDavis has provided a ResNet-based siamese network that is super useful for face recognition tasks. Adam’s library provides a wrapper around dlib to make the face recognition functionality easier to use.\nHowever, there\nare\nother face recognition methods that can be used\n, including both deep learning-based and traditional computer vision-based approaches.\nTo start, take a look at this tutorial on\nOpenCV Face Recognition\nwhich is a\npure OpenCV-based face recognizer\n(i.e., no other libraries, such as dlib, scikit-image, etc., are required to perform face recognition). That said, dlib’s face recognizer does tend to be a bit more accurate, so keep that in mind when implementing face recognition models of your own.\nFor non-deep learning-based face recognition, I suggest taking a look at both Eigenfaces and Local Binary Patterns (LBPs) for face recognition:\nFace Recognition with Local Binary Patterns (LBPs) and OpenCV\nOpenCV Eigenfaces for Face Recognition\nThese methods are less accurate than their deep learning-based face recognition counterparts, but tend to be much more computationally efficient and will run faster on embedded systems.\nFace Recognition Application ideas\nWhat can’t you build with face recognition?  Seriously, it’s so useful to be able to recognize a person’s face.\nHere are just a few ideas of what you can build\nSecurity\nAccount logon\nMarketing applications\nSales workflow\nSocial media engagement meter\nHealthcare patient ID\nVoting ID\nEducation safety and notification to parents and teachers\nGaming ID and age determination to avoid collecting data on minors\nLibrary card replacement\nWhat's next? We recommend\nPyImageSearch University\n.\nCourse information:\n120+ total classes • 115+ hours of on-demand code walkthrough videos • Last updated: October 2026\n★★★★★\n4.84 (128 Ratings) • 16,000+ Students Enrolled\nI strongly believe that if you had the right teacher you could\nmaster\ncomputer vision and deep learning.\nDo you think learning computer vision and deep learning has to be time-consuming, overwhelming, and complicated? Or has to involve complex mathematics and equations? Or requires a degree in computer science?\nThat’s\nnot\nthe case.\nAll you need to master computer vision and deep learning is for someone to explain things to you in\nsimple, intuitive\nterms.\nAnd that’s exactly what I do\n. My mission is to change education and how complex Artificial Intelligence topics are taught.\nIf you're serious about learning computer vision, your next stop should be PyImageSearch University, the most comprehensive computer vision, deep learning, and OpenCV course online today. Here you’ll learn how to\nsuccessfully\nand\nconfidently\napply computer vision to your work, research, and projects. Join me in computer vision mastery.\nInside PyImageSearch University you'll find:\n✓\n120+ courses\non essential computer vision, deep learning, and OpenCV topics\n✓\n94+ Certificates\nof Completion\n✓\n115+ hours\nof on-demand video\n✓\nBrand new courses released\nregularly\n, ensuring you can keep up with state-of-the-art techniques\n✓\nPre-configured Jupyter Notebooks in Google Colab\n✓ Run all code examples in your web browser — works on Windows, macOS, and Linux (no dev environment configuration required!)\n✓ Access to\ncentralized code repos for\nall\n540+ tutorials\non PyImageSearch\n✓\nEasy one-click downloads\nfor code, datasets, pre-trained models, etc.\n✓\nAccess\non mobile, laptop, desktop, etc.\nClick here to join PyImageSearch University\nSummary\nIn this tutorial, you learned how to perform face recognition with OpenCV, Python, and deep learning.\nAdditionally, we made use of Davis King’s\ndlib library\nand Adam Geitgey’s\nface_recognition module\nwhich wraps around dlib’s deep metric learning, making facial recognition easier to accomplish.\nAs we found out, our face recognition implementation is both:\nAccurate\nCapable of being executed in real-time with a GPU\nI hope you enjoyed today’s blog post on face recognition!\nTo download the source code to this post, and be notified when future tutorials are published here on PyImageSearch,\njust enter your email address in the form below!\nDownload the Source Code and FREE 17-page Resource Guide\nEnter your email address below to get a .zip of the code and a\nFREE 17-page Resource Guide on Computer Vision, OpenCV, and Deep Learning.\nInside you'll find my hand-picked tutorials, books, courses, and libraries to help you master CV and DL!\nDownload the code!\nWebsite",
  "metadata": {
    "title": "Face recognition with OpenCV, Python, and deep learning - PyImageSearch",
    "description": "Learn how to perform face recognition using OpenCV, Python, and dlib by applying deep learning for highly accurate facial recognition.",
    "keywords": null,
    "author": "Adrian Rosebrock",
    "og:locale": "en_US",
    "og:type": "article",
    "og:title": "Face recognition with OpenCV, Python, and deep learning - PyImageSearch",
    "og:description": "Learn how to perform face recognition using OpenCV, Python, and dlib by applying deep learning for highly accurate facial recognition.",
    "og:url": "https://pyimagesearch.com/2018/06/18/face-recognition-with-opencv-python-and-deep-learning/",
    "og:site_name": "PyImageSearch",
    "og:image": "https://pyimagesearch.com/wp-content/uploads/2018/06/face_recognition_opencv_example_02.jpg",
    "og:image:width": "600",
    "og:image:height": "363",
    "og:image:type": "image/jpeg",
    "twitter:label1": "Written by",
    "twitter:data1": "Adrian Rosebrock",
    "twitter:label2": "Est. reading time",
    "twitter:data2": "31 minutes",
    "article:published_time": "2018-06-18T14:00:19+00:00",
    "article:modified_time": "2024-12-20T20:11:08+00:00"
  },
  "paywall": {
    "listed_paid": false,
    "detected": false,
    "marker": "",
    "public_only": false,
    "policy": "付费/会员内容只保留页面公开可见部分，不绕过付费墙"
  },
  "crawl": {
    "success": true,
    "status_code": 200,
    "error": ""
  },
  "code_blocks": [
    {
      "file": "attachments/a8aa44ea93b7/code/body-000.txt",
      "chars": 39,
      "language": "text"
    },
    {
      "file": "attachments/a8aa44ea93b7/code/body-001.txt",
      "chars": 241,
      "language": "text"
    },
    {
      "file": "attachments/a8aa44ea93b7/code/body-002.txt",
      "chars": 279,
      "language": "text"
    },
    {
      "file": "attachments/a8aa44ea93b7/code/body-003.txt",
      "chars": 72,
      "language": "text"
    },
    {
      "file": "attachments/a8aa44ea93b7/code/body-004.txt",
      "chars": 63,
      "language": "text"
    },
    {
      "file": "attachments/a8aa44ea93b7/code/body-005.txt",
      "chars": 591,
      "language": "text"
    },
    {
      "file": "attachments/a8aa44ea93b7/code/body-006.txt",
      "chars": 133,
      "language": "text"
    },
    {
      "file": "attachments/a8aa44ea93b7/code/body-007.txt",
      "chars": 449,
      "language": "text"
    },
    {
      "file": "attachments/a8aa44ea93b7/code/body-008.txt",
      "chars": 237,
      "language": "text"
    },
    {
      "file": "attachments/a8aa44ea93b7/code/body-009.txt",
      "chars": 404,
      "language": "text"
    },
    {
      "file": "attachments/a8aa44ea93b7/code/body-010.txt",
      "chars": 476,
      "language": "text"
    },
    {
      "file": "attachments/a8aa44ea93b7/code/body-011.txt",
      "chars": 214,
      "language": "text"
    },
    {
      "file": "attachments/a8aa44ea93b7/code/body-012.txt",
      "chars": 406,
      "language": "text"
    },
    {
      "file": "attachments/a8aa44ea93b7/code/body-013.txt",
      "chars": 523,
      "language": "text"
    },
    {
      "file": "attachments/a8aa44ea93b7/code/body-014.txt",
      "chars": 659,
      "language": "text"
    },
    {
      "file": "attachments/a8aa44ea93b7/code/body-015.txt",
      "chars": 227,
      "language": "text"
    },
    {
      "file": "attachments/a8aa44ea93b7/code/body-016.txt",
      "chars": 705,
      "language": "text"
    },
    {
      "file": "attachments/a8aa44ea93b7/code/body-017.txt",
      "chars": 179,
      "language": "text"
    },
    {
      "file": "attachments/a8aa44ea93b7/code/body-018.txt",
      "chars": 33,
      "language": "text"
    },
    {
      "file": "attachments/a8aa44ea93b7/code/body-019.txt",
      "chars": 31,
      "language": "text"
    },
    {
      "file": "attachments/a8aa44ea93b7/code/body-020.txt",
      "chars": 406,
      "language": "text"
    },
    {
      "file": "attachments/a8aa44ea93b7/code/body-021.txt",
      "chars": 154,
      "language": "text"
    },
    {
      "file": "attachments/a8aa44ea93b7/code/body-022.txt",
      "chars": 154,
      "language": "text"
    },
    {
      "file": "attachments/a8aa44ea93b7/code/body-023.txt",
      "chars": 699,
      "language": "text"
    },
    {
      "file": "attachments/a8aa44ea93b7/code/body-024.txt",
      "chars": 343,
      "language": "text"
    },
    {
      "file": "attachments/a8aa44ea93b7/code/body-025.txt",
      "chars": 673,
      "language": "text"
    },
    {
      "file": "attachments/a8aa44ea93b7/code/body-026.txt",
      "chars": 959,
      "language": "text"
    },
    {
      "file": "attachments/a8aa44ea93b7/code/body-027.txt",
      "chars": 479,
      "language": "text"
    },
    {
      "file": "attachments/a8aa44ea93b7/code/body-028.txt",
      "chars": 430,
      "language": "text"
    },
    {
      "file": "attachments/a8aa44ea93b7/code/body-029.txt",
      "chars": 248,
      "language": "text"
    },
    {
      "file": "attachments/a8aa44ea93b7/code/body-030.txt",
      "chars": 160,
      "language": "text"
    },
    {
      "file": "attachments/a8aa44ea93b7/code/body-031.txt",
      "chars": 189,
      "language": "text"
    },
    {
      "file": "attachments/a8aa44ea93b7/code/body-032.txt",
      "chars": 156,
      "language": "text"
    }
  ],
  "images": [
    {
      "status": "ok",
      "url": "https://b2633864.assetcdn.net/2633864/wp-content/uploads/2018/06/face_recognition_opencv_example_02.jpg?lossy=2&strip=1&webp=1",
      "bytes": 44781,
      "reused": false,
      "local_path": "attachments/a8aa44ea93b7/images/body-773fb60b4ff521a0af89.jpg",
      "src": "https://b2633864.assetcdn.net/2633864/wp-content/uploads/2018/06/face_recognition_opencv_example_02.jpg?lossy=2&strip=1&webp=1",
      "alt": "",
      "downloaded": true
    },
    {
      "status": "ok",
      "url": "https://b2633864.assetcdn.net/2633864/wp-content/uploads/2020/01/source-code-icon.png?lossy=2&strip=1&webp=1",
      "bytes": 884,
      "reused": false,
      "local_path": "attachments/a8aa44ea93b7/images/body-0f8ec41d2103feb4399d.png",
      "src": "https://b2633864.assetcdn.net/2633864/wp-content/uploads/2020/01/source-code-icon.png?lossy=2&strip=1&webp=1",
      "alt": "",
      "downloaded": true
    },
    {
      "status": "ok",
      "url": "https://b2633864.assetcdn.net/2633864/wp-content/uploads/2018/06/face_recognition_opencv_triplet.jpg?lossy=2&strip=1&webp=1",
      "bytes": 30977,
      "reused": false,
      "local_path": "attachments/a8aa44ea93b7/images/body-166f20e1fd2e760d6cf5.jpg",
      "src": "https://b2633864.assetcdn.net/2633864/wp-content/uploads/2018/06/face_recognition_opencv_triplet.jpg?lossy=2&strip=1&webp=1",
      "alt": "",
      "downloaded": true
    },
    {
      "status": "ok",
      "url": "https://b2633864.assetcdn.net/2633864/wp-content/uploads/2018/06/build_face_dataset_jurassic_park.jpg?lossy=2&strip=1&webp=1",
      "bytes": 52848,
      "reused": false,
      "local_path": "attachments/a8aa44ea93b7/images/body-bf3a18c00ea23b8d7eed.jpg",
      "src": "https://b2633864.assetcdn.net/2633864/wp-content/uploads/2018/06/build_face_dataset_jurassic_park.jpg?lossy=2&strip=1&webp=1",
      "alt": "",
      "downloaded": true
    },
    {
      "status": "ok",
      "url": "https://b2633864.assetcdn.net/2633864/wp-content/uploads/2018/06/face_recognition_opencv_embedding.jpg?lossy=2&strip=1&webp=1",
      "bytes": 9289,
      "reused": false,
      "local_path": "attachments/a8aa44ea93b7/images/body-5150c50f619875f9de37.jpg",
      "src": "https://b2633864.assetcdn.net/2633864/wp-content/uploads/2018/06/face_recognition_opencv_embedding.jpg?lossy=2&strip=1&webp=1",
      "alt": "",
      "downloaded": true
    },
    {
      "status": "ok",
      "url": "https://b2633864.assetcdn.net/2633864/wp-content/uploads/2018/06/face_recognition_opencv_example_03.jpg?lossy=2&strip=1&webp=1",
      "bytes": 67743,
      "reused": false,
      "local_path": "attachments/a8aa44ea93b7/images/body-d255a5ee47c9c2b62e1b.jpg",
      "src": "https://b2633864.assetcdn.net/2633864/wp-content/uploads/2018/06/face_recognition_opencv_example_03.jpg?lossy=2&strip=1&webp=1",
      "alt": "",
      "downloaded": true
    },
    {
      "status": "ok",
      "url": "https://b2633864.assetcdn.net/2633864/wp-content/uploads/2018/06/face_recognition_opencv_example_01.jpg?lossy=2&strip=1&webp=1",
      "bytes": 42056,
      "reused": false,
      "local_path": "attachments/a8aa44ea93b7/images/body-afb9c06b176bcde2b145.jpg",
      "src": "https://b2633864.assetcdn.net/2633864/wp-content/uploads/2018/06/face_recognition_opencv_example_01.jpg?lossy=2&strip=1&webp=1",
      "alt": "",
      "downloaded": true
    },
    {
      "status": "ok",
      "url": "https://fast.wistia.com/embed/medias/kno0cmko2z/swatch",
      "bytes": 3143,
      "reused": false,
      "local_path": "attachments/a8aa44ea93b7/images/body-8ec9834d54100244f57f.img",
      "src": "https://fast.wistia.com/embed/medias/kno0cmko2z/swatch",
      "alt": "",
      "downloaded": true
    },
    {
      "status": "ok",
      "url": "https://b2633864.assetcdn.net/2633864/wp-content/uploads/2020/01/cta-source-guide-1.png?lossy=2&strip=1&webp=1",
      "bytes": 28126,
      "reused": false,
      "local_path": "attachments/a8aa44ea93b7/images/body-8cd5816cf73385d96fcd.png",
      "src": "https://b2633864.assetcdn.net/2633864/wp-content/uploads/2020/01/cta-source-guide-1.png?lossy=2&strip=1&webp=1",
      "alt": "",
      "downloaded": true
    }
  ],
  "audio": [],
  "videos": [
    {
      "url": "https://www.youtube.com/watch?v=dCKl4oGP69s",
      "src": "https://www.youtube.com/embed/dCKl4oGP69s",
      "status": "no_1080_or_720",
      "kind": "single_video",
      "error": "ERROR: [youtube] dCKl4oGP69s: Requested format is not available. Use --list-formats for a list of available formats\n",
      "title": "",
      "retried_at": "2026-10-20T18:02:41Z"
    },
    {
      "url": "https://www.youtube.com/watch?v=A5wqscP8OIE",
      "src": "https://www.youtube.com/embed/A5wqscP8OIE",
      "status": "no_1080_or_720",
      "kind": "single_video",
      "error": "ERROR: [youtube] A5wqscP8OIE: Requested format is not available. Use --list-formats for a list of available formats\n",
      "title": "",
      "retried_at": "2026-10-20T18:02:41Z"
    },
    {
      "url": "https://www.youtube.com/watch?v=ZweuQ_qcfrw",
      "src": "https://www.youtube.com/embed/ZweuQ_qcfrw",
      "status": "no_1080_or_720",
      "kind": "single_video",
      "error": "ERROR: [youtube] ZweuQ_qcfrw: Requested format is not available. Use --list-formats for a list of available formats\n",
      "title": "",
      "retried_at": "2026-10-20T18:02:45Z"
    }
  ],
  "links": [
    {
      "href": "https://opencv.org/",
      "label": "OpenCV",
      "type": "a"
    },
    {
      "href": "https://www.python.org/",
      "label": "Python",
      "type": "a"
    },
    {
      "href": "https://pyimagesearch.com/deep-learning-computer-vision-python-book/",
      "label": "deep learning",
      "type": "a"
    },
    {
      "href": "https://roboflow.com/?ref=pyimagesearch",
      "label": "Roboflow",
      "type": "a"
    },
    {
      "href": "https://universe.roboflow.com/pyimagesearch?ref=pyimagesearch",
      "label": "PyimageSearch’s assorted library of useful datasets",
      "type": "a"
    },
    {
      "href": "https://pyimagesearch.com/wp-content/uploads/2018/06/face_recognition_opencv_triplet.jpg",
      "label": "",
      "type": "a"
    },
    {
      "href": "https://medium.com/@ageitgey/machine-learning-is-fun-part-4-modern-face-recognition-with-deep-learning-c3cffc121d78",
      "label": "Adam Geitgey’s “Machine Learning is Fun” blog",
      "type": "a"
    },
    {
      "href": "https://arxiv.org/abs/1512.03385",
      "label": "Deep Residual Learning for Image Recognition",
      "type": "a"
    },
    {
      "href": "https://pyimagesearch.com/2017/03/13/an-interview-with-davis-king-creator-of-the-dlib-toolkit/",
      "label": "Davis King",
      "type": "a"
    },
    {
      "href": "http://vis-www.cs.umass.edu/lfw/",
      "label": "Labeled Faces in the Wild (LFW)",
      "type": "a"
    },
    {
      "href": "http://dlib.net/",
      "label": "dlib",
      "type": "a"
    },
    {
      "href": "https://adamgeitgey.com/",
      "label": "Adam Geitgey",
      "type": "a"
    },
    {
      "href": "https://github.com/ageitgey/face_recognition",
      "label": "face_recognition module",
      "type": "a"
    },
    {
      "href": "http://blog.dlib.net/2017/02/high-quality-face-recognition-with-deep.html",
      "label": "High Quality Face Recognition with Deep Metric Learning",
      "type": "a"
    },
    {
      "href": "https://www.pyimageconf.com/",
      "label": "Learn from Adam Geitgey and Davis King at PyImageConf 2018",
      "type": "a"
    },
    {
      "href": "https://pyimagesearch.com/opencv-tutorials-resources-guides/",
      "label": "OpenCV install tutorials",
      "type": "a"
    },
    {
      "href": "https://pyimagesearch.com/2018/01/22/install-dlib-easy-complete-guide/",
      "label": "following this guide",
      "type": "a"
    },
    {
      "href": "https://github.com/jrosebr1/imutils",
      "label": "imutils",
      "type": "a"
    },
    {
      "href": "https://pyimagesearch.com/wp-content/uploads/2018/06/build_face_dataset_jurassic_park.jpg",
      "label": "",
      "type": "a"
    },
    {
      "href": "https://www.imdb.com/title/tt0107290/",
      "label": "Jurassic Park",
      "type": "a"
    },
    {
      "href": "https://www.imdb.com/title/tt4881806/",
      "label": "Jurassic World: Fallen Kingdom",
      "type": "a"
    },
    {
      "href": "http://jurassicpark.wikia.com/wiki/Alan_Grant",
      "label": "Alan Grant",
      "type": "a"
    },
    {
      "href": "http://jurassicpark.wikia.com/wiki/Claire_Dearing",
      "label": "Claire Dearing",
      "type": "a"
    },
    {
      "href": "http://jurassicpark.wikia.com/wiki/Ellie_Sattler",
      "label": "Ellie Sattler",
      "type": "a"
    },
    {
      "href": "http://jurassicpark.wikia.com/wiki/Ian_Malcolm",
      "label": "Ian Malcolm",
      "type": "a"
    },
    {
      "href": "http://jurassicpark.wikia.com/wiki/John_Hammond",
      "label": "John Hammond",
      "type": "a"
    },
    {
      "href": "http://jurassicpark.wikia.com/wiki/Owen_Grady",
      "label": "Owen Grady",
      "type": "a"
    },
    {
      "href": "https://pyimagesearch.com/2018/04/09/how-to-quickly-build-a-deep-learning-image-dataset/",
      "label": "How to (quickly) build a deep learning image dataset",
      "type": "a"
    },
    {
      "href": "https://pyimagesearch.com/wp-content/uploads/2018/06/face_recognition_opencv_embedding.jpg",
      "label": "",
      "type": "a"
    },
    {
      "href": "https://pyimagesearch.com/2018/03/12/python-argparse-command-line-arguments/",
      "label": "command line arguments",
      "type": "a"
    },
    {
      "href": "https://pyimagesearch.com/2018/06/11/how-to-build-a-custom-face-recognition-dataset/",
      "label": "method #2 of last week’s blog post",
      "type": "a"
    },
    {
      "href": "https://pyimagesearch.com/wp-content/uploads/2018/06/face_recognition_opencv_example_03.jpg",
      "label": "",
      "type": "a"
    },
    {
      "href": "https://pyimagesearch.com/2016/08/08/k-nn-classifier-for-image-classification/",
      "label": "k-NN model",
      "type": "a"
    },
    {
      "href": "https://github.com/ageitgey/face_recognition/blob/master/face_recognition/api.py",
      "label": "compare_faces implementation",
      "type": "a"
    },
    {
      "href": "https://docs.python.org/3/library/pdb.html",
      "label": "Python docs page",
      "type": "a"
    },
    {
      "href": "https://pyimagesearch.com/wp-content/uploads/2018/06/face_recognition_opencv_example_02.jpg",
      "label": "",
      "type": "a"
    },
    {
      "href": "https://github.com/jrosebr1/imutils/blob/master/imutils/video/videostream.py",
      "label": "imutils",
      "type": "a"
    },
    {
      "href": "https://pyimagesearch.com/2016/02/22/writing-to-video-with-opencv/",
      "label": "writing video to disk with OpenCV",
      "type": "a"
    },
    {
      "href": "https://www.fourcc.org/",
      "label": "FourCC",
      "type": "a"
    },
    {
      "href": "https://www.youtube.com/embed/dCKl4oGP69s",
      "label": "",
      "type": "iframe"
    },
    {
      "href": "https://www.youtube.com/embed/A5wqscP8OIE",
      "label": "",
      "type": "iframe"
    },
    {
      "href": "https://www.youtube.com/embed/ZweuQ_qcfrw",
      "label": "",
      "type": "iframe"
    },
    {
      "href": "https://pyimagesearch.com/2018/09/24/opencv-face-recognition/",
      "label": "OpenCV Face Recognition",
      "type": "a"
    },
    {
      "href": "https://pyimagesearch.com/2021/05/03/face-recognition-with-local-binary-patterns-lbps-and-opencv/",
      "label": "Face Recognition with Local Binary Patterns (LBPs) and OpenCV",
      "type": "a"
    },
    {
      "href": "https://pyimagesearch.com/2021/05/10/opencv-eigenfaces-for-face-recognition/",
      "label": "OpenCV Eigenfaces for Face Recognition",
      "type": "a"
    },
    {
      "href": "https://pyimagesearch.com/pyimagesearch-university/?utm_source=blogPost&utm_medium=bottomBanner&utm_campaign=What%27s%20next%3F%20I%20recommend",
      "label": "PyImageSearch University",
      "type": "a"
    }
  ],
  "repair_version": 2,
  "repaired_at": "2026-10-14T10:54:07Z",
  "source_url": "https://pyimagesearch.com/2018/06/18/face-recognition-with-opencv-python-and-deep-learning/",
  "papers": [
    {
      "status": "ok",
      "url": "https://arxiv.org/pdf/1512.03385",
      "bytes": 819383,
      "reused": true,
      "local_path": "papers/repair/523013cf51110acbfe60.pdf"
    }
  ],
  "actual_video_files": [
    {
      "local_path": "attachments/a8aa44ea93b7/videos/kno0cmko2z.mp4",
      "bytes": 154424456,
      "valid": true,
      "height": 1080,
      "width": 1920,
      "duration": "231.500000",
      "status": "ok"
    }
  ],
  "body_chars": 43717,
  "expected_body_images": 9,
  "discovery_status": "ok",
  "delivery_status": "partial",
  "missing_reason": "no_1080_or_720",
  "raw_html": "attachments/a8aa44ea93b7/pages/source.html",
  "local_html": "attachments/a8aa44ea93b7/pages/article.html",
  "body_base_path": "attachments/a8aa44ea93b7/pages/",
  "body_markdown_path": "attachments/a8aa44ea93b7/pages/article.md"
}