Web Computer Vision Applications Using OpenCV and Flask: A Beginner Tutorial
OpenCV Tutorial
Web Computer Vision Applications Using OpenCV and Flask: A Beginner Tutorial

Web computer vision applications

using OpenCV and Flask

In this section, we will see how to create web computer vision applications using

OpenCV and Flask. We will start with the equivalent Hello world application

using OpenCV and Flask.

A minimal example to introduce

OpenCV and Flask

Script hello_opencv.py is coded in order to show how you can use OpenCV to

perform a very basic web computer vision application. The code of this script is

shown next:

# Import required packages:

import cv2

from flask import Flask, request, make_response

import numpy as np

import urllib.request

app = Flask(__name__)

@app.route('/canny', methods=['GET'])

def canny_processing():

# Get the image:

with urllib.request.urlopen(request.args.get('url')) as url:

image_array = np.asarray(bytearray(url.read()), dtype=np.uint8)

# Convert the image to OpenCV format:

img_opencv = cv2.imdecode(image_array, -1)

# Convert image to grayscale:

gray = cv2.cvtColor(img_opencv, cv2.COLOR_BGR2GRAY)

# Perform canny edge detection:

edges = cv2.Canny(gray, 100, 200)

# Compress the image and store it in the memory buffer:

retval, buffer = cv2.imencode('.jpg', edges)

# Build the response:

response = make_response(buffer.tobytes())

response.headers['Content-Type'] = 'image/jpeg'

# Return the response:

return response

if __name__ == "__main__":

# Add parameter host='0.0.0.0' to run on your machines IP address:

app.run(host='0.0.0.0')

The previous code can be explained with the help of the following steps:

1. The first step is to import the required packages. In this example, we have

used the route() decorator to bind the canny_processing() function to

the /canny URL. Additionally, the url parameter is also needed to perform

the GET request correctly. In order to get this parameter,

the request.args.get() function is used.

2. The next step is to read the image this URL holds as follows:

with urllib.request.urlopen(request.args.get('url')) as url:

image_array = np.asarray(bytearray(url.read()), dtype=np.uint8)

This way, the image is read as an array.

3. The next step is to convert the image to OpenCV format and perform

Canny edge processing, which should be performed on the corresponding

grayscale image:

# Convert the image to OpenCV format:

img_opencv = cv2.imdecode(image_array, -1)

# Convet image to grayscale:

gray = cv2.cvtColor(img_opencv, cv2.COLOR_BGR2GRAY)

# Perform canny edge detection:

edges = cv2.Canny(gray, 100, 200)

4. The next step is to compress the image and store it in the memory buffer,

shown as follows:

# Compress the image and store it in the memory buffer:

retval, buffer = cv2.imencode('.jpg', edges)

5. The final step is to build and return the response to the client, as follows:

# Build and return the response:

response = make_response(buffer.tobytes())

response.headers['Content-Type'] = 'image/jpeg'

# Return the response:

return response

If we run the script ($ python hello_opencv.py), the server will be running and, then,

if we perform a GET request from a client (for example, our mobile phone), we

will get the processed image, which can be seen in the next screenshot.

Additionally, take into consideration that you may need to disable the firewall

(on Windows) to be able to perform these requests:

As shown, we have performed the following GET request:

http://192.168.1.101:5000/canny?url=https://raw.githubusercontent.com/opencv/opencv/master/samples/data/lena.jpg

Here, https://raw.githubusercontent.com/opencv/opencv/master/samples/data/lena.jpg is the

image we want to process with our web computing vision application.

Minimal face API using OpenCV

In this example, we will see how to create a web face API using OpenCV and

Flask. The minimal_face_api project codes the web server application. The

main.py script is responsible for parsing the requests and building the response to

the client. The code of this script is as follows:

# Import required packages:

from flask import Flask, request, jsonify

import urllib.request

from face_processing import FaceProcessing

# Initialize application and FaceProcessing():

app = Flask(__name__)

fc = FaceProcessing()

@app.errorhandler(400)

def bad_request(e):

# return also the code error

return jsonify({"status": "not ok", "message": "this server could not understand your request"

@app.errorhandler(404)

def not_found(e):

# return also the code error

return jsonify({"status": "not found", "message": "route not found"}), 404

@app.errorhandler(500)

def not_found(e):

# return also the code error

return jsonify({"status": "internal error", "message": "internal error occurred in server"

@app.route('/detect', methods=['GET', 'POST', 'PUT'])

def detect_human_faces():

if request.method == 'GET':

if request.args.get('url'):

with urllib.request.urlopen(request.args.get('url')) as url:

return jsonify({"status": "ok", "result": fc.face_detection(url.read())})

else:

return jsonify({"status": "bad request", "message": "Parameter url is not present"

elif request.method == 'POST':

if request.files.get("image"):

return jsonify({"status": "ok", "result": fc.face_detection(request.files["image"

else:

return jsonify({"status": "bad request", "message": "Parameter image is not present"

else:

return jsonify({"status": "failure", "message": "PUT method not supported for API"

if __name__ == "__main__":

# Add parameter host='0.0.0.0' to run on your machines IP address:

app.run(host='0.0.0.0')

As you can see, we make use of the jsonify() function to create the JSON

representation of the given arguments, with an application/json MIME type. JSON

can be considered the de facto standard for information exchange and, in this

example, we will return a JSON response, rather than return an image as we

have performed in the previous example. As you can also see, this API supports

both GET and POST requests. Additionally, in the main.py script, we also register

error handlers by decorating functions with errorhandler(). Remember also to set

the error code when returning the response to the client.

The image processing is performed in the face_processing.py script, where the

FaceProcessing() class is coded:

# Import required packages:

import cv2

import numpy as np

import os

class FaceProcessing(object):

def __init__(self):

self.file = os.path.join(os.path.join(os.path.dirname(__file__), "data"), "haarcascade_frontalface_alt.xml"

self.face_cascade = cv2.CascadeClassifier(self.file)

def face_detection(self, image):

# Convert image to OpenCV format:

image_array = np.asarray(bytearray(image), dtype=np.uint8)

img_opencv = cv2.imdecode(image_array, -1)

output = []

# Detect faces and build output:

gray = cv2.cvtColor(img_opencv, cv2.COLOR_BGR2GRAY)

faces = self.face_cascade.detectMultiScale(gray, scaleFactor=1.1, minNeighbors=5

for face in faces:

# face.tolist(): returns a copy of the array data as a Python list

x, y, w, h = face.tolist()

face = {"box": [x, y, x + w, y + h]}

output.append(face)

# Return output:

return output

The face_detection() method performs face detection by using the

OpenCV detectMultiScale() function. For every detected face, we will get its

coordinates, (x, y, w, h), and build the box by encoding the detection in a proper

format:

face = {"box": [x, y, x + w, y + h]}

Finally, we add the encoded face detection to the output:

output.append(face)

When all the detected faces are added to the output, we will return it.

When all the detected faces are added to the output, we will return it.

To make use of this API, we can perform a GET request from the browser in the

same way as we performed in the previous examples. Additionally, as our API

also supports POST requests, we have included two scripts to test the functionality

of this API. These scripts perform both GET and POST requests to see how you can

interact with the aforementioned face API. More specifically, demo_request.py

performs several requests to the face API in order to obtain different responses

and, also, to see how error handling works.

In this script, we first perform a GET request using an incorrect URL:

# Import required packages:

import requests

FACE_DETECTION_REST_API_URL = "http://localhost:5000/detect"

FACE_DETECTION_REST_API_URL_WRONG = "http://localhost:5000/process"

IMAGE_PATH = "test_face_processing.jpg"

URL_IMAGE = "https://raw.githubusercontent.com/opencv/opencv/master/samples/data/lena.jpg"

# Submit the GET request:

r = requests.get(FACE_DETECTION_REST_API_URL_WRONG)

# See the response:

print("status code: {}".format(r.status_code))

print("headers: {}".format(r.headers))

print("content: {}".format(r.json()))

In this case, we get the following:

status code: 404

headers: {'Content-Type': 'application/json', 'Content-Length': '51', 'Server': 'Werkzeug/0.14.1 Python/3.6.6', 'Date': 'Sat, 16 Feb 2019 19:20:25 GMT'}

content: {'message': 'route not found', 'status': 'not found'}

The obtained status code (404) means that the client could communicate with the

server, but the server could not find what was requested. This is because the

URL of the request (http://localhost:5000/process) is incorrect.

The second request we perform is a correct GET request:

# Submit the GET request:

payload = {'url': URL_IMAGE}

r = requests.get(FACE_DETECTION_REST_API_URL, params=payload)

# See the response:

print("status code: {}".format(r.status_code))

print("headers: {}".format(r.headers))

print("content: {}".format(r.json()))

In this case, we get the following:

status code: 200

headers: {'Content-Type': 'application/json', 'Content-Length': '53', 'Server': 'Werkzeug/0.14.1 Python/3.6.6', 'Date': 'Sat, 16 Feb 2019 19:20:31 GMT'}

content: {'result': [{'box': [213, 200, 391, 378]}], 'status': 'ok'}

The status code (200) indicates that the request has been performed successfully.

Additionally, you can also see that one face has been detected corresponding to

Lenna's face.

The third request we perform is also a GET request, but the payload is missing:

# Submit the GET request:

r = requests.get(FACE_DETECTION_REST_API_URL)

# See the response:

print("status code: {}".format(r.status_code))

print("headers: {}".format(r.headers))

print("content: {}".format(r.json()))

In this case, the response we get is as follows:

status code: 400

headers: {'Content-Type': 'application/json', 'Content-Length': '66', 'Server': 'Werkzeug/0.14.1 Python/3.6.6', 'Date': 'Sat, 16 Feb 2019 19:20:32 GMT'}

content: {'message': 'Parameter url is not present', 'status': 'bad request'}

The status code (400) means a bad request. As you can see, the url parameter is

missing.

The fourth request we perform is a POST request with the correct payload:

# Load the image and construct the payload:

image = open(IMAGE_PATH, "rb").read()

payload = {"image": image}

# Submit the POST request:

r = requests.post(FACE_DETECTION_REST_API_URL, files=payload)

# See the response:

print("status code: {}".format(r.status_code))

print("headers: {}".format(r.headers))

print("content: {}".format(r.json()))

We get the following response:

status code: 200

headers: {'Content-Type': 'application/json', 'Content-Length': '449', 'Server': 'Werkzeug/0.14.1 Python/3.6.6', 'Date': 'Sat, 16 Feb 2019 19:20:34 GMT'}

content: {'result': [{'box': [151, 29, 193, 71]}, {'box': [77, 38, 115, 76]}, {'box': [448, 37, 490, 79]}, {'box': [81, 172, 127, 218]}, {'box': [536, 47, 574, 85]}, {'box': [288, 173, 331, 216]}, {'box': [509, 170, 553, 214]}, {'box': [357, 48, 399, 90]}, {'box': [182, 179, 219, 216]}, {'box': [251, 38, 293, 80]}, {'box': [400, 174, 444, 218]}, {'box': [390, 87, 430, 127]}, {'box': [54, 89, 97, 132]}, {'box': [499, 91, 542, 134]}, {'box': [159, 95, 198, 134]}, {'box': [310, 115, 344, 149]}, {'box': [225, 116, 265, 156]}], 'status': 'ok'}

As you can see, many faces are detected. This is because test_face_processing.jpg

contains a lot of faces.

The final request is PUT request:

# Submit the PUT request:

r = requests.put(FACE_DETECTION_REST_API_URL, files=payload)

# See the response:

print("status code: {}".format(r.status_code))

print("headers: {}".format(r.headers))

print("content: {}".format(r.json()))

We get the following output:

status code: 405

headers: {'Content-Type': 'application/json', 'Content-Length': '66', 'Server': 'Werkzeug/0.14.1 Python/3.6.6', 'Date': 'Sat, 16 Feb 2019 19:20:35 GMT'}

content: {'message': 'PUT method not supported for API', 'status': 'failure'}

As you can see, the PUT method is not supported. This face API only supports GET

and POST methods.

As you could see in the previous responses, when the request was performed

successfully, we got the detected faces as JSON data. In order to see how to

parse the response and use it to draw the detected faces, we can code the

script demo_request_drawing.py as follows:

# Import required packages:

import cv2

import numpy as np

import requests

from matplotlib import pyplot as plt

def show_img_with_matplotlib(color_img, title, pos):

"""Shows an image using matplotlib capabilities"""

img_RGB = color_img[:, :, ::-1]

ax = plt.subplot(1, 1, pos)

plt.imshow(img_RGB)

plt.title(title)

plt.axis('off')

FACE_DETECTION_REST_API_URL = "http://localhost:5000/detect"

IMAGE_PATH = "test_face_processing.jpg"

# Load the image and construct the payload:

image = open(IMAGE_PATH, "rb").read()

payload = {"image": image}

# Submit the POST request:

r = requests.post(FACE_DETECTION_REST_API_URL, files=payload)

# See the response:

print("status code: {}".format(r.status_code))

print("headers: {}".format(r.headers))

print("content: {}".format(r.json()))

# Get JSON data from the response and get 'result':

json_data = r.json()

result = json_data['result']

# Convert the loaded image to the OpenCV format:

image_array = np.asarray(bytearray(image), dtype=np.uint8)

img_opencv = cv2.imdecode(image_array, -1)

# Draw faces in the OpenCV image:

for face in result:

left, top, right, bottom = face['box']

# To draw a rectangle, you need top-left corner and bottom-right corner of rectangle:

cv2.rectangle(img_opencv, (left, top), (right, bottom), (0, 255, 255), 2)

# Draw top-left corner and bottom-right corner (checking):

cv2.circle(img_opencv, (left, top), 5, (0, 0, 255), -1)

cv2.circle(img_opencv, (right, bottom), 5, (255, 0, 0), -1)

# Create the dimensions of the figure and set title:

fig = plt.figure(figsize=(8, 8))

plt.suptitle("Using face detection API", fontsize=14, fontweight='bold')

fig.patch.set_facecolor('silver')

# Show the output image

show_img_with_matplotlib(img_opencv, "face detection", 1)

# Show the Figure:

plt.show()

As it can be seen above, we first load the image and construct the payload. Then,

we perform a POST request. Afterwards, we get the JSON data from the response

and get the result:

# Get JSON data from the response and get 'result':

json_data = r.json()

result = json_data['result']

At this point, we can draw the detected faces, iterating over all the detected

faces, as follows:

# Draw faces in the OpenCV image:

for face in result:

left, top, right, bottom = face['box']

# To draw a rectangle, you need top-left corner and bottom-right corner of rectangle:

cv2.rectangle(img_opencv, (left, top), (right, bottom), (0, 255, 255), 2)

# Draw top-left corner and bottom-right corner (checking):

cv2.circle(img_opencv, (left, top), 5, (0, 0, 255), -1)

cv2.circle(img_opencv, (right, bottom), 5, (255, 0, 0), -1)

For each detected face we draw a rectangle and also top-left and bottom-right

points. The output of this script can be seen in the next screenshot:

Faces detected with API using OpenCV

As shown in the previous screenshot, all the faces have been detected.

Related

Understanding Support Vector Machine (SVM) in OpenCV

A Support Vector Machine (SVM) is a supervised learning technique that constructs a hyperplane or a set of hyperplanes in a high-dimensional space by best separating the training examples according to its assigned class. This can be seen in the next diagram, where the green line is the representation of the hyperplane that best separates the two classes because the distance to the nearest element of each of the two classes is the largest: In the first case, the decision boundary is a line while, in the second case, the decision boundary is a circumference. The dashed lines and the dashed circumference represent other decision boundaries, but they do not best separate both classes. SVM implementation in OpenCV is based on LIBSVM: A library for support vector machines (2011) (https://www.csie.ntu.edu.tw/~cjlin/libsvm/). To create an empty model, the cv2.ml.SVM_create() function is used. Next, the main parameters should be assigned to the model: svmType: This sets the type of the SVM. See LibSVM for details. Possible values are as follows: SVM_C_SVC: C-support vector classification that can be used for n-class classification (n ≥ 2) NU_SVC: -support vector classification ONE_CLASS: Distribution estimation (one-class SVM) EPS_SVR: -support vector regression NU_SVR: -support vector regression kernelType: This sets the kernel type of the SVM. See LibSVM for details. Possible values are as follows: LINEAR: Linear kernel POLY: Polynomial kernel RBF: Radial Basis Function (RBF), a good choice in most cases SIGMOID: Sigmoid kernel CHI2: Exponential Chi2 kernel, similar to the RBF kernel INTER: Histogram intersection kernel; a fast kernel Kernel function selection can be tricky and is dataset dependent. In this sense, the RBF kernel is considered, in general, a good first choice because this kernel nonlinearly maps samples into a higher dimensional space dealing with cases when the relation between class labels and attributes is nonlinear. See A Practical Guide to Support Vector Classification (2003) for further details. degree: Parameter degree of a kernel function (POLY) gamma: The parameter of a kernel function (POLY/RBF/SIGMOID/CHI2) coef0: The coef0 parameter of a kernel function (POLY/SIGMOID) Cvalue: The C parameter of an SVM optimization problem (C_SVC/EPS_SVR/NU_SVR) nu: The parameter of a SVM optimization problem (NU_SVC/ONE_CLASS/NU_SVR) p: The parameter of an SVM optimization problem (EPS_SVR) classWeights: Optional weights in the C_SVC problem, assigned to particular classes termCrit: Termination criteria of the iterative SVM training procedure The default constructor initializes the structure with the following values: svmType: C_SVC, kernelType: RBF, degree: 0, gamma: 1, coef0: 0, C: 1, nu: 0, p: 0, classWeights: 0, termCrit: TermCriteria(MAX_ITER+EPS, 1000, FLT_EPSILON ) In this section, we will see two examples of how to use SVM in OpenCV. In the first example, an intuitive understanding of SVM will be given, and in the […]

Recognizing Handwritten Digits Using K-nearest Neighbor in OpenCV

Recognizing handwritten digits using k-nearest neighbor We are going to see how to perform handwritten digit recognition using the kNN classifier. We will start with a basic script that achieves an acceptable accuracy, and we will modify it to increase its performance. In these scripts, the training data is composed of handwritten digits. Instead of having many images, OpenCV provides a big image with handwritten digits inside. This image has a size of 2,000 x 1,000 pixels. Each digit is 20 x 20 pixels. Therefore, we have a total of 5,000 digits (100 x 50): In the knn_handwritten_digits_recognition_introduction.py script, we are going to perform our first approach trying to recognize digits using the kNN classifier. In this first approach, we will use raw pixel values as features. This way, each descriptor will be a size of 400 (20 x 20). The first step is to load all digits from the big image and to assign the corresponding label for each digit. This is performed with the load_digits_and_labels() function: digits, labels = load_digits_and_labels('digits.png') The code for the load_digits_and_labels() function is as follows: def load_digits_and_labels(big_image): """Returns all the digits from the 'big' image and creates the corresponding labels for each image""" # Load the 'big' image containing all the digits: digits_img = cv2.imread(big_image, 0) # Get all the digit images from the 'big' image: number_rows = digits_img.shape[1] / SIZE_IMAGE rows = np.vsplit(digits_img, digits_img.shape[0] / SIZE_IMAGE) digits = [] for row in rows: row_cells = np.hsplit(row, number_rows) for digit in row_cells: digits.append(digit) digits = np.array(digits) # Create the labels for each image: labels = np.repeat(np.arange(NUMBER_CLASSES), len(digits) / NUMBER_CLASSES) return digits, labels In the previous function, we first load the 'big' image and, afterwards, we get all the digits inside it. The last step of the previous function is to create the labels for each of the digits. The next step performed in the script is to compute the descriptors for each image. In this case, the raw pixels are the feature descriptors: # Compute the descriptors for all the images. # In this case, the raw pixels are the feature descriptors raw_descriptors = [] for img in digits: raw_descriptors.append(np.float32(raw_pixels(img))) raw_descriptors = np.squeeze(raw_descriptors) At this point, we split the data into training and testing (50% for each). Therefore, 2,500 digits will be used to train the classifier, and 2,500 digits will be used to test the trained classifier: partition = int(0.5 * len(raw_descriptors)) raw_descriptors_train, raw_descriptors_test = np.split(raw_descriptors, [partition]) labels_train, labels_test = np.split(labels, [partition]) Now, we can train the kNN model using knn.train() method and test it using get_accuracy() function: # Train the KNN model: print('Training KNN model - raw pixels as features') […]

Understand Thresholding Algorithms Using scikit-image

Introducing thresholding with scikit- image In order to test scikit-image, we are going to threshold a test image using Otsu's binarization algorithm. In order to try this method, the first step is to import the required packages. In this case, in connection with scikit-image as follows: from skimage.filters import threshold_otsu from skimage import img_as_ubyte The key code to apply Otsu's binarization algorithm with scikit-image is the following: thresh = threshold_otsu(gray_image) binary = gray_image > thresh binary = img_as_ubyte(binary) The threshold_otsu(gray_image) function returns the threshold value based on Otsu's binarization algorithm. Afterwards, with this value, the binary image is constructed (dtype= bool), which should be converted to 8-bit unsigned integer format (dtype= uint8) for proper visualization. The img_as_ubyte() function is used for this purpose. The full code for this example can be seen in the thresholding_scikit_image_otsu.py script. The output can be seen in the following screenshot: We will now try out some thresholding techniques with scikit-image. Trying out more thresholding techniques with scikit-image We are going to threshold a test image comparing Otsu's, triangle, Niblack's, and Sauvola's thresholding techniques. Otsu and triangle are global thresholding techniques, while Niblack and Sauvola are local thresholding techniques. Local thresholding techniques are considered a better approach when the background is not uniform. For more information about Niblack's and Sauvola's thresholding algorithms, see An Introduction to Digital Image Processing (1986) and Adaptive document image binarization (2000), respectively. The full code for this example can be seen in the thresholding_scikit_image_techniques.py script. In order to try these methods, the first step is to import the required packages. In this case, in connection with scikit-image as follows: from skimage.filters import (threshold_otsu, threshold_triangle, threshold_niblack, threshold_sauvola) from skimage import img_as_ubyte In order to perform the thresholding operations with scikit-image, we call each thresholding method (threshold_otsu(), threshold_niblack(), threshold_sauvola(), and threshold_triangle()): # Trying Otsu's scikit-image algorithm: thresh_otsu = threshold_otsu(gray_image) binary_otsu = gray_image > thresh_otsu binary_otsu = img_as_ubyte(binary_otsu) # Trying Niblack's scikit-image algorithm: thresh_niblack = threshold_niblack(gray_image, window_size=25, k=0.8) binary_niblack = gray_image > thresh_niblack binary_niblack = img_as_ubyte(binary_niblack) # Trying Sauvola's scikit-image algorithm: thresh_sauvola = threshold_sauvola(gray_image, window_size=25) binary_sauvola = gray_image > thresh_sauvola binary_sauvola = img_as_ubyte(binary_sauvola) # Trying triangle scikit-image algorithm: thresh_triangle = threshold_triangle(gray_image) binary_triangle = gray_image > thresh_triangle binary_triangle = img_as_ubyte(binary_triangle) The output can be seen in the next screenshot: […]

Deploying a Flask Application to the Cloud: A Step Guide

Deploying a Flask application to the cloud If you have developed a Flask application you can run in your computer, you can easily make it public by deploying it to the cloud. There are a lot of options if you want to deploy your application to the cloud (for example, Google App Engine: https://cloud.google.com/appengine/, Microsoft Azure: https://azure.microsoft. com, Heroku: https://devcenter.heroku.com/, and Amazon Web Services: https://aws.am azon.com, among others). Additionally, you can also use PythonAnywhere (www.pyth onanywhere.com), which is a Python online integrated development environment (IDE) and web hosting environment, making it easy to create and run Python programs in the cloud. PythonAnywhere is very simple, and also the recommended way of hosting machine learning-based web applications. PythonAnywhere provides some interesting features, such as WSGI-based web hosting (for example, Django, Flask, and Web2py). In this section, we will see how to create a Flask application and how to deploy it on PythonAnywhere. To show you how to deploy a Flask application to the cloud using PythonAnywhere, we are going to use the code of the mysite project. This code is very similar (with minor modifications) to the minimal face API we have previously seen in this chapter. These modifications will be explained after creating the site: 1. The first step is to create a PythonAnywhere account. For this example, a beginner account is enough (https://www.pythonanywhere.com/pricing/): 2. After registering, you will have access to your dashboard. This can be seen in the next screenshot: As you can see, I have created the user opencv. 3. The next step is to click on Web menu and then, click the Add new web app button, as shown in the next screenshot: 4. At this point, you are ready to create the new web app, as shown in the next screenshot: 5. Click Next and then, click Flask and also, click on the latest version of Python. Finally, click Next to accept the project path: This will create a Hello world Flask application that you can see if you visit https://your_user_name.pythonanywhere.com. In my case, the URL will be https://opencv.pythonanywhere.com. 6. At this point, we are ready to upload our own project. The first step is to click on Go to directory in the Code section of the Web menu, as shown in the next screenshot: 7. We can upload files to our site using the Upload a file button. We have uploaded three files, as follows: flask_app.py face_processing.py haarcascade_frontalface_alt.xml This can be seen in the next screenshot: You can see the uploaded content of these files by clicking the download icon. In this case, you can see the content of these files in the following URLs: […]

Recognizing Contours of Images in OpenCV: A Simple Guide

Recognizing contours We have previously introduced cv2.approxPolyDP(), which can be used to approximate one contour with another with fewer points using the Douglas- Peucker algorithm. A key parameter in this function is epsilon, which sets the approximation accuracy. In contours_shape_recognition.py, we will make use of cv2.approxPolyDP() in order to recognize the contours (for example, triangle, square, rectangle, pentagon, or hexagon, among others) based on the number of detected vertices in the decimated contour (the output of cv2.approxPolyDP()). In order to decimate the number of points, given a certain contour, we first compute the perimeter of the contour. Based on the perimeter, the epsilon parameter is established. This way, the decimated contour is invariant to scale. The epsilon parameter is calculated as follows: epsilon = 0.03 * perimeter The constant 0.03 is established after several tests. For example, if this constant is bigger (for example, 0.1), the epsilon parameter will also be bigger and, hence, the approximation accuracy will be decreased. This results in a contour with fewer points, and missing vertices are obtained. Therefore, recognition of the contours is performed incorrectly because it is based on the number of detected vertices. On the other hand, if this constant is smaller (for example, 0.001), the epsilon parameter will also be smaller and, hence, the approximation accuracy will increased, resulting in an approximation contour with more points. In this situation, the recognition of the contours is also performed incorrectly because false vertices are obtained. The output of the contours_shape_recognition.py script can be seen in the next screenshot: In the previous screenshot, the key steps (thresholding, contour approximation, and contour recognition) are shown.

Implement Simple Thresholding to Images in OpenCV: A Beginner Guide

In order to perform simple thresholding, OpenCV provides the cv2.threshold() function that was briefly introduced in the previous section. The signature for this method is as follows: cv2.threshold(src, thresh, maxval, type, dst=None) -> retval, dst The cv2.threshold() function applies a fixed-level thresholding to the src input array (multiple-channel, 8-bit or 32-bit floating point). The fixed level is adjusted by the thresh parameter, which sets the threshold value. The type parameter sets the thresholding type, which will be further explained in the next subsection. Different types are as follows: cv2.THRESH_BINARY cv2.THRESH_BINARY_INV cv2.THRESH_TRUNC cv2.THRESH_TOZERO cv2.THRESH_TOZERO_INV cv2.THRESH_OTSU cv2.THRESH_TRIANGLE Additionally, the maxval parameter sets the maximum value to use only with the cv2.THRESH_BINARY and cv2.THRESH_BINARY_INV thresholding types. Finally, the input image should be single channel only in the cv2.THRESH_OTSU and cv2.THRESH_TRIANGLE thresholding types. In this section, we will examine all the possible configurations to understand all of these parameters. Thresholding types The types of thresholding operation are described according to its formulation. Take into account that src is the source (original) image, and dst corresponds to the destination (result) image after thresholding. In this sense, src(x, y) will correspond to the intensity of the pixel (x, y) of the source image, and dst(x, y) will correspond to the intensity of the pixel (x, y) of the destination image. Here is the formula for cv2.THRESH_BINARY: So, if the intensity of the pixel src(x, y) is higher than thresh, then the new pixel intensity is set to a maxval parameter. Otherwise, the pixels are set to 0. Here is the formula for cv2.THRESH_BINARY_INV: So, if the intensity of the pixel src(x, y) is higher than thresh, then the new pixel intensity is set to 0. Otherwise, it is set to maxval. Here is the formula for cv2.THRESH_TRUNC: So, if the intensity of the pixel src(x, y) is higher than thresh, then the new pixel intensity is set to threshold. Otherwise, it is set to src(x, y). Here is the formula for cv2.THRESH_TOZERO: So, if the intensity of the pixel src(x, y) is higher than thresh, the new pixel value will be set to src(x, y). Otherwise, it is set to 0. Here is the formula for cv2.THRESH_TOZERO_INV: So, if the intensity of the pixel src(x, y) is greater than thresh, the new pixel value will be set to 0. Otherwise, it is set to src(x, y). Also, the special cv2.THRESH_OTSU and cv2.THRESH_TRIANGLE values can be combined with one of the values previously introduced (cv2.THRESH_BINARY, cv2.THRESH_BINARY_INV, cv2.THRESH_TRUNC, cv2.THRESH_TOZERO, and cv2.THRESH_TOZERO_INV). In these cases (cv2.THRESH_OTSU and cv2.THRESH_TRIANGLE), the thresholding operation (implemented only for 8-bit images) computes the optimal threshold value instead of the specified thresh value. It should be noted that the thresholding operation returns the computed optimal threshold value. The thresholding_simple_types.py script helps you understand the aforementioned types. We use the same sample image introduced in the previous section, and we perform a thresholding operation with a fixed threshold value (thresh = 100) with all the previous types. […]