Possible armadillo mat bug when saving a mat in an external array? - c++

I have a problem which is like this. I want to create an armadillo matrix backed by an array, which is fine and easy to do. However when I try to save the resulting mat in an array of armadillo mats' changes to the underlying c array no longer changes the mat. Example code:
#include<iostream>
#include<armadillo>
using namespace std;
using namespace arma;
int main() {
Mat<float>* test = (Mat<float>*)malloc(sizeof(Mat<float>));
float *Amem = (float*) malloc(4*sizeof(float));
Amem[0] = 0; Amem[1] = 1; Amem[2] = 2; Amem[3] = 3;
Mat<float> A = Mat<float>(Amem, 2, 2, false, false);
test[0] = A;
test[0].print();
Amem[1] = 100;
test[0].print();
A.print();
free(test);
free(Amem);
return 0;
}
When the following code is run, it results in:
test[0] = 0 2
1 3
test[0] = 0 2
1 3
A = 0 2
100 3
Why isn't A and test[0] the same? Is there anyway to make them the same?

Related

Iterating the creation of objects in C++

I want to be able to create N skyscrapers. Using an inputdata string, I would like to give them coordinate values of their X and Y positions. My main function I used "i" to demonstrate that I am trying to create as many skyscrapers as I can using the input data. Essentially, I would like to create N/3 skyscrapers and assign the input to coordinates for each.
#include <iostream>
#include <vector>
#include <string>
#include <math.h>
using namespace std;
vector<int> inputData = {1, 4, 10, 3, 5, 7, 9, 10, 4, 11, 3, 2, 14, 5, 5};
int N = inputData.size();
class Buildings{
public:
int yCoordinateLow;
int yCoordinateHigh;
int xCoordinateLeft;
int xCoordinateRight;
};
int main(){
for(int i=0; i<N; i=i+3){
Buildings skyscraper;
skyscraper.xCoordianteLeft = inputData.at(i);
skyscraper.yCoordianteLow = 0;
skyscraper.yCoordinateHigh = inputData.at(i+1);
skyscraper.xCoordinateRight = inputData.at(i+2);
}
return 0;
}
Jeff Atwood once said: use the best tools money can buy. And those aren't even expensive: Visual Studio community edition is free. Such a proper IDE will tell you that the skyscraper is unused except for the assignments.
Since you probably want to do something with those skyscrapers later, you should store them somewhere, e.g. in another vector.
int main() {
vector<Buildings> skyscrapers;
for (int i = 0; i < N; i = i + 3) {
Buildings skyscraper{};
skyscraper.xCoordinateLeft = inputData.at(i);
skyscraper.yCoordinateLow = 0;
skyscraper.yCoordinateHigh = inputData.at(i + 1);
skyscraper.xCoordinateRight = inputData.at(i + 2);
skyscrapers.push_back(skyscraper);
}
return 0;
}
Other than that, I'd say the loop works fine as long as there are N*3 coordinates in the original vector.
If you e.g. implement a game, you would probably not hard code the skyscraper coordinates in a vector but rather read that data from a file, potentially per level.
Instead of doing all the error-prone coding, maybe you want to initialize the skyscrapers immediately
vector<Buildings> skyscrapers = {{1,0,4,10}, {3,0,5,7}, {9,0,10,4}, {11,0,3,4}, {14,0,5,5}};

ANN OPENCV error assertion failed

I'm trying to make a simple ANN network with opencv in QT and develop it more later ,
I tried with simple data and i get an error says : OpenCV Error : asserion failed ((unsigned)(i1 *datatype<_tp>::channels)) < unsigned(size.p[1]* channels())) in cv::mat::at
here's the code I wrote
#include <iostream>
#include <opencv2/ml.hpp>
#include <opencv/cv.h>
#include <opencv2/core.hpp>
#include <opencv2/imgcodecs.hpp>
#include <opencv2/highgui/highgui.hpp>
#include "nnet.h"
using namespace std;
using namespace cv;
int main()
{
string filename="data.csv";
Ptr<cv::ml::TrainData> tdata = cv::ml::TrainData::loadFromCSV(filename,0,-1,-1);
Mat trainData = tdata->getTrainSamples();
Mat trainLabels = tdata->getTrainResponses();
int numClasses = 3;
Mat hot(trainLabels.rows, numClasses, CV_32F, 0.0f);
for (int i=0; i<trainLabels.rows; i++) {
int id = (int)trainLabels.at<float>(i);
hot.at<float>(i, id) = 1.0f;
}
int input_neurons = 5;
int hidden_neurons = 5;
int output_neurons = 3;
Mat layerSizes = Mat(3, 1, CV_32SC1);
layerSizes.row(0) = Scalar(input_neurons);
layerSizes.row(1) = Scalar(hidden_neurons);
layerSizes.row(2) = Scalar(output_neurons);
Ptr<cv::ml::ANN_MLP> myNetwork = cv::ml::ANN_MLP::create();
myNetwork->setLayerSizes(layerSizes);
myNetwork->setTrainMethod(ml::ANN_MLP::SIGMOID_SYM);
myNetwork->setTermCriteria(TermCriteria(CV_TERMCRIT_ITER | CV_TERMCRIT_EPS, 1000, 0.00001f));
myNetwork->setTrainMethod(ml::ANN_MLP::BACKPROP,0.1f,0.1f);
myNetwork->setActivationFunction(ml::ANN_MLP::SIGMOID_SYM, 1, 1);
myNetwork->train(trainData, 0, hot);
string testfilename="test-data.csv";
Ptr<cv::ml::TrainData> testdata = cv::ml::TrainData::loadFromCSV(testfilename, 0,0,-1);
Mat testData = testdata->getTrainSamples();
Mat testLabels = testdata->getTrainResponses();
Mat testResults;
myNetwork->predict(testData, testResults);
float accuracy = float(countNonZero(testResults == testLabels)) / testLabels.rows;
printf("%f",accuracy);
return 0;
}
and for the data set i have
data.csv contains
1,2,3,7,2
7,1,7,7,5
9,7,5,3,2
12,21,32,71,8
and data-test.csv contains :
1,2,1,1,2,
9,1,2,12,5,
11,28,14,50,8,
3,1,2,12,5,
11,28,24,20,8,
thank you in advance for your help.
i found the solution to my problem , in the csv file i've i have 3 classes and the response values should be between [0..2] and i gave random numbers 5 and 8 so changing them solved this problem

OpenCV Mat data member access

I've seen a lot of OpenCV code which accesses the data member of a cv::Mat directly. cv::Mat stores the pointer to the data in a unsigned char* data member. Access to the data member looks like:
cv::Mat matUC(3,3,CV_8U)
int rowIdx = 1;
int colIdx = 1;
unsigned char val = matUC.data[ rowIdx * matUC.cols + colIdx]
I'm wondering if this works for a cv::Mat with pixel type other than unsigned char.
cv::Mat matF(3,3,CV_32F)
int rowIdx = 1;
int colIdx = 1;
float val = matF.data[ rowIdx * matF.cols + colIdx];
My understanding would be that a typecast is needed to access the elements correctly. Something like:
float val = ((float*)matF.data)[ rowIdx * matF.cols + colIdx];
I've seen a lot of code which doesn't use a typecast. So my question is: Is the typecast mandatory to access the correct element?
Mat data is an uchar*. If you have a, say, float matrix CV_32FC1, you need to access data as float.
You can do in different ways, not necessarily using casting:
#include <opencv2\opencv.hpp>
using namespace cv;
int main()
{
cv::Mat matF(3, 3, CV_32F);
randu(matF, Scalar(0), Scalar(10));
int rowIdx = 1;
int colIdx = 1;
// 1
float f1 = matF.at<float>(rowIdx, colIdx);
// 2
float* fData2 = (float*)matF.data;
float f2 = fData2[rowIdx*matF.step1() + colIdx];
// 3
float* fData3 = matF.ptr<float>(0);
float f3 = fData3[rowIdx*matF.step1() + colIdx];
// 4
float* fData4 = matF.ptr<float>(rowIdx);
float f4 = fData4[colIdx];
// 5
Mat1f mm(matF); // Or directly create like: Mat1f mm(3, 3);
float f5 = mm(rowIdx, colIdx);
// f1 == f2 == f3 == f4 == f5
return 0;
}
Notes
it's better to use step1() instead of cols when accessing directly data through pointers, since the image may not be continuous. Check here for more details.
The snippet is adapted from this my other answer

C++ Eigen: How to concatenate matrices dynamically (pointer issue?)

I have the following problem:
I have several partial (eigen) MatrixXds I want to concatenate to another, larger, MatrixXd variable I only have as a pointer. However, both the size of the smaller matrices and their number are dynamic, so I cannot use the << operator easily.
So I'm trying the following (the smaller matrices are stored in list_subdiagrams, obviously, and basis->cols() defines the number of matrices), using Eigen's MatrixXd block funtionality:
// sd[] contains the smaller matrices to be concatenated; all are of the same size
// col defines the total number of smaller matrices
MatrixXd* ret = new MatrixXd(sd[0]->rows(), col*sd[0]->cols());
for (int i=0; i<col; ++i){
ret->block(0, i*sd[0]->cols(), sd[0]->rows(), sd[0]->cols()) = *(sd[i]);
}
This, unfortunately, appears to somehow overwrite some part of the *ret variable - for before the assignment via the block, the size is (in my test-case) correctly shown as being 2x1. After the assignment it becomes 140736006011136x140736006011376 ...
Thank you for your help!
What do you mean you don't know the size? You can use the member functions cols()/rows() to get the size. Also, I assume by concatenation you mean direct sum? In that case, you can do something like
#include <iostream>
#include <Eigen/Dense>
int main()
{
Eigen::MatrixXd *A = new Eigen::MatrixXd(2, 2);
Eigen::MatrixXd *B = new Eigen::MatrixXd(3, 3);
*A << 1, 2, 3, 4;
*B << 5, 6, 7, 8, 9, 10, 11, 12, 13;
Eigen::MatrixXd *result = new Eigen::MatrixXd(A->rows() + B->rows(), A->cols() + B->cols());
result->Zero(A->rows() + B->rows(), A->cols() + B->cols());
result->block(0, 0, A->rows(), A->cols()) = *A;
result->block(A->rows(), A->cols(), B->rows(), B->cols()) = *B;
std::cout << *result << std::endl;
delete A;
delete B;
delete result;
}
So first make sure it works for 2 matrices, test it, then extend it to N.

matrix inversion in boost

I am trying to do a simple matrix inversion operation using boost. But I
am getting an error.
Basically what I am trying to find is inversted_matrix =
inverse(trans(matrix) * matrix)
But I am getting an error
Check failed in file boost_1_53_0/boost/numeric/ublas/lu.hpp at line 299:
detail::expression_type_check (prod (triangular_adaptor<const_matrix_type,
upper> (m), e), cm2)
terminate called after throwing an instance of
'boost::numeric::ublas::internal_logic'
what(): internal logic
Aborted (core dumped)
My attempt:
#include <boost/numeric/ublas/matrix.hpp>
#include <boost/numeric/ublas/vector.hpp>
#include <boost/numeric/ublas/io.hpp>
#include <boost/numeric/ublas/vector_proxy.hpp>
#include <boost/numeric/ublas/matrix.hpp>
#include <boost/numeric/ublas/triangular.hpp>
#include <boost/numeric/ublas/lu.hpp>
namespace ublas = boost::numeric::ublas;
template<class T>
bool InvertMatrix (const ublas::matrix<T>& input, ublas::matrix<T>& inverse) {
using namespace boost::numeric::ublas;
typedef permutation_matrix<std::size_t> pmatrix;
// create a working copy of the input
matrix<T> A(input);
// create a permutation matrix for the LU-factorization
pmatrix pm(A.size1());
// perform LU-factorization
int res = lu_factorize(A,pm);
if( res != 0 )
return false;
// create identity matrix of "inverse"
inverse.assign(ublas::identity_matrix<T>(A.size1()));
// backsubstitute to get the inverse
lu_substitute(A, pm, inverse);
return true;
}
int main(){
using namespace boost::numeric::ublas;
matrix<double> m(4,5);
vector<double> v(4);
vector<double> thetas;
m(0,0) = 1; m(0,1) = 2104; m(0,2) = 5; m(0,3) = 1;m(0,4) = 45;
m(1,0) = 1; m(1,1) = 1416; m(1,2) = 3; m(1,3) = 2;m(1,4) = 40;
m(2,0) = 1; m(2,1) = 1534; m(2,2) = 3; m(2,3) = 2;m(2,4) = 30;
m(3,0) = 1; m(3,1) = 852; m(3,2) = 2; m(3,3) = 1;m(3,4) = 36;
std::cout<<m<<std::endl;
matrix<double> product = prod(trans(m), m);
std::cout<<product<<std::endl;
matrix<double> inversion(5,5);
bool inverted;
inverted = InvertMatrix(product, inversion);
std::cout << inversion << std::endl;
}
Boost Ublas has runtime checks to ensure among other thing numerical stability.
If you look at source of the error, you can see that it tries to make sure that
U*X = B, X = U^-1*B, U*X = B (or smth like that) are coorect to within some epsilon. If you have too much deviation numerically this will likely not hold.
You can disable checks via -DBOOST_UBLAS_NDEBUG or twiddle with BOOST_UBLAS_TYPE_CHECK_EPSILON, BOOST_UBLAS_TYPE_CHECK_MIN.
As m has only 4 rows, prod(trans(m), m) cannot have a rank higher than 4, and as the product is a 5x5 matrix, it must be singular (i.e. it has determinant 0) and calculating the inverse of a singular matrix is like division by 0. Add independent rows to m to solve this singularity problem.
I think your matrix dimension, 4 by 5, caused the error. Like what Maarten Hilferink mentioned, you may try with a square matrix like 5 by 5. Here are requirement to have an inverse:
The matrix must be square (same number of rows and columns).
The determinant of the matrix must not be zero (determinants are covered in section 6.4). This is instead of the real number not being zero to have an inverse, the determinant must not be zero to have an inverse.