web-dev-qa-db-fra.com

Faire pivoter la matrice Opencv de 90, 180, 270 degrés

Je capture une image de la webcam et je dois la faire pivoter à angle droit. Je me suis trouvé ces fonctions:

  1. getRotationMatrix2D - pour créer une matrice de rotation (quelle qu'elle soit)
  2. transform - transforme une matrice en une autre par matrice de rotation

Mais je ne reçois rien d'autre qu'une zone noire. Voici mon code:

   if(rotate_button.click%4>0) {
       double angle = (rotate_button.click%4)*90;  //button increments its click by 1 per click
       Mat transform_m = getRotationMatrix2D(Point(cam_frame_width/2, cam_frame_height/2), angle, 1);  //Creating rotation matrix
       Mat current_frame;
       transform(cam_frame, current_frame, transform_m);  //Transforming captured image into a new one
       cam_frame = Mat((int)current_frame.cols,(int)current_frame.rows, cam_frame_type) = Scalar(0,128,0);  //resizing captured matrix, so I can copy the resized one on it
       current_frame.copyTo(cam_frame);  //Copy resized to original
   }

Sort juste un écran noir.

34
user2041141

Utilisez warpAffine .:

Essayer:

Point2f src_center(source.cols/2.0F, source.rows/2.0F);
Mat rot_mat = getRotationMatrix2D(src_center, angle, 1.0);
Mat dst;
warpAffine(source, dst, rot_mat, source.size());

dst est l'image finale

30
Abhishek Thakur

Les réponses ci-dessus sont trop complexes et monopolisent votre processeur. Votre question n'était pas une rotation arbitraire, mais "Rotation de la matrice Opencv de 90, 180, 270 degrés".

MISE À JOUR DU 30 JUIN 2017:

Cette fonctionnalité est prise en charge par OpenCV, mais n'est pas documentée: https://github.com/opencv/opencv/blob/master/modules/core/include/opencv2/core.hpp#L1041

void rotate(InputArray src, OutputArray dst, int rotateCode);

avec

enum RotateFlags {
    ROTATE_90_CLOCKWISE = 0, //Rotate 90 degrees clockwise
    ROTATE_180 = 1, //Rotate 180 degrees clockwise
    ROTATE_90_COUNTERCLOCKWISE = 2, //Rotate 270 degrees clockwise
};

Réponse originale et rotation des degrés arbitraires:

Vous pouvez également le faire en utilisant l'opération de retournement et de transposition, c'est-à-dire pour 90CW:

transpose(matSRC, matROT);  
flip(matROT, matROT,1); //transpose+flip(1)=CW

etc. Déterminez vous-même les autres commandes (penser = apprendre) en vous présentant avec l'opération de transposition et de retournement des Docs.

void rot90(cv::Mat &matImage, int rotflag){
  //1=CW, 2=CCW, 3=180
  if (rotflag == 1){
    transpose(matImage, matImage);  
    flip(matImage, matImage,1); //transpose+flip(1)=CW
  } else if (rotflag == 2) {
    transpose(matImage, matImage);  
    flip(matImage, matImage,0); //transpose+flip(0)=CCW     
  } else if (rotflag ==3){
    flip(matImage, matImage,-1);    //flip(-1)=180          
  } else if (rotflag != 0){ //if not 0,1,2,3:
    cout  << "Unknown rotation flag(" << rotflag << ")" << endl;
  }
}

Donc, vous l'appelez comme ça et notez que la matrice est passée par référence.

cv::Mat matImage;
//Load in sensible data
rot90(matImage,3); //Rotate it

//Note if you want to keep an original unrotated version of 
// your matrix as well, just do this
cv::Mat matImage;
//Load in sensible data
cv::Mat matRotated = matImage.clone();
rot90(matImage,3); //Rotate it

Rotation par degrés arbitraires Pendant que j'y suis, voici comment faire pivoter par degrés arbitraires, ce qui devrait être 50 fois plus cher. Notez que la rotation de cette manière inclura un remplissage noir et que les bords seront pivotés pour ne pas correspondre à la taille d'origine de l'image.

void rotate(cv::Mat& src, double angle, cv::Mat& dst){
    cv::Point2f ptCp(src.cols*0.5, src.rows*0.5);
    cv::Mat M = cv::getRotationMatrix2D(ptCp, angle, 1.0);
    cv::warpAffine(src, dst, M, src.size(), cv::INTER_CUBIC); //Nearest is too rough, 
}

Appeler cela pour une rotation de 10,5 degrés est alors évidemment:

cv::Mat matImage, matRotated;
//Load in data
rotate(matImage, 10.5, matRotated);

Je trouve remarquable que ce type de fonctions extrêmement basiques ne fasse pas partie d'OpenCV, alors qu'OpenCV a des choses natives comme la détection de visage (qui n'est pas vraiment maintenue avec des performances discutables). Remarquable.

À votre santé

123
TimZaman

La réponse de @Abhishek Thakur ne fonctionne bien que pour faire pivoter l'image de 180 degrés. Il ne gère pas la rotation de 90 degrés car

  • le centre de rotation fourni à getRotationMatrix2D est incorrect et
  • la taille de la matrice de sortie transmise à warpAffline est incorrecte.

Voici le code qui fait pivoter une image de 90 degrés:

Mat src = imread("image.jpg");
Mat dst;

double angle = 90;  // or 270
Size src_sz = src.size();
Size dst_sz(src_sz.height, src_sz.width); 

int len = std::max(src.cols, src.rows); 
Point2f center(len/2., len/2.);
Mat rot_mat = cv::getRotationMatrix2D(center, angle, 1.0);
warpAffine(src, dst, rot_mat, dst_sz);

Modifier: ne autre approche pour faire pivoter les images de 90 180 ou 270 degrés implique de faire la matrice transpose puis flip. Cette méthode est probablement plus rapide.

9
Alexey

Le code ci-dessus fonctionne très bien, mais introduit une erreur numérique dans l'image en raison des calculs matriciels effectués en virgule flottante et de l'interpolation warpAffine.

Pour une rotation par incrément de 90 degrés, je préfère utiliser ce qui suit (en python/pencon opencv)

Depuis les images OpenCV dans Python sont des tableaux Numpy 2d.

90 deg.
theImage = numpy.rot90 (theImage, 1)
270 deg.
theImage = numpy.rot90 (theImage, 3)

Remarque: Je n'ai testé cela que sur des images de forme de gris (X, Y). Si vous avez une image en couleur (ou une autre multi-séparation), vous devrez peut-être la remodeler d'abord pour vous assurer que la rotation fonctionne le long de l'axe correct.

0
Jeffrey Zampieron