Library OpenCV

【Python】Marker creation and detection with ArUco of OpenCV.

OpenCV provides a module called "ArUco" that can easily handle AR markers.

This article shows basic usage of ArUco.

Contents

  • Preparation for using ArUco
  • How to generate markers using ArUco
  • How to detect markers using ArUco
  • How to extract coordinates of a marker using ArUco
  • How to overlay marker IDs and video

sponsored link

Preparation for using ArUco : Install OpenCV-contrib.

ArUco module can be used by installing OpenCV-contrib, an extension module of OpenCV.

OpenCV-contrib can be installed with following command.

$ pip install opencv-contrib-python

Versions of OpenCV and OpenCV-contrib must be the same.

Specify version and install OpenCV-contrib.

This is an example specifying version 3.4.5.20.

$ pip install opencv-contrib-python==3.4.5.20

If you want to install OpenCV-contrib on Raspberry Pi, please refer to this page.

How to install OpenCV on Raspberry Pi

sponsored link

How to generate markers using ArUco

First, I show how to generate markers.

In the following sample code, marker images are generated and saved.

### Generate markers
import cv2
from cv2 import aruco
import os

### --- parameter --- ###

# Save location
dir_mark = r'C:\test'

# Parameter
num_mark = 20 #Number of markers
size_mark = 500 #Size of markers

### --- marker images are generated and saved --- ###
# Call marker type
dict_aruco = aruco.Dictionary_get(aruco.DICT_4X4_50)

for count in range(num_mark) :

    id_mark = count
    img_mark = aruco.drawMarker(dict_aruco, id_mark, size_mark)

    if count < 10 :
        img_name_mark = 'mark_id_0' + str(count) + '.jpg'
    else :
        img_name_mark = 'mark_id_' + str(count) + '.jpg'
    path_mark = os.path.join(dir_mark, img_name_mark)

    cv2.imwrite(path_mark, img_mark)

Output

Here are the generated markers.

The 20 marker images were saved in test folder.

sponsored link

How to detect markers using ArUco

I show how to detect markers.

In the following sample code, detected marker IDs is returned.

### Detect markers
import cv2
from cv2 import aruco
import numpy as np
import time

class MarkSearch :

    dict_aruco = aruco.Dictionary_get(aruco.DICT_4X4_50)
    parameters = aruco.DetectorParameters_create()

    def __init__(self, cameraID):
        self.cap = cv2.VideoCapture(cameraID)

    def get_markID(self):
        """
        Obtain marker id list from still image
        """
        ret, frame = self.cap.read()
        gray = cv2.cvtColor(frame, cv2.COLOR_RGB2GRAY)

        corners, ids, rejectedImgPoints = aruco.detectMarkers(gray, dict_aruco, parameters=parameters)

        list_ids = np.ravel(ids)

        return list_ids

 
if __name__ == "__main__" :
    import cv2
    from cv2 import aruco
    import numpy as np
    import time

    dict_aruco = aruco.Dictionary_get(aruco.DICT_4X4_50)
    parameters = aruco.DetectorParameters_create()

    ### --- parameter --- ###
    cameraID = 0
    cam0_mark_search = MarkSearch(cameraID)

    try:
        while True:
            print(' ----- get_markID ----- ')
            print(cam0_mark_search.get_markID())
            time.sleep(0.5)
    except KeyboardInterrupt:
        cam0_mark_search.cap.release()

Output

List of markers displayed on the camera is returned.

For example, When ID1~5 markers are detected, this is output.

[5 1 2 3 4]

Supplementary explanation

ID is extracted from still image converted to gray image.

corners, ids, rejectedImgPoints = aruco.detectMarkers(gray, dict_aruco, parameters=parameters)

Marker IDs are stored in "ids".

"ids" is difficult to use, as shown below.

[[1]
[3]
[4]
[5]
[2]]

Therefore, it is converted to one-dimensional list.

list_ids = np.ravel(ids)

sponsored link

How to extract coordinates of a marker using ArUco

I show how to extract coordinates of a marker.

In the following sample code, coordinates are returned in list when specified marker is detected.

### Extract coordinates of a marker
import cv2
from cv2 import aruco
import numpy as np
import time

class MarkSearch :

    dict_aruco = aruco.Dictionary_get(aruco.DICT_4X4_50)
    parameters = aruco.DetectorParameters_create()

    def __init__(self, cameraID):
        self.cap = cv2.VideoCapture(cameraID)

    def get_mark_coordinate(self, num_id):
        """
        Obtain marker id list from still image
        """
        ret, frame = self.cap.read()
        gray = cv2.cvtColor(frame, cv2.COLOR_RGB2GRAY)

        corners, ids, rejectedImgPoints = aruco.detectMarkers(gray, dict_aruco, parameters=parameters)

        ### If marker of num_id is detected ###
        if num_id in np.ravel(ids) :
            index = np.where(ids == num_id)[0][0] #Extract index of num_id
            cornerUL = corners[index][0][0]
            cornerUR = corners[index][0][1]
            cornerBR = corners[index][0][2]
            cornerBL = corners[index][0][3]

            center = [ (cornerUL[0]+cornerBR[0])/2 , (cornerUL[1]+cornerBR[1])/2 ]

            print('Upper left : {}'.format(cornerUL))
            print('Upper right : {}'.format(cornerUR))
            print('Lower right : {}'.format(cornerBR))
            print('Lower Left : {}'.format(cornerBL))
            print('Center : {}'.format(center))

            print(corners[index])

            return center

        return None


if __name__ == "__main__" :

    import cv2
    from cv2 import aruco
    import numpy as np
    import time

    dict_aruco = aruco.Dictionary_get(aruco.DICT_4X4_50)
    parameters = aruco.DetectorParameters_create()

    ### --- parameter --- ###
    cameraID = 0
    cam0_mark_search = MarkSearch(cameraID)

    markID = 1

    try:
        while True:
            print(' ----- get_mark_coordinate ----- ')
            print(cam0_mark_search.get_mark_coordinate(markID))
            time.sleep(0.5)
    except KeyboardInterrupt:
        cam0_mark_search.cap.release()

Output

Coordinates are returned in list when specified marker is detected.

For example, if mark with ID=1 is specified and it is detected, this is output.

[216.5, 448.0]

In this sample code, center coordinates of mark are returned.

Supplementary explanation

ID is extracted from still image converted to gray image.

corners, ids, rejectedImgPoints = aruco.detectMarkers(gray, dict_aruco, parameters=parameters)

Check if list of markers includes marker with specified ID.

if num_id in np.ravel(ids) :

"np.where" is used to find index corresponding to specified mark in "ids".

index = np.where(ids == num_id)[0][0]

Upper left coordinates of mark is extracted by the following command.

cornerUL = corners[index][0][0]

sponsored link

How to overlay marker IDs and video

I show how to overlay marker ID and video.

In the following sample code, display video with marker IDs.

### Overlay marker ID and video
import cv2
from cv2 import aruco
import time

dict_aruco = aruco.Dictionary_get(aruco.DICT_4X4_50)
parameters = aruco.DetectorParameters_create()

cap = cv2.VideoCapture(0)

try:
    while True:
        ret, frame = cap.read()
        gray = cv2.cvtColor(frame, cv2.COLOR_RGB2GRAY)

        corners, ids, rejectedImgPoints = aruco.detectMarkers(gray, dict_aruco, parameters=parameters)

        frame_markers = aruco.drawDetectedMarkers(frame.copy(), corners, ids)
        cv2.imshow('frame', frame_markers)
        if cv2.waitKey(1) & 0xFF == ord('q'):
            break
    cv2.destroyWindow('frame')
    cap.release()
except KeyboardInterrupt:
    cv2.destroyWindow('frame')
    cap.release()

Output

sponsored link

-Library, OpenCV
-,