How to create a customized non-square aruco board


I am trying to find information and examples on how to create a custom aruco board. In my case, I need to place several markers on the surface of an object to perform pose detection.

In this case, as the object is relatively small, the markers to be used must be small and, in this way, with only one marker I get too much error in the X or Y rotation.

Here are the topic created on the problem that I have:

In case you need more extra information, dont hesitate to ask it!

cv.aruco.Board_create(boardpts, arucodict, ids)

boardpts needs to be (N,4,3)

N for the number of markers
4 for the four corners of one marker
3 for the xyz of that corner

arucodict could be getPredefinedDictionary(cv.aruco.DICT_4X4_1000)

ids is an array of just the IDs

so what you might wanna do is define a list of markers. id, size, and marker’s pose in “board space” (marker to board).

for that it’s useful to have functions that give you primitive 4x4 transformations like translation, rotation, scaling… and then you compose them with @ (matrix multiplication).

then you can generate the corners of each marker (top left is -x+y, top right +x+y, bottom right +x-y, bottom left -x-y), scale them to size, transform to board space, and keep around. that’s another matrix mul, applying the transformation to these points so they’re now in board space.

that’s the array of corners for the Board_create call

for estimatePoseBoard, you dump all your found markers in there (ids and corners) along with the desired board object, and it will figure out what belongs, and what the board’s pose should be.

Thanks for your quick response.

I have done this prototype of code, I have not test it because I’m not in the laboratory but I will test it the next week. Could you see something wrong there? Do you think this will work?

def DetectMarkerBoard(self):
        Funcion que permite detectar el "tablero" de marcadores ArUco tras obtener los pareametros asociados
        a la camara
        :return: vector de desalineamientos [X,Y,Z,Rx,Ry,Rz] que determinan la pose del SIROM (TABLERO)
        respecto de la camara
        #Configuro la camara para la captura del objetivo
        cam.set(3, 1280)  # width --> Anchura
        cam.set(4, 720)  # height--> altura
        cam.set(39, 0) #Autofocus OFF
        ArucoDict = cv2.aruco.Dictionary_get(self.ArucoDict)
        ArucoParams = cv2.aruco.DetectorParameters_create()
        ArucoParams.cornerRefinementMethod = 1
        while True:
            ret, frame
            if ret != True:
                esquinas, ids, rechazados = cv2.aruco.detectMarkers(Frame_procesado, ArucoDict, parameters=ArucoParams,cameraMatrix=self.CamMtx, distCoeff=self.CamDst)
                #Convierto las esquinas a X,Y,Z
                new_corners = np.zeros(shape=(len(esquinas), 4, 3))
                for cnt, corner in enumerate(esquinas):
                    new_corners[cnt, :, :-1] = corner
                # Creo mi board compuesto de dos marcadores
                ArucoBoard=cv2.aruco.Board_create(new_corners.astype(np.float32), self.ArucoDict, ids)
                if len(esquinas)>0: #En caso de que como minimo 1 marcador detectado
                    #Detecto el board compuesto de los dos aruco
                    ret,rvec_Aruco_respect_Camara, tvec_Aruco_respect_Camara=cv2.aruco.estimatePoseBoard(esquinas,ids,ArucoBoard,self.CamMtx,self.CamDst,rvec,tvec)
                    #Calculo FPS de la camara
                    fps="FPS: "+str(int(self.FPS))
                    if ret>0:
                        frame=cv2.aruco.drawAxis(Frame_procesado, self.CamMtx, self.CamDst, rvec_Aruco_respect_Camara, tvec_Aruco_respect_Camara, 0.05)
                        cv2.putText(frame, fps, (3, 25), cv2.FONT_HERSHEY_SIMPLEX, 1, (100, 255, 0), 3, cv2.LINE_AA)
                    cv2.imshow("SIROM detectado", frame)
                    #Calculo FPS de la camara, dibujo los ejes de coordenadas, el nº de FPS...
                    stop = time.time()
                    self.FPS = 1 / (stop - start)
                    start = stop
                    fps = "FPS: " + str(int(self.FPS))
                    cv2.putText(frame, fps, (3, 25), cv2.FONT_HERSHEY_SIMPLEX, 1, (100, 255, 0), 3, cv2.LINE_AA)
                    cv2.imshow("SIROM detectado", frame)
                    print("NO SE HA DETECTADO NINGUN SIROM")

It must be said that I calculated the aruco board in each iteration because the object which have the markers will be moving during the test, so I need to know the aruco points for each iteration and also, calculate the board in each iteration.

that won’t work and it doesn’t make sense.

the definition of a “board” requires 3D points, all in “board space”. you don’t have 3D points there. you have 2D points, in screen space.

I’m not sure you understand what aruco “board” objects are meant for.

besides that, I don’t speak the language you use for your identifiers. that makes following the code less convenient.

tutorial for this stuff: OpenCV: Detection of ArUco Boards

the API docs themselves aren’t clear on some details.

1 Like

related: python - How to create a customized non-square aruco board - Stack Overflow

Of course, you are right.

So from what I understand, I must define the position of the marker in the space of the board itself. That is, in my case, I will use three markers located in the center of the sides of an equilateral triangle. In this way, the markers will be in the same plane (Z=0).

My question now is, with respect to what point should I define the position of the upper left corner of each of the markers that make up my board?Could I do it from the center of the equilateral triangle? In this way, the reference system of my board would be the center of the equilateral triangle?

Thanks in advance, your answers are helping me a lot!

yes, you could, and that would be a sensible place for the origin.

you could put the origin anywhere that makes sense for your situation.

a “flat board” would make sense if any of the markers could be occluded. then recovery is still possible from a complete view of at least one of the markers.

if occlusion is not the issue, but noisy rotation data from a frontal view is the issue, such a flat board has no advantage over a single marker in the same plane. it’d be better to have the “board” be 3-dimensional in some way.

1 Like