0

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++.

ajaye
  • 11
  • 3
  • Which platform do you plan to execute this on? For the performance issues it is interesting to know. Which cpu? could you use a gpu? – 87VN0 Jan 06 '20 at 14:26
  • This should be just a transpose and a flip, and OpenCV should do this optimally, already. Check this: https://stackoverflow.com/questions/2259678/easiest-way-to-rotate-by-90-degrees-an-image-using-opencv – chtz Jan 06 '20 at 16:05
  • Does this answer your question? [Easiest way to rotate by 90 degrees an image using OpenCV?](https://stackoverflow.com/questions/2259678/easiest-way-to-rotate-by-90-degrees-an-image-using-opencv) – chtz Jan 06 '20 at 16:05
  • @87VN0 I am running it on Windows 10 on an i5 machine. I don't intend to use a GPU. – ajaye Jan 07 '20 at 05:54
  • @chtz Yes but the timing is not acceptable. I compared it against numpy `rot90` function in Python which is extremely fast. Unfortunately numpy is not available in C++. I want a similar fast function in C++ for image rotation. I read that the libraries like Eigen and Armadillo can do these operations fast. Hence I want to try using these libraries. – ajaye Jan 07 '20 at 06:00
  • 1
    How did you benchmark this? (What difference did you measure? For what image size/type?) Where did you read that Eigen or Armadillo can do this faster than OpenCV? Is your OpenCV built with all available SIMD optimizations? – chtz Jan 07 '20 at 07:50
  • @chtz I tested them in Visual Studio 2019. The image size is 1280x500 and the type is integer. I found that the `numpy` rot 90 in Python is roughly 10 times faster than OpenCV `rotate` function. I have read online in many sites that the Eigen and Armadillo libraries are well optimised and can perform matrix operations very fast. I have no idea whether the OpenCV I used has SIMD optimizations. – ajaye Jan 09 '20 at 06:10

1 Answers1

1

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!

87VN0
  • 775
  • 3
  • 10
  • 1
    There's no way `warpAffine` is going to be anywhere close to performance of a simple rotation in 90 degree steps, which involves just a copy/rearrangement of the pixels. – Dan Mašek Jan 06 '20 at 14:45
  • I have tried using `warpAffine` function. It takes a lot of time compared to the `rotate` function. I want something even faster than the `rotate` function. – ajaye Jan 07 '20 at 06:03
  • rot90 doesn't do anything on the array itself, it just creates a view on the original array. (You can check this by looking on the flags). This is of course very fast, but working with this non-aligned view can be slower. eg. `%timeit rotated*rotated` -> 13.1ms `%timeit img*img` -> 3.59 ms. – max9111 Jan 08 '20 at 08:42
  • @max9111 Also feeding the result of `rot90` back to an OpenCV function will introduce new issues, since `Mat` isn't as flexible as a numpy array (no negative stride, no column-major order support). At best this will involved a copy (basically doing what `rotate` does), at worst some odd malfunctions (I've seen that a few times already). – Dan Mašek Jan 08 '20 at 14:43
  • 1
    @87VN0. Thanks a lot. I tried using the `ippiMirror` and `ippiTranspose` functions from Intel IPP library for the 90 degree image rotation and it is extremely fast. For image size of 1280x500, OpenCV `rotate` function took 0.83 milliseconds while the `ippiMirror` and `ippiTranspose` functions together just took 0.22 milliseconds on my intel i5 machine. – ajaye Jan 10 '20 at 12:43
  • @ajaye I'm glad it helped and that the performance is good enough for you! I never could manage to beat the performance of IPP for image processing, I guess that OpenCV doesn't use these functions in rotate (for some other functions it does). – 87VN0 Jan 10 '20 at 13:37