pcaccompute()不触及Matrix<>输出数组参数

本文关键字:输出 数组 参数 Matrix pcaccompute | 更新日期: 2023-09-27 18:10:08

我使用EmguCV 3.0.0包装器到OpenCV 3.0。EmguCV PCACompute方法封装了OpenCV PCA::operator()方法。

编译并运行以下代码。注释应该能很好地解释意图。

// Populate the 5 row by 8 column input array (5 samples of 8 dimensions).
// The sample dimensions (columns) vary like this:
//   - low variance: 0, 1, 4, 5, 6, 7
//   - high variance: 2, 3
Matrix<double> input = new Matrix<double>(5, 8);
var r = new Random();
for (int row = 0; row < 5; row++) {
    input.Data[row,0] = r.Next(0, 10);     // low variance
    input.Data[row,1] = r.Next(0, 20);     // low variance
    input.Data[row,2] = r.Next(80, 210);   // high variance
    input.Data[row,3] = r.Next(0, 240);    // highest variance
    input.Data[row,4] = r.Next(20, 21);    // very low variance
    input.Data[row,5] = r.Next(0, 10);     // low variance
    input.Data[row,6] = r.Next(0, 10);     // low variance
    input.Data[row,7] = r.Next(200, 210);  // low variance
}
// create output array for PCACompute()
var eigenvectors = new Matrix<double>(8, 8);
// create *empty* mean array so that PCACompute() calculates its own means
var means = new Mat();
// HERE IS THE MAGIC.
CvInvoke.PCACompute(input, means, eigenvectors);

但是魔法被打破了。eigenvectors都是0。这个漂亮的打印代码:

// print each eigenvector on its own line
for (int vectorIdx = 0; vectorIdx < eigenvectors.Rows; vectorIdx++) {
    string vectorStr = "";
    for(int dimension = 0; dimension < eigenvectors.Cols; dimension++) {
        vectorStr += eigenvectors.Data[vectorIdx, dimension].ToString() + ", ";
    }
    Console.WriteLine("{ " + vectorStr.Substring(0, vectorStr.Length - 2) + " }");
}

给出如下输出:

{ 0, 0, 0, 0, 0, 0, 0, 0 }
{ 0, 0, 0, 0, 0, 0, 0, 0 }
{ 0, 0, 0, 0, 0, 0, 0, 0 }
{ 0, 0, 0, 0, 0, 0, 0, 0 }
{ 0, 0, 0, 0, 0, 0, 0, 0 }
{ 0, 0, 0, 0, 0, 0, 0, 0 }
{ 0, 0, 0, 0, 0, 0, 0, 0 }
{ 0, 0, 0, 0, 0, 0, 0, 0 }

实际上,如果在传递给PCACompute之前设置eigenvectors 的成员:

eigenvectors.Data[1,1] = 42;
CvInvoke.PCACompute(input, means, eigenvectors);

漂亮的字体显示 eigenvectors完全没有被PCACompute触及:

{ 0, 0, 0, 0, 0, 0, 0, 0 }
{ 0, 42, 0, 0, 0, 0, 0, 0 }
{ 0, 0, 0, 0, 0, 0, 0, 0 }
{ 0, 0, 0, 0, 0, 0, 0, 0 }
{ 0, 0, 0, 0, 0, 0, 0, 0 }
{ 0, 0, 0, 0, 0, 0, 0, 0 }
{ 0, 0, 0, 0, 0, 0, 0, 0 }
{ 0, 0, 0, 0, 0, 0, 0, 0 }

这是一个bug,还是我做错了?

pcaccompute()不触及Matrix<>输出数组参数

尽管根据类型系统是兼容的,但是传递给PCACompute的第三个参数不能是Matrix<>类型的。不过,如果是Mat类型,一切都可以正常工作!

Matrix<double> input = new Matrix<double>(5, 8);
var r = new Random();
for (int row = 0; row < 5; row++) {
    input.Data[row,0] = r.Next(0, 10);     // low variance
    input.Data[row,1] = r.Next(0, 20);     // low variance
    input.Data[row,2] = r.Next(80, 210);   // high variance
    input.Data[row,3] = r.Next(0, 240);    // highest variance
    input.Data[row,4] = r.Next(20, 21);    // very low variance
    input.Data[row,5] = r.Next(0, 10);     // low variance
    input.Data[row,6] = r.Next(0, 10);     // low variance
    input.Data[row,7] = r.Next(200, 210);  // low variance
}
// CHANGE HERE
// Matrix<> was not changed by PCACompute(), so change eigenvectors to a Mat
var eigenvectors = new Mat(8, 8, DepthType.Cv64F, 1);
// create *empty* mean array so that PCACompute() calculates its own means
var means = new Mat();
// Now the magic works fine.
CvInvoke.PCACompute(input, means, eigenvectors);

现在eigenvectors包含了更合理的数据(尽管它在pretty print函数中使用了不同的访问器代码)

 > eigenvectors.GetValueRange().Max
0.999418
 > eigenvectors.GetValueRange().Min
-0.6326281