радужная оболочка для расчета экрана для отслеживания взгляда

В настоящее время я экспериментирую с отслеживанием глаз. Я успешно построил алгоритм отслеживания радужной оболочки, используя OpenCV с контурами и преобразованием Хафа. Но следующий шаг для меня не ясен. Я хочу знать, верны ли мои вычисления для перевода центра глаза на экран. Голова пользователя имеет фиксированное положение.

результат

Что мне нужно, так это алгоритм, который, конечно же, работает на всех глазах. Есть ли расчет угла? Итак, когда пользователь смотрит вправо, линейно?

Что я делаю прямо сейчас: сначала я позволяю пользователю смотреть на определенные точки и использую RANSAC для определения положения радужной оболочки, наиболее близкого к положению на экране. Я делаю это с четырьмя 2D-точками на экране и радужной оболочке. Я использую гомографию для этого, чтобы получить правильный расчет.

void gaussian_elimination(float *input, int n){
// ported to c from pseudocode in
// http://en.wikipedia.org/wiki/Gaussian_elimination

float * A = input;
int i = 0;
int j = 0;
int m = n-1;
while (i < m && j < n){
    // Find pivot in column j, starting in row i:
    int maxi = i;
    for(int k = i+1; k<m; k++){
        if(fabs(A[k*n+j]) > fabs(A[maxi*n+j])){
            maxi = k;
        }
    }
    if (A[maxi*n+j] != 0){
        //swap rows i and maxi, but do not change the value of i
        if(i!=maxi)
            for(int k=0;k<n;k++){
                float aux = A[i*n+k];
                A[i*n+k]=A[maxi*n+k];
                A[maxi*n+k]=aux;
            }
        //Now A[i,j] will contain the old value of A[maxi,j].
        //divide each entry in row i by A[i,j]
        float A_ij=A[i*n+j];
        for(int k=0;k<n;k++){
            A[i*n+k]/=A_ij;
        }
        //Now A[i,j] will have the value 1.
        for(int u = i+1; u< m; u++){
            //subtract A[u,j] * row i from row u
            float A_uj = A[u*n+j];
            for(int k=0;k<n;k++){
                A[u*n+k]-=A_uj*A[i*n+k];
            }
            //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.
        }

        i++;
    }
    j++;
}

//back substitution
for(int i=m-2;i>=0;i--){
    for(int j=i+1;j<n-1;j++){
        A[i*n+m]-=A[i*n+j]*A[j*n+m];
        //A[i*n+j]=0;
    }
}
}



ofMatrix4x4 findHomography(ofPoint src[4], ofPoint dst[4]){
ofMatrix4x4 matrix;

// create the equation system to be solved
//
// from: Multiple View Geometry in Computer Vision 2ed
//       Hartley R. and Zisserman A.
//
// x' = xH
// where H is the homography: a 3 by 3 matrix
// that transformed to inhomogeneous coordinates for each point
// gives the following equations for each point:
//
// x' * (h31*x + h32*y + h33) = h11*x + h12*y + h13
// y' * (h31*x + h32*y + h33) = h21*x + h22*y + h23
//
// as the homography is scale independent we can let h33 be 1 (indeed any of the terms)
// so for 4 points we have 8 equations for 8 terms to solve: h11 - h32
// after ordering the terms it gives the following matrix
// that can be solved with gaussian elimination:

float P[8][9]={
    {-src[0].x, -src[0].y, -1,   0,   0,  0, src[0].x*dst[0].x, src[0].y*dst[0].x, -dst[0].x }, // h11
    {  0,   0,  0, -src[0].x, -src[0].y, -1, src[0].x*dst[0].y, src[0].y*dst[0].y, -dst[0].y }, // h12

    {-src[1].x, -src[1].y, -1,   0,   0,  0, src[1].x*dst[1].x, src[1].y*dst[1].x, -dst[1].x }, // h13
    {  0,   0,  0, -src[1].x, -src[1].y, -1, src[1].x*dst[1].y, src[1].y*dst[1].y, -dst[1].y }, // h21

    {-src[2].x, -src[2].y, -1,   0,   0,  0, src[2].x*dst[2].x, src[2].y*dst[2].x, -dst[2].x }, // h22
    {  0,   0,  0, -src[2].x, -src[2].y, -1, src[2].x*dst[2].y, src[2].y*dst[2].y, -dst[2].y }, // h23

    {-src[3].x, -src[3].y, -1,   0,   0,  0, src[3].x*dst[3].x, src[3].y*dst[3].x, -dst[3].x }, // h31
    {  0,   0,  0, -src[3].x, -src[3].y, -1, src[3].x*dst[3].y, src[3].y*dst[3].y, -dst[3].y }, // h32
};

gaussian_elimination(&P[0][0],9);

matrix(0,0)=P[0][8];
matrix(0,1)=P[1][8];
matrix(0,2)=0;
matrix(0,3)=P[2][8];

matrix(1,0)=P[3][8];
matrix(1,1)=P[4][8];
matrix(1,2)=0;
matrix(1,3)=P[5][8];

matrix(2,0)=0;
matrix(2,1)=0;
matrix(2,2)=0;
matrix(2,3)=0;

matrix(3,0)=P[6][8];
matrix(3,1)=P[7][8];
matrix(3,2)=0;
matrix(3,3)=1;

return matrix;

}


person Martijn Mellens    schedule 05.02.2016    source источник
comment
Вы можете использовать оба глаза, или вам приходится поддерживать косоглазие?   -  person Jonas Byström    schedule 05.02.2016
comment
В настоящее время я отслеживаю только один глаз с помощью этой версии. Моя цель — взаимодействовать с экранными кнопками, поэтому я использую глаз в качестве курсора.   -  person Martijn Mellens    schedule 05.02.2016
comment
Что ж, этот комментарий более конкретен, чем весь вопрос, теперь мы знаем, чего вы хотите. Вероятно, это может быть немного сложнее. Лучшее объяснение вашей установки может быть более полезным, потому что проблему можно решить разными способами. Как у вас с камерой и компьютером? Вы используете стационарную камеру ноутбука?   -  person Alexander Leon VI    schedule 05.02.2016
comment
Нет, Raspberry Pi в сочетании с платой NoIR Camera Board — инфракрасной камерой. Камера устанавливается в фиксированное положение. Экран из фиксированного положения, чтобы избежать сложных вычислений от диафрагмы до экрана. Расстояние от экрана до пользователя около полуметра.   -  person Martijn Mellens    schedule 07.02.2016
comment
Пытался отредактировать ваш код, но что-то не так со скобками. Посмотрите на строки номер 19, 53 и последнюю. Сам не хотел редактировать, чтобы не испортить.   -  person Hafenkranich    schedule 04.08.2016


Ответы (2)


Вам следует взглянуть на существующие решения для этого:

  • Eye Writer для рисования глазами (я тестировал это только для управления мышью)

Eyewriter.org

Руководство по написанию текстов

Eyewriter на Github

  • Отслеживание зрачков EyeLike

информационная страница EyeLike (здесь обсуждается алгоритм, похожий на want you want)

EyeLike на Github

Удачи!

person Gillsoft AB    schedule 03.08.2016

Может быть, это ссылка полезно для вас, удачи

cv::Mat computeMatXGradient(const cv::Mat &mat) {
  cv::Mat out(mat.rows,mat.cols,CV_64F);

  for (int y = 0; y < mat.rows; ++y) {
    const uchar *Mr = mat.ptr<uchar>(y);
    double *Or = out.ptr<double>(y);

    Or[0] = Mr[1] - Mr[0];
    for (int x = 1; x < mat.cols - 1; ++x) {
      Or[x] = (Mr[x+1] - Mr[x-1])/2.0;
    }
    Or[mat.cols-1] = Mr[mat.cols-1] - Mr[mat.cols-2];
  }

  return out;
}
person Yogesh Rathi    schedule 04.08.2016