Title: Detecting ArUco markers with OpenCV and Python - PyImageSearch

URL Source: https://pyimagesearch.com/2020/12/21/detecting-aruco-markers-with-opencv-and-python/

Published Time: 2020-12-21T15:00:00+00:00

Markdown Content:
![Image 1: Detecting AruCo markers with OpenCV and Python](https://embed-ssl.wistia.com/deliveries/be0d27609b4564eda32e5905b845c5f0.webp?image_crop_resized=960x540)

In this tutorial you will learn how to detect ArUco markers in images and real-time video streams using OpenCV and Python.

![Image 2](data:image/svg+xml,%3Csvg%20xmlns='http://www.w3.org/2000/svg'%20viewBox='0%200%20748%20419'%3E%3C/svg%3E)

This blog post is part two in our three-part series on ArUco markers and fiducials:

1.  _[Generating ArUco markers with OpenCV and Python](https://pyimagesearch.com/2020/12/14/generating-aruco-markers-with-opencv-and-python/)_ (last week’s post)
2.  _Detecting ArUco markers in images and video with OpenCV_ (today’s tutorial)
3.  _Automatically determining ArUco marker type with OpenCV_ (next week’s post)

Last week we learned:

*   What an ArUco dictionary is
*   How to select an ArUco dictionary appropriate to our task
*   How to generate ArUco markers using OpenCV
*   How to create ArUco markers using online tools

Today we’re going to learn how to actually _detect_ ArUco markers using OpenCV.

**To learn how to detect ArUco markers in images and real-time video with OpenCV, _just keep reading._**

![Image 3](data:image/svg+xml,%3Csvg%20xmlns='http://www.w3.org/2000/svg'%20viewBox='0%200%20128%20128'%3E%3C/svg%3E)

#### Looking for the source code to this post?

[Jump Right To The Downloads Section](#download-the-code)

In the first part of this tutorial, you will learn about OpenCV’s `cv2.aruco` module and how to detect ArUco markers in images and real-time video streams by:

1.  Specifying your ArUco dictionary
2.  Creating the parameters to the ArUco detector (which is typically just a single line of code using the default values)
3.  Applying the `cv2.aruco.detectMarkers` to actually detect the ArUco markers in your image or video stream

From there we’ll review our project directory structure and implement two Python scripts:

1.  One Python script to detect ArUco markers in images
2.  And another Python script to detect ArUco markers in real-time video streams

We’ll wrap up this tutorial on ArUco marker detection using OpenCV with a discussion of our results.

### **OpenCV ArUCo marker detection**

![Image 4](data:image/svg+xml,%3Csvg%20xmlns='http://www.w3.org/2000/svg'%20viewBox='0%200%20700%20450'%3E%3C/svg%3E)

**Figure 1:** Flowchart of steps required to detect ArUco markers with OpenCV.

[As I discussed in last week’s tutorial](https://pyimagesearch.com/2020/12/14/generating-aruco-markers-with-opencv-and-python/), the OpenCV library comes with built-in ArUco support, both for _generating_ ArUco markers and for _detecting_ them.

Detecting ArUco markers with OpenCV is a three-step process made possible via the `` `cv2.aruco` `` submodule:

*   **Step #1:** Use the `cv2.aruco.Dictionary_get` function to grab the dictionary of ArUco markers we’re using.
*   **Step #2:** Define the ArUco detection parameters using `cv2.aruco.DetectorParameters_create`**.**
*   **Step #3:** Perform ArUco marker detection via the `cv2.aruco.detectMarkers` function.

Most important to us, we need to learn how to use the `detectMarkers` function.

### Understanding the _“cv2.aruco.detectMarkers”_ function

We can define an ArUco marker detection procedure in, essentially, only 3-4 lines of code:

arucoDict = cv2.aruco.Dictionary\_get(cv2.aruco.DICT\_6X6\_50)
arucoParams = cv2.aruco.DetectorParameters\_create()
(corners, ids, rejected) = cv2.aruco.detectMarkers(image, arucoDict,
	parameters=arucoParams)

The `` `cv2.aruco.detectMarkers` `` function accepts three arguments:

1.  `image`: The input image that we want to detect ArUco markers in
2.  `` `arucoDict` ``: The ArUco dictionary we are using
3.  `` `parameters` ``: The ArUco parameters used for detection (unless you have a good reason to modify the parameters, the default parameters returned by `cv2.aruco.DetectorParameters_create` are typically sufficient)

After applying ArUco tag detection, the `cv2.aruco.detectMarkers` method returns three values:

1.  `` `corners` ``: A list containing the _(x, y)_\-coordinates of our detected ArUco markers
2.  `` `ids` ``: The ArUco IDs of the detected markers
3.  `` `rejected` ``: A list of _potential_ markers that were found but ultimately rejected due to the inner code of the marker being unable to be parsed (visualizing the `rejected` markers is often useful for debugging purposes)

Later in this post you will see how to use the `cv2.aruco.detectMarkers` function to detect ArUco markers in images and real-time video streams.

### **Configuring your development environment**

In order to generate and detect ArUco markers, you need to have the OpenCV library installed.

Luckily, OpenCV is pip-installable:

$ pip install opencv-contrib-python

**If you need help configuring your development environment for OpenCV 4.3+, I _highly recommend_ that you read my [_pip install opencv_ guide](https://pyimagesearch.com/2018/09/19/pip-install-opencv/)** — it will have you up and running in a matter of minutes.

### **Having problems configuring your development environment?**

[![Image 5: Screenshot of PyImageSearch Plus and Google Colab Notebook with Jupyter logo overlaid](data:image/svg+xml,%3Csvg%20xmlns='http://www.w3.org/2000/svg'%20viewBox='0%200%20500%20334'%3E%3C/svg%3E)](https://pyimagesearch.com/pyimagesearch-plus/)

**Figure 2:** Having trouble configuring your dev environment? Want access to pre-configured Jupyter Notebooks running on Google Colab? Be sure to join [PyImageSearch Plus](https://pyimagesearch.com/pyimagesearch-plus/) — you’ll be up and running with this tutorial in a matter of minutes.

All that said, are you:

*   Short on time?
*   Learning on your employer’s administratively locked system?
*   Wanting to skip the hassle of fighting with the command line, package managers, and virtual environments?
*   **Ready to run the code _right now_ on your Windows, macOS, or Linux system?**

Then join [PyImageSearch Plus](https://pyimagesearch.com/pyimagesearch-plus/) today!

**Gain access to Jupyter Notebooks for this tutorial and other PyImageSearch guides that are _pre-configured_ to run on Google Colab’s ecosystem right in your web browser!** No installation required.

And best of all, these Jupyter Notebooks will run on Windows, macOS, and Linux!

### **Project structure**

Before we can learn how to detect ArUco tags in images, let’s first review our project directory structure so you have a good idea on how our project is organized and what Python scripts we’ll be using.

Start by using the **_“Downloads”_** section of this tutorial to download the source code and example images.

From there, we can inspect the project directory:

$ tree . --dirsfirst
.
├── images
│   ├── example\_01.png
│   └── example\_02.png
├── detect\_aruco\_image.py
└── detect\_aruco\_video.py

2 directories, 9 files

Today we’ll be reviewing two Python scripts:

1.  `` `detect_aruco_image.py` ``: Detects ArUco tags in _images._ The example images we’ll be applying this script to reside in the `` `images/` `` directory.
2.  `` `detect_aruco_video.py` ``: Applies ArUco detection to _real-time video streams._ I’ll be using my webcam as an example, but you could pipe in frames from a video file residing on disk as well.

With our project directory structure reviewed, we can move on to implementing ArUco tag detection with OpenCV!

### **Detecting ArUco markers with OpenCV in images**

Ready to learn how to detect ArUco tags in images using OpenCV?

Open up the `` `detect_aruco_image.py` `` file in your project directory, and let’s get to work:

\# import the necessary packages
import argparse
import imutils
import cv2
import sys

We start off by importing our required Python packages.

We’ll use `argparse` to parse our command line arguments, `imutils` for resizing images, `cv2` for our OpenCV bindings, and `sys`in the event that we need to prematurely exit our script.

Next comes our command line arguments:

\# construct the argument parser and parse the arguments
ap = argparse.ArgumentParser()
ap.add\_argument("-i", "--image", required=True,
	help="path to input image containing ArUCo tag")
ap.add\_argument("-t", "--type", type=str,
	default="DICT\_ARUCO\_ORIGINAL",
	help="type of ArUCo tag to detect")
args = vars(ap.parse\_args())

We have two command line arguments that we need to parse:

1.  `--image`: The path to the input image containing any ArUco tags we want to detect
2.  `` `--type` ``: The type of ArUco tags that we’ll be detecting

Setting the `` `--type` `` argument correctly is _absolutely critical_ to successfully detect ArUco tags in input images.

Simply put:

**The** `--type` **argument that we supply here _must_ be the same ArUco type used to _generate_ the tags in the input images.** If one type was used to generate ArUco tags and then you use a different type when trying to detect them, the detection will fail, and you’ll end up with zero detected ArUco tags.

**Therefore, you must make absolutely certain that the type used to _generate_ the ArUco tags is the same type you are using for the _detection_ phase.**

_**Note:** Don’t know what ArUco dictionary was used to generate the tags in your input images? Don’t worry, I’ve got you covered. Next week I’ll be showing you one of the Python scripts in my personal arsenal that I break out when I can’t identify what type a given ArUco tag is. This script **automatically identifies** the ArUco tag type. Stay tuned for next week’s tutorial, where I’ll review it in detail._

Next up comes our `` `ARUCO_DICT` ``, which enumerates each of the ArUco tag types that OpenCV supports:

\# define names of each possible ArUco tag OpenCV supports
ARUCO\_DICT = {
	"DICT\_4X4\_50": cv2.aruco.DICT\_4X4\_50,
	"DICT\_4X4\_100": cv2.aruco.DICT\_4X4\_100,
	"DICT\_4X4\_250": cv2.aruco.DICT\_4X4\_250,
	"DICT\_4X4\_1000": cv2.aruco.DICT\_4X4\_1000,
	"DICT\_5X5\_50": cv2.aruco.DICT\_5X5\_50,
	"DICT\_5X5\_100": cv2.aruco.DICT\_5X5\_100,
	"DICT\_5X5\_250": cv2.aruco.DICT\_5X5\_250,
	"DICT\_5X5\_1000": cv2.aruco.DICT\_5X5\_1000,
	"DICT\_6X6\_50": cv2.aruco.DICT\_6X6\_50,
	"DICT\_6X6\_100": cv2.aruco.DICT\_6X6\_100,
	"DICT\_6X6\_250": cv2.aruco.DICT\_6X6\_250,
	"DICT\_6X6\_1000": cv2.aruco.DICT\_6X6\_1000,
	"DICT\_7X7\_50": cv2.aruco.DICT\_7X7\_50,
	"DICT\_7X7\_100": cv2.aruco.DICT\_7X7\_100,
	"DICT\_7X7\_250": cv2.aruco.DICT\_7X7\_250,
	"DICT\_7X7\_1000": cv2.aruco.DICT\_7X7\_1000,
	"DICT\_ARUCO\_ORIGINAL": cv2.aruco.DICT\_ARUCO\_ORIGINAL,
	"DICT\_APRILTAG\_16h5": cv2.aruco.DICT\_APRILTAG\_16h5,
	"DICT\_APRILTAG\_25h9": cv2.aruco.DICT\_APRILTAG\_25h9,
	"DICT\_APRILTAG\_36h10": cv2.aruco.DICT\_APRILTAG\_36h10,
	"DICT\_APRILTAG\_36h11": cv2.aruco.DICT\_APRILTAG\_36h11
}

The _key_ to this dictionary is a human-readable string (i.e., the name of the ArUco tag type). The key then maps to the _value,_ which is OpenCV’s unique identifier for the ArUco tag type.

Using this dictionary we can take our input `--type` command line argument, pass it through `ARUCO_DICT`, and then obtain the unique identifier for the ArUco tag type.

The following Python shell block shows you a simple example of how this lookup operation is performed:

\>>> print(args)
{'type': 'DICT\_5X5\_100'}
>>> arucoType = ARUCO\_DICT\[args\["type"\]\]
>>> print(arucoType)
5
>>> 5 == cv2.aruco.DICT\_5X5\_100
True
>>> 

I covered the types of ArUco dictionaries, including their name conventions in my previous tutorial, _[Generating ArUco markers with OpenCV and Python](https://pyimagesearch.com/2020/12/14/generating-aruco-markers-with-opencv-and-python/)_.

If you would like more information on ArUco dictionaries, please refer there; otherwise, **simply understand that this dictionary lists out all possible ArUco tags that OpenCV can detect.**

Next, let’s move on to loading our input image from disk:

\# load the input image from disk and resize it
print("\[INFO\] loading image...")
image = cv2.imread(args\["image"\])
image = imutils.resize(image, width=600)

# verify that the supplied ArUCo tag exists and is supported by
# OpenCV
if ARUCO\_DICT.get(args\["type"\], None) is None:
	print("\[INFO\] ArUCo tag of '{}' is not supported".format(
		args\["type"\]))
	sys.exit(0)

# load the ArUCo dictionary, grab the ArUCo parameters, and detect
# the markers
print("\[INFO\] detecting '{}' tags...".format(args\["type"\]))
arucoDict = cv2.aruco.Dictionary\_get(ARUCO\_DICT\[args\["type"\]\])
arucoParams = cv2.aruco.DetectorParameters\_create()
(corners, ids, rejected) = cv2.aruco.detectMarkers(image, arucoDict,
	parameters=arucoParams)

**Lines 43 and 44** load our input `image` and then resize it to have a width of 600 pixels (such that the image can easily fit on our screen).

If you have a _high resolution_ input image that has _small ArUco tags,_ you may need to adjust this resizing operation; otherwise, the ArUco tags may be too small to detect after the resizing operation.

**Line 48** checks to see if the ArUco `--type` name exists in the `ARUCO_DICT`. If it _does not,_ then we exit the script, since we don’t have an ArUco dictionary available for the supplied `--type`.

Otherwise, we:

1.  Load the ArUco dictionary using the `--type` and the `ARUCO_DICT` lookup (**Line 56**)
2.  Instantiate our ArUco detector parameters (**Line 57**)
3.  Apply ArUco detection using the `cv2.aruco.detectMarkers` function (**Lines 58 and 59**)

The `cv2.aruco.detectMarkers` results in a 3-tuple of:

1.  `` `corners` ``: The (_x, y_)-coordinates of our detected ArUco markers
2.  `` `ids` ``: The identifiers of the ArUco markers (i.e., the ID encoded in the marker itself)
3.  `` `rejected` ``: A list of potential markers that were detected but ultimately rejected due to the code inside the marker not being able to be parsed

Let’s now start visualizing the ArUco markers we have detected:

\# verify \*at least\* one ArUco marker was detected
if len(corners) > 0:
	# flatten the ArUco IDs list
	ids = ids.flatten()

	# loop over the detected ArUCo corners
	for (markerCorner, markerID) in zip(corners, ids):
		# extract the marker corners (which are always returned in
		# top-left, top-right, bottom-right, and bottom-left order)
		corners = markerCorner.reshape((4, 2))
		(topLeft, topRight, bottomRight, bottomLeft) = corners

		# convert each of the (x, y)-coordinate pairs to integers
		topRight = (int(topRight\[0\]), int(topRight\[1\]))
		bottomRight = (int(bottomRight\[0\]), int(bottomRight\[1\]))
		bottomLeft = (int(bottomLeft\[0\]), int(bottomLeft\[1\]))
		topLeft = (int(topLeft\[0\]), int(topLeft\[1\]))

**Line 62** makes a check to ensure _at least_ one marker was detected.

If so, we proceed to flatten the ArUco `ids` list (**Line 64**) and then loop over each of the `corners` and `ids` together.

Each `markerCorner` is represented by a list of four _(x, y)_\-coordinates (**Line 70**).

**These _(x, y)_\-coordinates represent the top-left, top-right, bottom-right, and bottom-left corners of the ArUco tag (Line 71).** Furthermore, the _(x, y)_\-coordinates are _always_ returned in that order.

The `topRight`, `bottomRight`, `bottomLeft`, and `topLeft` variables are NumPy arrays; however, we need to cast them to integer values (`int`) such that we can use OpenCV’s drawing functions to visualize the markers on our `image` (**Lines 74-77**).

With the marker _(x, y)_\-coordinates cast of integers, we can draw them on `image`:

		# draw the bounding box of the ArUCo detection
		cv2.line(image, topLeft, topRight, (0, 255, 0), 2)
		cv2.line(image, topRight, bottomRight, (0, 255, 0), 2)
		cv2.line(image, bottomRight, bottomLeft, (0, 255, 0), 2)
		cv2.line(image, bottomLeft, topLeft, (0, 255, 0), 2)

		# compute and draw the center (x, y)-coordinates of the ArUco
		# marker
		cX = int((topLeft\[0\] + bottomRight\[0\]) / 2.0)
		cY = int((topLeft\[1\] + bottomRight\[1\]) / 2.0)
		cv2.circle(image, (cX, cY), 4, (0, 0, 255), -1)

		# draw the ArUco marker ID on the image
		cv2.putText(image, str(markerID),
			(topLeft\[0\], topLeft\[1\] - 15), cv2.FONT\_HERSHEY\_SIMPLEX,
			0.5, (0, 255, 0), 2)
		print("\[INFO\] ArUco marker ID: {}".format(markerID))

		# show the output image
		cv2.imshow("Image", image)
		cv2.waitKey(0)

**Lines 80-83** draw the bounding box of the ArUco tag on our `` `image` `` using `cv2.line` calls.

We then compute the center _(x, y)_\-coordinates of the ArUco marker and draw the center on the `image` via a call to `cv2.circle` (**Lines 87-89**).

Our final visualization step is to draw the `markerID` on the `image` and print it to our terminal (**Lines 92-95**).

The final output visualization is displayed to our screen on **Lines 98 and 99.**

### **OpenCV ArUco marker detection results**

Let’s put our OpenCV ArUco detector to work!

Use the **_“Downloads”_** section of this tutorial to download the source code and example images.

From there, you can execute the following command:

$ python detect\_aruco\_image.py --image images/example\_01.png --type DICT\_5X5\_100
\[INFO\] loading image...
\[INFO\] detecting 'DICT\_5X5\_100' tags...
\[INFO\] ArUco marker ID: 42
\[INFO\] ArUco marker ID: 24
\[INFO\] ArUco marker ID: 70
\[INFO\] ArUco marker ID: 66
\[INFO\] ArUco marker ID: 87

This image contains the ArUco markers that we generated in [last week’s blog post](https://pyimagesearch.com/2020/12/14/generating-aruco-markers-with-opencv-and-python/). I took each of the five individual ArUco markers and constructed a montage of them in a single image.

As **Figure 3** shows, we’ve been able to correctly detect each of the ArUco markers and extract their IDs.

Let’s try a different image, this one containing ArUco markers _not_ generated by us:

$ python detect\_aruco\_image.py --image images/example\_02.png --type DICT\_ARUCO\_ORIGINAL
\[INFO\] loading image...
\[INFO\] detecting 'DICT\_ARUCO\_ORIGINAL' tags...
\[INFO\] ArUco marker ID: 241
\[INFO\] ArUco marker ID: 1007
\[INFO\] ArUco marker ID: 1001
\[INFO\] ArUco marker ID: 923

![Image 6](data:image/svg+xml,%3Csvg%20xmlns='http://www.w3.org/2000/svg'%20viewBox='0%200%20700%20600'%3E%3C/svg%3E)

**Figure 4:** Detecting ArUco tags with OpenCV and Python.

**Figure 4** displays the results of our OpenCV ArUco detector. As you can see, I have detected each of the four ArUco markers on my [Pantone color matching card](https://www.pantone.com/pantone-color-match-card) (which we’ll be using in a number of upcoming tutorials, so get used to seeing it).

Looking at the command line arguments to the above script, you may be wondering:

> _“Hey Adrian, how did you know to use `DICT_ARUCO_ORIGINAL` and not some other ArUco dictionary.”_

**The short answer is that I _didn’t_ … at least, not initially.**

**I actually have a “secret weapon” up my sleeve.** I’ve put together a Python script that can _automatically_ infer ArUco marker type, _even if I don’t know what type of marker is in an image._

I’ll be sharing that script with you next week, so be on the lookout for it.

### **Detecting ArUco markers in real-time video streams with OpenCV**

In our previous section we learned how to detect ArUco markers in images …

**… but is it possible to detect ArUco markers in _real-time_ video streams?**

The answer is _yes, it absolutely is_ — and I’ll be showing you how to do so in this section.

Open up the `detect_aruco_video.py` file in your project directory structure, and let’s get to work:

\# import the necessary packages
from imutils.video import VideoStream
import argparse
import imutils
import time
import cv2
import sys

**Lines 2-7** import our required Python packages. These imports are identical to our previous script, with two exceptions:

1.  `` `VideoStream` ``: Used to access our webcam
2.  `` `time` ``: Inserts a small delay, allowing our camera sensor to warm up

Let’s now parse our command line arguments:

\# construct the argument parser and parse the arguments
ap = argparse.ArgumentParser()
ap.add\_argument("-t", "--type", type=str,
	default="DICT\_ARUCO\_ORIGINAL",
	help="type of ArUCo tag to detect")
args = vars(ap.parse\_args())

We only need a single command line argument here, `--type`, which is the type of ArUco tags we are going to detect in our video stream.

Next we define the `ARUCO_DICT`, used to map the `--type` to OpenCV’s unique ArUco tag type:

\# define names of each possible ArUco tag OpenCV supports
ARUCO\_DICT = {
	"DICT\_4X4\_50": cv2.aruco.DICT\_4X4\_50,
	"DICT\_4X4\_100": cv2.aruco.DICT\_4X4\_100,
	"DICT\_4X4\_250": cv2.aruco.DICT\_4X4\_250,
	"DICT\_4X4\_1000": cv2.aruco.DICT\_4X4\_1000,
	"DICT\_5X5\_50": cv2.aruco.DICT\_5X5\_50,
	"DICT\_5X5\_100": cv2.aruco.DICT\_5X5\_100,
	"DICT\_5X5\_250": cv2.aruco.DICT\_5X5\_250,
	"DICT\_5X5\_1000": cv2.aruco.DICT\_5X5\_1000,
	"DICT\_6X6\_50": cv2.aruco.DICT\_6X6\_50,
	"DICT\_6X6\_100": cv2.aruco.DICT\_6X6\_100,
	"DICT\_6X6\_250": cv2.aruco.DICT\_6X6\_250,
	"DICT\_6X6\_1000": cv2.aruco.DICT\_6X6\_1000,
	"DICT\_7X7\_50": cv2.aruco.DICT\_7X7\_50,
	"DICT\_7X7\_100": cv2.aruco.DICT\_7X7\_100,
	"DICT\_7X7\_250": cv2.aruco.DICT\_7X7\_250,
	"DICT\_7X7\_1000": cv2.aruco.DICT\_7X7\_1000,
	"DICT\_ARUCO\_ORIGINAL": cv2.aruco.DICT\_ARUCO\_ORIGINAL,
	"DICT\_APRILTAG\_16h5": cv2.aruco.DICT\_APRILTAG\_16h5,
	"DICT\_APRILTAG\_25h9": cv2.aruco.DICT\_APRILTAG\_25h9,
	"DICT\_APRILTAG\_36h10": cv2.aruco.DICT\_APRILTAG\_36h10,
	"DICT\_APRILTAG\_36h11": cv2.aruco.DICT\_APRILTAG\_36h11
}

Refer to the _“Detecting ArUco markers with OpenCV in images”_ section above for a more detailed review of this code block.

We can now load our ArUco dictionary:

\# verify that the supplied ArUCo tag exists and is supported by
# OpenCV
if ARUCO\_DICT.get(args\["type"\], None) is None:
	print("\[INFO\] ArUCo tag of '{}' is not supported".format(
		args\["type"\]))
	sys.exit(0)

# load the ArUCo dictionary and grab the ArUCo parameters
print("\[INFO\] detecting '{}' tags...".format(args\["type"\]))
arucoDict = cv2.aruco.Dictionary\_get(ARUCO\_DICT\[args\["type"\]\])
arucoParams = cv2.aruco.DetectorParameters\_create()

# initialize the video stream and allow the camera sensor to warm up
print("\[INFO\] starting video stream...")
vs = VideoStream(src=0).start()
time.sleep(2.0)

**Lines 43-46** check to see if the ArUco tag `--type` exists in our `ARUCO_DICT`. If not, we exit the script.

Otherwise, we load the `arucoDict` and grab the `arucoParams` for the detector (**Lines 50 and 51**).

From there, we start our `VideoStream` and allow our camera sensor to warm up (**Lines 55 and 56**).

We’re now ready to loop over frames from our video stream:

\# loop over the frames from the video stream
while True:
	# grab the frame from the threaded video stream and resize it
	# to have a maximum width of 1000 pixels
	frame = vs.read()
	frame = imutils.resize(frame, width=1000)

	# detect ArUco markers in the input frame
	(corners, ids, rejected) = cv2.aruco.detectMarkers(frame,
		arucoDict, parameters=arucoParams)

**Line 62** grabs a `` `frame` `` from our video stream, which we then resize to have a width of 1000 pixels.

We then apply the `cv2.aruco.detectMarkers` function to detect ArUco tags in the current `frame`.

Let’s now parse the results of the ArUco tag detection:

	# verify \*at least\* one ArUco marker was detected
	if len(corners) > 0:
		# flatten the ArUco IDs list
		ids = ids.flatten()

		# loop over the detected ArUCo corners
		for (markerCorner, markerID) in zip(corners, ids):
			# extract the marker corners (which are always returned
			# in top-left, top-right, bottom-right, and bottom-left
			# order)
			corners = markerCorner.reshape((4, 2))
			(topLeft, topRight, bottomRight, bottomLeft) = corners

			# convert each of the (x, y)-coordinate pairs to integers
			topRight = (int(topRight\[0\]), int(topRight\[1\]))
			bottomRight = (int(bottomRight\[0\]), int(bottomRight\[1\]))
			bottomLeft = (int(bottomLeft\[0\]), int(bottomLeft\[1\]))
			topLeft = (int(topLeft\[0\]), int(topLeft\[1\]))

The above code block is essentially identical to the one from our `` `detect_aruco_image.py` `` script.

Here we are:

1.  Verifying that at least one ArUco tag was detected (**Line 70**)
2.  Flattening the ArUco `ids` list (**Line 72**)
3.  Looping over all `corners` and `ids` together (**Line 75**)
4.  Extracting the marker corners in top-left, top-right, bottom-right, and bottom-left order (**Lines 79 and 80**)
5.  Converting the corner _(x, y)_\-coordinates from NumPy array data types to Python integers such that we can draw the coordinates using OpenCV’s drawing functions (**Lines 83-86**)

The final step here is to draw our ArUco tag bounding boxes just as we did in `` `detect_aruco_image.py` ``:

			# draw the bounding box of the ArUCo detection
			cv2.line(frame, topLeft, topRight, (0, 255, 0), 2)
			cv2.line(frame, topRight, bottomRight, (0, 255, 0), 2)
			cv2.line(frame, bottomRight, bottomLeft, (0, 255, 0), 2)
			cv2.line(frame, bottomLeft, topLeft, (0, 255, 0), 2)

			# compute and draw the center (x, y)-coordinates of the
			# ArUco marker
			cX = int((topLeft\[0\] + bottomRight\[0\]) / 2.0)
			cY = int((topLeft\[1\] + bottomRight\[1\]) / 2.0)
			cv2.circle(frame, (cX, cY), 4, (0, 0, 255), -1)

			# draw the ArUco marker ID on the frame
			cv2.putText(frame, str(markerID),
				(topLeft\[0\], topLeft\[1\] - 15),
				cv2.FONT\_HERSHEY\_SIMPLEX,
				0.5, (0, 255, 0), 2)

	# show the output frame
	cv2.imshow("Frame", frame)
	key = cv2.waitKey(1) & 0xFF

	# if the \`q\` key was pressed, break from the loop
	if key == ord("q"):
		break

# do a bit of cleanup
cv2.destroyAllWindows()
vs.stop()

Our visualization steps include:

*   Drawing the outlines of the ArUco tag on the `frame` (**Lines 89-92**)
*   Drawing the center of the ArUco tag (**Lines 96-98**)
*   Displaying the ID of the detected ArUco tag (**Lines 101-104**)

Finally, we display the output `frame` to our screen.

If the `q` key is pressed while the window opened by OpenCV is active, we `break` from the script and cleanup our video pointers.

### **OpenCV ArUco video detection results**

Ready to apply ArUco detection to real-time video streams?

Start by using the **_“Downloads”_** section of this tutorial to download the source code and example images.

From there, pop open a shell, and execute the following command:

$ python detect\_aruco\_video.py

![Image 7: Video Thumbnail](https://embed-ssl.wistia.com/deliveries/81219a09bbe0c1b8b2ede66d6b6e070914b13edb.webp?image_crop_resized=960x540)

As you can see, I’m easily able to detect the ArUco markers in real-time video.

### What's next? We recommend [PyImageSearch University](https://pyimagesearch.com/pyimagesearch-university/?utm_source=blogPost&utm_medium=bottomBanner&utm_campaign=What%27s%20next%3F%20I%20recommend).

![Image 8: Video Thumbnail](https://embed-ssl.wistia.com/deliveries/4bda0a1602c8b4d96d63a02617f3069e.webp?image_crop_resized=640x360)

**Course information:**  
84 total classes • 114+ hours of on-demand code walkthrough videos • Last updated: February 2024  
★★★★★ 4.84 (128 Ratings) • 16,000+ Students Enrolled

**I strongly believe that if you had the right teacher you could _master_ computer vision and deep learning.**

Do 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?

That’s _not_ the case.

All you need to master computer vision and deep learning is for someone to explain things to you in _simple, intuitive_ terms. _And that’s exactly what I do_. My mission is to change education and how complex Artificial Intelligence topics are taught.

If 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 _successfully_ and _confidently_ apply computer vision to your work, research, and projects. Join me in computer vision mastery.

**Inside PyImageSearch University you'll find:**

*   ✓ **84 courses** on essential computer vision, deep learning, and OpenCV topics
*   ✓ **84 Certificates** of Completion
*   ✓ **114+ hours** of on-demand video
*   ✓ **Brand new courses released _regularly_**, ensuring you can keep up with state-of-the-art techniques
*   ✓ **Pre-configured Jupyter Notebooks in Google Colab**
*   ✓ Run all code examples in your web browser — works on Windows, macOS, and Linux (no dev environment configuration required!)
*   ✓ Access to **centralized code repos for _all_ 536+ tutorials** on PyImageSearch
*   ✓ **Easy one-click downloads** for code, datasets, pre-trained models, etc.
*   ✓ **Access** on mobile, laptop, desktop, etc.

[Click here to join PyImageSearch University](https://pyimagesearch.com/pyimagesearch-university/?utm_source=blogPost&utm_medium=bottomBanner&utm_campaign=What%27s%20next%3F%20I%20recommend)

**Summary**
-----------

In this tutorial you learned how to detect ArUco markers in images and real-time video streams using OpenCV and Python.

Detecting ArUco markers with OpenCV is a three-step process:

1.  Set what ArUco dictionary you are using.
2.  Define the parameters to the ArUco detector (typically the default options suffice).
3.  Apply the ArUco detector with OpenCV’s `` `cv2.aruco.detectMarkers` `` function.

**OpenCV’s ArUco marker is _extremely fast_ and, as our results showed, is capable of detecting ArUco markers in real-time.**

Feel free to use this code as a starting point when using ArUco markers in your own computer vision pipelines.

However, let’s say you are developing a computer vision project to automatically detect ArUco markers in images, _but you don’t know what marker type is being used,_ and therefore, _you can’t explicitly set the ArUco marker dictionary_ — what do you do then?

How are you going to detect ArUco markers if you don’t know what marker type is being used?

I’ll be answering that exact question in next week’s blog post.

**To download the source code to this post (and be notified when future tutorials are published here on PyImageSearch), _simply enter your email address in the form below!_**

![Image 9](data:image/svg+xml,%3Csvg%20xmlns='http://www.w3.org/2000/svg'%20viewBox='0%200%20410%20567'%3E%3C/svg%3E)

#### Download the Source Code and FREE 17-page Resource Guide

Enter your email address below to get a .zip of the code and a **FREE 17-page Resource Guide on Computer Vision, OpenCV, and Deep Learning.** Inside you'll find my hand-picked tutorials, books, courses, and libraries to help you master CV and DL!