ti-enxame.com

Gire a matriz Opencv em 90, 180, 270 graus

Estou capturando imagens da webcam e preciso girá-las em ângulo reto. Eu me vi nessas funções:

  1. getRotationMatrix2D - para criar matriz de rotação (seja ela qual for)
  2. transform - transforma uma matriz em outra pela matriz de rotação

Mas não recebo nada além da área preta. Este é o meu código:

   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
   }

Produz apenas tela preta.

34
user2041141

Use warpAffine .:

Experimentar:

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 é a imagem final

30
Abhishek Thakur

As respostas acima são muito complexas e sobrecarregam sua CPU. Sua pergunta não foi de rotação arbitrária, mas 'Girar a matriz Opencv em 90, 180, 270 graus'.

ATUALIZAÇÃO 30 DE JUNHO DE 2017:

Essa funcionalidade é suportada pelo OpenCV, mas não documentada: https://github.com/opencv/opencv/blob/master/modules/core/include/opencv2/core.hpp#L1041

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

com

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

Resposta original e rotação do grau arbitrário:

Você também pode fazer isso usando a operação flip e transpose, ou seja, para 90CW:

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

etc. Descubra você mesmo os outros comandos (pensando = aprendendo) apresentando-se com a operação de transposição e flip dos Documentos.

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

Então você chama assim, e observe que a matriz é passada por referência.

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

Gire em graus arbitrários Enquanto eu estou nisso, aqui está como girar em um grau arbitrário, que eu espero que seja 50x mais caro. Observe que a rotação dessa maneira incluirá preenchimento preto e as bordas serão giradas para fora do tamanho original da imagem.

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

Chamar isso para uma rotação de 10,5 graus é obviamente:

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

Acho notável que esse tipo de função extremamente básica não faça parte do OpenCV, enquanto o OpenCV possui itens nativos, como detecção de rosto (que não é realmente mantido com desempenho questionável). Notável.

Felicidades

123
TimZaman

A resposta de @Abhishek Thakur só funciona bem para girar a imagem em 180 graus. Ele não suporta a rotação em 90 graus porque

  • o centro de rotação fornecido para getRotationMatrix2D está incorreto e
  • o tamanho da matriz de saída passado para warpAffline está incorreto.

Aqui está o código que gira uma imagem em 90 graus:

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

Editar: Outra abordagem girar imagens em 90.180 ou 270 graus envolve fazer a matriz transpose e depois flip. Este método é provavelmente mais rápido.

9
Alexey

O código acima funciona muito bem, mas introduz um erro numérico na imagem devido ao fato de os cálculos da matriz serem feitos em ponto flutuante e a interpolação warpAffine.

Para uma rotação de incremento de 90 graus, eu prefiro usar o seguinte (em python/opencv python)

Como as imagens OpenCV em Python são matrizes numpy 2D.

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

Nota: Eu testei isso apenas em imagens em escala de cinza da forma (X, Y). Se você tiver uma imagem colorida (ou outra multi-separação), talvez seja necessário remodelá-la primeiro para garantir que a rotação funcione no eixo correto.

0
Jeffrey Zampieron