0

I have a quick question if someone of you can help me with this kind of information :). What is the faster method to rotate an image with 90 degree(or multiples of 90 degree) if we speak about the execution speed and memory management. I've search a lot with Google and I've found the faster method to do this is OpenCV in both languages Python or Java(and anothors languages). It's true? Do you know and other method to rotate an image faster then 90 degree? Thanks a lot for

cavaler12345
  • 367
  • 1
  • 5
  • 15

4 Answers4

1

JPEG images can be rotated without re-compressing the image data.

For a Python project, see jpegtran-cffi.

You probably can't get faster than that if you want to apply the rotation.

Another possibility is to edit the EXIF orientation of a JPEG image. It basically tells the viewer application on how to rotate the image. This is just changing a single value, however not all readers/viewers will support the orientation flag.

ypnos
  • 50,202
  • 14
  • 95
  • 141
1

I had a more general question last week, how can I rotate an Image by any angel as fast as possible, and I ended up comparing different libraries which offered the rotation function in this article I wrote.

The quick answer is OpenCV, a more elaborate answer is written in the article:

I am going to focus on three most used libraries for image editing in python namely , Pillow, OpenCV and Scipy.

In the following code you can learn how to import these libraries and how to rotate an image using them. I have defined a function for each library to use it for our experiments

import numpy as np
import PIL
import cv2
import matplotlib.pylab as plt
from PIL import Image
from scipy.ndimage import rotate
from scipy.ndimage import interpolation

def rotate_PIL (image, angel, interpolation):
    '''
    input :
    image           :  image                    : PIL image Object
    angel           :  rotation angel           : int
    interpolation   :  interpolation mode       : PIL.Image.interpolation_mode
    
                                                    Interpolation modes :
                                                    PIL.Image.NEAREST (use nearest neighbour), PIL.Image.BILINEAR (linear interpolation in a 2×2 environment), or PIL.Image.BICUBIC 
                                                    https://pillow.readthedocs.io/en/stable/reference/Image.html#PIL.Image.Image.rotate
    returns : 
    rotated image 
    
    '''

    return image.rotate(angel,interpolation)
    
    
def rotate_CV(image, angel , interpolation):

    '''
        input :
        image           :  image                    : ndarray
        angel           :  rotation angel           : int
        interpolation   :  interpolation mode       : cv2 Interpolation object
        
                                                        Interpolation modes :
                                                        interpolation cv2.INTER_CUBIC (slow) & cv2.INTER_LINEAR
                                                        https://theailearner.com/2018/11/15/image-interpolation-using-opencv-python/
                                                        
        returns : 
        rotated image   : ndarray
        
        '''



    #in OpenCV we need to form the tranformation matrix and apply affine calculations
    #
    h,w = image.shape[:2]
    cX,cY = (w//2,h//2)
    M = cv2.getRotationMatrix2D((cX,cY),angel,1)
    rotated = cv2.warpAffine(image,M , (w,h),flags=interpolation)
    return rotated

    

def rotate_scipy(image, angel , interpolation):
    '''
        input :
        image           :  image                    : ndarray
        angel           :  rotation angel           : int
        interpolation   :  interpolation mode       : int
        
                                                        Interpolation modes :
                                                        https://stackoverflow.com/questions/57777370/set-interpolation-method-in-scipy-ndimage-map-coordinates-to-nearest-and-bilinea
                                                        order=0 for nearest interpolation
                                                        order=1 for linear interpolation
        returns : 
        rotated image   : ndarray
        
        '''

    return  scipy.ndimage.interpolation.rotate(image,angel,reshape=False,order=interpolation)

To understand which library is more efficient in rotating and interpolating images, we design a simple experiment at first. We apply a 20 degree rotation using all three libraries on a 200 x 200 pixel 8bit image generated by our function rand_8bit().

def rand_8bit(n):
    im =np.random.rand(n,n)*255
    im = im.astype(np.uint8)
    im[n//2:n//2+n//2,n//2:n//4+n//2]= 0 # a self scaling rectangle 
    im[n//3:50+n//3,n//3:200+n//3]= 0 #  a constant rectangle 
    return im
  
#generate images of 200x200 pixels
im = rand_8bit(200)
#for PIL library we need to first convert the image array into a PIL image object 
image_for_PIL=Image.fromarray(im)
    

%timeit rotate_PIL(image_for_PIL,20,PIL.Image.BILINEAR)
%timeit rotate_CV(im,20,cv2.INTER_LINEAR)
%timeit rotate_scipy(im,20,1)

the result is : 987 µs ± 76 µs per loop (mean ± std. dev. of 7 runs, 1000 loops each) 414 µs ± 79.8 µs per loop (mean ± std. dev. of 7 runs, 1000 loops each) 4.46 ms ± 1.07 ms per loop (mean ± std. dev. of 7 runs, 100 loops each)

This means that OpenCV is the most efficient and Scipy is the slowest of them when it comes to image rotation.

Tomerikoo
  • 18,379
  • 16
  • 47
  • 61
0

The fastest way, known to me yet, to do basic image manipulation like rotating, cutting, resizing, and filtering is by using pillow module in python. OpenCV is used when advanced manipulations have to be done, that can't be done by Pillow. Pillow's rotate will answer your question.

Image.rotate(angle)

This is all you have to do to rotate the angle by any degree you want.

Swati Srivastava
  • 1,102
  • 1
  • 12
  • 18
0

I have used in my java project this implementation of opencv to rotate images and I am pleased with the performance of the rotate image.

*OpenCV dependency version is like below.

        <dependency>
            <groupId>nu.pattern</groupId>
            <artifactId>opencv</artifactId>
            <version>2.4.9-4</version>
        </dependency>

The method below does the rotation of image based on the angle you provide.

    @Override
    public BufferedImage rotateImage(BufferedImage image, double angle) {
        Mat imageMat = OpenCVHelper.img2Mat(image);
        // Calculate size of new matrix
        double radians = Math.toRadians(angle);
        double sin = Math.abs(Math.sin(radians));
        double cos = Math.abs(Math.cos(radians));
        int newWidth = (int) Math.floor(imageMat.width() * cos + imageMat.height() * sin);
        int newHeight = (int) Math.floor(imageMat.width() * sin + imageMat.height() * cos);
        int dx = (int) Math.floor(newWidth / 2 - (imageMat.width() / 2));
        int dy = (int) Math.floor(newHeight / 2 - (imageMat.height() / 2));
        // rotating image
        Point center = new Point(imageMat.cols() / 2, imageMat.rows() / 2);
        Mat rotMatrix = Imgproc.getRotationMatrix2D(center, 360 - angle, 1.0); // 1.0 means 100 % scale
        // adjusting the boundaries of rotMatrix
        double[] rot_0_2 = rotMatrix.get(0, 2);
        for (int i = 0; i < rot_0_2.length; i++) {
            rot_0_2[i] += dx;
        }
        rotMatrix.put(0, 2, rot_0_2);

        double[] rot_1_2 = rotMatrix.get(1, 2);
        for (int i = 0; i < rot_1_2.length; i++) {
            rot_1_2[i] += dy;
        }
        rotMatrix.put(1, 2, rot_1_2);

        Mat rotatedMat = new Mat();
        Imgproc.warpAffine(imageMat, rotatedMat, rotMatrix, new Size(newWidth, newHeight));
        return OpenCVHelper.mat2Img(rotatedMat);
    }

The rotateImage method above takes an input an image of type BufferedImage and the angle in degrees that you need to rotate your image. First operation of rotateImage method is to calculate the new width and new height that will have the rotated image by using the angle you provided and width and height of image that you want to rotate. Second important operation is adjusting the boundaries of the matrix that is used to rotate the image. This is done to prevent the image to be cropped from the rotation operation.

Below is the class that i have used to convert the image from BufferedImage to Mat and vice versa.

public class OpenCVHelper {
    /**
     * The Mat type image is converted to BufferedImage type.
     * 
     * @param mat
     * @return 
     */
    public static BufferedImage mat2Img(Mat mat) {
        BufferedImage image = new BufferedImage(mat.width(), mat.height(), BufferedImage.TYPE_3BYTE_BGR);
        WritableRaster raster = image.getRaster();
        DataBufferByte dataBuffer = (DataBufferByte) raster.getDataBuffer();
        byte[] data = dataBuffer.getData();
        mat.get(0, 0, data);
        return image;
    }

    /**
     * The BufferedImage type image is converted to Mat type.
     * 
     * @param image
     * @return 
     */
    public static Mat img2Mat(BufferedImage image) {
        image = convertTo3ByteBGRType(image);
        byte[] data = ((DataBufferByte) image.getRaster().getDataBuffer()).getData();
        Mat mat = new Mat(image.getHeight(), image.getWidth(), CvType.CV_8UC3);
        mat.put(0, 0, data);
        return mat;
    }
}

In my case it was need for me to converted the image in BufferedImage. If you don't need that, you can skip , and read the image directly as Mat type and pass it to that method rotateImage.


public Mat rotateImage(File input, double angle) {
Mat imageMat = Highgui.imread(input.getAbsolutePath())
...
}
Rando Shtishi
  • 1,222
  • 1
  • 21
  • 31