Python 2.7.3 + OpenCV 2.4后旋转窗口不适合图片

问题描述:

我试图旋转图像一些度数,然后在窗口中显示它。 我的想法是旋转,然后在新的宽度和窗口的高度,一个新的窗口,从旧的宽度和高度计算表现出来:Python 2.7.3 + OpenCV 2.4后旋转窗口不适合图片

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

我期待的结果看起来像下面:

enter image description here

但事实证明,结果是这样的:

enter image description 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) 

必须有在我的代码导致此问题的一些愚蠢的错误,但我不出来... 我知道我的代码是不是Python的足够:(..对此的承诺..

任何人都可以帮助我吗?

最佳,

bearzk

由于BloodyD的回答说,cv2.warpAffine不会自动居中转换后的图像。相反,它只是使用变换矩阵变换每个像素。 (这可以在笛卡尔空间中的任何位置移动像素,包括在原始图像区域之外)。然后,当您指定目标图像大小时,它将抓取该大小的区域,从(0,0)开始,即左上角原始的框架。不在该区域的转换图像的任何部分都将被切断。

这里的Python代码旋转和缩放图像,与中心的结果:

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 

enter image description here

+0

感谢您的简洁的答案和注释的代码。很好地解决了这个问题。 – leomelzer 2015-10-22 10:29:04

当你旋转矩阵是这样的:

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

你的“规模”参数设置为1.0,所以如果你用它来改变你的形象矩阵到相同大小的结果矩阵,它必然会被剪切。

可以代替得到一个旋转矩阵是这样的:

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

,将两个旋转和收缩,留有余地周围的边缘(可以先扩展它,以便你还是会最终有一个大图片)。

此外,它看起来像你正在混淆图像大小numpy和OpenCV约定。 OpenCV使用(x,y)表示图像大小和点坐标,而numpy使用(y,x)。这可能是您为什么要从纵向比例到纵向比例。

我倾向于要明确它是这样的:

imageHeight = image.shape[0] 
imageWidth = image.shape[1] 
pointcenter = (imageHeight/2, imageWidth/2) 

等等

最终,这正常工作对我来说:

def rotateImage(image, angel):#parameter angel in degrees 
    height = image.shape[0] 
    width = image.shape[1] 
    height_big = height * 2 
    width_big = width * 2 
    image_big = cv2.resize(image, (width_big, height_big)) 
    image_center = (width_big/2, height_big/2)#rotation center 
    rot_mat = cv2.getRotationMatrix2D(image_center,angel, 0.5) 
    result = cv2.warpAffine(image_big, rot_mat, (width_big, height_big), flags=cv2.INTER_LINEAR) 
    return result 

更新:

这是我执行的完整脚本。只是cv2.imshow不带参数(“winname”,图像)和cv2.waitkey(),以保持它打开:

import cv2 

def rotateImage(image, angel):#parameter angel in degrees 
    height = image.shape[0] 
    width = image.shape[1] 
    height_big = height * 2 
    width_big = width * 2 
    image_big = cv2.resize(image, (width_big, height_big)) 
    image_center = (width_big/2, height_big/2)#rotation center 
    rot_mat = cv2.getRotationMatrix2D(image_center,angel, 0.5) 
    result = cv2.warpAffine(image_big, rot_mat, (width_big, height_big), flags=cv2.INTER_LINEAR) 
    return result 

imageOriginal = cv2.imread("/Path/To/Image.jpg") 
# this was an iPhone image that I wanted to resize to something manageable to view 
# so I knew beforehand that this is an appropriate size 
imageOriginal = cv2.resize(imageOriginal, (600,800)) 
imageRotated= rotateImage(imageOriginal, 45) 

cv2.imshow("Rotated", imageRotated) 
cv2.waitKey() 

真的不是很多那里......你是绝对正确的使用if __name__ == '__main__':如果是你正在开发的一个真正的模块。

+0

谢谢您的回答!你介意写下你的图像显示功能吗? :) – bearzk 2012-08-02 08:50:27

嗯,这个问题似乎并不是最新的,但我有同样的问题,并花了一段时间来解决它没有缩放原始图像上下。我只是张贴我的解决方案(不幸的是C++代码,但它可以在需要时方便地移植到Python):

#include <math.h> 
#define PI 3.14159265 
#define SIN(angle) sin(angle * PI/180) 
#define COS(angle) cos(angle * PI/180) 

void rotate(const Mat src, Mat &dest, double angle, int borderMode, const Scalar &borderValue){ 

    int w = src.size().width, h = src.size().height; 

    // resize the destination image 
    Size2d new_size = Size2d(abs(w * COS((int)angle % 180)) + abs(h * SIN((int)angle % 180)), abs(w * SIN((int)angle % 180)) + abs(h * COS((int)angle % 180))); 
    dest = Mat(new_size, src.type()); 

    // this is our rotation point 
    Size2d old_size = src.size(); 
    Point2d rot_point = Point2d(old_size.width/2.0, old_size.height/2.0); 

    // and this is the rotation matrix 
    // same as in the opencv docs, but in 3x3 form 
    double a = COS(angle), b = SIN(angle); 
    Mat rot_mat = (Mat_<double>(3,3) << a, b, (1 - a) * rot_point.x - b * rot_point.y, -1 * b, a, b * rot_point.x + (1 - a) * rot_point.y, 0, 0, 1); 

    // next the translation matrix 
    double offsetx = (new_size.width - old_size.width)/2, 
      offsety = (new_size.height - old_size.height)/2; 
    Mat trans_mat = (Mat_<double>(3,3) << 1, 0, offsetx , 0, 1, offsety, 0, 0, 1); 

    // multiply them: we rotate first, then translate, so the order is important! 
    // inverse order, so that the transformations done right 
    Mat affine_mat = Mat(trans_mat * rot_mat).rowRange(0, 2); 

    // now just apply the affine transformation matrix 
    warpAffine(src, dest, affine_mat, new_size, INTER_LINEAR, borderMode, borderValue); 
} 

一般的解决方法是旋转翻译旋转图片以正确的位置。所以我们创建两个变换矩阵(首先是旋转,第二个是平移),并将它们乘以最终的仿射变换。由于opencv的getRotationMatrix2D返回的矩阵只有2×3,我不得不以3x3格式手动创建矩阵,所以它们可以相乘。然后,只需取前两行并应用仿射变形。

编辑:我创建了一个Gist,因为我在不同的项目中经常需要这个功能。还有一个Python版本:https://gist.github.com/BloodyD/97917b79beb332a65758