2012-08-01 29 views
13

Tôi đang cố gắng xoay một hình ảnh một số độ rồi hiển thị nó trong cửa sổ. ý tưởng của tôi là để xoay và sau đó hiển thị nó trong một cửa sổ mới với chiều rộng mới và chiều cao của cửa sổ được tính từ chiều rộng cũ và height:Python 2.7.3 + OpenCV 2.4 sau khi cửa sổ xoay không vừa với Hình ảnh

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

Tôi đã chờ đợi kết quả để trông giống như dưới đây:

enter image description here

nhưng nó quay ra kết quả như sau:

enter image description here

và mã của tôi là ở đây:

#!/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) 

Phải có một số sai lầm ngu ngốc trong mã dẫn của tôi cho vấn đề này, nhưng tôi không thể hình dung nó ra ... và tôi biết mã của tôi là không đủ pythonic :(.. xin lỗi vì điều đó ..

Có ai có thể giúp tôi không?

nhất,

bearzk

Trả lời

7

Khi câu trả lời của BloodyD cho biết, cv2.warpAffine không tự động căn giữa hình ảnh được chuyển đổi. Thay vào đó, nó chỉ đơn giản biến đổi từng pixel bằng ma trận chuyển đổi. (Điều này có thể di chuyển các điểm ảnh ở bất kỳ nơi nào trong không gian Descartes, bao gồm cả vùng ảnh gốc). Sau đó, khi bạn chỉ định kích thước ảnh đích, nó lấy một vùng có kích thước đó, bắt đầu từ (0,0), tức là phía trên bên trái của khung gốc. Bất kỳ phần nào của hình ảnh được biến đổi không nằm trong khu vực đó sẽ bị cắt bỏ.

Dưới đây là Python mã để xoay và mở rộng quy mô một hình ảnh, với kết quả làm trung tâm:

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

Cảm ơn câu trả lời ngắn gọn và mã được chú thích. Giải quyết vấn đề một cách độc đáo. – leomelzer

3

Khi bạn nhận được ma trận xoay như thế này:

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

bạn tham số "quy mô" được thiết lập để 1.0, vì vậy nếu bạn sử dụng nó để chuyển đổi hình ảnh của bạn ma trận cho ma trận kết quả của bạn có cùng kích thước, nó nhất thiết sẽ bị cắt bớt.

Bạn thay vì có thể nhận được một ma trận xoay như thế này:

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

rằng cả hai sẽ xoay và co lại, để lại căn phòng xung quanh các cạnh (bạn có thể mở rộng nó lên đầu tiên để bạn vẫn sẽ kết thúc với một lớn hình ảnh).

Ngoài ra, có vẻ như bạn đang bối rối các quy ước numpy và OpenCV cho kích thước hình ảnh. OpenCV sử dụng (x, y) cho kích thước hình ảnh và tọa độ điểm, trong khi sử dụng gọn gàng (y, x). Đó có lẽ là lý do tại sao bạn đang đi từ một tỷ lệ bức chân dung đến cảnh quan.

Tôi có xu hướng rõ ràng về nó như thế này:

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

vv ...

Cuối cùng, điều này hoạt động tốt đối với tôi:

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 

Cập nhật:

Đây là tập lệnh hoàn chỉnh mà tôi đã thực hiện. Chỉ cần cv2.imshow ("winname", hình ảnh) và cv2.waitkey() không có đối số để giữ cho nó mở:

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() 

Thật không nhiều đó ... Và bạn đã chắc chắn quyền sử dụng if __name__ == '__main__': nếu nó là một mô-đun thực sự mà bạn đang làm việc.

+0

nhờ cho câu trả lời của bạn! bạn có nhớ ghi lại chức năng hiển thị hình ảnh của bạn không? :) – bearzk

1

Vâng, câu hỏi này có vẻ không cập nhật, nhưng tôi đã có cùng một vấn đề và mất một lúc để giải quyết nó mà không cần mở rộng hình ảnh gốc lên xuống. Tôi chỉ sẽ gửi giải pháp của tôi (tiếc là C++, nhưng nó có thể được dễ dàng chuyển đến python nếu cần):

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

Các giải pháp chung là xoaydịch hình xoay tới vị trí đúng . Vì vậy, chúng tôi tạo ra hai ma trận chuyển đổi (đầu tiên cho phép quay, thứ hai cho bản dịch) và nhân chúng với phép biến đổi affine cuối cùng. Khi ma trận được trả về bởi getRotationMatrix2D của opencv chỉ là 2x3, tôi phải tạo ra các ma trận bằng tay theo định dạng 3x3, do đó chúng có thể nhân lên. Sau đó, chỉ cần lấy hai hàng đầu tiên và áp dụng các biến dạng affine.

EDIT: Tôi đã tạo Gist, vì tôi cần chức năng này quá thường xuyên trong các dự án khác nhau. Ngoài ra còn có một phiên bản Python của nó: https://gist.github.com/BloodyD/97917b79beb332a65758

Các vấn đề liên quan