python-3.xopencvimage-processingaruco

Display an image over another image at a particular co-ordinates in openCV


I am trying to display an image over another image at a particular co-ordinates. I have detected the aruco markers using the webcam and I want to display another image over the aruco marker. The aruco marker can be moved and the overlaying image should move along with the marker.

There is various draw functions and to input text into the image. I have tried image overlay and image homography.

I can obtain the co-ordinates for the corners. Is there any function to insert the image at those co-ordinates?

import cv2
import cv2.aruco as aruco
import glob

markerLength = 0.25

cap = cv2.VideoCapture(0)

criteria = (cv2.TERM_CRITERIA_EPS + cv2.TERM_CRITERIA_MAX_ITER, 30, 0.001)

objp = np.zeros((6*7,3), np.float32)
objp[:,:2] = np.mgrid[0:7,0:6].T.reshape(-1,2)

objpoints = [] 
imgpoints = []

images = glob.glob('calib_images/*.jpg')

for fname in images:
    img = cv2.imread(fname)
    gray = cv2.cvtColor(img,cv2.COLOR_BGR2GRAY)

    ret, corners = cv2.findChessboardCorners(gray, (7,6),None)

    if ret == True:
        objpoints.append(objp)

        corners2 = cv2.cornerSubPix(gray,corners,(11,11),(-1,-1),criteria)
        imgpoints.append(corners2)
        img = cv2.drawChessboardCorners(img, (7,6), corners2,ret)


ret, mtx, dist, rvecs, tvecs = cv2.calibrateCamera(objpoints, imgpoints, gray.shape[::-1],None,None)

calibrationFile = "calibrationFileName.xml"
calibrationParams = cv2.FileStorage(calibrationFile, cv2.FILE_STORAGE_READ) 
camera_matrix = calibrationParams.getNode("cameraMatrix").mat() 
dist_coeffs = calibrationParams.getNode("distCoeffs").mat() 

while(True):
    ret, frame = cap.read()

    gray = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)
    aruco_dict = aruco.Dictionary_get(aruco.DICT_6X6_250)
    arucoParameters =  aruco.DetectorParameters_create()

    corners, ids, rejectedImgPoints = aruco.detectMarkers(gray, aruco_dict, parameters=arucoParameters)
    if np.all(ids != None):
        rvec, tvec, _ = aruco.estimatePoseSingleMarkers(corners, markerLength, mtx, dist) 
        axis = aruco.drawAxis(frame, mtx, dist, rvec, tvec, 0.3) 
        print(ids)
        display = aruco.drawDetectedMarkers(axis, corners)
        display = np.array(display)
    else:
        display = frame

    cv2.imshow('Display',display)
    if cv2.waitKey(1) & 0xFF == ord('q'):
            break

cap.release()
cv2.destroyAllWindows()```

Solution

  • Actually, I found that image homography can be used to do it. Here is the updated code.

    import numpy as np
    import cv2
    import cv2.aruco as aruco
    
    cap = cv2.VideoCapture(0)
    
    while(True):
        ret, frame = cap.read()
    
        gray = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)
        aruco_dict = aruco.Dictionary_get(aruco.DICT_6X6_250)
        arucoParameters =  aruco.DetectorParameters_create()
    
        corners, ids, rejectedImgPoints = aruco.detectMarkers(gray, aruco_dict, parameters=arucoParameters)
        if np.all(ids != None):
            display = aruco.drawDetectedMarkers(frame, corners)
            x1 = (corners[0][0][0][0], corners[0][0][0][1]) 
            x2 = (corners[0][0][1][0], corners[0][0][1][1]) 
            x3 = (corners[0][0][2][0], corners[0][0][2][1]) 
            x4 = (corners[0][0][3][0], corners[0][0][3][1])  
    
            im_dst = frame 
            im_src = cv2.imread("mask.jpg")
            size = im_src.shape
            pts_dst = np.array([x1,x2,x3,x4])
            pts_src = np.array(
                           [
                            [0,0],
                            [size[1] - 1, 0],
                            [size[1] - 1, size[0] -1],
                            [0, size[0] - 1 ]
                            ],dtype=float
                           );
    
    
            h, status = cv2.findHomography(pts_src, pts_dst)
            temp = cv2.warpPerspective(im_src, h, (im_dst.shape[1],im_dst.shape[0])) 
            cv2.fillConvexPoly(im_dst, pts_dst.astype(int), 0, 16);
            im_dst = im_dst + temp  
            cv2.imshow('Display',im_dst) 
        else:
            display = frame
            cv2.imshow('Display',display)
        if cv2.waitKey(1) & 0xFF == ord('q'):
                break
    
    cap.release()
    cv2.destroyAllWindows()