2010-02-14 157 views
34

Cách tốt nhất (trong c/C++) để xoay IplImage/cv :: Mat bằng 90 độ là gì? Tôi sẽ giả định rằng phải có một cái gì đó tốt hơn so với chuyển đổi nó bằng cách sử dụng một ma trận, nhưng tôi dường như không thể tìm thấy bất cứ điều gì khác hơn là trong API và trực tuyến.Cách dễ nhất để xoay 90 độ một hình ảnh bằng cách sử dụng OpenCV?

+0

C++ Câu trả lời là [ở đây] (http://stackoverflow.com/a/16278334/2436175). – Antonio

Trả lời

14

Tính đến OpenCV3.2, cuộc sống chỉ có một chút dễ dàng hơn, bây giờ bạn có thể xoay một hình ảnh trong một dòng mã:

cv::rotate(image, image, ROTATE_90_CLOCKWISE); 

Đối với hướng bạn có thể chọn bất cứ điều nào sau đây:

ROTATE_90_CLOCKWISE 
ROTATE_180 
ROTATE_90_COUNTERCLOCKWISE 
10

Cập nhật cho chuyển vị:

Bạn nên sử dụng cvTranspose() hay cv::transpose() vì (như bạn đúng chỉ ra) đó là hiệu quả hơn. Một lần nữa, tôi khuyên bạn nên nâng cấp lên OpenCV2.0 vì hầu hết các chức năng cvXXX chỉ chuyển đổi cấu trúc IplImage* thành các đối tượng Mat (không có bản sao sâu). Nếu bạn đã lưu hình ảnh trong một đối tượng Mat, Mat.t() sẽ trả về vị trí chuyển tiếp.

Bất kỳ luân chuyển:

Bạn nên sử dụng cvWarpAffine bằng cách xác định ma trận xoay trong khuôn khổ chung của ma trận chuyển đổi. Tôi rất muốn giới thiệu nâng cấp lên OpenCV2.0 có một số tính năng cũng như lớp Mat bao gói ma trận và hình ảnh. Với 2.0, bạn có thể sử dụng warpAffine ở trên.

+0

Cảm ơn! Bạn có chắc chắn điều đó không kém hiệu quả hơn là chỉ chuyển mảng pixel? Vấn đề là, tôi không chắc liệu OpenCV thậm chí có thể biểu diễn nội bộ hình ảnh như một mảng pixel hay không, tức là một cái gì đó giống như một int * 32-bit, và nếu nó đã làm, làm thế nào để có được một con trỏ đến mảng đó. –

+0

Tôi xin lỗi, tôi đã không đọc câu hỏi của bạn đúng cách, tôi đã cập nhật câu trả lời của mình. – Jacob

+22

Việc chuyển tiếp phải được theo sau bởi một lật (cvFlip) để xoay chính xác hình ảnh – Amnon

1

Tôi đang tìm một số chi tiết và không tìm thấy bất kỳ ví dụ nào. Vì vậy, tôi đăng một hàm transposeImage đó, tôi hy vọng, sẽ giúp những người đang tìm kiếm một cách trực tiếp để xoay 90 ° mà không làm mất dữ liệu:

IplImage* transposeImage(IplImage* image) { 

    IplImage *rotated = cvCreateImage(cvSize(image->height,image->width), 
     IPL_DEPTH_8U,image->nChannels); 
    CvPoint2D32f center; 
    float center_val = (float)((image->width)-1)/2; 
    center.x = center_val; 
    center.y = center_val; 
    CvMat *mapMatrix = cvCreateMat(2, 3, CV_32FC1);   
    cv2DRotationMatrix(center, 90, 1.0, mapMatrix); 
    cvWarpAffine(image, rotated, mapMatrix, 
     CV_INTER_LINEAR + CV_WARP_FILL_OUTLIERS, 
     cvScalarAll(0));  
    cvReleaseMat(&mapMatrix); 

    return rotated; 
} 

Câu hỏi: Tại sao điều này?

float center_val = (float)((image->width)-1)/2; 

Trả lời: Vì nó hoạt động :) Trung tâm duy nhất tôi thấy không dịch hình ảnh. Mặc dù nếu ai đó có một lời giải thích tôi sẽ được quan tâm.

+1

Lý do toán học của bạn có thể do phân chia số nguyên. Những gì bạn muốn làm là: float center_val = (float) image-> width/2.0f. –

+0

Lưu ý rằng phương pháp cvTranspose + cvFlip sẽ nhanh hơn một chút nếu bạn chỉ yêu cầu xoay theo gia số 90 độ. –

55

Luân phiên là thành phần của chuyển vị và lật.

R_{+90} = F_x \circ T

R_{-90} = F_y \circ T

nào trong OpenCV có thể được viết như thế này (Python ví dụ dưới đây):

img = cv.LoadImage("path_to_image.jpg") 
timg = cv.CreateImage((img.height,img.width), img.depth, img.channels) # transposed image 

# rotate counter-clockwise 
cv.Transpose(img,timg) 
cv.Flip(timg,timg,flipMode=0) 
cv.SaveImage("rotated_counter_clockwise.jpg", timg) 

# rotate clockwise 
cv.Transpose(img,timg) 
cv.Flip(timg,timg,flipMode=1) 
cv.SaveImage("rotated_clockwise.jpg", timg) 
+0

xem 'cv2' của tôi bên dưới: http://stackoverflow.com/questions/2259678/easiest-way-to-rotate-by-90-degrees-an-image-using-opencv/42359233#42359233 –

+0

Lật theo chiều dọc (flipMode = 0) nên hơi đắt hơn so với lật theo chiều ngang, vì bạn đang sử dụng bộ nhớ cache tốt hơn. Do đó, quay ngược chiều kim đồng hồ sẽ nhanh hơn một chút khi thực hiện lật ngang trước và sau đó chuyển vị trí. –

4

Đây là một ví dụ mà không có giao diện mới C++ (chỉ hoạt động đối với 90, 180 và 270 độ, sử dụng param = 1, 2 và 3). Hãy nhớ gọi cvReleaseImage trên hình ảnh đã trả lại sau khi sử dụng.

IplImage *rotate_image(IplImage *image, int _90_degrees_steps_anti_clockwise) 
{ 
    IplImage *rotated; 

    if(_90_degrees_steps_anti_clockwise != 2) 
     rotated = cvCreateImage(cvSize(image->height, image->width), image->depth, image->nChannels); 
    else 
     rotated = cvCloneImage(image); 

    if(_90_degrees_steps_anti_clockwise != 2) 
     cvTranspose(image, rotated); 

    if(_90_degrees_steps_anti_clockwise == 3) 
     cvFlip(rotated, NULL, 1); 
    else if(_90_degrees_steps_anti_clockwise == 1) 
     cvFlip(rotated, NULL, 0); 
    else if(_90_degrees_steps_anti_clockwise == 2) 
     cvFlip(rotated, NULL, -1); 

    return rotated; 
} 
2

Dưới đây là EmguCV tôi (C# cảng OpenCV) giải pháp:

public static Image<TColor, TDepth> Rotate90<TColor, TDepth>(this Image<TColor, TDepth> img) 
    where TColor : struct, IColor 
    where TDepth : new() 
{ 
    var rot = new Image<TColor, TDepth>(img.Height, img.Width); 
    CvInvoke.cvTranspose(img.Ptr, rot.Ptr); 
    rot._Flip(FLIP.HORIZONTAL); 
    return rot; 
} 

public static Image<TColor, TDepth> Rotate180<TColor, TDepth>(this Image<TColor, TDepth> img) 
    where TColor : struct, IColor 
    where TDepth : new() 
{ 
    var rot = img.CopyBlank(); 
    rot = img.Flip(FLIP.VERTICAL); 
    rot._Flip(FLIP.HORIZONTAL); 
    return rot; 
} 

public static void _Rotate180<TColor, TDepth>(this Image<TColor, TDepth> img) 
    where TColor : struct, IColor 
    where TDepth : new() 
{ 
    img._Flip(FLIP.VERTICAL); 
    img._Flip(FLIP.HORIZONTAL); 
} 

public static Image<TColor, TDepth> Rotate270<TColor, TDepth>(this Image<TColor, TDepth> img) 
    where TColor : struct, IColor 
    where TDepth : new() 
{ 
    var rot = new Image<TColor, TDepth>(img.Height, img.Width); 
    CvInvoke.cvTranspose(img.Ptr, rot.Ptr); 
    rot._Flip(FLIP.VERTICAL); 
    return rot; 
} 

không nên quá khắt khe để dịch nó trở lại vào C++.

2

Đây là python tôi cv2 thực hiện:

import cv2 

img=cv2.imread("path_to_image.jpg") 

# rotate ccw 
out=cv2.transpose(img) 
out=cv2.flip(out,flipCode=0) 

# rotate cw 
out=cv2.transpose(img) 
out=cv2.flip(out,flipCode=1) 

cv2.imwrite("rotated.jpg", out) 
+0

mã ccw của bạn thực hiện chuyển đổi cw. – Jason

+0

đã sửa. Cảm ơn @ Jason! –

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