Transforme um quadro para ser como se tivesse sido tirado de cima usando o OpenCV
Estou trabalhando em um projeto para estimar uma localização de UAV (quadcopter) usando a técnica de fluxo óptico. Atualmente, tenho um código que está usandofarneback algoritmo do OpenCV. O código atual está funcionando bem quando a câmera está sempre apontando para o chão.
Agora, quero adicionar suporte ao gabinete quando a câmera não está apontando diretamente para baixo - o que significa que o quadcopter agora tem um pitch / roll / yaw (ângulos de Euler). Os ângulos de Euler dos quadcopters são conhecidos e estou procurando um método para calcular e aplicar a transformação necessária com base nos ângulos de Euler atuais. Para que a imagem resultante seja como se tivesse sido tirada de cima (veja a imagem abaixo).
Encontrei métodos que calculam a transformação ao ter 2 conjuntos (origem e destino) de 4 cantos viafindHomography
ougetPerspectiveTransform
funções do OpenCV. Mas não consegui encontrar nenhum método que pudesse fazê-lo sabendo apenas o ângulo de Euler (porque não conheço a imagem de destino correspondente).
Portanto, minha pergunta é: qual método posso usar e como transformar um quadro como se fosse tirado de cima usando apenas ângulos de Euler e altura da câmera do chão, se necessário?
Para demonstrar o que eu preciso:
A parte relevante do meu código atual está abaixo:
for(;;)
{
Mat m, disp, warp;
vector<Point2f> corners;
// take out frame- still distorted
cap >> origFrame;
// undistort the frame using the calibration parameters
cv::undistort(origFrame, undistortFrame, cameraMatrix, distCoeffs, noArray());
// lower the process effort by transforming the picture to gray
cvtColor(undistortFrame, gray, COLOR_BGR2GRAY);
if( !prevgray.empty() )
{
// calculate flow
calcOpticalFlowFarneback(prevgray, gray, uflow, 0.5, 3/*def 3 */, 10/* def 15*/, 3, 3, 1.2 /* def 1.2*/, 0);
uflow.copyTo(flow);
// get average
calcAvgOpticalFlow(flow, 16, corners);
// calculate range of view - 2*tan(fov/2)*distance
rovX = 2*0.44523*distanceSonar*100; // 2 * tan(48/2) * dist(cm)
rovY = 2*0.32492*distanceSonar*100; // 2 * tan(36/2) * dist(cm)
// calculate final x, y location
location[0] += (currLocation.x/WIDTH_RES)*rovX;
location[1] += (currLocation.y/HEIGHT_RES)*rovY;
}
//break conditions
if(waitKey(1)>=0)
break;
if(end_run)
break;
std::swap(prevgray, gray);
}
ATUALIZAR:Depois de adicionar a rotação com sucesso, ainda preciso que minha imagem esteja centralizada (e não sair da janela do quadro, como mostrado abaixo). Acho que preciso de algum tipo de tradução.Quero que o centro da imagem de origem esteja no centro da imagem de destino. Como posso adicionar isso também?
A função de rotação que funciona:
void rotateFrame(const Mat &input, Mat &output, Mat &A , double roll, double pitch, double yaw){
Mat Rx = (Mat_<double>(3, 3) <<
1, 0, 0,
0, cos(roll), -sin(roll),
0, sin(roll), cos(roll));
Mat Ry = (Mat_<double>(3, 3) <<
cos(pitch), 0, sin(pitch),
0, 1, 0,
-sin(pitch), 0, cos(pitch));
Mat Rz = (Mat_<double>(3, 3) <<
cos(yaw), -sin(yaw), 0,
sin(yaw), cos(yaw), 0,
0, 0, 1);
Mat R = Rx*Ry*Rz;
Mat trans = A*R*A.inv();
warpPerspective(input, output, trans, input.size());
}
Quando eu corro comrotateFrame(origFrame, processedFrame, cameraMatrix, 0, 0, 0);
Recebo a imagem conforme o esperado:
Mas quando eu corro com 10 graus em rolorotateFrame(origFrame, processedFrame, cameraMatrix, 20*(M_PI/180), 0, 0);
. A imagem está saindo da janela do quadro: