web-dev-qa-db-fra.com

Le moyen le plus simple de faire pivoter de 90 degrés une image à l'aide d'OpenCV?

Quelle est la meilleure façon (en c/c ++) de faire pivoter un IplImage/cv :: Mat de 90 degrés? Je suppose qu'il doit y avoir quelque chose de mieux que de le transformer à l'aide d'une matrice, mais je n'arrive pas à trouver autre chose que cela dans l'API et en ligne.

45
Ben H

Depuis OpenCV3.2, la vie est devenue un peu plus facile, vous pouvez maintenant faire pivoter une image sur une seule ligne de code:

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

Pour la direction, vous pouvez choisir l'une des options suivantes:

ROTATE_90_CLOCKWISE
ROTATE_180
ROTATE_90_COUNTERCLOCKWISE
41
Morris Franken

La rotation est une composition de transposition et de flip.

R_{+90} = F_x \circ T

R_{-90} = F_y \circ T

Qui dans OpenCV peut être écrit comme ceci (exemple Python ci-dessous):

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)
60
sastanin

Mise à jour pour la transposition:

Vous devriez utiliser cvTranspose() ou cv::transpose() parce que (comme vous l'avez souligné à juste titre) c'est plus efficace. Encore une fois, je recommande la mise à niveau vers OpenCV2.0 car la plupart des fonctions cvXXX convertissent simplement les structures IplImage* En objets Mat (pas de copies complètes). Si vous stockiez l'image dans un objet Mat, Mat.t() renverrait la transposition.

Toute rotation:

Vous devez utiliser cvWarpAffine en définissant la matrice de rotation dans le cadre général de la matrice de transformation. Je recommanderais fortement de passer à OpenCV2. qui a plusieurs fonctionnalités ainsi qu'une classe Mat qui encapsule les matrices et les images. Avec 2.0, vous pouvez utiliser warpAffine à ce qui précède.

10
Jacob

Ceci est un exemple sans la nouvelle interface C++ (fonctionne pour 90, 180 et 270 degrés, en utilisant param = 1, 2 et 3). N'oubliez pas d'appeler cvReleaseImage sur l'image retournée après l'avoir utilisée.

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;
}
4
Andres Hurtis

Voici mon python cv2 la mise en oeuvre:

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)
4
Eran W

Voici ma solution EmguCV (un port C # d'OpenCV):

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

Cela ne devrait pas être trop difficile de le traduire en C++.

2
mpen

Eh bien, je cherchais des détails et je n'ai trouvé aucun exemple. Je publie donc une fonction transposeImage qui, je l'espère, aidera ceux qui recherchent un moyen direct de pivoter de 90 ° sans perdre de données:

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

Question: pourquoi cela?

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

Réponse: Parce que ça marche :) Le seul centre que j'ai trouvé qui ne traduit pas l'image. Mais si quelqu'un a une explication, je serais intéressé.

1
Artem