3

私はOpenCVを使用して、Webカメラで見たボールの動きを予測していました。ただし、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

コンパイルにはMSVisualC++10でcmakeを使用しています。

4

1 に答える 1

5

もっともらしい解釈

詳細なエラーメッセージを読むと、アサーションはAとBがDのサイズに準拠しているかどうかをテストしているように見えます。おそらく、このチェックは、cvKalmanPredictこれら3つの行列を含むcomputation()の前に行われます。

エラーメッセージで指定された行列A、B、およびDは、例で提供されている3つ以上の行列に直接関連している可能性があります(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     

a。マトリックスサイズ

kalmRサイズが異なる唯一のマトリックスであるため、このマトリックスはアサーションの失敗の原因となる可能性があります。

アサーションが他の6x6マトリックスのトリプルの組み合わせのみを含む場合、アサーションはトリガーされませんが、起動します。これは、マトリックス変数kalmRがコードの追跡を開始するのに役立つ変数であることを示しています。

このロジックは、A、B、およびDが表にリストされている3つのマトリックスに マップされていることを前提としています。

b。転置行列

配列は正しいサイズである可能性がありますが、誤って転置される可能性があります。

上記の表は、行列が1x36ベクトルまたはその転置、36x1列形式ではなく、6x6形式で解釈されることを前提としています。コンパイラーによってプロンプトが出された式の関連フラグはflags & CV_GEMM_B_T、配列がMxN形式かNxM形式かを示すために設定できます。

または、問題のある行列の初期化値を、openCVのGEMM(Generalized Matrix Multiplication)関数で期待される形式に準拠するように書き直すこともできます。この操作は、2つの行列間の乗算だけでなく、それ以上のものを含むため、一般化されたものとして説明されます。

c。複合エラー

エラーメッセージは、両方のポイントの組み合わせである可能性があります。およびb。


代替説明

別の解釈は、アサーションが正しくコーディングされていないというものです。エラーメッセージにBマトリックスが含まれていることは、アサーションの意図と矛盾しているように見えます。

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

論理積の最後のオペランドは、2つの行列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  

アサーションは、タイプの明示的なチェックを行う前に、2つの行列が等しい次元であるかどうかをチェックしているように見えます。

行数または列数が異なる2つの行列は、短絡type()するため、アサーションでの呼び出しを除外します。&&しかし、元のアサーションでは、DとAの1つの次元のみが等しいかどうかがテストされており、2つの行列が乗算に互換性があるかどうかをチェックすることを示唆しています。

AをBに置き換える場合も、同じロジックが適用されます。

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


行列演算の前のアサーティブチェック

驚いたことに、コンパイラーによって発行された複雑なエラーメッセージから、アサーションに関連するマトリックス操作を推測できます。これは、openCVライブラリのソースコードにアクセスせずに、openCVドキュメントがない場合に実現できます。

論理およびオペランド内には、openCV GEMM関数(エラーメッセージを起動する)でプログラムされた行列方程式と一致する行列方程式(A、B、およびDを含む)を部分的に復元するのに十分な情報があります。

これは、ファイル内の特定の関数と行番号を見つけることとは異なります。違いは、アサーションでテストされた一連の数学的プロパティに基づいて、行列演算のシーケンスを推測していることです。

ロジックは次のとおりです。

a。最初の推測

アサーションは、および-オペランドのそれぞれで発生する変数Dに重点を置いています。

この主張は、DがAとBの両方と何らかの形で互換性がある必要があることを示唆していますが、AとBの適合性については言及していません。

おそらく、これらの行列のペアは以前に比較され、ある意味で互換性があることがわかりました(エラーメッセージでは、AとBに関連するビットマスクの存在がCV_GEMM_A_TこのCV_GEMM_B_Tビューをサポートしています-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の場合(この場合、Dの列サイズがBの行サイズに対してチェックされます)、このテストは乗算演算と一致しているため、がありB * Dます。

これらの用語をまとめて収集すると、GEMM関数によって、提案D * A + B * Dまたは場合によってはD * A - B * D、または同様の行列の組み合わせが実行されます。

b。2番目の推測

乗法または加法オペランドとして継続するのではなく、Dは、AとBの間の行列演算のシーケンスの結果を格納するために再発明されます。最も単純な演算シーケンスはA * BまたはA + Bです。

アサーションの行と列のチェックは、前者の推測をサポートしますD = A * B

ペアの変数A、Bは、B = D * Aおよびなどの他の組み合わせを割引するために十分に関連しています。A = B * D

結果の宛先として機能するDの役割は、この変数に指定された文字によって暫定的に示されます。

c。推測のいずれかが行列演算を回復しましたか?

openCVのドキュメントを読むと、2番目の推測が正しい説明に最も近いものとして識別されます。

特に、アサーションをトリガーするopenCV関数は、次の3つのルーチンのいずれかである可能性があります。cvMatMulcvMatMulAddまたは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 

これらの関数宣言の詳細については、ここに記載されています。

flagsAとBのビット単位の変数

flags上記では、CV_GEMM_A_TおよびCV_GEMM_B_Tによって識別される変数のビットフィールドを想定しています。これらのフラグ設定のさまざまな組み合わせについても、同様の説明が当てはまります。

When the bits corresponding to CV_GEMM_A_T and CV_GEMM_B_T are non-zero, the first of two assertions applies(the prime indicates the transpose operation):

// 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

For comparison, when the subexpressions flags & CV_GEMM_A_T and flags & CV_GEMM_B_T are zero, the assertion assumes a different form.

The error message implies the flags variable represents at least the matrices A and B. The openCV documentation specifies that all three input matrices A, B and C are representable by this single variable.

Final Point: Assertive Checks Prior to Matrix operations

In preempting the particular matrix computations the assertion alludes to, we are narrowing down the possible paths through the code and the location where the matrix algorithm resides.

この合理的な推測を容易にするために、行列計算のアサーションは、それらが保護する基礎となる行列演算を示唆する形式で作成する必要があります。

ここでは、単純な行列式について見てきました。ささいな行列アルゴリズムによって生成された同様のエラーメッセージに直面した場合、説明されたアプローチは、トリガーされたアサーションでエンコードされた暗号化された行列操作を解読するのに役立つ可能性があります。

拡張:アサーションステートメントの自動生成

おそらくテンプレートを使用して、そのようなアサーションの自動生成を可能にするマトリックスコードを書く方法があるかもしれません。行列クラスと行列操作は、そのようなチェックの生成を容易にするためにコーディングできます。

于 2012-05-05T08:51:18.523 に答える