bearzk - 2 months ago 29

Python Question

I'm trying to rotate a image some degrees then show it in a window.

my idea is to rotate and then show it in a new window with new width and height of window calculated from the old width and height:

`new_width = x * cos angle + y * sin angle`

new_height = y * cos angle + x * sin angle

I was expecting the result to look like below:

but it turns out the result looks like this:

and my code is here:

`#!/usr/bin/env python -tt`

#coding:utf-8

import sys

import math

import cv2

import numpy as np

def rotateImage(image, angel):#parameter angel in degrees

if len(image.shape) > 2:#check colorspace

shape = image.shape[:2]

else:

shape = image.shape

image_center = tuple(np.array(shape)/2)#rotation center

radians = math.radians(angel)

x, y = im.shape

print 'x =',x

print 'y =',y

new_x = math.ceil(math.cos(radians)*x + math.sin(radians)*y)

new_y = math.ceil(math.sin(radians)*x + math.cos(radians)*y)

new_x = int(new_x)

new_y = int(new_y)

rot_mat = cv2.getRotationMatrix2D(image_center,angel,1.0)

print 'rot_mat =', rot_mat

result = cv2.warpAffine(image, rot_mat, shape, flags=cv2.INTER_LINEAR)

return result, new_x, new_y

def show_rotate(im, width, height):

# width = width/2

# height = height/2

# win = cv2.cv.NamedWindow('ro_win',cv2.cv.CV_WINDOW_NORMAL)

# cv2.cv.ResizeWindow('ro_win', width, height)

win = cv2.namedWindow('ro_win')

cv2.imshow('ro_win', im)

if cv2.waitKey() == '\x1b':

cv2.destroyWindow('ro_win')

if __name__ == '__main__':

try:

im = cv2.imread(sys.argv[1],0)

except:

print '\n', "Can't open image, OpenCV or file missing."

sys.exit()

rot, width, height = rotateImage(im, 30.0)

print width, height

show_rotate(rot, width, height)

There must be some stupid mistakes in my code lead to this problem, but I can not figure it out...

and I know my code is not pythonic enough :( ..sorry for that..

Can anyone help me?

Best，

bearzk

Answer

As BloodyD's answer said, `cv2.warpAffine`

doesn't auto-center the transformed image. Instead, it simply transforms each pixel using the transformation matrix. (This could move pixels anywhere in Cartesian space, including out of the original image area.) Then, when you specify the destination image size, it grabs an area of that size, beginning at (0,0), i.e. the upper left of the original frame. Any parts of your transformed image that don't lie in that region will be cut off.

Here's Python code to rotate and scale an image, with the result centered:

```
def rotateAndScale(img, scaleFactor = 0.5, degreesCCW = 30):
(oldY,oldX) = img.shape #note: numpy uses (y,x) convention but most OpenCV functions use (x,y)
M = cv2.getRotationMatrix2D(center=(oldX/2,oldY/2), angle=degreesCCW, scale=scaleFactor) #rotate about center of image.
#choose a new image size.
newX,newY = oldX*scaleFactor,oldY*scaleFactor
#include this if you want to prevent corners being cut off
r = np.deg2rad(degreesCCW)
newX,newY = (abs(np.sin(r)*newY) + abs(np.cos(r)*newX),abs(np.sin(r)*newX) + abs(np.cos(r)*newY))
#the warpAffine function call, below, basically works like this:
# 1. apply the M transformation on each pixel of the original image
# 2. save everything that falls within the upper-left "dsize" portion of the resulting image.
#So I will find the translation that moves the result to the center of that region.
(tx,ty) = ((newX-oldX)/2,(newY-oldY)/2)
M[0,2] += tx #third column of matrix holds translation, which takes effect after rotation.
M[1,2] += ty
rotatedImg = cv2.warpAffine(img, M, dsize=(int(newX),int(newY)))
return rotatedImg
```