Ошибка фильтра Калмана OpenCV

Я использовал OpenCV для прогнозирования движения мяча, видимого с помощью веб-камеры. Однако я продолжаю получать сообщение об ошибке в состоянии cvKalmanPredict, поэтому я упрощаю код до этих нескольких строк и пытаюсь протестировать только фильтр:

        CvKalman* kalman = cvCreateKalman(6,3,1);
        kalman->temp2 = cvCreateMat(1, 1, CV_32FC1);

        float alpha = 0.1, beta = 0.2;

        float kalmA[] = {1.0+t0/t1, 0, 0, -t0/t1, 0, 0,
                         0, 1.0+t0/t1, 0, 0, -t0/t1, 0,
                         0, 0, 1.0+t0/t1, 0, 0, -t0/t1,
                         1, 0, 0, 0, 0, 0,
                         0, 1, 0, 0, 0, 0,
                         0, 0, 1, 0, 0, 0};
        float kalmB[] = {0, 0, 1, 0, 0, 0};
        float kalmH[] = {1, 0, 0, 0, 0, 0,
                         0, 1, 0, 0, 0, 0,
                         0, 0, 1, 0, 0, 0};
        float kalmQ[] = {alpha, 0, 0, 0, 0, 0,
                         0, alpha, 0, 0, 0, 0,
                         0, 0, beta, 0, 0, 0,
                         0, 0, 0, alpha, 0, 0,
                         0, 0, 0, 0, alpha, 0,
                         0, 0, 0, 0, 0, beta};
        float kalmR[] = {alpha, 0, 0,
                         0, alpha, 0,
                         0, 0, beta};
        float kalmS[] = {0,0,0, 0, 0, 0};
        float kalmP[] = {480, 0, 0, 0, 0, 0,
                         0, 480, 0, 0, 0, 0,
                         0, 0, 480, 0, 0, 0,
                         0, 0, 0, 480, 0, 0,
                         0, 0, 0, 0, 480, 0,
                         0, 0, 0, 0, 0, 480};

        memcpy( kalman->transition_matrix->data.fl, kalmA, sizeof(kalmA) );
        memcpy( kalman->control_matrix->data.fl, kalmB, sizeof(kalmB) );
        memcpy( kalman->measurement_matrix->data.fl, kalmH, sizeof(kalmH) );
        memcpy( kalman->process_noise_cov->data.fl, kalmQ, sizeof(kalmQ) );
        memcpy( kalman->measurement_noise_cov->data.fl, kalmR, sizeof(kalmR) );


        // initialize state and covariance
        memcpy( kalman->state_post->data.fl, kalmS, sizeof(kalmS) );
        cvSetIdentity( kalman->error_cov_post, cvRealScalar(3));

        // update the control
        float t0 = 0.3;
        cvSetReal2D( kalman->temp2, 0, 0, -490 * t0 * t0 );

        const CvMat* kalmanPred = cvKalmanPredict(kalman, kalman->temp2);

        CvMat* kalmMeas = cvCreateMat(3,1,CV_32FC1);
        cvSetReal2D(kalmMeas, 0, 0, 3);
        cvSetReal2D(kalmMeas, 1, 0, 2);
        cvSetReal2D(kalmMeas, 2, 0, 5.5);
        cvKalmanCorrect(kalman, kalmMeas);
        cvReleaseMat(&kalmMeas);

        // release memory

Однако я все еще получаю ту же ошибку при вызове cvKalmanPredict:

        OpenCV Error: Assertion failed ((D.rows == ((flags & CV_GEMM_A_T) == 0 ? A.rows : A.cols)) && (D.cols == ((flags & CV_GEMM_B_T) == 0 ? B.cols : B.rows)) && D.type() == A.type() in unknown function. file C:\Users\opencv\modules\core\src\matmul.cpp. line 2930

Я использую cmake с MS Visual C++ 10 для компиляции.


person ucl    schedule 05.05.2012    source источник
comment
Кажется, у вас проблема с размером или типом. Вы проверяли, как выглядят ваши kalman->transition_matrix->data и другие после того, как вы скопировали в них свои матрицы?   -  person vsz    schedule 05.05.2012
comment
Я печатаю содержимое в data.fl для всех матриц перед вызовом kalmanPredic. У меня все выглядит нормально, и поэтому я не знаю, откуда эта ошибка.   -  person ucl    schedule 05.05.2012


Ответы (1)


Правдоподобная интерпретация

При чтении подробного сообщения об ошибке кажется, что утверждение проверяет, соответствуют ли A и B размеру D. Предположительно, эта проверка происходит до вычисления (cvKalmanPredict) с участием этих трех матриц.

Матрицы A, B и D, указанные в сообщении об ошибке, могут быть напрямую связаны с тремя или более матрицами, представленными в примере (A, возможно, соответствует kalmA и т. д.).

Требуется дополнительный код, чтобы прояснить связь, если таковая имеется, между A, B и D и объявленными матрицами. Может помочь установка точек останова в библиотеке openCV.

Список размеров матрицы может дать представление:

Variable  Size   Variable  Size   Variable  Size 
kalmA     6x6    kalmQ     6x6    kalmR     3x3
kalmB     6x6    kalmS     6x6         
kalmH     6x6    kalmP     6x6     

а. Размер матрицы

Поскольку kalmR — единственная матрица, отличающаяся по размеру, эта матрица может быть источником ошибки утверждения.

Если бы утверждение включало исключительно любую тройную комбинацию других матриц 6x6, утверждение не срабатывало бы, но срабатывало. Это говорит о том, что матричная переменная kalmR полезна для начала отслеживания кода.

Эта логика предполагает, что A, B и D сопоставляются с тремя матрицами, перечисленными в таблице.

б. Транспонирование матриц

Массивы могут иметь правильный размер, но могут быть неправильно транспонированы.

В приведенной выше таблице предполагается, что матрицы интерпретируются в формате 6x6, а не как вектор 1x36 или его транспонированный формат столбца 36x1. Связанный с ними флаг в выражении flags & CV_GEMM_B_T, запрашиваемом компилятором, может быть установлен, чтобы указать, форматируются ли массивы MxN или NxM.

В качестве альтернативы значения инициализации некорректных матриц можно переписать, чтобы они соответствовали формату, ожидаемому функцией openCV GEMM(Общее умножение матриц). Операция описывается как обобщенная, поскольку она включает в себя больше, чем просто умножение двух матриц.

в. Составные ошибки

Сообщение об ошибке может быть комбинацией обоих пунктов a. и б.


Альтернативное объяснение

Другая интерпретация состоит в том, что утверждение закодировано неправильно. Наличие матрицы B в сообщении об ошибке кажется несовместимым с целью утверждения.

//should that solitary B be an A?
D.rows == .. A.rows && D.cols == .. B.cols && D.type() == A.type()

Последний операнд в логическом и проверяет тип двух матриц D и A.

D.type() == A.type()

Перед сравнением типов находится пара операндов и, сравнивающая количество строк D и A и количество столбцов D и A соответственно.

//simplified assertion with B replaced by A
D.rows == .. A.rows && D.cols == .. A.cols  

Утверждение, по-видимому, проверяет, имеют ли две матрицы одинаковые размеры, прежде чем выполнять явную проверку их типа.

Любые две матрицы с разным количеством строк или столбцов исключат вызов type() в утверждении, поскольку && замыкает. Тем не менее, в исходном утверждении только одно измерение D и A проверяется на равенство, предполагая, что проверка должна определить, совместимы ли две матрицы для умножения.

Та же логика применяется, когда A заменяется на B:

D.rows == .. B.rows && D.cols == .. B.cols && D.type == B.type()


Настойчивые проверки перед операцией Matrix

Удивительно, но из запутанного сообщения об ошибке, выдаваемого компилятором, мы можем догадаться о матричной операции, связанной с утверждением — этого можно добиться, не имея доступа к исходному коду библиотеки openCV и при отсутствии какой-либо документации openCV.

В логических операндах and достаточно информации для частичного восстановления матричного уравнения (включая A, B и D), которое согласуется с запрограммированным матричным уравнением в функции openCV GEMM (которое вызывает сообщение об ошибке ).

Это отличается от поиска конкретной функции и номера строки в файле. Отличие в том, что мы выводим последовательность матричных операций на основе ряда математических свойств, проверенных в утверждении.

Логика следующая:

а. Начальное предположение

Акцент в утверждении делается на переменной D, поскольку она встречается в каждом из операндов и.

Утверждение намекает, что D должно быть каким-то образом совместимо как с А, так и с В, тогда как в нем не упоминается пригодность А для В.

Возможно, эти пары матриц ранее сравнивались и в каком-то смысле были признаны совместимыми. (В сообщении об ошибке наличие битовых масок CV_GEMM_A_T, CV_GEMM_B_T, относящихся к A и B, подтверждает эту точку зрения — информация для A и B, в отличие от D , содержится в единственной переменной flags.

Это также намекает, почему в утверждении нет сравнения типов D.type() == B.type(), поскольку оно было бы избыточным).

Имея это в виду и переписав утверждение с операндами, переупорядоченными для сбора похожих терминов, мы имеем:

D.rows == .. A.cols && D.type() == A.type() && D.cols == .. B.rows

Сравнение размера строки D с размером столбца A предполагает D * A, операцию умножения (операция сложения потребует сравнения каждого измерения матрицы, чего здесь нет).

Аналогично для D и B — в этом случае размер столбца D сравнивается с размером строки B — этот тест согласуется с операцией умножения, поэтому мы имеем B * D.

Собирая эти термины вместе, можно предположить, что D * A + B * D или, возможно, D * A - B * D, или какая-то аналогичная комбинация матриц выполняется функцией GEMM.

б. Второе предположение

Вместо продолжения в качестве мультипликативного или аддитивного операнда D изобретается заново для хранения результата некоторой последовательности матричных операций между A и B. Простейшая последовательность операций — это A * B или A + B.

Проверка строки и столбца в утверждении поддерживает прежнее предположение, D = A * B.

Парные переменные A, B достаточно связаны, чтобы исключить другие комбинации, такие как B = D * A и A = B * D.

Роль D в качестве получателя результата предварительно обозначена буквой, обозначающей эту переменную.

в. Любая из догадок восстановила матричные операции?

При чтении документации openCV второе предположение определяется как наиболее близкое к правильному описанию.

В частности, функция openCV, запускающая утверждение, может быть одной из трех подпрограмм: cvMatMul, cvMatMulAdd или cvGEMM, а соответствующие матричные операции:

D =   A * B         // cvMatMul
D =   A * B +   C   // cvMatMulAdd 
D = α A * B + β C   // cvGEMM - Generalized Matrix Multiplication 
                    //          alpha, beta are scalars unlike A, B, C, D 

Дополнительная информация об этих объявлениях функций задокументирована здесь

Побитовая переменная flags для A и B

Выше мы предположили, что битовые поля в переменной flags идентифицируются CV_GEMM_A_T и CV_GEMM_B_T. Аналогичное обсуждение применимо для различных комбинаций этих настроек флажков.

Когда биты, соответствующие CV_GEMM_A_T и CV_GEMM_B_T, не равны нулю, применяется первое из двух утверждений (штрих указывает на операцию транспонирования):

// matrix-size selected by the conditional operator when the ...
D.rows == .. A'.rows && D.cols == .. B'.cols    // ... bit fields are set 
D.rows == .. A .cols && D.cols == .. B .rows    // ... bit fields are unset

Для сравнения, когда подвыражения flags & CV_GEMM_A_T и flags & CV_GEMM_B_T равны нулю, утверждение принимает другую форму.

Сообщение об ошибке подразумевает, что переменная flags представляет как минимум матрицы A и B. В документации openCV указано, что все три входные матрицы A, B и C могут быть представлены этой единственной переменной.

Заключительный момент: настойчивые проверки перед операциями с матрицей

Упреждая конкретные матричные вычисления, на которые ссылается утверждение, мы сужаем возможные пути через код и место, где находится матричный алгоритм.

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

Здесь мы рассмотрели простые матричные выражения. При столкновении с аналогичными сообщениями об ошибках, генерируемыми менее тривиальными матричными алгоритмами, описанный подход может оказаться полезным для расшифровки зашифрованных матричных операций, закодированных в срабатывающем утверждении.

Расширение: автоматическое создание утверждений

Может существовать способ написания матричного кода, позволяющего автоматически генерировать такие утверждения, возможно, с использованием шаблонов. Матричный класс и матричные операции могут быть закодированы для облегчения создания таких проверок.

person damienh    schedule 05.05.2012
comment
Большое спасибо за предложения. Проблема в том, что я использую одну из временных переменных в фильтре Калмана и инициализирую ее матрицей 3 на 1. В cvKalmanPredict они пытаются сохранить произведение двух матриц 6 на 6, и это приводит к ошибке. - person ucl; 06.05.2012