Search code examples
python-3.xopencvwebcam

Easy way to make OpenCV's "undistort" run more efficiently?


I'm currently in the works of making an auto-aiming turret, and my camera's have a noticeable fish eye effect, which is totally fine. I'm using OpenCV's undistort() function to handle this, with data from a camera checkerboard calibration.

I will most likely be running the vision system on a raspberry pi 4, and currently, my undistort function takes 80-90% of my CPU (i5-8600k OC 5GHz) when processing both of my cameras at 1280x720px, ideally this px as it's the largest and will provide best accuracy. Also note I'm aiming for a 15Hz update time.

Any ideas on how to make this more lightweight? Here's my code that I'm currently running as a test:

from cv2 import cv2
import numpy as np
import yaml
import time

cam1 = cv2.VideoCapture(0)
cam2 = cv2.VideoCapture(1)
cam1.set(3, 1280)
cam1.set(4, 720)
cam2.set(3, 1280)
cam2.set(4, 720)

#load calibration matrix
with open ("calibration_matrix.yaml") as file:

    documents = yaml.full_load(file)
    x=0
    for item, doc in documents.items():
        if x == 0:
            mtx = np.matrix(doc)
            x = 1
        else:
            dist = np.matrix(doc)

def camera(ID, asd):
    if asd == -1:
        ID.release()

    ret, frame = ID.read()

    if ret:
        newcameramtx, roi = cv2.getOptimalNewCameraMatrix(mtx,dist,(w,h),1,(w,h))
        undistortedFrame = cv2.undistort(frame, mtx, dist, None, newcameramtx)
        undistortedFrame = undistortedFrame[y:y+h, x:x+w]
        return undistortedFrame
while True:
    frame1 = camera(cam1, 0)
    frame2 = camera(cam2, 0)
    cv2.imshow('Frame 1', frame1)
    cv2.imshow('Frame 2', frame2)
    if cv2.waitKey(1) & 0xFF == ord('q'):
        camera(cam1, -1)
        camera(cam2, -1)
        cv2.destroyAllWindows()

Solution

  • Comments above resolved, here's the solution:

    As @Micka said,

    use initundistortrectifymap() (once) and remap() (for each image)

    initundistortrectifymap() basically takes the heavy load off of the undistort function (Micka) In practice, you run initundistortrectifymap() at the start of the program with the image calibration matrix and distance coefficients, and then initundistortrectifymap() returns two maps, map1 and map2.

    These maps can be passed into the remap() function to remap your image, which is a significantly lighter function than undistort(). In my particular case, I have a fisheye camera, and OpenCV has fisheye modules that are optimized to undistort fish eye cameras with ease.