Calcola x, y coordinate (3D) dal punto immagine

Ho un compito per localizzare un object nel sistema di coordinate 3D. Dato che devo ottenere coordinate X e Y quasi esatte, ho deciso di tracciare un marker di colore con una coordinata Z nota che verrà posizionata sulla parte superiore dell’object in movimento, come la pallina arancione in questa immagine: undistored

Innanzitutto, ho eseguito la calibrazione della telecamera per ottenere parametri intrinseci e successivamente ho usato cv :: solvePnP per ottenere il vettore di rotazione e traduzione come nel seguente codice:

std::vector imagePoints; std::vector objectPoints; //img points are green dots in the picture imagePoints.push_back(cv::Point2f(271.,109.)); imagePoints.push_back(cv::Point2f(65.,208.)); imagePoints.push_back(cv::Point2f(334.,459.)); imagePoints.push_back(cv::Point2f(600.,225.)); //object points are measured in millimeters because calibration is done in mm also objectPoints.push_back(cv::Point3f(0., 0., 0.)); objectPoints.push_back(cv::Point3f(-511.,2181.,0.)); objectPoints.push_back(cv::Point3f(-3574.,2354.,0.)); objectPoints.push_back(cv::Point3f(-3400.,0.,0.)); cv::Mat rvec(1,3,cv::DataType::type); cv::Mat tvec(1,3,cv::DataType::type); cv::Mat rotationMatrix(3,3,cv::DataType::type); cv::solvePnP(objectPoints, imagePoints, cameraMatrix, distCoeffs, rvec, tvec); cv::Rodrigues(rvec,rotationMatrix); 

Dopo avere tutte le matrici, questa equazione che può aiutarmi a trasformare il punto dell’immagine in coordinate wolrd:

transform_equation

dove M è cameraMatrix, R – rotationMatrix, t – tvec e s è uno sconosciuto. Zconst rappresenta l’altezza in cui si trova la palla arancione, in questo esempio è 285 mm. Quindi, prima devo risolvere l’equazione precedente, per ottenere “s”, e dopo aver trovato le coordinate X e Y selezionando il punto dell’immagine: equation2

    Risolvendo questo posso trovare la variabile “s”, usando l’ultima riga in matrici, perché Zconst è noto, quindi ecco il seguente codice per questo:

     cv::Mat uvPoint = (cv::Mat_(3,1) << 363, 222, 1); // u = 363, v = 222, got this point using mouse callback cv::Mat leftSideMat = rotationMatrix.inv() * cameraMatrix.inv() * uvPoint; cv::Mat rightSideMat = rotationMatrix.inv() * tvec; double s = (285 + rightSideMat.at(2,0))/leftSideMat.at(2,0)); //285 represents the height Zconst std::cout << "P = " << rotationMatrix.inv() * (s * cameraMatrix.inv() * uvPoint - tvec) << std::endl; 

    Dopo questo, ho ottenuto il risultato: P = [-2629,5, 1272,6, 285.]

    e quando lo paragono alla misurazione, che è: Preal = [-2629.6, 1269.5, 285.]

    l’errore è molto piccolo, il che è molto buono, ma quando sposto questa scatola sui bordi di questa stanza, gli errori sono forse di 20-40mm e vorrei migliorarlo. Qualcuno può aiutarmi, hai qualche suggerimento?

    Data la tua configurazione, gli errori di 20-40 mm ai bordi sono nella media. Sembra che tu abbia fatto tutto bene.

    Senza modificare la configurazione della telecamera / sistema, fare meglio sarà difficile. Puoi provare a ripetere la calibrazione della videocamera e sperare in risultati migliori, ma questo non li migliorerà molto (e potresti eventualmente ottenere risultati peggiori, quindi non cancellare i parametri instrinsic effettivi)

    Come detto da count0, se hai bisogno di più precisione dovresti andare per misurazioni multiple.

    Otterrai i punti verdi (imagepoint) dall’immagine distorta o non distorta? Poiché la funzione solvePnP non distingue già i punti immagine (a meno che non si superino i coefficienti di distorsione o li si passi come null). Potresti non riuscire a decodificare quei due punti immagine se li stai riprendendo dall’immagine non distorta, e questo finirebbe per causare un errore maggiore negli angoli.

    https://github.com/Itseez/opencv/blob/master/modules/calib3d/src/solvepnp.cpp