2015-10-05 3 views
1

Недавно я пытался завершить этап моего проекта, создав матрицу гомографии 3x3 из 4 обнаруженных и 4-х истинных двумерных точек. Я пробовал несколько разных алгоритмов и несколько различных реализаций SVD и до сих пор не могу получить хороший результат.Гомографический алгоритм работает не так, как ожидалось

Я взял Openframework's homography implementation (из которого IIRC взят из opencv) и приближается ... но все еще не правильные результаты. Я уверен, что все матричные правила правильны, но я сделал что-то испорченное (возможно, даже окончательное преобразование?)

Вот изображение точек, которые я пытаюсь совместить, src (совпадения) слева, dst (правда) справа. (Я могу получить координаты, если хотите, но размер изображения составляет около 640x1000). Крайний правый (цветной на белом) - это соответствия, преобразованные в dst/true, и изображение, искаженное той же гомографией, используемой в тестовом коде. enter image description here

примечание: игнорировать типы opencl, все они используются правильно (просто сократите для краткости здесь). std :: Debug - это просто ostream. Это массив из 16 с плавающей точкой, но я просто с помощью первого 9

void gaussian_elimination(float *input, int n) 
 
{ 
 
\t // ported to c from pseudocode in 
 
\t // http://en.wikipedia.org/wiki/Gaussian_elimination 
 
\t 
 
\t float * A = input; 
 
\t int i = 0; 
 
\t int j = 0; 
 
\t int m = n-1; 
 
\t while (i < m && j < n){ 
 
\t \t // Find pivot in column j, starting in row i: 
 
\t \t int maxi = i; 
 
\t \t for(int k = i+1; k<m; k++){ 
 
\t \t \t if(fabs(A[k*n+j]) > fabs(A[maxi*n+j])){ 
 
\t \t \t \t maxi = k; 
 
\t \t \t } 
 
\t \t } 
 
\t \t if (A[maxi*n+j] != 0){ 
 
\t \t \t //swap rows i and maxi, but do not change the value of i 
 
\t \t \t if(i!=maxi) 
 
\t \t \t \t for(int k=0;k<n;k++){ 
 
\t \t \t \t \t float aux = A[i*n+k]; 
 
\t \t \t \t \t A[i*n+k]=A[maxi*n+k]; 
 
\t \t \t \t \t A[maxi*n+k]=aux; 
 
\t \t \t \t } 
 
\t \t \t //Now A[i,j] will contain the old value of A[maxi,j]. 
 
\t \t \t //divide each entry in row i by A[i,j] 
 
\t \t \t float A_ij=A[i*n+j]; 
 
\t \t \t for(int k=0;k<n;k++){ 
 
\t \t \t \t A[i*n+k]/=A_ij; 
 
\t \t \t } 
 
\t \t \t //Now A[i,j] will have the value 1. 
 
\t \t \t for(int u = i+1; u< m; u++){ 
 
\t \t \t \t //subtract A[u,j] * row i from row u 
 
\t \t \t \t float A_uj = A[u*n+j]; 
 
\t \t \t \t for(int k=0;k<n;k++){ 
 
\t \t \t \t \t A[u*n+k]-=A_uj*A[i*n+k]; 
 
\t \t \t \t } 
 
\t \t \t \t //Now A[u,j] will be 0, since A[u,j] - A[i,j] * A[u,j] = A[u,j] - 1 * A[u,j] = 0. 
 
\t \t \t } 
 
\t \t \t 
 
\t \t \t i++; 
 
\t \t } 
 
\t \t j++; 
 
\t } 
 
\t 
 
\t //back substitution 
 
\t for(int i=m-2;i>=0;i--){ 
 
\t \t for(int j=i+1;j<n-1;j++){ 
 
\t \t \t A[i*n+m]-=A[i*n+j]*A[j*n+m]; 
 
\t \t \t //A[i*n+j]=0; 
 
\t \t } 
 
\t } 
 
} 
 
            
 
            
 
            
 
cl_float16 of_findHomography(cl_float2 src[4], cl_float2 dst[4]) 
 
{ 
 
\t // create the equation system to be solved 
 
\t // 
 
\t // from: Multiple View Geometry in Computer Vision 2ed 
 
\t //  Hartley R. and Zisserman A. 
 
\t // 
 
\t // x' = xH 
 
\t // where H is the homography: a 3 by 3 matrix 
 
\t // that transformed to inhomogeneous coordinates for each point 
 
\t // gives the following equations for each point: 
 
\t // 
 
\t // x' * (h31*x + h32*y + h33) = h11*x + h12*y + h13 
 
\t // y' * (h31*x + h32*y + h33) = h21*x + h22*y + h23 
 
\t // 
 
\t // as the homography is scale independent we can let h33 be 1 (indeed any of the terms) 
 
\t // so for 4 points we have 8 equations for 8 terms to solve: h11 - h32 
 
\t // after ordering the terms it gives the following matrix 
 
\t // that can be solved with gaussian elimination: 
 
\t 
 
\t float P[8][9]={ 
 
\t \t {-src[0][0], -src[0][1], -1, 0, 0, 0, src[0][0]*dst[0][0], src[0][1]*dst[0][0], -dst[0][0] }, // h11 
 
\t \t { 0, 0, 0, -src[0][0], -src[0][1], -1, src[0][0]*dst[0][1], src[0][1]*dst[0][1], -dst[0][1] }, // h12 
 
\t \t 
 
\t \t {-src[1][0], -src[1][1], -1, 0, 0, 0, src[1][0]*dst[1][0], src[1][1]*dst[1][0], -dst[1][0] }, // h13 
 
\t \t { 0, 0, 0, -src[1][0], -src[1][1], -1, src[1][0]*dst[1][1], src[1][1]*dst[1][1], -dst[1][1] }, // h21 
 
\t \t 
 
\t \t {-src[2][0], -src[2][1], -1, 0, 0, 0, src[2][0]*dst[2][0], src[2][1]*dst[2][0], -dst[2][0] }, // h22 
 
\t \t { 0, 0, 0, -src[2][0], -src[2][1], -1, src[2][0]*dst[2][1], src[2][1]*dst[2][1], -dst[2][1] }, // h23 
 
\t \t 
 
\t \t {-src[3][0], -src[3][1], -1, 0, 0, 0, src[3][0]*dst[3][0], src[3][1]*dst[3][0], -dst[3][0] }, // h31 
 
\t \t { 0, 0, 0, -src[3][0], -src[3][1], -1, src[3][0]*dst[3][1], src[3][1]*dst[3][1], -dst[3][1] }, // h32 
 
\t }; 
 
\t 
 
\t gaussian_elimination(&P[0][0],9); 
 
/* 
 
\t // gaussian elimination gives the results of the equation system 
 
\t // in the last column of the original matrix. 
 
\t // opengl needs the transposed 4x4 matrix: 
 
\t float aux_H[]= 
 
\t { 
 
\t \t P[0][8],P[3][8],0,P[6][8], // h11 h21 0 h31 
 
\t \t P[1][8],P[4][8],0,P[7][8], // h12 h22 0 h32 
 
\t \t 0  ,  0,0,0,  // 0 0 0 0 
 
\t \t P[2][8],P[5][8],0,1 // h13 h23 0 h33 
 
\t }; 
 
*/ 
 
\t // \t non transposed 3x3 
 
\t cl_float16 Result; 
 
\t Result.s[0] = P[0][8]; 
 
\t Result.s[1] = P[1][8]; 
 
\t Result.s[2] = P[2][8]; 
 
\t 
 
\t Result.s[3] = P[3][8]; 
 
\t Result.s[4] = P[4][8]; 
 
\t Result.s[5] = P[5][8]; 
 
\t 
 
\t Result.s[6] = P[6][8]; 
 
\t Result.s[7] = P[7][8]; 
 
\t Result.s[8] = 1; 
 
\t //Result.s[8] = P[8][8]; 
 

 
\t 
 
\t // \t test 
 
\t for (int i=0; \t i<4; \t i++) 
 
\t { 
 
\t \t auto H = Result.s; 
 
\t \t float x = H[0]*src[i][0] + H[1]*src[i][1] + H[2]; 
 
\t \t float y = H[3]*src[i][0] + H[4]*src[i][1] + H[5]; 
 
\t \t float z = H[6]*src[i][0] + H[7]*src[i][1] + H[8]; 
 
\t \t 
 
\t \t x /= z; 
 
\t \t y /= z; 
 
\t \t 
 
\t \t float diffx = dst[i][0] - x; 
 
\t \t float diffy = dst[i][1] - y; 
 
\t \t std::Debug << "err src->dst #" << i << ": " << diffx << "," << diffy << std::endl; 
 
\t } 
 
\t for (int i=0; \t i<4; \t i++) 
 
\t { 
 
\t \t auto H = Result.s; 
 
\t \t float x = H[0]*dst[i][0] + H[1]*dst[i][1] + H[2]; 
 
\t \t float y = H[3]*dst[i][0] + H[4]*dst[i][1] + H[5]; 
 
\t \t float z = H[6]*dst[i][0] + H[7]*dst[i][1] + H[8]; 
 
\t \t 
 
\t \t x /= z; 
 
\t \t y /= z; 
 
\t \t 
 
\t \t float diffx = src[i][0] - x; 
 
\t \t float diffy = src[i][1] - y; 
 
\t \t std::Debug << "err src->dst #" << i << ": " << diffx << "," << diffy << std::endl; 
 
\t } 
 

 
\t 
 
\t return Result; 
 
}

Выходной сигнал с изображения

эээ src-> ДСТ # 0: 0,00195, 0,0132

ERR src-> ДСТ # 1: 0,6.1e-05

ERR src-> ДСТ # 2: -0,00161, -8,9 6e-05

ERR src-> ДСТ # 3: 1.91e-06,0.000122

ERR DST-> SRC# 0: 2.31e + 03.551

ERR DST-> SRC# 1: - 3.34e + 03, -4.23e + 03

эээ DST-> ЦСИ # 2: 1.07e + 03,1.25e + 04

эээ DST-> ЦСИ # 3: 456.771

Что-то явно не так с m y матричный код преобразования? или я помещаю результаты SVD в матрицу в неправильном порядке строки/col? Может быть, весь алгоритм не то, что мне нужно? (конечно, он должен генерировать довольно простую, малую матрицу вращения?)

+0

Как насчет использования cv :: findHomography? – Miki

+0

Я пытаюсь избежать использования opencv полностью для одного алгоритма, это будет кросс-платформенный, мне также нужна скорость, поэтому вы хотите избежать преобразования в/из cv :: mat, И это происходит в opencl & gles вычислить ядра (этот код уже работает в ядрах ...просто неправильно :) –

+0

Следующим этапом тестирования будет запуск всего через opencv и отладка различий/результатов, хотя –

ответ

0

Плохо, как обычно. Эта реализация, похоже, работает отлично (до сих пор) и будет полезна для распараллеливания графических процессоров.

Я кормился плохими координатами. Выделенные точки отличались от точек, введенных в алгоритм (новый код и старый код).

Предупреждение о будущем, чтобы всегда генерировать данные сначала, затем визуализировать, а не визуализировать & генерировать с помощью [того, что было когда-то] того же кода.

+0

Редактирование: while цикл НЕ подходит для GPU :) –

Смежные вопросы