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.
Related
There are a function called inner_product, but I failed miserably in use that. I'll need to use this function several times for different matrices and vectors. Bellow my current code:
std::vector<vector<int>> matrix_a = {{0, 0},
{0, 1},
{1, 0},
{1, 1}};
std::vector<float> vector_b = {0.5, 0.8};
dot_produt(matrix_a, vettor_b);
float dot_produt(vector<vector<int>> e, vector<float> p){
return std::inner_product(std::begin(e), std::end(e), std::begin(p), 0.0);
}
The process is like:
(0.5 * 0) + (0.8 * 0) + (0.5 * 0) + (0.8 * 1)... ...
Expected output:
2.6
Error:
no match for 'operator*' (operand types are 'std::vector<int>' and 'float')
__init = __init + (*__first1 * *__first2);
You are trying to use pointers to begin and end of a vector of vectors, inner_product requires pointers to beginning and end of a vector.
Also, vectors have their own iterators, you can use them instead of std::begin and std::end.
Live demo
#include <iostream>
#include <numeric>
#include <vector>
//passing vectors by reference avoids unnecessary copies
double dot_produt(const std::vector<std::vector<int>> &e, const std::vector<float> &p)
{
double result = 0;
for (auto& v : e) //range based loop
result += std::inner_product(v.begin(), v.end(), p.begin(), 0.0);
return result;
}
int main()
{
std::vector<std::vector<int>> matrix_a = {{0, 0},
{0, 1},
{1, 0},
{1, 1}};
std::vector<float> vector_b = {0.5, 0.8};
std::cout << dot_produt(matrix_a, vector_b); //test print
}
Output:
2.6
I have a vector of digits, for example {3, 6, 0, 1, 8}
I need to covert it to an integer using every digit of a vector consistently.
So the number i'll get is 36018.
Possible solution:
std::vector<int> values = {1, 3, 4, 5};
int res = 0, s = values.size();
for(int num : values) res += num * pow(10, --s);
I want to know if there is some more "elegant", or short maybe, way to do this using stl algorithms.
You could use std::accumulate
std::vector<int> values = {1, 3, 4, 5};
int result = std::accumulate(values.begin(), values.end(), 0, [](int acc, int val){
return 10 * acc + val;
});
std::cout << result << std::endl; // 1345
A regular for loop is easier to read and therefore IMO is the more elegant choice:
int num = 0;
for (int d : values) {
num = num * 10 + d;
}
With C++20-Ranges or range-v3 it can be made quite readable
#include <iostream>
#include <vector>
#include <range/v3/all.hpp>
int main() {
std::vector<int> values{1, 2, 3};
auto powers_of_10 = ranges::view::generate([n = 1]() mutable {
auto res = n;
n *= 10;
return res;
});
auto num = ranges::inner_product(powers_of_10, values | ranges::view::reverse, 0);
std::cout << num << '\n';
}
The idea here is to produce a range of powers of 10 [1, 10, 100, ...] and then to simply calculate the dot product with the reversed input vector.
It could have been even more expressive if there were a iterate_view that iteratively applies a function to a value.
I'm trying to store simulation data from C++ in HDF5 (later I will analyse this data in Python + Pandas). My goal is try to organise all the data properly in C++ so later I will only have to read it.
My problem is trying to store a dynamic array in different columns of HDF5: I am using H5::VarLenType to store the array. I success, but I am getting the array in one single column, and it is not convenient for me: I need every value in a single column.
I can do it if I used fixed-size arrays, but not using a temporary buffer with the hvl_t datatype. If I use the same approach (iterating over a loop calculating offsets by hand and adding the datatype) with the variable length array I get garbage data.
I have learned this approach in this SO answer
This is my proof of concept, later I will add it to my project.
#include <stddef.h>
#include <cstring>
#include <string>
#include <sstream>
#include <iostream>
#include "H5Cpp.h"
const int MAX_NAME_LENGTH = 32;
const int N_PLACES = 3;
const int N_ROWS = 3;
const std::string FileName("SimulationResults-test.h5");
const std::string DatasetName("SimulationData");
const std::string member_simulation("Simulation");
const std::string member_iteration("Iteration");
const std::string member_time_elapsed("Time_elapsed");
const std::string member_place_states("States");
const std::string member_fired_transition("Fired_transition");
typedef struct {
int simulation;
int iteration;
double time_elapsed;
char fired_transition[MAX_NAME_LENGTH];
int * place_states;
} SimulationData;
typedef struct {
int simulation;
int iteration;
double time_elapsed;
char fired_transition[MAX_NAME_LENGTH]; // MAX_NAME_LENGTH
hvl_t place_states; // N_PLACES
} SimulationData_buffer;
int main(void) {
// Data to write
SimulationData states_simulation[N_ROWS];
SimulationData_buffer states_simulation_buffer[N_ROWS];
// {
// { 1, 0, 0.0, {0, 0, 0}, "T1" },
// { 1, 1, 1.0, {0, 1, 0}, "T2" },
// { 1, 2, 5.0, {0, 0, 1}, "T1" }
// };
for (int i = 0; i< N_ROWS; i++) {
states_simulation[i].simulation = 1;
states_simulation[i].iteration = 0;
states_simulation[i].time_elapsed = 0.0;
// states_simulation[i].fired_transition = "T1";
strncpy(states_simulation[i].fired_transition, "T1",
sizeof(states_simulation[i].fired_transition) - 1);
states_simulation[i].fired_transition[sizeof(states_simulation[i].fired_transition) - 1] = 0;
states_simulation[i].place_states = new int[N_PLACES];
states_simulation[i].place_states[0] = 0;
states_simulation[i].place_states[1] = 10;
states_simulation[i].place_states[2] = 20;
}
// Number of rows
hsize_t dim[] = {sizeof(states_simulation) / sizeof(SimulationData)};
// Dimension of each row
int rank = sizeof(dim) / sizeof(hsize_t);
// defining the datatype to pass HDF5
H5::CompType mtype(sizeof(SimulationData_buffer));
mtype.insertMember(member_simulation,
HOFFSET(SimulationData, simulation),
H5::PredType::NATIVE_INT);
mtype.insertMember(member_iteration,
HOFFSET(SimulationData, iteration),
H5::PredType::NATIVE_INT);
mtype.insertMember(member_time_elapsed,
HOFFSET(SimulationData, time_elapsed),
H5::PredType::NATIVE_DOUBLE);
mtype.insertMember(member_fired_transition,
HOFFSET(SimulationData, fired_transition),
H5::StrType(H5::PredType::C_S1, MAX_NAME_LENGTH));
auto vlen_id_places = H5::VarLenType(H5::PredType::NATIVE_INT);
// Set different columns for the array <-------------------------
// auto offset = HOFFSET(SimulationData, place_states);
// for (int i = 0; i < N_PLACES; i++) {
// std::stringstream ss;
// ss << "Place_" << i+1;
// auto new_offset = offset + i*sizeof(int);
// std::cout << offset << " -> " << new_offset << std::endl;
// mtype.insertMember(ss.str(),
// new_offset,
// H5::PredType::NATIVE_INT);
// }
// Set the column as an array <-----------------------------------
mtype.insertMember("Places", HOFFSET(SimulationData, place_states), vlen_id_places);
// Filling buffer
for (int i = 0; i < N_ROWS; ++i) {
states_simulation_buffer[i].simulation = states_simulation[i].simulation;
states_simulation_buffer[i].iteration = states_simulation[i].iteration;
states_simulation_buffer[i].time_elapsed = states_simulation[i].time_elapsed;
strncpy(states_simulation_buffer[i].fired_transition,
states_simulation[i].fired_transition,
MAX_NAME_LENGTH);
states_simulation_buffer[i].place_states.len = N_PLACES;
states_simulation_buffer[i].place_states.p = states_simulation[i].place_states;
}
// preparation of a dataset and a file.
H5::DataSpace space(rank, dim);
H5::H5File *file = new H5::H5File(FileName, H5F_ACC_TRUNC);
H5::DataSet *dataset = new H5::DataSet(file->createDataSet(DatasetName,
mtype,
space));
H5::DataSet *dataset2 = new H5::DataSet(file->createDataSet("Prueba2",
mtype,
space));
// Write
dataset->write(states_simulation_buffer, mtype);
dataset2->write(states_simulation_buffer, mtype);
delete dataset;
delete file;
return 0;
}
Can be compiled with g++ h5-test-dynamic.cpp -lhdf5 -lhdf5_cpp -o h5-test-dynamic.
As said before I need one column per value, not an array in a single column. I don't know why it is not working as I have set the pointers and the offsets for the hvl_t variable properly. If I toggle on the block of code which handles the offsets and the datatypes manually and toggle off the one immediately later, I get garbage values.
This is what I get
[(1, 0, 0., b'T1', 3, 0, -971058832),
(1, 0, 0., b'T1', 3, 0, -971058800),
(1, 0, 0., b'T1', 3, 0, -971058768)]
And this is the best I can get
[(1, 0, 0., b'T1', array([ 0, 10, 20], dtype=int32)),
(1, 0, 0., b'T1', array([ 0, 10, 20], dtype=int32)),
(1, 0, 0., b'T1', array([ 0, 10, 20], dtype=int32))]
It's possible to convert an Eigen::Map to a Matrix by assignment:
vector<float> v = { 1, 2, 3, 4 };
auto m_map = Eigen::Map<Eigen::Matrix<float, 2, 2, Eigen::RowMajor>>(&v[0]);
Eigen::MatrixXf m = m_map;
cout << m << endl;
This produces:
1 2
3 4
If I try to do something similar with a Tensor:
vector<float> v = { 1, 2, 3, 4 };
auto mapped_t = Eigen::TensorMap<Eigen::Tensor<float, 2, Eigen::RowMajor>>(&v[0], 2, 2);
Eigen::Tensor<float, 2> t = mapped_t;
I simply get the compiler error YOU_MADE_A_PROGRAMMING_MISTAKE. Is there any way to convert a TensorMap to a Tensor?
Well, Eigen::RowMajor is not the default for Eigen::Tensor which means you are not assigning to the same type which means YOU_MADE_A_PROGRAMMING_MISTAKE. You have to explicitly request swapping the layout.
#include <vector>
#include <unsupported/Eigen/CXX11/Tensor>
int main()
{
std::vector<float> v = { 1, 2, 3, 4 };
auto mapped_t = Eigen::TensorMap<Eigen::Tensor<float, 2, Eigen::RowMajor>>(&v[0], 2, 2);
Eigen::Tensor<float, 2> t = Eigen::TensorLayoutSwapOp<Eigen::Tensor<float, 2, Eigen::RowMajor>>(mapped_t);
}
Using C++14 you could write a nice instantiator function for that.
#include <type_traits>
#include <vector>
#include <unsupported/Eigen/CXX11/Tensor>
namespace Eigen {
template < typename T >
decltype(auto) TensorLayoutSwap(T&& t)
{
return Eigen::TensorLayoutSwapOp<typename std::remove_reference<T>::type>(t);
}
}
int main()
{
std::vector<float> v = { 1, 2, 3, 4 };
auto mapped_t = Eigen::TensorMap<Eigen::Tensor<float, 2, Eigen::RowMajor>>(&v[0], 2, 2);
Eigen::Tensor<float, 2> t = Eigen::TensorLayoutSwap(mapped_t);
}
I have some problems with the Eigen library. When I try t access the matrices in the second for loop, I get the
eigen assertion index = 0 && index size() failed
error though I am calling the resize function of the Matrix.
Eigen::Matrix<float, 1, 2> linearRegression(Eigen::Vector2f *p, int pointCount)
{
Eigen::MatrixXf M;
Eigen::Matrix<float, 1, 2> A;
Eigen::MatrixXf Y;
M.resize(pointCount, 2);
Y.resize(pointCount, 1);
for (int i = 0; i < pointCount; i++)
{
M(i, 0) = p[i].x();
M(i, 1) = 1;
Y(i, 0) = p[i].y();
}
A = (M.transpose() * M).inverse() * M.transpose() * Y;
return A;
}
I can see the members m_rows and m_cols of matrix M in the visual studio debugger and i does not exceed them. The error occurs directly at i = 0.
MatrixXf should be the same as Matrix<float, Dynamic, Dynamic>.
When I declare a constant pointCount and use fixed size matrices, everything works fine.
Eigen::Matrix<float, 1, 2> linearRegression(Eigen::Vector2f *p, int pointCount)
{
const int pointCount = 30;
...
Eigen::Matrix<float, pointCount, 2> M;
Eigen::Matrix<float, 1, 2> A;
Eigen::Matrix<float, pointCount, 1> Y;
...
}
What am I doing wrong?
Your expression (M.transpose() * M).inverse() * M.transpose() * Y results in a matrix with 2 rows and 1 column, while A has 1 row and 2 columns. Because A is a fixed size, the resizing doesn't happen upon assignment. To fix, add a transpose to your expression:
((M.transpose() * M).inverse() * M.transpose() * Y).transpose()