Programming


Technical Deep Dive: Multi-Method Face and Person Detection in Python

In this technical post, we’ll dissect a Python script integrating several libraries and techniques for detecting faces and people in video footage. This script is an excellent example of how diverse computer vision tools can be merged to produce a robust solution for image analysis.

# import the necessary packages
import numpy as np
import cv2
import sys
import os
from datetime import datetime
import face_recognition
import dlib

inputVideo = sys.argv[1];
basenameVideo = os.path.basename(inputVideo);
outputDirectory = sys.argv[2];
datetimeNow = datetime.now().strftime("%m-%d-%Y %H:%M:%S");

#Creating the folder to save the output
videoOutputDirectory = outputDirectory + '/' + datetimeNow + '/' + basenameVideo + '/';
os.makedirs(videoOutputDirectory);

##METHOD 1 -- START
# initialize the HOG descriptor/person detector
hog = cv2.HOGDescriptor()
hog.setSVMDetector(cv2.HOGDescriptor_getDefaultPeopleDetector())
##METHOD 1 -- STOP

##METHOD 2 -- START
faceCascade = cv2.CascadeClassifier(cv2.data.haarcascades + "haarcascade_frontalface_default.xml");
##METHOD 2 -- STOP

##METHOD 5 -- START
# Initialize face detector, facial landmarks detector and face recognizer
faceDetector = dlib.get_frontal_face_detector()
##METHOD 5 -- STOP

cv2.startWindowThread()

## open webcam video stream
#cap = cv2.VideoCapture(0)
# create a VideoCapture object
cap = cv2.VideoCapture(inputVideo)

frameIndex = 0;

while(True):
	# Capture frame-by-frame
	ret, frame = cap.read()

	# using a greyscale picture, also for faster detection
	gray = cv2.cvtColor(frame, cv2.COLOR_RGB2GRAY)

##METHOD 1 -- START
	if True:
		# detect people in the image
		persons, weights = hog.detectMultiScale(frame, winStride=(8,8) )

		persons = np.array([[x, y, x + w, y + h] for (x, y, w, h) in persons])
		print("[INFO][1][{0}] Found {1} Persons.".format(frameIndex, len(persons)));

		for (left, top, right, bottom) in persons:
			print("A person is located at pixel location Top: {}, Left: {}, Bottom: {}, Right: {}".format(top, left, bottom, right))
			match_image = frame[top:bottom, left:right];
			cv2.imwrite(videoOutputDirectory + str(frameIndex) + '_(' + str(top) + ',' + str(right) + ')(' + str(bottom) + ',' + str(left) + ')_persons_M1.jpg', match_image);
##METHOD 1 -- STOP

##METHOD 2 -- START
	if True:
		faces = faceCascade.detectMultiScale(
			gray,
			scaleFactor=1.05,
			minNeighbors=7,
			minSize=(50, 50)
		);

		faces = np.array([[x, y, x + w, y + h] for (x, y, w, h) in faces])
		print("[INFO][2][{0}] Found {1} Faces.".format(frameIndex, len(faces)));

		for (left, top, right, bottom) in faces:
			print("A face is located at pixel location Top: {}, Left: {}, Bottom: {}, Right: {}".format(top, left, bottom, right))
			match_image = frame[top:bottom, left:right];
			cv2.imwrite(videoOutputDirectory + str(frameIndex) + '_(' + str(top) + ',' + str(right) + ')(' + str(bottom) + ',' + str(left) + ')_faces_M2.jpg', match_image);
##METHOD 2 -- STOP

##METHOD 3 -- START
	if True:
		faces = face_recognition.face_locations(frame);
		print("[INFO][3][{0}] Found {1} Faces.".format(frameIndex, len(faces)));

		for (top, right, bottom, left) in faces:
			#print("[INFO] Object found. Saving locally.");
			print("A face is located at pixel location Top: {}, Left: {}, Bottom: {}, Right: {}".format(top, left, bottom, right))
			match_image = frame[top:bottom, left:right];
			cv2.imwrite(videoOutputDirectory + str(frameIndex) + '_(' + str(top) + ',' + str(right) + ')(' + str(bottom) + ',' + str(left) + ')_faces_M3.jpg', match_image);
##METHOD 3 -- STOP

##METHOD 4 -- START
	if True:
		faces = face_recognition.face_locations(frame, model="cnn");
		print("[INFO][4][{0}] Found {1} Faces.".format(frameIndex, len(faces)));

		for (top, right, bottom, left) in faces:
			#print("[INFO] Object found. Saving locally.");
			print("A face is located at pixel location Top: {}, Left: {}, Bottom: {}, Right: {}".format(top, left, bottom, right))
			match_image = frame[top:bottom, left:right];
			cv2.imwrite(videoOutputDirectory + str(frameIndex) + '_(' + str(top) + ',' + str(right) + ')(' + str(bottom) + ',' + str(left) + ')_faces_M4.jpg', match_image);
##METHOD 4 -- STOP

##METHOD 5 -- START
	if True:
		# detect faces in image
		faces = faceDetector(cv2.cvtColor(frame, cv2.COLOR_BGR2RGB))

		print("[INFO][5][{0}] Found {1} Faces.".format(frameIndex, len(faces)));
		# Now process each face we found
		for k, face in enumerate(faces):
			top = face.top()
			bottom = face.bottom()
			left = face.left()
			right = face.right()
			print("A face is located at pixel location Top: {}, Left: {}, Bottom: {}, Right: {}".format(top, left, bottom, right))
			match_image = frame[top:bottom, left:right];
			cv2.imwrite(videoOutputDirectory + str(frameIndex) + '_(' + str(top) + ',' + str(right) + ')(' + str(bottom) + ',' + str(left) + ')_faces_M5.jpg', match_image);
##METHOD 5 -- STOP
	
	frameIndex += 1

# When everything done, release the capture
cap.release()

Core Libraries and Initial Setup

The script begins by importing several critical libraries:

  • numpy: Essential for numerical computations in Python.
  • cv2 (OpenCV): A cornerstone in computer vision projects.
  • sys and os: For system-level operations and file management.
  • datetime: To handle date and time operations, crucial for timestamping.
  • face_recognition: A high-level facial recognition library.
  • dlib: A toolkit renowned for its machine learning and image processing capabilities.

Video File Handling

The script processes a video file whose path is passed as a command-line argument. It extracts the file name and prepares a unique output directory using the current date and time. This approach ensures that outputs from different runs are stored separately, avoiding overwrites and confusion.

Methodological Overview

The script showcases five distinct methodologies for detecting faces and people:

  1. HOG Person Detector with OpenCV: Uses the Histogram of Oriented Gradients (HOG) descriptor combined with a Support Vector Machine (SVM) for detecting people.
  2. Haar Cascade for Face Detection: Employs OpenCV’s Haar Cascade classifier, a widely-used method for face detection.
  3. Face Detection Using face_recognition (Method 1): Implements the face_recognition library’s default face detection technique.
  4. CNN-Based Face Detection Using face_recognition (Method 2): Utilizes a Convolutional Neural Network (CNN) model within the face_recognition library for face detection.
  5. Dlib’s Frontal Face Detector: Applies Dlib’s frontal face detector, effective for detecting faces oriented towards the camera.

Processing Workflow

The script processes the video on a frame-by-frame basis. For each frame, it:

  • Converts the frame to grayscale when necessary. This conversion can speed up detection in methods that don’t require color information.
  • Sequentially applies each of the five detection methods.
  • For each detected face or person, it outputs the coordinates and saves a cropped image of the detection to the output directory.

Iterative Frame Analysis

The script employs a loop to process each frame of the video. It includes a frame index to keep track of the number of frames processed, which is particularly useful for debugging and analysis purposes.

Resource Management

After processing the entire video, the script releases the video capture object, ensuring that system resources are appropriately freed.

Key Takeaways

This script is a rich demonstration of integrating various face and person detection techniques in a single Python application. It highlights the versatility and power of Python in handling complex tasks like video processing and computer vision. This analysis serves as a guide for developers and enthusiasts looking to understand or venture into the realm of image processing with Python.


Bug Fix: Resolving TypeError in Face Descriptor Computation

In the realm of facial recognition software development, it’s not uncommon to encounter a TypeError when integrating different libraries. We recently addressed an issue with the following error message:

TypeError: compute_face_descriptor(): incompatible function arguments.

This error resulted from a misalignment in the expected color format of image data between OpenCV and the face_recognition library. Here’s how we resolved it.

The Problem

OpenCV, a powerful library for image processing, represents images in BGR (Blue, Green, Red) color space by default. Conversely, the face_recognition library, which excels at recognizing and manipulating faces in images, expects images in RGB (Red, Green, Blue) format. When the image data does not match the expected color format, the compute_face_descriptor() function raises a TypeError.

Our Solution

To fix this issue, we modified how we convert the image from OpenCV’s BGR format to the RGB format required by the face_recognition library. Previously, we used a slicing technique to reverse the color channels:

# Incorrect color conversion
rgb_frame = frame[:, :, ::-1]

However, this approach led to the aforementioned TypeError. We realized that using OpenCV’s cvtColor function provides a more reliable conversion:

# Correct color conversion
rgb_frame = cv2.cvtColor(frame, cv2.COLOR_BGR2RGB)

The cvtColor function is explicitly designed for color space conversions, ensuring the image data is properly formatted for the face_recognition library.

Conclusion

With this small but crucial change, we eliminated the TypeError and improved the robustness of our facial recognition pipeline. This example serves as a reminder that understanding the intricacies of our libraries is essential for creating seamless and error-free integrations.For developers facing similar issues, consider the specific requirements of each function and library you’re using. It’s these details that can make or break your application.


Solving the ‘numpy._DTypeMeta’ Subscriptable Error in Python

Are you struggling with an unexpected TypeError when working with the OpenCV library in Python? If you’ve encountered the error message TypeError: ‘numpy._DTypeMeta’ object is not subscriptable and wonder what went wrong, you’re not alone. This error can be a significant roadblock when you’re trying to import the cv2 module, which is essential for computer vision tasks.

The root of this problem lies in a compatibility issue between numpy and other packages that rely on it, such as OpenCV. The ‘numpy._DTypeMeta’ object is a part of numpy’s core system, and when it’s not subscriptable, it suggests that the version of numpy you’re using is not playing nicely with the version of OpenCV.

Fortunately, the fix for this is often straightforward. By updating numpy to the latest version, you ensure that all the subscriptable features OpenCV needs are available. Here’s the magic command that usually does the trick:

pip install -U numpy;

This command asks pip, Python’s package installer, to upgrade numpy to the latest version available. The -U flag is short for --upgrade, which tells pip to overwrite the current version with the newest one.

Why does updating numpy work? It’s because newer versions of libraries like OpenCV often require the latest features and bug fixes from their dependencies. An outdated numpy package might not have the necessary functionality, leading to errors like the one mentioned.

So next time you face this TypeError, remember that a quick update of numpy could save the day. Keep your packages up to date, and you’ll minimize these sorts of issues significantly.

Remember, it’s good practice to keep your development environment updated. But always back up your work before doing so, as sometimes new versions can introduce their own issues. Happy coding!


Analyzing Data with Python: Counting how many times each value in a CSV occurs

Data analysis is an essential aspect of many fields, from business and research to sports and education. Python, with its versatile libraries, is a popular choice for data analysis tasks. In this blog post, we’ll explore a Python script that reads data from a CSV file and counts the occurrences of each value in 3 columns. The script can be a valuable tool for gaining insights into educational information datasets.

#!/bin/python

import csv

# Create empty dictionaries
d_university = dict()
d_country = dict()
d_region = dict()

with open('XtremeScores.csv') as f:
    reader = csv.reader(f, delimiter=',', quoting=csv.QUOTE_NONE)
    # Loop through each line of the file
    for line in reader:
        word = line[6]
        # Check if the word is already in dictionary
        if word in d_region:
            # Increment count of word by 1
            d_region[word] = d_region[word] + 1
        else:
            # Add the word to dictionary with count 1
            d_region[word] = 1

        word = line[5]
        # Check if the word is already in dictionary
        if word in d_country:
            # Increment count of word by 1
            d_country[word] = d_country[word] + 1
        else:
            # Add the word to dictionary with count 1
            d_country[word] = 1

        word = line[4]
        # Check if the word is already in dictionary
        if word in d_university:
            # Increment count of word by 1
            d_university[word] = d_university[word] + 1
        else:
            # Add the word to dictionary with count 1
            d_university[word] = 1

sorted_university = sorted(d_university.items(), key=lambda x:x[1], reverse=True)
print(sorted_university[:10])
sorted_country = sorted(d_country.items(), key=lambda x:x[1], reverse=True)
print(sorted_country[:10])
sorted_region = sorted(d_region.items(), key=lambda x:x[1], reverse=True)
print(sorted_region[:10])

Let’s break down the code step by step:

#!/bin/python

import csv

The script starts by importing the csv module, which is essential for handling comma-separated value (CSV) files.

# Create empty dictionaries
d_university = dict()
d_country = dict()
d_region = dict()

Three empty dictionaries, d_university, d_country, and d_region, are created. These dictionaries will be used to store the counts of universities, countries, and regions, respectively.

with open('XtremeScores.csv') as f:
    reader = csv.reader(f, delimiter=',', quoting=csv.QUOTE_NONE)

The script opens a CSV file named ‘XtremeScores.csv’ using a with statement. The csv.reader object is used to read the contents of the file. We specify that the delimiter is a comma (,), and we don’t want to perform any special quoting.

    # Loop through each line of the file
    for line in reader:

A for loop iterates through each line in the CSV file. The variable line contains the data for each row in the file.

        word = line[6]

The code extracts the word at index 6 (zero-based index) from the current line. In this context, it typically represents a region.

        # Check if the word is already in the dictionary
        if word in d_region:
            # Increment count of word by 1
            d_region[word] = d_region[word] + 1
        else:
            # Add the word to the dictionary with count 1
            d_region[word] = 1

The code checks if the extracted word (representing a region) is already present in the d_region dictionary. If it is, it increments the count by 1. If not, it adds the word to the dictionary with a count of 1. This process counts the occurrences of each region in the dataset.

The code repeats the same process for words representing countries (at index 5) and universities (at index 4), using the d_country and d_university dictionaries, respectively.

sorted_university = sorted(d_university.items(), key=lambda x:x[1], reverse=True)
print(sorted_university[:10])

After counting the universities, the code sorts them in descending order of frequency and prints the top 10 universities based on their occurrence.

sorted_country = sorted(d_country.items(), key=lambda x:x[1], reverse=True)
print(sorted_country[:10])

Similarly, it does the same for countries and prints the top 10 countries.

sorted_region = sorted(d_region.items(), key=lambda x:x[1], reverse=True)
print(sorted_region[:10])

Finally, it sorts and prints the top 10 regions based on their occurrence.

In summary, this Python script provides a simple but effective way to analyze data in a CSV file, specifically counting universities, countries, and regions. It leverages dictionaries to maintain counts and uses the csv module for reading data from the file. This can be a useful starting point for more advanced data analysis tasks and visualization in Python.