Basically what I'm trying to do is get the x and y coordinates from a ProtoBuf message that is similar to the SHPObject type. I know that with SHPObject I can do things like double* x = obj->padfX and double* y = obj->padfY. However, I'm not entirely sure how to extract this same information from my ProtoBuf (code is shown below). Thank you for your help!
This what I have tried so far:
myProject::protobuf::NewShape _NewShape;
auto obj = _NewShape.shape(0);
double* x = obj.polygon(0).point(0);
Gives the error:
cannot initialize a variable of the type 'double' with an rvalue of type 'unsigned int'
And, then I tried this which compiles but doesn't do anything (does not give me the desired output):
double x_coordinate = obj.polygon(0).point(0);
double *x_ptr = &x_coordinate;
Here's my ProtoBuf file:
newShape.proto
syntax = "proto2";
package myProject.protobuf;
message NewShape {
message Polygon
{
enum PolygonType {
POLY_TYPE_OUTER = 1;
POLY_TYPE_INNER = 2;
};
optional PolygonType type = 1 [default = POLY_TYPE_OUTER];
// x, y coordinates
repeated uint32 point = 2 [packed = true];
}
message Shape
{
repeated Polygon polygon = 1;
}
repeated Shape shape = 2;
}
Given your format, you can access points from a properly populated and deserialized object like this:
// newShape is the deserialized object here
const auto s0p0p0 = newShape.shape(0).polygon(0).point(0);
const auto s0p0p1 = newShape.shape(0).polygon(0).point(1);
Similarly, shape(1) would give you the second shape to access it points in the polygon object. You should check the *_size() methods before accessing an index to ensure valid access e.g. newShape.shape_size(), shape.polygon_size() and polygon.point_size().
If you intend to modify the message, you can use mutable_* methods to get the pointers to respective objects and then you can change those.
For example (change points of first polygon of first shape):
auto p = newShape2.mutable_shape(0);
p->mutable_polygon(0)->set_point(0, 123);
p->mutable_polygon(0)->set_point(1, 345);
Here's a complete working example of serialization and deserialization:
#include <iostream>
#include "newShape.pb.h"
int main()
{
// Serailization
::myProject::protobuf::NewShape newShape1;
auto shape1 = newShape1.add_shape();
auto polygon1 = shape1->add_polygon();
polygon1->add_point(1);
polygon1->add_point(2);
auto shape2 = newShape1.add_shape();
auto polygon2 = shape2->add_polygon();
polygon2->add_point(3);
polygon2->add_point(4);
const auto serializedData = newShape1.SerializeAsString();
std::cout << "Serialized Data Size: " << serializedData.size() << "\n\n";
// Send/Store Serialized Data
// Deserialization
::myProject::protobuf::NewShape newShape2;
if ( !newShape2.ParseFromString( serializedData ) )
{
std::cerr << "Deserialization failed!\n";
return -1;
}
std::cout << "Deserialized Data Size: " << newShape2.ByteSize() << "\n\n";
std::cout << "NewShape [Shapes: " << newShape2.shape_size() << "]\n";
for ( int i {0}; i < newShape2.shape_size(); ++i )
{
std::cout << " Shape # " << i << '\n';
const auto& shape = newShape2.shape( i );
for ( int j {0}; j < shape.polygon_size(); ++j )
{
std::cout << " Polygon # " << j << '\n';
const auto& polygon = shape.polygon( j );
for ( int k {0}; k < polygon.point_size(); ++k )
{
const auto& point = polygon.point( k );
std::cout << " Point # " << k << ": " << point << '\n';
}
}
}
return 0;
}
Output:
Serialized Data Size: 16
Deserialized Data Size: 16
NewShape [Shapes: 2]
Shape # 0
Polygon # 0
Point # 0: 1
Point # 1: 2
Shape # 1
Polygon # 0
Point # 0: 3
Point # 1: 4
Related
I want to assign a value (here 0.0f) to a complex variable which I defined first using std::complex<float>. The real and imaginary part of the variable should be then assigned using real(...)=0.0f and imag(...)=0.0f. But by compiling I get the error "lvalue required as left operand of assignment". I tried g++ 7.5 and also 6.5 and I got this error from both.
temp = new float[ nfft ];
tempComplex = new std::complex< float >[ nf ];
if ( processing->getComponentNSToProc() ) {
for ( int i = 0; i < sampNum; i++ ) {
temp[ i ] = srcData[ iSrc ].rcvData[ iRcv ].dataNS[ i ];
qDebug() << "before: temp[" << i << "] =" << temp[ i ] << "; ....dataNS[" << i << "] =" << srcData[ iSrc ].rcvData[ iRcv ].dataNS[ i ] << ";";
}
for ( int i = sampNum; i < nfft; i++ ) {
temp[ i ] = 0.0f;
qDebug() << "before: temp[" << i << "] =" << temp[ i ] << ";";
}
for ( int i = 0; i < nf; i++ ) {
real( tempComplex[ i ] ) = 0.0f;
imag( tempComplex[ i ] ) = 0.0f;
For using a non-static member function of a class we need to use(call) it through an object of that class. So you can change your code to look like:
int main()
{
std::complex<float> *tempComplex = new std::complex< float >[ 3];
for ( int i = 0; i < 3; i++ )
{
tempComplex[i].real(0.0f);
tempComplex[i].imag(0.0f);
std::cout<<tempComplex[i]<<std::endl;
}
}
The above code now works because tempComplex[i] is an object and we access the non-static member function named real and imag of the class std::complext<float>through this(tempComplex[i]) object.
Also after everything(at appropriate point) don't forget to use delete.
real, and imag, can be invoked without arguments, then they will return the read only real part or imaginary part of the object. If you call them with one argument then they will modify the real/imaginary part.
For instance
std::complex<float> z;
z.real(1.0f); // Sets the real part
x.imag(-2.0f); // Sets the imaginary part
I have a network with two inputs, two hidden nodes in a single layer, and an output node.
I am trying to solve XOR problem:
| i0 | i1 | desired output |
----------------------------
| 0 | 0 | 0 |
| 1 | 0 | 1 |
| 0 | 1 | 1 |
| 1 | 1 | 0 |
With my current code, I am running all 4 records above in a single epoch. I then repeat the epoch 20,000 times. I calculate the error after each record, not each epoch, and I back-propagate the error at this same time.
I use only sigmoid in the output layer, as I understand I want a result between 0 and 1.
My network, most of the time, converges. Other times, it doesn't.
I have tried using both sigmoid and tanh in the hidden layer, but neither seems to guarantee convergence.
I have tried randomly generating weights between 0 and 1 as well as between -1 and 1 using a uniform distribution. I have tried using Xavier Initialisation as both uniform and normal distribution. None of these seems to prevent the network from failing to converge. I have tried different combinations of activation function and weight generation.
Here is my complete code:
#include <iostream>
#include <array>
#include <random>
#include <chrono>
#include <iomanip>
#include <fstream>
#include <algorithm>
#include <iomanip>
typedef float DataType;
typedef DataType (*ActivationFuncPtr)(const DataType&);
const DataType learningRate = std::sqrt(2.f);
const DataType momentum = 0.25f;
const std::size_t numberEpochs = 20000;
DataType sigmoid(const DataType& x)
{
return DataType(1) / (DataType(1) + std::exp(-x));
}
DataType sigmoid_derivative(const DataType& x)
{
return x * (DataType(1) - x);
}
DataType relu(const DataType& x)
{
return x <= 0 ? 0 : x;
}
DataType relu_derivative(const DataType& x)
{
return x <= 0 ? 0 : 1;
}
DataType tanh(const DataType& x)
{
return std::tanh(x);
}
DataType tanh_derivative(const DataType& x)
{
return DataType(1) - x * x;
}
DataType leaky_relu(const DataType& x)
{
return x <= 0 ? DataType(0.01) * x : x;
}
DataType leaky_relu_derivative(const DataType& x)
{
return x <= 0 ? DataType(0.01) : 1;
}
template<std::size_t NumInputs>
class Neuron
{
public:
Neuron(ActivationFuncPtr activationFunction, ActivationFuncPtr derivativeFunc)
:
m_activationFunction(activationFunction),
m_derivativeFunction(derivativeFunc)
{
RandomiseWeights();
}
void RandomiseWeights()
{
std::generate(m_weights.begin(),m_weights.end(),[&]()
{
return m_xavierNormalDis(m_mt);
});
m_biasWeight = m_xavierNormalDis(m_mt);
for(std::size_t i = 0; i < NumInputs+1; ++i)
m_previousWeightUpdates[i] = 0;
}
void FeedForward(const std::array<DataType,NumInputs>& inputValues)
{
DataType sum = m_biasWeight;
for(std::size_t i = 0; i < inputValues.size(); ++i)
sum += inputValues[i] * m_weights[i];
m_output = m_activationFunction(sum);
m_netInput = sum;
}
DataType GetOutput() const
{
return m_output;
}
DataType GetNetInput() const
{
return m_netInput;
}
std::array<DataType,NumInputs> Backpropagate(const DataType& error,
const std::array<DataType,NumInputs>& inputValues,
std::array<DataType,NumInputs+1>& weightAdjustments)
{
DataType errorOverOutput = error;
DataType outputOverNetInput = m_derivativeFunction(m_output);
std::array<DataType,NumInputs> netInputOverWeight;
for(std::size_t i = 0; i < NumInputs; ++i)
{
netInputOverWeight[i] = inputValues[i];
}
DataType netInputOverBias = DataType(1);
std::array<DataType,NumInputs> errorOverWeight;
for(std::size_t i = 0; i < NumInputs; ++i)
{
errorOverWeight[i] = errorOverOutput * outputOverNetInput * netInputOverWeight[i];
}
DataType errorOverBias = errorOverOutput * outputOverNetInput * netInputOverBias;
for(std::size_t i = 0; i < NumInputs; ++i)
{
weightAdjustments[i] = errorOverWeight[i];
}
weightAdjustments[NumInputs] = errorOverBias;
DataType errorOverNetInput = errorOverOutput * outputOverNetInput;
std::array<DataType,NumInputs> errorWeights;
for(std::size_t i = 0; i < NumInputs; ++i)
{
errorWeights[i] = errorOverNetInput * m_weights[i];
}
return errorWeights;
}
void AdjustWeights(const std::array<DataType,NumInputs+1>& adjustments)
{
for(std::size_t i = 0; i < NumInputs; ++i)
{
m_weights[i] = m_weights[i] - learningRate * adjustments[i] + momentum * m_previousWeightUpdates[i];
m_previousWeightUpdates[i] = learningRate * adjustments[i] + momentum * m_previousWeightUpdates[i];
}
m_biasWeight = m_biasWeight - learningRate * adjustments[NumInputs] + momentum * m_previousWeightUpdates[NumInputs];
m_previousWeightUpdates[NumInputs] = learningRate * adjustments[NumInputs] + momentum * m_previousWeightUpdates[NumInputs];
}
const std::array<DataType,NumInputs>& GetWeights() const { return m_weights; }
const DataType& GetBiasWeight() const { return m_biasWeight; }
protected:
static std::mt19937 m_mt;
static std::uniform_real_distribution<DataType> m_uniformDisRandom;
static std::uniform_real_distribution<DataType> m_xavierUniformDis;
static std::normal_distribution<DataType> m_xavierNormalDis;
std::array<DataType,NumInputs> m_weights;
DataType m_biasWeight;
ActivationFuncPtr m_activationFunction;
ActivationFuncPtr m_derivativeFunction;
DataType m_output;
DataType m_netInput;
std::array<DataType,NumInputs+1> m_previousWeightUpdates;
};
template<std::size_t NumInputs>
std::mt19937 Neuron<NumInputs>::m_mt(std::chrono::duration_cast<std::chrono::milliseconds>(std::chrono::system_clock::now().time_since_epoch()).count());
template<std::size_t NumInputs>
std::uniform_real_distribution<DataType> Neuron<NumInputs>::m_uniformDisRandom(-1,1);
template<std::size_t NumInputs>
std::uniform_real_distribution<DataType> Neuron<NumInputs>::m_xavierUniformDis(-std::sqrt(6.f / NumInputs+1),std::sqrt(6.f / NumInputs+1));
template<std::size_t NumInputs>
std::normal_distribution<DataType> Neuron<NumInputs>::m_xavierNormalDis(0,std::sqrt(2.f / NumInputs+1));
main()
{
std::ofstream file("error_out.csv", std::ios::out | std::ios::trunc);
if(!file.is_open())
{
std::cout << "couldn't open file" << std::endl;
return 0;
}
file << std::fixed << std::setprecision(80);
std::array<std::array<DataType,2>,4> inputData = {{{0,0},{0,1},{1,0},{1,1}}};
std::array<std::array<DataType,1>,4> desiredOutputs = {{{0},{1},{1},{0}}};
std::array<Neuron<2>*,2> hiddenLayer1 =
{{
new Neuron<2>(tanh, tanh_derivative),
new Neuron<2>(tanh, tanh_derivative)
}};
std::array<Neuron<2>*,1> outputLayer =
{{
new Neuron<2>(sigmoid, sigmoid_derivative)
}};
std::cout << std::fixed << std::setprecision(80);
std::cout << "Initial Weights: " << std::endl;
const std::array<DataType,2>& outputWeights = outputLayer[0]->GetWeights();
const DataType& outputBias = outputLayer[0]->GetBiasWeight();
const std::array<DataType,2>& hidden1Weights = hiddenLayer1[0]->GetWeights();
const DataType& hidden1Bias = hiddenLayer1[0]->GetBiasWeight();
const std::array<DataType,2>& hidden2Weights = hiddenLayer1[1]->GetWeights();
const DataType& hidden2Bias = hiddenLayer1[1]->GetBiasWeight();
std::cout << "W0: " << hidden1Weights[0] << "\n"
<< "W1: " << hidden1Weights[1] << "\n"
<< "B0: " << hidden1Bias << "\n"
<< "W2: " << hidden2Weights[0] << "\n"
<< "W3: " << hidden2Weights[1] << "\n"
<< "B1: " << hidden2Bias << "\n"
<< "W4: " << outputWeights[0] << "\n"
<< "W5: " << outputWeights[1] << "\n"
<< "B2: " << outputBias << "\n" << std::endl;
DataType finalMSE = 0;
std::size_t epochNumber = 0;
while(epochNumber < numberEpochs)
{
DataType epochMSE = 0;
for(std::size_t row = 0; row < inputData.size(); ++row)
{
const std::array<DataType,2>& dataRow = inputData[row];
const std::array<DataType,1>& outputRow = desiredOutputs[row];
// Feed the values through to the output layer
hiddenLayer1[0]->FeedForward(dataRow);
hiddenLayer1[1]->FeedForward(dataRow);
DataType output0 = hiddenLayer1[0]->GetOutput();
DataType output1 = hiddenLayer1[1]->GetOutput();
outputLayer[0]->FeedForward({output0,output1});
DataType finalOutput0 = outputLayer[0]->GetOutput();
// if there was more than 1 output neuron these errors need to be summed together first to create total error
DataType totalError = 0.5 * std::pow(outputRow[0] - finalOutput0,2.f);
epochMSE += totalError * totalError;
DataType propagateError = -(outputRow[0] - finalOutput0);
std::array<DataType,3> weightAdjustmentsOutput;
std::array<DataType,2> outputError = outputLayer[0]->Backpropagate(propagateError,
{output0,output1},
weightAdjustmentsOutput);
std::array<DataType,3> weightAdjustmentsHidden1;
hiddenLayer1[0]->Backpropagate(outputError[0],dataRow,weightAdjustmentsHidden1);
std::array<DataType,3> weightAdjustmentsHidden2;
hiddenLayer1[1]->Backpropagate(outputError[1],dataRow,weightAdjustmentsHidden2);
outputLayer[0]->AdjustWeights(weightAdjustmentsOutput);
hiddenLayer1[0]->AdjustWeights(weightAdjustmentsHidden1);
hiddenLayer1[1]->AdjustWeights(weightAdjustmentsHidden2);
}
epochMSE *= DataType(1) / inputData.size();
file << epochNumber << "," << epochMSE << std::endl;
finalMSE = epochMSE;
++epochNumber;
}
std::cout << std::fixed << std::setprecision(80)
<< "\n\n====================================\n"
<< " TRAINING COMPLETE"
<< "\n\n====================================" << std::endl;
std::cout << "Final Error: " << finalMSE << std::endl;
std::cout << "Number epochs: " << epochNumber << "/" << numberEpochs << std::endl;
// output tests
std::cout << std::fixed << std::setprecision(2)
<< "\n\n====================================\n"
<< " FINAL TESTS"
<< "\n\n====================================" << std::endl;
for(std::size_t row = 0; row < inputData.size(); ++row)
{
const std::array<DataType,2>& dataRow = inputData[row];
const std::array<DataType,1>& outputRow = desiredOutputs[row];
std::cout << dataRow[0] << "," << dataRow[1] << " (" << outputRow[0] << ") : ";
// Feed the values through to the output layer
hiddenLayer1[0]->FeedForward(dataRow);
hiddenLayer1[1]->FeedForward(dataRow);
DataType output0 = hiddenLayer1[0]->GetOutput();
DataType output1 = hiddenLayer1[1]->GetOutput();
outputLayer[0]->FeedForward({output0,output1});
DataType finalOutput0 = outputLayer[0]->GetOutput();
std::cout << finalOutput0 << std::endl;
}
file.close();
return 0;
}
When things are working, I get an output like:
====================================
FINAL TESTS
====================================
0.00,0.00 (0.00) : 0.00
0.00,1.00 (1.00) : 0.99
1.00,0.00 (1.00) : 0.99
1.00,1.00 (0.00) : 0.00
When it's not working I get an output like:
====================================
FINAL TESTS
====================================
0.00,0.00 (0.00) : 0.57
0.00,1.00 (1.00) : 0.57
1.00,0.00 (1.00) : 1.00
1.00,1.00 (0.00) : 0.00
When it's working, the error for each epoch looks like:
The initial weights were:
W0: -0.47551780939102172851562500000000000000000000000000000000000000000000000000000000
W1: 0.40949764847755432128906250000000000000000000000000000000000000000000000000000000
B0: 2.33756542205810546875000000000000000000000000000000000000000000000000000000000000
W2: 2.16713166236877441406250000000000000000000000000000000000000000000000000000000000
W3: -2.74766492843627929687500000000000000000000000000000000000000000000000000000000000
B1: 0.34863436222076416015625000000000000000000000000000000000000000000000000000000000
W4: -0.53460156917572021484375000000000000000000000000000000000000000000000000000000000
W5: 0.04940851405262947082519531250000000000000000000000000000000000000000000000000000
B2: 0.97842389345169067382812500000000000000000000000000000000000000000000000000000000
But when it doesn't work, the error for each epoch looks like:
the initial weights in this particular one was:
W0: 1.16670060157775878906250000000000000000000000000000000000000000000000000000000000
W1: -2.37987256050109863281250000000000000000000000000000000000000000000000000000000000
B0: 0.41097882390022277832031250000000000000000000000000000000000000000000000000000000
W2: -0.23449644446372985839843750000000000000000000000000000000000000000000000000000000
W3: -1.99990248680114746093750000000000000000000000000000000000000000000000000000000000
B1: 1.77582693099975585937500000000000000000000000000000000000000000000000000000000000
W4: 1.98818421363830566406250000000000000000000000000000000000000000000000000000000000
W5: 2.71223402023315429687500000000000000000000000000000000000000000000000000000000000
B2: -0.79067271947860717773437500000000000000000000000000000000000000000000000000000000
I see nothing really telling about these weights that can help me generate good starting weights (which is what I believe the problem to be, regardless of the activation function used).
Question: What can I do to ensure convergence occurs?
Do I need to change the weight initialisation?
Do I need to use different activation functions?
Do I need more layers or a different number of nodes?
I haven't read all your code because it is quite long, but:
It would be nice to have a NeuralNetwork class and a Connection class eventually to avoid writing all the logic in main.
I like the ActivationFuncPtr typedef which you could use to try and mixup different activation functions for different Neurons (maybe with a genetic algorithm)?
Now, to answer your question, there are really no definitive answers, but I can give you a few advice:
Initializing with a predetermined set of weights should indeed help prevent falling into a local minimum. You could try different sets of weights and see which ones work best and what happens when you change a specific one(you're doing supervised learning anyway.) If you are doing research, it would give you a few free paragraphs ;)
Different activation functions usually don't help much with convergence, but it is worth a try. You could adjust sigmoid to 1/(1+exp(-4*x)), 4 being arbitrary for instance.
XOR has been solved with less nodes than that (see Neat Paper, a Neuro Evolution NN). Increasing the number of nodes could make it even harder to converge.
One (dirty) way to prevent early convergence would be to detect that if you have fallen in a local minimum, then restart with new random weights.
Another way, would be to use a genetic algorithm (I'm a bit biased because it is my field of study.)
I am running a Tensorflow model return a 3D array as output, and I couldn't get that array of data from the tensor.
I did print the shape of the output of the model without any problem.
std::vector<tf::Tensor> outputs;
auto start_inference = std::chrono::high_resolution_clock::now();
_status = _session->Run({inputs}, {"k2tfout_0", "k2tfout_1"}, {}, &outputs);
if (!_status.ok())
{
std::cerr << _status.ToString() << std::endl;
return 0;
}
unsigned int output_img_n0 = outputs[0].shape().dim_size(0);
unsigned int output_img_h0 = outputs[0].shape().dim_size(1);
unsigned int output_img_w0 = outputs[0].shape().dim_size(2);
unsigned int output_img_c0 = outputs[0].shape().dim_size(3);
That code worked without any error and showed the shape of the array. But still, I couldn't get the data from the outputs Tensor object.
The only function is worked is
float_t *plant_pointer = outputs[1].flat<float_t>().data();
But it destroy the array shape.
EDIT:
The output shape of the tensor is [num,high,width,channel] === [1,480,600,3]. So, the output is an image of semantic segmentation image of the model. I just want the image part without the first dim which always be 1.
The tensorflow::Tensor class allows you to access its contents through several methods. With .flat you get a flattened version of the array, .tensor gives you a full Eigen tensor, and then there are a few other like .vec/.matrix (like .tensor with number of dimensions fixed to 1 or 2) and flat_inner_dims/flat_outer_dims/flat_inner_outer_dims (gives you a tensor with some dimensions collapsed). You can use the one that suits you best. In this case, for example if you want to print all the values in the tensor, you can use .flat and compute the corresponding offset or use .tensor if you know that the number of dimensions is 4:
std::vector<tf::Tensor> outputs;
auto start_inference = std::chrono::high_resolution_clock::now();
_status = _session->Run({inputs}, {"k2tfout_0", "k2tfout_1"}, {}, &outputs);
if (!_status.ok())
{
std::cerr << _status.ToString() << std::endl;
return 0;
}
unsigned int output_img_n0 = outputs[0].shape().dim_size(0);
unsigned int output_img_h0 = outputs[0].shape().dim_size(1);
unsigned int output_img_w0 = outputs[0].shape().dim_size(2);
unsigned int output_img_c0 = outputs[0].shape().dim_size(3);
for (unsigned int ni = 0; ni < output_img_n0; ni++)
{
for (unsigned int hi = 0; hi < output_img_h0; hi++)
{
for (unsigned int wi = 0; wi < output_img_w0; wi++)
{
for (unsigned int ci = 0; ci < output_img_c0; ci++)
{
float_t value;
// Get vaule through .flat()
unsigned int offset = ni * output_img_h0 * output_img_w0 * output_img_c0 +
hi * output_img_w0 * output_img_c0 +
wi * output_img_c0 +
ci;
value = outputs[0].flat<float_t>()(offset);
// Get value through .tensor()
value = outputs[0].tensor<float_t, 4>()(ni, hi, wi, ci);
std::cout << "output[0](" << ni << ", " << hi << ", " << wi << ", " << ci << ") = ";
std::cout << value << std::endl;
}
}
}
}
Note that, although these methods create Eigen::TensorMap objects, which are not really expensive, you may prefer to call them only once and then query the tensor object multiple times. For example:
// Make tensor
tf::TTypes<float_t, 4>::Tensor outputTensor0 = outputs[0].tensor<float_t, 4>();
// Query tensor multiple times
for (...)
{
std::cout << outputTensor0(ni, hi, wi, ci) << std::endl;
}
EDIT:
If you want to obtain a pointer to the data of the tensor (for example to build another object from the same buffer avoiding copies or iteration), you can also do that. One option is to use the .tensor_data method, which returns a tensorflow::StringPiece, which is in turn a absl::string_view, which is just a polyfill for std::string_view. So the .data method of this object will give you a pointer to the underlying byte buffer for the tensor (note the warning in the documentation of .tensor_data: "the underlying tensor buffer is refcounted", so do not let the returned object be destroyed while you use the buffer). You can therefore do:
tf::StringPiece output0Str = outputs[0].tensor_data();
const char* output0Ptr = output0Str.data();
This however gives you a pointer to char so you would have to cast it to use it as float. It should be safe, but it looks ugly, so you can let Eigen do that for you. All Eigen objects have a .data method that returns a pointer of its type to the underlying buffer. For example:
const float_t* output0Ptr = outputs[0].flat<float_t>().data();
I am working on a problem where i have multiple arrays that are to be compared against a single array. The array with the shortest span between indexes will be returned.
Here is an example of a set of arrays i would be working with:
(if it is of any importance these values represent RGB values)
int[] workingset = {55, 34,102};
int[] test1 = {54,36,99};`
int[] test2 = {21,65,231};
int[] test3 = {76,35,1};
int[] test4 = {133,22,3};
Because test1[] values are closest to workingset[], test1[] would be the array that would be returned.
*I apologize for not putting up sample code, but i simply could not think of a way to piece this puzzle together.
you could easily sum up all components (r,g,b) and check which has the smallest difference.
#include <iostream>
int main(int argc, char* args[])
{
int workingset [] = {55, 34,102};
int test1 [] = {54,36,99};
int test2 []= {21,65,231};
int test3 [] = {76,35,1};
int test4 [] = {133,22,3};
int sums [4] = {};
for(int i=0; i<3;++i){
sums[0] += abs(test1[i]-workingset[i]);
}
std::cout << "diff test1 " << sums[0] << std::endl;
for(int i=0; i<3;++i){
sums[1] += abs(test2[i]-workingset[i]);
}
std::cout << "diff test2 " << sums[1] << std::endl;
for(int i=0; i<3;++i){
sums[2] += abs(test3[i]-workingset[i]);
}
std::cout << "diff test3 " << sums[2] << std::endl;
for(int i=0; i<3;++i){
sums[3] += abs(test4[i]-workingset[i]);
}
std::cout << "diff test4 " << sums[3] << std::endl;
int smallestIndex = 0;
int smallestDiff = INT_MAX;
for(int i=0; i< 4; i++){
if(sums[i] < smallestDiff){
smallestIndex = i;
smallestDiff = sums[i];
}
}
std::cout << "array with smallest index: " << smallestIndex << std::endl;
return 0;
}
I edited the microsoft specific includes and datatypes.
What's your metric for "shortest span between indexes"? I'm guessing that you're trying to minimize the sum of the absolute values of the differences between the two arrays?
Once you've defined your metric, try something like this pseudocode:
min_metric = MAX_INT
min_array = null
for array in arrays:
if array.length() == workingset.length():
metric = calculateMetric(workingset, array)
if metric < min_metric:
min_metric = metric
min_array = array
Let me guess too. Assuming you are trying to write a color matcher. Consider these arrays vectors. Then the absolute length of the vector difference between workingset and testX will be the metric to use.
Or in the code:
int [] delta = { 0, 0, 0 };
for (int i = 0; i < delta.length; ++i) delta[i] = workingset[i] - testX[i];
double metric = 0;
for (int x: delta) metric += x * x;
metric = sqrt(metric); // and use this to assess how far away the testX color is from the workingset color (sqrt operation is optional)
I am creating a multi-dimensional MAT object, and would like to get the size of the object - e.g.,
const int sz[] = {10,10,9};
Mat temp(3,sz,CV_64F);
std::cout << "temp.dims = " << temp.dims << " temp.size = " << temp.size() << " temp.channels = " << temp.channels() << std::endl;
I believe the resulting MAT to be 10x10x9, and I'd like to confirm, but the COUT statement gives:
temp.dims = 3 temp.size = [10 x 10] temp.channels = 1
I was hoping to see either:
temp.dims = 3 temp.size = [10 x 10 x 9] temp.channels = 1
Or:
temp.dims = 3 temp.size = [10 x 10] temp.channels = 9
How can I get the dimensionality of this Mat object? I didn't see any methods in Mat::Mat or MatND
You just found yourself one of the many flaws of the OpenCV C++ API.
If you take a look at the source code of OpenCV, version 2.4.6.1, you will realize cv::Mat::size is a member object of type cv::Mat::MSize, which is defined as
struct CV_EXPORTS MSize
{
MSize(int* _p);
Size operator()() const;
const int& operator[](int i) const;
int& operator[](int i);
operator const int*() const;
bool operator == (const MSize& sz) const;
bool operator != (const MSize& sz) const;
int* p;
};
Thus cv::Mat::size() actually refers to cv::Mat::MSize::operator ()(), whose return type Size is defined as
typedef Size_<int> Size2i;
typedef Size2i Size;
Quoting from the OpenCV manual, Size is a
"Template class for specifying the size of an image or rectangle. The class includes two members called width and height."
In other words, Size is only suitable for 2D matrices.
Fortunately all hope is not lost as you can use cv::Mat::MSize::operator [](int i) to get the size of the matrix along its i-th dimension.
const int sz[] = {10,10,9};
cv::Mat temp(3,sz,CV_64F);
std::cout << "temp.dims = " << temp.dims << "temp.size = [";
for(int i = 0; i < temp.dims; ++i) {
if(i) std::cout << " X ";
std::cout << temp.size[i];
}
std::cout << "] temp.channels = " << temp.channels() << std::endl;
temp.dims = 3 temp.size = [10 x 10 x 9] temp.channels = 1
OpenCV 2.4.9 deals with multi-dimensional sizes just fine. The struct cv::Mat::MSize can stores and return multiple dimensions. The data member cv::Mat::size is of the type cv::Mat::MSize. This code will enumerate the dimensions for you:
const int sz[] = {3, 4, 3, 6};
cv::Mat bigm(4, sz, CV_8UC1);
cout << bigm.dims << '\t';
for (int i=0; i<bigm.dims; ++i)
cout << bigm.size[i] << ',';
cout << endl;
The output is:
4 3,4,3,6,
std::vector<size_t> getMatDims(const cv::Mat& m)
{
std::vector<size_t> dims(m.dims);
std::partial_sum(&m.step[0],&m.step[0]+m.dims,dims.begin(),[](size_t a,size_t b){ return a/b; });
return dims;
}