OpenCV warpperspective

Per qualche ragione ogni volta che utilizzo la funzione warpPerspective () di OpenCV, l’immagine finale deformata non contiene tutto nell’immagine originale. La parte sinistra dell’immagine sembra essere tagliata. Penso che la ragione per cui ciò stia accadendo è perché l’immagine deformata viene creata nella posizione più a sinistra della canvas per warpPerspective (). C’è un modo per risolvere questo problema? Grazie

Il problema si verifica perché l’omografia esegue il mapping di una parte dell’immagine a valori x, y negativi che si trovano all’esterno dell’area dell’immagine, quindi non possono essere tracciati. ciò che desideriamo è compensare l’uscita distorta di un numero di pixel per “deviare” l’intera immagine deformata in coordinate positive (e quindi all’interno dell’area dell’immagine).

Le omografie possono essere combinate usando la moltiplicazione della matrice (che è il motivo per cui sono così potenti). Se A e B sono omografie, allora AB rappresenta l’omografia che applica prima B, e poi A.

Per questo motivo tutto ciò che dobbiamo fare per compensare l’output è creare la matrice di omografia per una traduzione di qualche offset, e quindi pre-moltiplicare quella con la nostra matrice di omografia originale

Una matrice di omografia 2D si presenta così:

[R11,R12,T1] [R21,R22,T2] [ P , P , 1] 

dove R rappresenta una matrice di rotazione, T rappresenta una traduzione, e P rappresenta un ordito di prospettiva. E così un’omografia puramente traslazionale si presenta così:

 [ 1 , 0 , x_offset] [ 0 , 1 , y_offset] [ 0 , 0 , 1 ] 

Quindi premoltiplicamente la tua omografia con una matrice simile alla precedente e l’immagine di output verrà compensata.

(Assicurati di utilizzare la moltiplicazione della matrice, non la moltiplicazione degli elementi!)

Il segreto si presenta in due parti: la matrice di trasformazione (omografia) e la dimensione dell’immagine risultante.

  • calcola una trasformazione corretta usando getPerspectiveTransform (). Prendi 4 punti dall’immagine originale, calcola la loro posizione corretta nella destinazione, inseriscili in due vettori nello stesso ordine e usali per calcolare la matrice di trasformazione prospettica.

  • Assicurati che la dimensione dell’immagine di destinazione (terzo parametro per warpPerspective ()) sia esattamente quello che desideri. Definirlo come Size (myWidth, myHeight).

Ho fatto un metodo … Sta funzionando.

  perspectiveTransform(obj_corners,scene_corners,H); int maxCols(0),maxRows(0); for(int i=0;i 

Trovo solo il massimo dei punti x e y rispettivamente e lo metto su

 warpPerspective( tmp, transformsdImage, homography, Size( maxCols, maxRows ) ); 

Prova il sotto homography_warp .

 void homography_warp(const cv::Mat& src, const cv::Mat& H, cv::Mat& dst); 

src è l’immagine sorgente.

H è la tua omografia.

dst è l’immagine deformata.

homography_warp modifica la tua omografia come descritto da https://stackoverflow.com/users/1060066/matt-freeman nella sua risposta https://stackoverflow.com/a/8229116/15485

 // Convert a vector of non-homogeneous 2D points to a vector of homogenehous 2D points. void to_homogeneous(const std::vector< cv::Point2f >& non_homogeneous, std::vector< cv::Point3f >& homogeneous) { homogeneous.resize(non_homogeneous.size()); for (size_t i = 0; i < non_homogeneous.size(); i++) { homogeneous[i].x = non_homogeneous[i].x; homogeneous[i].y = non_homogeneous[i].y; homogeneous[i].z = 1.0; } } // Convert a vector of homogeneous 2D points to a vector of non-homogenehous 2D points. void from_homogeneous(const std::vector< cv::Point3f >& homogeneous, std::vector< cv::Point2f >& non_homogeneous) { non_homogeneous.resize(homogeneous.size()); for (size_t i = 0; i < non_homogeneous.size(); i++) { non_homogeneous[i].x = homogeneous[i].x / homogeneous[i].z; non_homogeneous[i].y = homogeneous[i].y / homogeneous[i].z; } } // Transform a vector of 2D non-homogeneous points via an homography. std::vector transform_via_homography(const std::vector& points, const cv::Matx33f& homography) { std::vector ph; to_homogeneous(points, ph); for (size_t i = 0; i < ph.size(); i++) { ph[i] = homography*ph[i]; } std::vector r; from_homogeneous(ph, r); return r; } // Find the bounding box of a vector of 2D non-homogeneous points. cv::Rect_ bounding_box(const std::vector& p) { cv::Rect_ r; float x_min = std::min_element(p.begin(), p.end(), [](const cv::Point2f& lhs, const cv::Point2f& rhs) {return lhs.x < rhs.x; })->x; float x_max = std::max_element(p.begin(), p.end(), [](const cv::Point2f& lhs, const cv::Point2f& rhs) {return lhs.x < rhs.x; })->x; float y_min = std::min_element(p.begin(), p.end(), [](const cv::Point2f& lhs, const cv::Point2f& rhs) {return lhs.y < rhs.y; })->y; float y_max = std::max_element(p.begin(), p.end(), [](const cv::Point2f& lhs, const cv::Point2f& rhs) {return lhs.y < rhs.y; })->y; return cv::Rect_(x_min, y_min, x_max - x_min, y_max - y_min); } // Warp the image src into the image dst through the homography H. // The resulting dst image contains the entire warped image, this // behaviour is the same of Octave's imperspectivewarp (in the 'image' // package) behaviour when the argument bbox is equal to 'loose'. // See http://octave.sourceforge.net/image/function/imperspectivewarp.html void homography_warp(const cv::Mat& src, const cv::Mat& H, cv::Mat& dst) { std::vector< cv::Point2f > corners; corners.push_back(cv::Point2f(0, 0)); corners.push_back(cv::Point2f(src.cols, 0)); corners.push_back(cv::Point2f(0, src.rows)); corners.push_back(cv::Point2f(src.cols, src.rows)); std::vector< cv::Point2f > projected = transform_via_homography(corners, H); cv::Rect_ bb = bounding_box(projected); cv::Mat_ translation = (cv::Mat_(3, 3) << 1, 0, -bb.tl().x, 0, 1, -bb.tl().y, 0, 0, 1); cv::warpPerspective(src, dst, translation*H, bb.size()); } 

warpPerspective () funziona bene. Non c’è bisogno di riscriverlo. Probabilmente lo usi in modo errato.

Ricorda i seguenti suggerimenti:

  1. (0,0) i pixel non sono al centro ma piuttosto all’angolo superiore sinistro. Quindi se ingrandisci l’immagine x2 perderai le parti inferiore e destra, non il bordo (come in MATLAB).
  2. Se si deforma l’immagine due volte, è meglio moltiplicare le trasformazioni e triggersre una volta la funzione.
  3. Penso che funzioni solo su matrici char / int e non su float / double.
  4. Quando hai una trasformazione, vengono applicati prima zoom / skew / rotation / perspective e infine la traduzione. Quindi se manca una parte dell’immagine basta cambiare la transizione (due righe superiori dell’ultima colonna) nella matrice.

questa è la mia soluzione

poiché il terzo parametro in “warpPerspective ()” è una matrice di trasformazione,

possiamo creare una matrice di trasformazione, che sposta prima l’immagine all’indietro, quindi ruota l’immagine, infine sposta l’immagine in avanti.

Nel mio caso, ho un’immagine con altezza di 160 px e larghezza di 160 px. Voglio ruotare l’immagine attorno a [80,80] anziché intorno a [0,0]

per prima cosa sposta l’immagine all’indietro (che significa T1)

quindi ruota l’immagine (che significa R)

infine sposta l’immagine in avanti (che significa T2)

 void rotateImage(Mat &src_img,int degree) { float radian=(degree/180.0)*M_PI; Mat R(3,3,CV_32FC1,Scalar(0)); R.at(0,0)=cos(radian);R.at(0,1)=-sin(radian); R.at(1,0)=sin(radian);R.at(1,1)=cos(radian); R.at(2,2)=1; Mat T1(3,3,CV_32FC1,Scalar(0)); T1.at(0,2)=-80; T1.at(1,2)=-80; T1.at(0,0)=1; T1.at(1,1)=1; T1.at(2,2)=1; Mat T2(3,3,CV_32FC1,Scalar(0)); T2.at(0,2)=80; T2.at(1,2)=80; T2.at(0,0)=1; T2.at(1,1)=1; T2.at(2,2)=1; std::cerr< 

Ecco una soluzione opencv-python per il tuo problema, l’ho messa su github: https://github.com/Sanster/notes/blob/master/opencv/warpPerspective.md

Il punto chiave è come utente3094631 detto, ottenere due matrici di traduzione (T1, T2) e applicare alla matrice Rotate (M) T2*M*T1

Nel codice che ho dato, T1 è dall’immagine del punto centrale dell’origine e T2 è dal punto in alto a sinistra del boundingBox trasformato. Il boundingBox trasformato proviene dai punti d’angolo dell’origine:

 height = img.shape[0] width = img.shape[1] #..get T1 #..get M pnts = np.asarray([ [0, 0], [width, 0], [width, height], [0, height] ], dtype=np.float32) pnts = np.array([pnts]) dst_pnts = cv2.perspectiveTransform(pnts, M * T1)[0] dst_pnts = np.asarray(dst_pnts, dtype=np.float32) bbox = cv2.boundingRect(dst_pnts) T2 = np.matrix([[1., 0., 0 - bbox[0]], [0., 1., 0 - bbox[1]], [0., 0., 1.]])