OpenCV卡尔曼滤波器错误

时间:2012-05-05 05:23:59

标签: c++ opencv kalman-filter

我正在使用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进行编译。

1 个答案:

答案 0 :(得分:5)

似是而非的解释

在读取详细的错误消息时,如果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(广义矩阵乘法)函数所期望的格式。该操作被描述为 generalized ,因为它包含的不仅仅是两个矩阵之间的乘法。

℃。复合错误

错误消息可能是两个点的某种组合a。和b。


替代解释

另一种解释是断言编码不正确。错误消息中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()


矩阵操作之前的断言检查

令人惊讶的是,从编译器发出的错综复杂的错误消息中,我们可以猜测与断言相关的矩阵操作 - 这可以在不访问openCV库的源代码且没有任何openCV的情况下实现。文档。

逻辑 -opends中有足够的信息可以部分恢复与openCV GEMM函数中编程的矩阵方程一致的矩阵方程(包括A,B和D)(触发)错误信息)。

这与在文件中查找特定功能和行号不同。区别在于我们基于断言中测试的一系列数学属性来推断矩阵运算的序列。

逻辑如下:

一个。初步猜测

断言的重点在于变量D,因为它出现在每个 - 变量中。

断言暗示D必须以某种方式与A和B兼容,而它没有提到A与B的适用性。

也许这些矩阵先前已被比较,并且在某种意义上被发现是兼容的。(在错误消息中,存在与A和B相关的位掩码CV_GEMM_A_TCV_GEMM_B_T,支持这一点view - 与D不同,A和B的信息包含在单数变量flags中。

这也暗示了为什么断言中没有类型比较D.type() == B.type(),因为它是多余的。)

考虑到这一点并重新编写断言,并重新排序以收集类似术语的操作数,我们有:

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

D行的行大小与A的列大小的比较表明D * A,乘法运算(加法运算需要比较每个矩阵维度,这里不会发生) 。

同样对于D和B - 在这种情况下,根据B的行大小检查D的列大小 - 该测试与乘法运算一致,因此我们得到B * D

收集这些术语,建议D * A + B * D或可能D * A - B * D或某些类似的矩阵组合由GEMM函数执行。

湾第二次猜测

而不是作为乘法或加法操作数继续,D被重新发明以存储A和B之间的一些矩阵运算序列的结果。最简单的操作序列是A * BA + B

断言中的行和列检查支持前一个猜测,D = A * B

配对变量A,B与其他组合(例如B = D * AA = B * D

的折扣充分相关

D作为结果目的地的作用,暂定用指定给该变量的字母表示。

℃。是否有任何猜测恢复了矩阵运算?

在阅读openCV文档时,第二个猜测被确定为最接近正确的描述。

特别是,触发断言的openCV函数可以是以下三个例程之一:cvMatMulcvMatMulAddcvGEMM,其对应的矩阵运算是:

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 

有关这些函数声明的更多信息记录在here

A和B的按位flags变量

在上文中,我们假设flags变量中的位字段由CV_GEMM_A_T和CV_GEMM_B_T标识。类似的讨论适用于这些标志设置的各种组合。

CV_GEMM_A_TCV_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_Tflags & CV_GEMM_B_T为零时,断言采用不同的形式。

错误消息暗示flags变量至少表示矩阵A和B. openCV文档指定所有三个输入矩阵A,B和C都可由此单个变量表示。

最终要点:Matrix操作之前的自信检查

在抢占断言所暗示的特定矩阵计算时,我们正在缩小通过代码的可能路径和矩阵算法所在的位置。

为了促进这种合理的猜测,矩阵计算的断言应该以一种形式写出,以暗示它们所保护的基础矩阵运算。

这里我们看一下简单的矩阵表达式。当遇到由不太平凡的矩阵算法生成的类似错误消息时,所描述的方法可能对解密在触发的断言中编码的加密矩阵运算有用。

扩展名:自动生成断言语句

可能有一种方法可以编写矩阵代码,以便使用模板自动生成此类断言。可以对矩阵类和矩阵运算进行编码以便于生成这种检查。