'mapping [x,y] coordinates on plane aruco defined plane and servo movement on mapped points

I am new to this and I am sorry to poorly ask but I don't know where else to search.

I have 4 Aruco markers placed in a square position respectively by ids

0 1
2 3 

I am calculating the distance between 0 and 1 and 0 and 2 so to have w and h

w = math.dist(toprxy,toplxy)
h = math.dist(toplxy,botlxy)

Then I have some normalized points between 0 and 1 in a 2d array

points = np.array([[0.3791454386035252, 0.5089704263689607], [0.4983802415059109, 0.4865878212776629],[0.5101597581790689, 0.21719483055184013], [0.39370939342390643, 0.21645334444157344], [0.3703281257159549, 0.34746637604116004]], np.float64) 

if I try to map them inside the w and the h for x, y in points:

screenX = (x * w) + toplxy[0] 
screenY = (y * h) + toplxy[1] 
cv2.circle(img,(int(screenX),int(screenY)),5,(255, 0, 250),-1)

It doesn't, If I run the live camera points are sprayed around but not inside the 4 markers.

My aim is to point a laser to each point using a pan/tilt mechanism with servos. Any suggestion on how to continue?

I am using this code to find

dx =  canvasXpoint - servoXcentrepoint 
dy =  canvasYpoint - servoYcentrepoint
pan = abs(np.arctan((distanceZ/dx))) * 180/np.pi
tilt = abs(np.arctan(distanceZ/dy)) * 180/np.pi

or

lx = (2 * canvasXpoint / canvasW - 1) * np.tan(fov / 2)
ly = (-2 * canvasYpoint / canvasH + 1) * np.tan(fov / 2) 
lz = 70
tx = np.cos(pan) * np.cos(tilt) * lx - np.cos(tilt) * np.sin(pan) * ly - np.sin(tilt) * lz
ty = np.sin(pan) * lx + np.cos(pan) * ly
tz = np.cos(pan) * np.sin(tilt) * lx - np.sin(pan) * np.sin(tilt) * ly + np.cos(tilt) * lz
tilt = abs(np.arctan2(tz, tx) )*180 /np.pi
pan  = np.arcsin(ty / np.sqrt(tx**2 + ty**2 + tz**2))*180 /np.pi

considering the machine to be at the centre of the 4 markers

here is the entire code

    import cv2
import math
import numpy as np
import pandas as pd

# Load Aruco detector
parameters = cv2.aruco.DetectorParameters_create()
aruco_dict = cv2.aruco.Dictionary_get(cv2.aruco.DICT_5X5_100)
points = np.array([[0.3791454386035252, 0.5089704263689607], [0.4983802415059109, 0.4865878212776629], [0.4191061040406586, 0.4890729258496474], [0.48898375092596835, 0.6904554156787046], [0.41117320428962, 0.6855686449973655], [0.48969027909831686, 0.8806483247709954], [0.4096722346480175, 0.8725103831012889], [0.45146556567120294, 0.216198952126905], [0.6304876750748412, 0.1994776546413951], [0.6406976694235704, 0.1861724655606558], [0.6199918357274865, 0.18561325370105788], [0.6525936779272056, 0.201758477474465], [0.6013198509477334, 0.20041966221830415], [0.6683290543094758, 0.29699362669473495], [0.5645238852104717, 0.3113999818240313], [0.6545654774178274, 0.49620430200480303], [0.5898070573107588, 0.49659117464889346], [0.6592482998457356, 0.6834740545963035], [0.5840631897032319, 0.6828527784533074], [0.6408640096147972, 0.8299668209407426], [0.5829181988101784, 0.8173392725052692], [0.6197806290284397, 0.30050890733295843], [0.8252923243905792, 0.23409826375167195], [0.835683753646597, 0.2185883280832016], [0.8131540844750428, 0.21904862499113367], [0.8506741192799976, 0.2279991219170517], [0.7959142481709739, 0.22725381616179272], [0.8733570624656342, 0.3256920048853457], [0.7652207837892534, 0.3239122878098148], [0.893097550288673, 0.44273291363944955], [0.7346131146711571, 0.4430594635999311], [0.902709244982588, 0.5343829401117663], [0.8520378940615836, 0.543215423861057], [0.7842126810888624, 0.5430821914771806], [0.8496391467917583, 0.7170072127563635], [0.7934480818135997, 0.7157067918591926], [0.8415470663986131, 0.8790693270711738], [0.7969306654944098, 0.8786970205344115], [0.8191112469834433, 0.32444646417244244], [0.4544294400182521, 0.10802826838116084], [0.4652589441860643, 0.09470838455219986], [0.44184697991125976, 0.09401847354478254], [0.4784184639521475, 0.1113126386155105], [0.42270482157448985, 0.10977393520172159], [0.5101597581790689, 0.21719483055184013], [0.39370939342390643, 0.21645334444157344], [0.3703281257159549, 0.34746637604116004]], np.float64)

def calculateDistance(x1,y1,x2,y2):  
    dist = math.sqrt((x2 - x1)**2 + (y2 - y1)**2)  
    return dist  

def defineCornerValues(arr,value):
    for i in arr:
            if i[0] == value:
                a = np.where(ids==i)
                return a[0][0]

# Load Cap
cap = cv2.VideoCapture(0)
cap.set(cv2.CAP_PROP_FRAME_WIDTH, 1280)
cap.set(cv2.CAP_PROP_FRAME_HEIGHT, 720)

#Reading the first frame
(grabbed, img) = cap.read()

while cap.isOpened(): 
    grabbed, img = cap.read()

    cv2.namedWindow('img')
   
    # Get Aruco marker
    
    corners, ids, _ = cv2.aruco.detectMarkers(img, aruco_dict, parameters=parameters)

    corners2 = np.array([c[0] for c in corners])

    # if corners:
    if len(corners)>=4:

        posArrTopl = defineCornerValues(ids, 0)
        posArrTopr = defineCornerValues(ids, 1)
        posArrBotl = defineCornerValues(ids, 2)
        posArrBotr = defineCornerValues(ids, 3)

        topl = corners[posArrTopl]
        topr = corners[posArrTopr]
        botl = corners[posArrBotl]
        botr = corners[posArrBotr]

        data = pd.DataFrame({"x": corners2[:,:,0].flatten(), "y": corners2[:,:,1].flatten()}, index = pd.MultiIndex.from_product(
                        [ids.flatten(), ["c{0}".format(i)
                        for i in np.arange(4)+1]], 
                        names = ["marker", ""]))
             

        # Draw polygon around the marker
        int_corners = np.int0(corners)
        cv2.polylines(img, int_corners, True, (0, 255, 0), 5)

        # Aruco Perimeter
        aruco_perimeter = cv2.arcLength(corners[0], True)

        # Pixel to cm ratio
        pixel_cm_ratio = aruco_perimeter / 100  

        Dist = []

        toplxy = ((topl[0][2][0]).astype(int), (topl[0][2][1]).astype(int))
        toprxy = ((topr[0][3][0]).astype(int), (topr[0][3][1]).astype(int))
        botlxy = ((botl[0][0][0]).astype(int), (botl[0][0][1]).astype(int))
        botrxy = ((botr[0][0][0]).astype(int), (botr[0][0][1]).astype(int))

        # red
        cv2.line(img, toplxy, toprxy, (255, 0, 0), 2)
        # yellow
        cv2.line(img, toprxy, botlxy, (255, 253, 0), 2)
        # pink
        cv2.line(img, botlxy, botrxy, (255, 2, 255), 2)
        # green
        cv2.line(img, botrxy, toplxy, (0, 255, 0), 2)

        wX = int((toplxy[0] + toprxy[0])//2)
        wY = int((toplxy[1] + toprxy[1])//2)
        hX = int((toplxy[0] + botrxy[0])//2)
        hY = int((toplxy[1] + botrxy[1])//2)

        def distance_estimator(square_side_dimension_px):
            return 1.129e+04 * math.pow(square_side_dimension_px, -0.9631) + (-11.26)


        measure = abs(100/(toplxy[0]-wX))
        
        # width center point
        cv2.circle(img, (wX, wY), 4, (255, 255, 0), -1)
        # heigh center point
        cv2.circle(img, (hX, hY), 4, (255, 255, 0), -1)
        # center
        cv2.circle(img, (wX, hY), 4, (255, 255, 0), -1)

        # print(math.hypot(toplxy[0]-toprxy[0],  toplxy[1])-toprxy[1])

        w = math.dist(toprxy,toplxy)
        
        h = math.dist(toplxy,botlxy) 
        
        

        cv2.circle(img,(int(w),int(h)),5,(255, 45, 250),3)

        for x, y in points:
           
            screenX = (x * w) + toplxy[0] 
            # #+ rect[0] #- differencesqrx
            screenY = (y * h) + toplxy[1] 
            # #+ rect[1] #- differencesqry


  
            cv2.circle(img,(int(screenX),int(screenY)),5,(255, 0, 250),-1)

  
    cv2.imshow('img',img)
    if cv2.waitKey(1)==ord('q'):
        break


cap.release()
cv2.destroyAllWindows()


Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source