Related
I am writing my own library for a university project, containing the template classes: Vector and Matrix. In addition to these template classes, there are also related template functions for vectors and matrices. The professor explicitly told us to define the matrix as a one-dimensional array in which the elements are sorted by column (reasons of efficiency / optimization). The "matrix" template class has 3 template parameters: type of data allowed by the matrix, number of rows, number of columns.
template <class T, unsigned int M, unsigned int N>
class Matrix
Having said that, I immediately get to the problem. I'm writing a function that calculates the determinant of any matrix of dimension > 4, using the LaPlace rule for columns (using the first column).
I also wrote a function for two-dimensional matrices (called D2MatrixDet) and a function for three-dimensional matrices (called D3MatrixDet) tested and working:
template <class T>
double D2MatrixDet(const Matrix<T, 2, 2>& _m)
template <class T>
double D3MatrixDet(const Matrix<T, 3, 3>& _m)
The template function that I have to write has two template parameters: data type of the input matrix, dimension of the matrix (since the determinant is calculated for square matrices, only one dimension is enough). It is a recursive function; the variable "result" is the one that keeps the determinant in memory at each step. Below, the code I wrote.
template <class T, unsigned int D>
void DNMatrixDet(Matrix<T, D, D> _m, double result) //LaPlace Rule respect to the first column
{
const unsigned int new_D = D - 1;
Matrix<T, new_D, new_D> temp;
if (D > 3)
{
for (unsigned int i = 0; i < _m.row; ++i)
//Indicate the element to multiply
{
for (unsigned int j = _m.row, l = 0; j < _m.row * _m.column && l < pow(new_D, 2); ++j)
//Manage the element to be inserted in temp
{
bool invalid_row = false;
for (unsigned int k = 1; k < _m.row && invalid_row == false; ++k) //Slide over row
{
if (j == (i + k * _m.row))
{
invalid_row = true;
}
}
if (invalid_row == false)
{
temp.components[l] = _m.components[j];
++l;
}
}
DNMatrixDet(temp, result);
result += pow((-1), i) * _m.components[i] * result;
}
}
else if (D == 3)
{
result += D3MatrixDet(_m);
}
}
In main, I test the function using a 5 x 5 matrix.
When I try to compile, several errors come out, all very similar and that have to do with the size of the matrix which is decreased by one at each step. This is when the initial matrix size is 5 (LA is the name of the library and Test.cpp is the file that contains the main):
LA.h: In instantiation of 'void LA::DNMatrixDet(LA::Matrix<T, M, M>, double) [with T = double;
unsigned int D = 5]':
Test.cpp:437:33: required from here
LA.h:668:34: error: no matching function for call to 'D3MatrixDet(LA::Matrix<double, 5, 5>&)'
result += D3MatrixDet(_m);
~~~~~~~~~~~^~~~
In file included from Test.cpp:1:
LA.h:619:12: note: candidate: 'template<class T> double LA::D3MatrixDet(const LA::Matrix<T, 3, 3>&)'
double D3MatrixDet(const Matrix<T, 3, 3>& _m)
^~~~~~~~~~~
LA.h:619:12: note: template argument deduction/substitution failed:
In file included from Test.cpp:1:
LA.h:668:34: note: template argument '5' does not match '3'
result += D3MatrixDet(_m);
~~~~~~~~~~~^~~~
This is when the size becomes 4:
LA.h: In instantiation of 'void LA::DNMatrixDet(LA::Matrix<T, M, M>, double) [with T = double;
unsigned int D = 4]':
LA.h:662:28: required from 'void LA::DNMatrixDet(LA::Matrix<T, M, M>, double) [with T = double;
unsigned int D = 5]'
Test.cpp:437:33: required from here
LA.h:668:34: error: no matching function for call to 'D3MatrixDet(LA::Matrix<double, 4, 4>&)'
In file included from Test.cpp:1:
LA.h:619:12: note: candidate: 'template<class T> double LA::D3MatrixDet(const LA::Matrix<T, 3, 3>&)'
double D3MatrixDet(const Matrix<T, 3, 3>& _m)
^~~~~~~~~~~
LA.h:619:12: note: template argument deduction/substitution failed:
In file included from Test.cpp:1:
LA.h:668:34: note: template argument '4' does not match '3'
result += D3MatrixDet(_m);
~~~~~~~~~~~^~~~
And so on. It keeps going down until starting over at 4294967295 (which I found to be the upper limit of a 32 bit "unsigned int") and continuing to go down until I reach the maximum number of template instances (= 900).
At each iteration, the compiler always checks the function for calculating the determinant of a 3 x 3, even if that function is only executed when the input matrix is a 3 x 3. So why does it check something that in theory should never to happen?
I double-checked the mathematical logic of what I wrote several times, even with the help of a matrix written on paper and slowly carrying out the first steps. I believe and hope it is right. I'm pretty sure the problem has to do with using templates and recursive function.
I apologize for the very long question, I tried to explain it in the best possible way. I hope I have well explained the problem.
EDIT:
Fixed problem by defining "if constexpr" at the beginning of DNMatrixDet function. The compilation is successful. I just need to fix the algorithm, but this is beyond the scope of the post. Below is the reprex with the changes made:
template <class T, unsigned int M, unsigned int N>
class Matrix
{
public:
T components[M * N];
unsigned int row = M;
unsigned int column = N;
Matrix()
{
for (unsigned int i = 0; i < M * N; ++i)
{
components[i] = 1;
}
}
Matrix(T* _c)
{
for (unsigned int i = 0; i < M * N; ++i, ++_c)
{
components[i] = *_c;
}
}
friend std::ostream& operator<<(std::ostream& output, const Matrix& _m)
{
output << _m.row << " x " << _m.column << " matrix:" << std::endl;
for (unsigned int i = 0; i < _m.row; ++i)
{
for (unsigned int j = 0; j < _m.column; ++j)
{
if (j == _m.column -1)
{
output << _m.components[i + j*_m.row];
}
else
{
output << _m.components[i + j*_m.row] << "\t";
}
}
output << std::endl;
}
return output;
}
};
template <class T>
double D3MatrixDet(const Matrix<T, 3, 3>& _m)
{
double result = _m.components[0] * _m.components[4] * _m.components[8] +
_m.components[3] * _m.components[7] * _m.components[2] +
_m.components[6] * _m.components[1] * _m.components[5] -
(_m.components[6] * _m.components[4] * _m.components[2] +
_m.components[3] * _m.components[1] * _m.components[8] +
_m.components[0] * _m.components[7] * _m.components[5]);
return result;
}
template <class T, unsigned int D>
void DNMatrixDet(Matrix<T, D, D> _m, double result)
{
Matrix<T, D - 1, D - 1> temp;
if constexpr (D > 3)
{
for (unsigned int i = 0; i < D; ++i)
{
for (unsigned int j = D, l = 0; j < D * D && l < (D - 1) * (D - 1); ++j)
{
bool invalid_row = false;
for (unsigned int k = 1; k < D && invalid_row == false; ++k)
{
if (j == (i + k * D))
{
invalid_row = true;
}
}
if (invalid_row == false)
{
temp.components[l] = _m.components[j];
++l;
}
}
DNMatrixDet(temp, result);
result += i & 1 ? -1 : 1 * _m.components[i] * result;
}
}
else if (D == 3)
{
result += D3MatrixDet(_m);
}
}
int main()
{
double m_start[25] = {4, 9, 3, 20, 7, 10, 9, 50, 81, 7, 20, 1, 36, 98, 4, 20, 1, 8, 5, 93, 47, 21, 49, 36, 92};
Matrix<double, 5, 5> m = Matrix<double, 5, 5> (m_start);
double m_det = 0;
DNMatrixDet(m, m_det);
std::cout << "m is " << m << std::endl;
std::cout << "Det of m is " << m_det << std::endl;
return 0;
}
When you pass as an argument _m with the type Matrix<T, 5, 5>, the trailing else branch contains the code result += D3MatrixDet(_m);. The compiler will still try to compile this and notice that it cannot find a matching constructor.
Since we know at compile-time whether to take this branch or not, we can instruct the compiler by using if constexpr instead. Since we are within a template, the compiler will no longer check this branch if it is discarded.
So let's change if (D > 3) to if constexpr (D > 3).
I am trying to build a spars Matrix using a Eigen or Armadillo library in C++ to solve a system of linear equations Ax=b. A is the coefficient matrix with a dimension of n*n, and B is a vector of right hand side with a dimension of n
the Spars Matrix A is like this, see the figure
I had a look though the Eigen document but I have a problem with defining and filling the Spars Matrix in C++.
could you please give me an example code to define the spars matrix and how to fill the values into the matrix using Eigen library in c++?
consider for example a simple spars matrix A:
1 2 0 0
0 3 0 0
0 0 4 5
0 0 6 7
int main()
{
SparseMatrix<double> A;
// fill the A matrix ????
VectorXd b, x;
SparseCholesky<SparseMatrix<double> > solver;
solver.compute(A);
x = solver.solve(b);
return 0;
}
The sparse matrix could be filled with the values mentioned in the post by using the .coeffRef() member function, as shown in this routine:
SparseMatrix<double> fillMatrix() {
int N = 4;
int M = 4;
SparseMatrix<double> m1(N,M);
m1.reserve(VectorXi::Constant(M, 4)); // 4: estimated number of non-zero enties per column
m1.coeffRef(0,0) = 1;
m1.coeffRef(0,1) = 2.;
m1.coeffRef(1,1) = 3.;
m1.coeffRef(2,2) = 4.;
m1.coeffRef(2,3) = 5.;
m1.coeffRef(3,2) = 6.;
m1.coeffRef(3,3) = 7.;
m1.makeCompressed();
return m1;
}
However, the SparseCholesky module (SimplicialCholesky<SparseMatrix<double> >) won't work in this case because the matrix is not Hermitian. The system could be solved with a LU or BiCGStab solver. Also note that sizes ofx and b need to be defined:
VectorXd b(A.rows()), x(A.cols());
In case of larger sparse matrices you may also want to look at the .reserve() function in order to allocate memory before filling the elements. The .reserve() function can be used to provide an estimate of the number of non-zero entries per column (or row, depending on the storage order. The default is comumn-major). In the example above that estimate is 4, but it does not make sense in such a small matrix. The documentation states that it is preferable to overestimate the number of non-zeros per column.
Since this question also asks about Armadillo, here is the corresponding Armadillo-based code. Best to use Armadillo version 9.100+ or later, and link with SuperLU.
#include <armadillo>
using namespace arma;
int main()
{
sp_mat A(4,4); // don't need to explicitly reserve the number of non-zeros
// fill with direct element access
A(0,0) = 1.0;
A(0,1) = 2.0;
A(1,1) = 3.0;
A(2,2) = 4.0;
A(2,3) = 5.0;
A(3,2) = 6.0;
A(3,3) = 7.0; // etc
// or load the sparse matrix from a text file with the data stored in coord format
sp_mat AA;
AA.load("my_sparse_matrix.txt", coord_ascii)
vec b; // ... fill b here ...
vec x = spsolve(A,b); // solve sparse system
return 0;
}
See also the documentation for SpMat, element access, .load(), spsolve().
The coord file format is simple. It stores non-zeros values.
Each line contains:
row col value
The row and column counts start at zero. Example:
0 0 1.0
0 1 2.0
1 1 3.0
2 2 4.0
2 3 5.0
3 2 6.0
3 3 7.0
1000 2000 9.0
Values not explicitly listed are assumed to be zero.
#include <vector>
#include <iostream>
#include <Eigen/Dense>
#include <Eigen/Sparse>
#include <Eigen/Core>
#include <cstdlib>
using namespace Eigen;
using namespace std;
int main()
{
double L = 5; // Length
const int N = 120; // No of cells
double L_cell = L / N;
double k = 100; // Thermal Conductivity
double T_A = 100.;
double T_B = 200.;
double S = 1000.;
Vector<double, N> d, D, A, aL, aR, aP, S_u, S_p;
vector<double> xp;
xp.push_back((0 + L_cell) / 2.0);
double xm = xp[0];
for (int i = 0; i < N - 1; i++)
{
xm = xm + L_cell;
xp.push_back(xm);
}
for (int i = 0; i < N; i++)
{
A(i) = .1;
d(i) = L_cell;
D(i) = k / d(i);
}
aL(0) = 0;
aR(0) = D(0) * A(0);
S_p(0) = -2 * D(0) * A(0);
aP(0) = aL(0) + aR(0) - S_p(0);
S_u(0) = 2 * D(0) * A(0) * T_A + S * L_cell * A(0);
for (int i = 1; i < N - 1; i++)
{
aL(i) = D(i) * A(i);
aR(i) = D(i) * A(i);
S_p(i) = 0;
aP(i) = aL(i) + aR(i) - S_p(i);
S_u(i) = S * A(i) * L_cell;
}
aL(N - 1) = D(N - 1) * A(N - 1);
aR(N - 1) = 0;
S_p(N - 1) = -2 * D(N - 1) * A(N - 1);
aP(N - 1) = aL(N - 1) + aR(N - 1) - S_p(N - 1);
S_u(N - 1) = 2 * D(N - 1) * A(N - 1) * T_B + S * L_cell * A(N - 1);
typedef Eigen::Triplet<double> T;
std::vector<T> tripletList;
tripletList.reserve(N * 3);
Matrix<double, N, 3> v; // v is declared here
v << (-1) * aL, aP, (-1) * aR;
for (int i = 0, j = 0; i < N && j < N; i++, j++)
{
tripletList.push_back(T(i, j, v(i, 1)));
if (i + 1 < N && j + 1 < N)
{
tripletList.push_back(T(i + 1, j, v(i + 1, 0)));
tripletList.push_back(T(i, j + 1, v(i, 2)));
}
}
SparseMatrix<double> coeff(N, N);
coeff.setFromTriplets(tripletList.begin(), tripletList.end());
SimplicialLDLT<SparseMatrix<double> > solver;
solver.compute(coeff);
if (solver.info() != Success) {
cout << "decomposition failed" << endl;
return;
}
Vector<double, N> temparature;
temparature = solver.solve(S_u);
if (solver.info() != Success)
{
cout << "Solving failed" << endl;
return;
}
vector<double> Te = {}, x = {};
Te.push_back(T_A);
x.push_back(0);
for (int i = 0; i < N; i++)
{
Te.push_back(temparature(i));
x.push_back(xp[i]);
}
Te.push_back(T_B);
x.push_back(L);
for (int i = 0; i < N + 2; i++)
{
cout << x[i] << " " << Te[i] << endl;
}
return 0;
}
Here is a full code of a solution to numerical problem which uses SparseMatrix. Look at the matrix v. It has the values of all the nonzero elements of coeff matrix yet to be defined. In the next loop I made a series of tripletList.push_back(...) adding a triplet consisting of row and column index and corresponding value taken from v for each non-zero element of coeff. Now declare a Sparse Matrix coeff with appropriate size and use the method setFromTriplets (documentation) to set its non-zero elements from tripletList triplets.
I need to minimize H in following equation:
Where H is 3x3 Matrix.
Pn is 3x1 matrix (point).
Euclidean() gives distance between 2 points.
Dn is the actual distance.
I have one initial estimate of H and m points(P0 to Pm)
I need optimize value of H such that for all m points error is minimized.
(All the values in the expression are known)
How can I implement this using opencv or dlib (or using boost/NLopt).
Although the documentation of find_optimal_parameters function of dlib library was really not enough, there is a unit test that you can find on github which shows how to use the function.
I saw the other question you've asked and seems that the solution was something different than in this question. However, here is an example, how to use the library (this is the first time I'm hearing about it) to calculate what you need or something very close to that. Probably you will need to change the DistanceQuality() function (by replacing the existing loop with two nested ones) and I'll let you do it yourself.
Please note, that everything all over the code is hardcoded, no error handling is done and the testing is done right in the main() function. There's lots of work to be done, though you can find the code working for illustration purposes.
Here we go:
#include <iostream>
#include <dlib/optimization.h>
#include <dlib/optimization/find_optimal_parameters.h>
using namespace dlib;
typedef matrix<double, 3, 1> MyPoint;
std::vector<MyPoint> points;
std::vector<double> distances;
double MyDistance(MyPoint point1, MyPoint point2)
{
double sum = 0;
for (int i = 0; i < 3; i++)
{
sum += (point1(i, 0) - point2(i, 0)) * (point1(i, 0) - point2(i, 0));
}
return sqrt(sum);
}
double DistanceQuality(const matrix<double, 3, 3>& H)
{
double sum = 0;
for (int i = 0; i < points.size() - 1; i++)
{
auto proj1 = H*points[i];
auto proj2 = H*points[i+1];
sum += abs(MyDistance(proj1, proj2) - distances[i]);
}
return sum;
}
matrix<double, 3, 3> VecToMatrix(matrix<double, 0, 1> vec)
{
matrix<double, 3, 3> matrix;
for (int i = 0; i < 9; i++)
{
matrix(i / 3, i % 3) = vec(i);
}
return matrix;
}
double test_function(matrix<double, 0, 1> H)
{
matrix<double, 3, 3> newH = VecToMatrix(H);
auto result = DistanceQuality(newH);
return result;
}
int main()
{
matrix<double, 3, 1> p1;
matrix<double, 3, 1> p2;
matrix<double, 3, 1> p3;
p1 = { 1, 1, 1 };
p2 = { 2, 2, 3 };
p3 = { 3, 1.6, 7};
points.push_back(p1);
points.push_back(p2);
points.push_back(p3);
double d1 = 2.44949;
double d2 = 4.142463;
distances.push_back(d1);
distances.push_back(d2);
matrix<double, 0, 1> H;
H = { 3, 1, 1,
1, 1, 6,
1, 4, 1 };
matrix<double, 0, 1> H_min;
matrix<double, 0, 1> H_max;
H_min = { 0.5, 0.6, 0.5,
0.5, 0.7, 0.5,
0.8, 0.3, 0.5, };
H_max = { 10, 10, 10,
10, 10, 10,
10, 10, 10, };
dlib::find_optimal_parameters(4, 0.001, 1000, H, H_min, H_max, test_function);
std::cout << "new H: " << std::endl << VecToMatrix(H) << std::endl;
return 0;
}
Hope you can adapt the parameters for you specific case.
I am using Eigen library for my project. I am searching how to remove a certain row or column from the given matrix in Eigen. I am not successful.
MatrixXd A = X1 X2 X3 X4
Y1 Y2 Y3 Y4
Z1 Z2 Z3 Z4
A1 A2 A3 A4
MatrixXd Atransform = X1 X2 X4
Y1 Y2 Y4
Z1 Z2 Z4
A1 A2 A4
enter code here
other than iterating through whole matrix or by using block operations on matrix A . Is there a method to do it simply.
Using the block functions is a bit cleaner:
void removeRow(Eigen::MatrixXd& matrix, unsigned int rowToRemove)
{
unsigned int numRows = matrix.rows()-1;
unsigned int numCols = matrix.cols();
if( rowToRemove < numRows )
matrix.block(rowToRemove,0,numRows-rowToRemove,numCols) = matrix.block(rowToRemove+1,0,numRows-rowToRemove,numCols);
matrix.conservativeResize(numRows,numCols);
}
void removeColumn(Eigen::MatrixXd& matrix, unsigned int colToRemove)
{
unsigned int numRows = matrix.rows();
unsigned int numCols = matrix.cols()-1;
if( colToRemove < numCols )
matrix.block(0,colToRemove,numRows,numCols-colToRemove) = matrix.block(0,colToRemove+1,numRows,numCols-colToRemove);
matrix.conservativeResize(numRows,numCols);
}
You can do it a lot easier and shorter by using Eigen 3.3.0+(released 2016.08):
vector<int> indicesToKeep = vector<int>{ 1, 2, 3 };
VectorXi indicesToKeepVector = VectorXi(indicesToKeep.data(), indicesToKeep.size());
MatrixXf matrix = MatrixXf(); // your data should be here!
matrix = matrix(Eigen::placeholders::all, indicesToKeepVector); // select columns you want to keep(indicesToKeep), discard others
matrix = matrix(indicesToKeepVector, Eigen::placeholders::all); // select rows you want to keep(indicesToKeep), discard others
matrix = matrix(Eigen::seq(5, 10), Eigen::placeholders::all); // keep rows from 5 to 10
matrix = matrix(Eigen::placeholders::all, Eigen::seq(5, 10)); // keep columns from 5 to 10
matrix = matrix(Eigen::seqN(5, 5), Eigen::placeholders::all); // keep rows from 5 to 10
matrix = matrix(Eigen::placeholders::all, Eigen::seqN(5, 5)); // keep columns from 5 to 10
To improve Andrew's answer, use bottomRows/rightCols.
void removeRow(Eigen::MatrixXd& matrix, unsigned int rowToRemove)
{
unsigned int numRows = matrix.rows()-1;
unsigned int numCols = matrix.cols();
if( rowToRemove < numRows )
matrix.block(rowToRemove,0,numRows-rowToRemove,numCols) = matrix.bottomRows(numRows-rowToRemove);
matrix.conservativeResize(numRows,numCols);
}
void removeColumn(Eigen::MatrixXd& matrix, unsigned int colToRemove)
{
unsigned int numRows = matrix.rows();
unsigned int numCols = matrix.cols()-1;
if( colToRemove < numCols )
matrix.block(0,colToRemove,numRows,numCols-colToRemove) = matrix.rightCols(numCols-colToRemove);
matrix.conservativeResize(numRows,numCols);
}
You may find the following static version better for certain uses (and more in-line with the spirit of Eigen's compile-time efficiency). In this case, you will be creating a new matrix without the row. A similar function can be constructed for columns using .leftCols() .rightCols()
template<typename T>
inline constexpr auto removeRow(const Eigen::Matrix<T, Eigen::Dynamic, Eigen::Dynamic>& matrix, const int& rowNum)
{
return (Eigen::Matrix<T, Eigen::Dynamic, Eigen::Dynamic>(matrix.rows() - 1, matrix.cols())
<< static_cast<Eigen::Matrix<T, Eigen::Dynamic, Eigen::Dynamic>>(matrix.topRows(rowNum - 1)),
static_cast<Eigen::Matrix<T, Eigen::Dynamic, Eigen::Dynamic>>(matrix.bottomRows(matrix.rows() - rowNum))).finished();
}
Enjoy!
I know it is an old question but it seems that Eigen now support creating a submatrix defined by the rows and columns indexed:
http://eigen.tuxfamily.org/bz/show_bug.cgi?id=329
http://eigen.tuxfamily.org/dox-devel/classEigen_1_1DenseBase.html#a0b44220621cd59a75cd0f48cc499518f
It is just not in the documentation it seems...
inline Eigen::MatrixXd removeMatrixRow(const Eigen::MatrixXd original_matrix, const int row_to_remove)
{
// New matrix has one fewer rows
Eigen::MatrixXd new_matrix(original_matrix.rows()-1, original_matrix.cols());
// Track rows in new matrix. Skip one at row_to_remove.
int row_to_fill = 0;
for (int orig_matrix_row = 0; orig_matrix_row < original_matrix.rows(); ++orig_matrix_row)
{
if (orig_matrix_row != row_to_remove)
{
new_matrix.row(row_to_fill) = original_matrix.row(orig_matrix_row);
++row_to_fill;
}
}
return new_matrix;
}
I'm very new in c++ but this code works in may application.
It works only for full dynamic matrixs but can adapt it.
If anyone has a better way please show me i really want to learn.
template<typename ScalarType>
void MatrixXdRemoveCol(Eigen::Matrix<ScalarType,-1,-1,0,-1,-1> *mat, int colindex)
{
Eigen::Matrix<ScalarType,-1,-1,0,-1,-1> *auxmat = new Eigen::Matrix<ScalarType,-1,-1,0,-1,-1>;
*auxmat = *mat;
mat->resize(mat->rows(),mat->cols()-1);
int rightColsSize = auxmat->cols()-colindex-1;
mat->leftCols(colindex) = auxmat->leftCols(colindex);
mat->rightCols(rightColsSize) = auxmat->rightCols(rightColsSize);
}
template<typename ScalarType>
void MatrixXdRemoveCols(Eigen::Matrix<ScalarType,-1,-1,0,-1,-1> *mat, std::vector<int>* cols)
{
for(auto iter = cols->rbegin();iter != cols->rend();iter++)
MatrixXdRemoveCol<ScalarType>(mat,*iter);
}
template<typename ScalarType>
void MatrixXdRemoveRow(Eigen::Matrix<ScalarType,-1,-1,0,-1,-1> *mat, int rowindex)
{
Eigen::Matrix<ScalarType,-1,-1,0,-1,-1> *auxmat = new Eigen::Matrix<ScalarType,-1,-1,0,-1,-1>;
*auxmat = *mat;
mat->resize(mat->rows()-1,mat->cols());
int BottomRowsSize = auxmat->rows()-rowindex-1;
mat->topRows(rowindex) = auxmat->topRows(rowindex);
mat->bottomRows(BottomRowsSize) = auxmat->bottomRows(BottomRowsSize);
}
I am making a simple calibration program in C++ using OpenCV. Everything goes fine until I actually try to call CVCalibrateCamera2. At this point, I get one of several errors:
If the number of images which I am using is equal to 4 (which is the number of points being drawn from each image:
OpenCV Error: Sizes of input arguments do not match (Both matrices must have the same number of points) in unknown function, file ......\src\cv\cvfundam.cpp, line 870
If the number of images is below 20:
OpenCV Error: Bad argument (The total number of matrix elements is not divisible by the new number of rows) in unknown function, file ......\src\cxcore\cxarray.cpp, line 2749
Otherwise, if the number of image is 20 or above:
OpenCV Error: Unsupported format or combination of formats (Invalid matrix type) in unknown function, file ......\src\cxcore\cxarray.cpp, line 117
I have checked the arguments for CVCalibrateCamera2 many times, and I am certain that they are of the correct dimensions relative to one another. It seems like somewhere the program is trying to reshape a matrix based on the number of images, but I can't figure out where or why. Any ideas? I am using Eclipse Galileo, MINGW 5.1.6, and OpenCV 2.1.
I am not 100% sure about this, but I don't think your object points can be collinear. In your code, you have
const float points [] [2] = {{0, 0}, {1, 0}, {2, 0}, {3, 0}};
These points are all on the same line (the x-axis). I think the object points must define a plane for cvCalibrateCamera2 to work. This might explain the errors you are seeing.
As far as I know, the OpenCV calibration routines were designed mostly for use with the checkerboard pattern (or some other planar set of object points), I don't know if the same algorithms will work in your situation.
Update:
This is the code which calls CVCalibrateCamera2():
void calibrate(CvMat * object_points, CvMat * image_points, CvMat * intrinsicsMatrix, CvMat * distortionVector){
const int point_count = object_points->rows;
const int image_count = image_points->rows / point_count;
CvMat * const full_object_points = cvCreateMat(image_count * point_count, 3, CV_32FC1);
CvMat * const point_counts = cvCreateMat(image_count, 1, CV_32SC1);
for (int i = 0; i < image_count; i++){
CV_MAT_ELEM(*point_counts, float, i, 0) = point_count;
for (int j = 0; j < point_count; j++){
for (int k = 0; k < 3; k++){
CV_MAT_ELEM(*full_object_points, float, i * point_count + j, k) = CV_MAT_ELEM(*object_points, float, j, k);
}
}
}
cvCalibrateCamera2(full_object_points, image_points, point_counts, cvSize(1, 1), intrinsicsMatrix, distortionVector, NULL, NULL, 0);
}
And this is the piece which collects the point values and passes them to the above function:
int main(){
const float points [] [2] = {{0, 0}, {1, 0}, {2, 0}, {3, 0}};
const int image_count = 5;
const int point_count = sizeof (points) / sizeof(points[1]);
CvMat * const object_points = cvCreateMat(point_count, 3, CV_32FC1);
for (int i = 0; i < point_count; i++){
CV_MAT_ELEM(*object_points, float, i, 0) = points[i][0];
CV_MAT_ELEM(*object_points, float, i, 1) = points[i][1];
CV_MAT_ELEM(*object_points, float, i, 2) = 0;
}
CvMat * const image_points = cvCreateMat(image_count * point_count, 2, CV_32FC1);
collectPoints(setup, image_count, point_count, image_points); // See below about this
CvMat * const intrinsicsMatrix = cvCreateMat(3, 3, CV_32FC1);
CvMat * const distortionVector = cvCreateMat(5, 1, CV_32FC1);
calibrate(object_points, image_points, intrinsicsMatrix, distortionVector);
}
In the above code, collectPoints() is a function making use of a third party library (gl.tter's WiiYourself wiimote library, if it matters). The code is below, but the important thing is that the points returned have values ranging from -.5 to .5.
void collectPoints(wiimote_setup & setup, const int image_count, const int point_count, CvMat * const image_points){
image_points->rows = image_count * point_count;
image_points->cols = 2;
bool A_pressed = false;
for (int i = 0; i < image_count; i++){
while (true){
setup.remote.RefreshState();
if (setup.remote.Button.A()){
if (!A_pressed){
for (int j = 0; j < point_count; j++){
wiimote_state::ir::dot & dot = setup.remote.IR.Dot[j];
CV_MAT_ELEM(*image_points, float, i * point_count + j, 0) = .5 - dot.X;
CV_MAT_ELEM(*image_points, float, i * point_count + j, 1) = .5 - dot.Y;
cout << dot.X <<", " << dot.Y << "\n";
}
cout << "\n";
cout.flush();
A_pressed = true;
break;
}
} else{
A_pressed = false;
}
}
}
}