【问题标题】:Faster method to rotate an image in Python or Java在 Python 或 Java 中旋转图像的更快方法
【发布时间】:2017-03-22 05:15:10
【问题描述】:

如果你们中的任何人可以帮助我提供此类信息,我有一个简短的问题 :)。 如果我们谈论执行速度和内存管理,将图像旋转 90 度(或 90 度的倍数)更快的方法是什么? 我用谷歌搜索了很多,我发现更快的方法是 OpenCV 两种语言 PythonJava(和其他语言)。 这是真的?你知道和其他方法可以更快地旋转图像 90 度吗? 非常感谢

【问题讨论】:

    标签: java python image opencv image-processing


    【解决方案1】:

    JPEG 图像可以在不重新压缩图像数据的情况下旋转。

    对于 Python 项目,请参阅 jpegtran-cffi

    如果您想应用轮换,您可能无法获得比这更快的速度。

    另一种可能性是编辑 JPEG 图像的 EXIF 方向。它基本上告诉查看器应用程序如何旋转图像。这只是更改单个值,但并非所有读者/查看者都支持方向标志。

    【讨论】:

      【解决方案2】:

      据我所知,进行基本图像处理(如旋转、剪切、调整大小和过滤)的最快方法是在 python 中使用枕头模块。当必须完成高级操作时使用 OpenCV,而 Pillow 无法完成。枕头旋转会回答你的问题。

      Image.rotate(angle)
      

      这就是将角度旋转任意角度所需的全部操作。

      【讨论】:

        【解决方案3】:

        我在我的 java 项目中使用了这个 opencv 实现来旋转图像,我对旋转图像的性能感到满意。

        *OpenCV 依赖版本如下。

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

        以下方法根据您提供的角度旋转图像。

            @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);
            }
        
        

        上面的 rotateImage 方法输入一个 BufferedImage 类型的图像和旋转图像所需的角度(以度为单位)。 rotateImage 方法的第一个操作是使用您提供的角度以及要旋转的图像的宽度和高度来计算将具有旋转图像的新宽度和新高度。 第二个重要操作是调整用于旋转图像的矩阵的边界。这样做是为了防止图像因旋转操作而被裁剪。

        下面是我用来将图像从 BufferedImage 转换为 Mat 的类,反之亦然。

        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;
            }
        }
        
        

        就我而言,我需要在 BufferedImage 中转换图像。如果不需要,可以跳过,直接将图像读取为 Mat 类型并将其传递给该方法 rotateImage。

        
        public Mat rotateImage(File input, double angle) {
        Mat imageMat = Highgui.imread(input.getAbsolutePath())
        ...
        }
        

        【讨论】:

          【解决方案4】:

          上周我有一个更笼统的问题,我怎样才能以任何角度尽可能快地旋转图像,最后我比较了在我写的this article 中提供旋转功能的不同库。

          快速回答是OpenCV,更详细的回答写在文章里:

          我将重点介绍三个最常用的 Python 图像编辑库,即 Pillow、OpenCV 和 Scipy。

          在以下代码中,您可以了解如何导入这些库以及如何使用它们旋转图像。我为每个库定义了一个函数,用于我们的实验

          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)
          

          为了了解哪个库在旋转和插值图像方面效率更高,我们首先设计了一个简单的实验。我们使用所有三个库对我们的函数 rand_8bit() 生成的 200 x 200 像素 8 位图像应用 20 度旋转。

          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)
          

          结果是: 每个循环 987 µs ± 76 µs(7 次运行的平均值 ± 标准偏差,每次 1000 个循环) 每个循环 414 µs ± 79.8 µs(7 次运行的平均值 ± 标准偏差,每次 1000 个循环) 每个循环 4.46 毫秒 ± 1.07 毫秒(平均值 ± 标准偏差,7 次运行,每次 100 次循环)

          这意味着在图像旋转方面,OpenCV 是最高效的,而 Scipy 是最慢的。

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2013-04-22
            • 2014-11-07
            相关资源
            最近更新 更多