Search code examples
pythonc++numpyopencveigen

Rotate an image by 90 degrees using Eigen from OpenCV Matrix in C++


How can I rotate an image by 90 degrees using Eigen from OpenCV Matrix and then convert the rotated image back to OpenCV Matrix in C++. The rotate function of OpenCV takes time and I want to do it as fast as possible. I have tried using Numpy rot90 function in Python and it is extremely fast compared to OpenCV rotate function in C++. Unfortunately Numpy is not available for C++. I have read that there are other libraries like Eigen and Armadillo in C++ which can do these matrix operations quickly. That is the reason I want to rotate the image using Eigen and check the timing.

I tested the functions in Visual Studio 2019 on an i5 machine in Windows 10. The numpy rot90 function in Python is roughly 10 times faster than the OpenCV rotate function in C++.


Solution

  • I guess that the function warpAffine is faster. At least you should compare to check.
    There is an example here:
    https://docs.opencv.org/master/dd/d52/tutorial_js_geometric_transformations.html.

    The same kind of functions are available with cuda:
    https://docs.opencv.org/master/db/d29/group__cudawarping.html

    EDIT:
    warpAffine in OpenCV can actually use the ippiWarpAffine* function from the Intel Performance Primitives library. This is probably the fastest performance that could get. The cuda version is expected to be faster if you can run your software on a platform with an nvidia gpu. The performance depends on the type of data that you use. If you can use 8bit unsigned images you can be much faster.

    EDIT 2: After the comment saying that warpAffine is slower I ran a few tests and it can sometimes be faster. However, when compare to the numpy's rotate there is nothing comparable, even a cv2.flip or cv2.transpose are way slower. Therefore I would recommend to look into this recommendation on Intel's developer zone which is to use ippiRotate and ippiMirror functions to perform 90 rotations. If you are really interested into getting the best performance out of an Intel cpu, that would be my guess. Also take care about the multithreading, some functions can be multithreaded in IPP. In the end this depend if you look for a solution to rotate a single large image or multiple ones, of the type of data, the number of channels. With IPP at least you use the best function for your type of data.
    Hereafter a few trials in python to compare with numpy's rot90 function. Of course the results can change with the parameters but still there is a large difference with numpy. It is also not obvious from my trials that cv2.rotate is so faster.

    100x np.rot90 time       : 0.001626729965209961
    100x cv2.rotate time     : 0.21501994132995605
    100x cv2.transpose time  : 0.18512678146362305
    100x cv2.remap time      : 0.6473801136016846
    100x cv2.warpAffine time : 0.11946868896484375
    
    import cv2
    import numpy as np
    import time
    
    img = np.random.randint(0, 255, (1000, 1000, 3)).astype(np.uint8)
    
    ##################################
    start = time.time()
    for i in range(100):
        rotated = np.rot90(img)
    end = time.time()
    print("100x np.rot90 time       :", end - start)
    
    ##################################
    start = time.time()
    for i in range(100):
        rotated = cv2.rotate(img, cv2.ROTATE_90_COUNTERCLOCKWISE)
    end = time.time()
    print("100x cv2.rotate time     :", end - start)
    
    ##################################
    start = time.time()
    for i in range(100):
        rotated = cv2.transpose(img, 1)
    end = time.time()
    print("100x cv2.transpose time  :", end - start)
    
    ##################################
    mapx, mapy = np.meshgrid(np.arange(0, img.shape[1]), np.arange(0, img.shape[0]))
    mapx = mapx.transpose()
    mapy = mapy.transpose()
    
    start = time.time()
    for i in range(100):
        rotated = cv2.remap(img, mapx.astype(np.float32), mapy.astype(np.float32), cv2.INTER_NEAREST)
    end = time.time()
    print("100x cv2.remap time      :", end - start)
    
    ##################################
    rows = img.shape[0]
    cols = img.shape[1]
    M = cv2.getRotationMatrix2D((rows / 2, cols / 2), 90, 1)
    M[0, 2] = 0
    M[1, 2] = cols
    
    start = time.time()
    for i in range(100):
        rotated = cv2.warpAffine(img, M, (rows, cols), flags=cv2.INTER_NEAREST)
    end = time.time()
    print("100x cv2.warpAffine time :", end - start)
    
    

    I hope this helps!