Transformiere einen Frame so, als wäre er mit OpenCV von oben aufgenommen worden
Ich arbeite an einem Projekt zur Schätzung eines UAV-Standorts (Quadrocopter) mithilfe der optischen Strömungstechnik. Ich habe derzeit einen Code, der @ verwend Farneback Algorithmus von OpenCV. Der aktuelle Code funktioniert einwandfrei, wenn die Kamera immer auf den Boden zeigt.
Nun möchte ich den Fall unterstützen, dass die Kamera nicht gerade nach unten zeigt - was bedeutet, dass der Quadrocopter jetzt einen Neigungs- / Roll- / Gierwinkel (Euler-Winkel) hat. Die Euler-Winkel des Quadcopters sind bekannt, und ich suche nach einer Methode, um die Transformation zu berechnen und anzuwenden, die auf den bekannten aktuellen Euler-Winkeln basiert. Damit das Ergebnisbild so aussieht, als wäre es von oben aufgenommen worden (siehe Bild unten).
Ich habe Methoden gefunden, die die Transformation berechnen, wenn 2 Sätze (Quelle und Ziel) von 4 Ecken über @ vorliegefindHomography
odergetPerspectiveTransform
funktioniert von OpenCV. Aber ich konnte keine Methoden finden, die es mit der Kenntnis nur des Euler-Winkels schaffen (weil ich die Zielbild-Korrektoren nicht kenne).
So ist meine Frage, welche Methode ich verwenden kann und wie, um einen Rahmen so zu transformieren, als ob er von oben aufgenommen worden wäre, wenn nötig, nur mit Euler-Winkeln und Kamerahöhe vom Boden?
Um zu demonstrieren, was ich brauche:
Der relevante Teil meines aktuellen Codes ist unten:
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);
}
AKTUALISIERENNach dem erfolgreichen Hinzufügen der Drehung muss mein Bild noch zentriert werden (und nicht außerhalb des Rahmenfensters gehen, wie unten gezeigt). Ich brauche wohl eine Art Übersetzung.Ich möchte, dass die Mitte des Quellbilds in der Mitte des Zielbilds liegt. Wie kann ich das auch hinzufügen?
Die Rotationsfunktion, die funktioniert:
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());
}
Wenn ich es mit @ starrotateFrame(origFrame, processedFrame, cameraMatrix, 0, 0, 0);
Ich erhalte das Bild wie erwartet:
Aber wenn ich es mit 10 Grad in der Rolle laufen lasserotateFrame(origFrame, processedFrame, cameraMatrix, 20*(M_PI/180), 0, 0);
. Das Bild verlässt das Rahmenfenster: