【问题标题】:OpenCV Python : rotate image without cropping sidesOpenCV Python:旋转图像而不裁剪边
【发布时间】:2017-10-09 02:29:48
【问题描述】:

想象一下我有这些图片:

我希望左边的图像像中间的图像一样旋转,而不是右边的图像。我如何使用 Python 和 OpenCV 做到这一点。我查看了getRotationMatrix2DwarpAffine,但有关它的示例将我的图像转换为正确的图像。

【问题讨论】:

标签: python opencv rotation


【解决方案1】:

这是迄今为止我找到的旋转图像同时避免裁剪图像的最佳解决方案。

Rotate an image without cropping in OpenCV in C++

import cv2

def rotate_image(mat, angle):
    """
    Rotates an image (angle in degrees) and expands image to avoid cropping
    """

    height, width = mat.shape[:2] # image shape has 3 dimensions
    image_center = (width/2, height/2) # getRotationMatrix2D needs coordinates in reverse order (width, height) compared to shape

    rotation_mat = cv2.getRotationMatrix2D(image_center, angle, 1.)

    # rotation calculates the cos and sin, taking absolutes of those.
    abs_cos = abs(rotation_mat[0,0]) 
    abs_sin = abs(rotation_mat[0,1])

    # find the new width and height bounds
    bound_w = int(height * abs_sin + width * abs_cos)
    bound_h = int(height * abs_cos + width * abs_sin)

    # subtract old image center (bringing image back to origo) and adding the new image center coordinates
    rotation_mat[0, 2] += bound_w/2 - image_center[0]
    rotation_mat[1, 2] += bound_h/2 - image_center[1]

    # rotate image with the new bounds and translated rotation matrix
    rotated_mat = cv2.warpAffine(mat, rotation_mat, (bound_w, bound_h))
    return rotated_mat

当角度为 90*n 时,您可以添加检查以避免一些计算,但此功能适用于任何角度。

【讨论】:

  • 这比 OP 要求的更通用,但它是一个很好的解决方案,我认为它应该是公认的答案。
  • 在 warpAffine 上使用 "borderMode=" 标志来控制边框的填充方式(如果结果中存在)。
【解决方案2】:

如果您只关心 90 度旋转 numpy。它更容易并且适用于 opencv 输入:

import numpy as np
rotated_image = np.rot90(im)

【讨论】:

  • 某些功能(例如 cv.rectangle)在此之后将无法工作。
  • 你可以使用:np.ascontiguousarray(np.rot90(im)) 或:np.rot90(im).copy()
【解决方案3】:

由于我不知道您的代码,我仍然猜想使用 imutils.rotate_boundfunction 可以解决问题。例如:rotate = imutils.rotate_bound(image, angle)

【讨论】:

  • imutils 是 OpenCV 的一部分还是我应该添加它?
  • 您需要通过pip install imutils 安装它,当然还要将import imutils 导入到您的python 代码中
  • 好的,谢谢,我试试看!
  • 奇怪的是,该方法假定您想要纵向模式的图片。即,将0.0 作为旋转角度将确保更长的尺寸现在是高度,即使这意味着将其旋转到 90 度。
【解决方案4】:

这是使用 cv2.rotate(frame,rotateCode = 1) 旋转图像帧并使用帧的 cv2.CAP_PROP_FRAME_WIDTH 和 cv2.CAP_PROP_FRAME_HEIGHT 重新缩放或调整大小的最简单方法。

import numpy as np
import cv2

cam = cv2.VideoCapture(2)

while(True):
    # Capture frame-by-frame
    cam.set(cv2.CAP_PROP_FRAME_WIDTH, 640) # You can change frame width by chaning number.

    cam.set(cv2.CAP_PROP_FRAME_HEIGHT, 480) # You can change frame height by chaning number.

    ret, frame = cam.read()

    new_frame=cv2.rotate(frame,rotateCode = 1) 

您可以输入 rotateCode= 0 或 1 或 2。取决于您的轮换。它会给你 0 或 90 或 180 或 270 个角度

    # Display the resulting frame
    cv2.imshow('frame',new_frame)

    if cv2.waitKey(1) & 0xFF == ord('q'):
        break

# When everything done, release the capture
cam.release()
cv2.destroyAllWindows()

希望对你有所帮助。

【讨论】:

    【解决方案5】:

    虽然这个问题是针对 CV2 提出的,但您可以使用 python 的本机图像库来做到这一点。

    rotate_degrees = -90
    img = Image.open(input_file_path)
    img2 = img.rotate(rotate_degrees, expand=True)
    img2.save(output_file_path)
    

    如果您在旋转命令中省略expand=True,您将获得类似于 OP 右手照片的结果。

    【讨论】:

      【解决方案6】:

      您也可以使用填充,即在图像的两侧添加边框,然后将其旋转以避免从原始图像中裁剪。

      def rotate_im(image, angle)
          image_height = image.shape[0]
          image_width = image.shape[1]
          diagonal_square = (image_width*image_width) + (
              image_height* image_height
          )
          #
          diagonal = round(sqrt(diagonal_square))
          padding_top = round((diagonal-image_height) / 2)
          padding_bottom = round((diagonal-image_height) / 2)
          padding_right = round((diagonal-image_width) / 2)
          padding_left = round((diagonal-image_width) / 2)
          padded_image = cv2.copyMakeBorder(image,
                                            top=padding_top,
                                            bottom=padding_bottom,
                                            left=padding_left,
                                            right=padding_right,
                                            borderType=cv2.BORDER_CONSTANT,
                                            value=0
                  )
          padded_height = padded_image.shape[0]
          padded_width = padded_image.shape[1]
          transform_matrix = cv2.getRotationMatrix2D(
                      (padded_height/2,
                       padded_width/2), # center
                      angle, # angle
            1.0) # scale
          rotated_image = cv2.warpAffine(padded_image,
                                         transform_matrix,
                                         (diagonal, diagonal),
                                         flags=cv2.INTER_LANCZOS4)
          return rotated_image
      

      【讨论】:

        【解决方案7】:

        它很简单,不需要任何warpaffine或任何计算检查此代码

        import numpy as np
        from PIL import ImageGrab
        import cv2
        
        angle = -90
        scale = 1.0
        
        while True:
            img = ImageGrab.grab()
            img_np = np.array(img)
            frame = cv2.cvtColor(img_np, cv2.COLOR_BGR2RGB)
            new = cv2.rotate(frame,rotateCode = 0)# this is the line to rotate the image
            true = cv2.resize(new, (0,0), fx = 0.6, fy = 0.6) # with fxand fy u can control the size
            cv2.imshow('output', true)
            if cv2.waitKey(1) == 27:
                break
        
        
        cv2.destroyAllWindows()
        

        【讨论】:

          猜你喜欢
          • 2015-08-23
          • 1970-01-01
          • 2014-03-29
          • 1970-01-01
          • 2023-03-05
          • 2013-05-18
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多