The function call is slow in C++ - c++

I'm calling a function in C++ main function, for some reason it's taking long to call the function.
#include <iostream>
#include <opencv2/opencv.hpp>
#include "Eigen/Dense"
int inRo(float val){
return (int)round(val);}
std::pair<int,int> inRo(std::pair<float,float> pt){
return std::make_pair(inRo(pt.first),inRo(pt.second));}
// Gives the boundary points of Obstacles (in this case, the boundary points of white region in img)
std::vector<std::pair<int,int>> getBoundPts(cv::Mat img){
std::vector<std::pair<int,int>> bound_pts;
cv::Mat img_dilate;
cv::dilate(img.clone(),img_dilate,cv::Mat(),cv::Point(-1,-1),1,1,1);
cv::Mat img_bound = img_dilate - img;
std::vector<cv::Point> bound_pts_cv;
cv::findNonZero(img_bound,bound_pts_cv);
for(int i = 0;i < bound_pts_cv.size();i++){
std::pair<int,int> pt = std::make_pair(bound_pts_cv[i].x,bound_pts_cv[i].y);
bound_pts.push_back(pt);
}
return bound_pts;
}
void getNeighPts(std::pair<float,float> pt,Eigen::MatrixXf potentials_map,std::vector<std::pair<int,int>>& list_pts_bound,std::vector<float>& list_vals_bound,std::vector<std::pair<int,int>>& list_pts_empty){
//this function tries divides the neighbourhood points of a point 'pt'
//into two categories, empty (or list_pts_empty, are the ones with zero
//potential value, which can be obtained from map_potential) and non-zero ones
//(list_pts_bound, which are the ones with a non-zero potential value which
//can also be obtained from map_potential and list_val_bound is the corresponding
//potential values of the list_pts_bound).
//I'M SURE THE FUNCTION CAN BE WRITTEN IN SIMPLER WAYS BUT THE ONE I
//NEED IS MORE GENERIC AND COULD ABLE TO MODIFIED FOR VARIOUS TYPES OF
//NEIGHBOURHOODS AROUND A POINT.
clock_t ct1,ct2;
ct1 = clock();
list_pts_empty.clear();
list_vals_bound.clear();
list_pts_bound.clear();
std::pair<int,int> ind;
float pot_val_ind;
std::vector<std::pair<int,int>> neighs_perp;
neighs_perp.push_back(std::make_pair(0,1));
neighs_perp.push_back(std::make_pair(0,-1));
neighs_perp.push_back(std::make_pair(1,0));
neighs_perp.push_back(std::make_pair(-1,0));
int i,j;
for(int k = 0;k < neighs_perp.size();k++)
{
i = neighs_perp[k].first;
j = neighs_perp[k].second;
ind = std::make_pair(pt.first+i,pt.second+j);
if(ind.first >= 0 && ind.second >= 0 && ind.first < potentials_map.cols() && ind.second < potentials_map.rows())
{
pot_val_ind = potentials_map(ind.second,ind.first);
if(pot_val_ind > 0)
{
list_pts_bound.push_back(ind);
list_vals_bound.push_back(potentials_map(ind.second,ind.first) + 1);
}
else if(inRo(pot_val_ind) == 0)
{
list_pts_empty.push_back(ind);
}
}
}
ct2 = clock();
std::cout<<"Inside : "<<float(ct2-ct0)/CLOCKS_PER_SEC<<std::endl;
}
int main(){
clock_t t1,t2;
cv::Mat img = cv::Mat::zeros(500,500,CV_8UC1);
cv::Mat img_win = img(cv::Rect(125,125,250,250));
img_win.setTo(255);
std::vector<std::pair<int,int>> brush_que = getBoundPts(img);
Eigen::MatrixXf mat_potential(500,500);
Eigen::MatrixXf mat_block = Eigen::MatrixXf::Ones(250,250);
mat_potential.block(125,125,250,250) = -255*mat_block;
for(int i = 0;i < brush_que.size();i++){
std::pair<float,float> pt = brush_que[i];
mat_potential(pt.second,pt.first) = 1;
}
std::vector<std::pair<int,int>> neighs_empty;
std::vector<std::pair<int,int>> neighs_pts;
std::vector<float> neighs_val;
std::pair<int,int> pt_ex = brush_que[0];
t1 = clock();
getNeighPts(pt_ex,mat_potential,neighs_pts,neighs_val,neighs_empty);
t2 = clock();
std::cout<<"Outside : "<<float(t2-t1)/CLOCKS_PER_SEC<<std::endl;
}
the t2-t1 >>> ct2-ct1.
This is the trimmed version of my main code, and here I'm getting,
Inside : 1e-05
Outside : 0.002574
and in the main code, the difference is going way higher depending on the type of 'img'. Any suggesions on the problem would be appreciated.
Thanks in advance :)

Related

Copy vector (returned from a function) into a specific point of another vector directly at function call without needing extra temp variables [c++]

I have a function that returns a vector and I want all of that vector inserted into another vector at a specific point directly when calling that function.
What I would like to do is something like this:
#include <vector>
#include <iostream>
using namespace std;
typedef vector<double> Double1D;
Double1D myFunction(Double1D vector, int vector_size){
Double1D result;
result.resize (vector_size, 0);
result = vector; //here is where I would do calculations
return result;
}
int main()
{
int vector_size1 = 3;
int vector_size2 = 6;
Double1D vector_results;
vector_results.resize (9, 3);
vector_results[0-2] = myFunction(randomvector, vector_size1);
vector_results[3-8] = myFunction(randomvector2, vector_size2);
At the moment I am doing this which needs a for loop and needs extra temporary variables (minimal reproducible example):
#include <vector>
#include <iostream>
using namespace std;
typedef vector<double> Double1D;
Double1D myFunction(Double1D vector, int vector_size){
Double1D result;
result.resize (vector_size, 0);
result = vector; //here is where I would do calculations
return result;
}
int main()
{
int vector_size1 = 3;
int vector_size2 = 6;
Double1D vector_results;
vector_results.resize (9, 3);
Double1D vector1 ;
vector1.resize (vector_size1, 0);
Double1D vector2 ;
vector2.resize (vector_size2, 0);
Double1D temp_vector1 = myFunction(vector1, vector_size1);
Double1D temp_vector2 = myFunction(vector2, vector_size2);
for (int i = 0; i < (vector_size1 + vector_size2); i++){
if (i < vector_size1) vector_results[i] = temp_vector1[i];
if (i < vector_size2) vector_results[i+vector_size1] = temp_vector2[i];
cout<<vector_results[i]<<endl;
}
return 0;
}
The idiomatic method for writing a range of results is to take OutputIterators as function parameters.
#include <vector>
using Double1D = std::vector<double>;
void myFunction(Double1D::iterator dFirst, Double1D::iterator dLast) {
int n = /* number between 0 and dLast - dFirst */
dFirst[n] = /* calculations */
// or
for (; dFirst != dLast; ++dFirst) {
*dFirst = /* calculation */
}
}
int main() {
Double1D array_results;
array_results.resize(9, 0);
myFunction(randomvector, vector_size1);
myFunction(randomvector1, vector_size2);
}
If you insist on assigning a Double1D to something:
class AssignableSlice {
Double1D::iterator first;
Double1D::iterator last;
public:
AssignableSlice(Double1D & values, size_t first, size_t last)
: first(values.begin() + first), last(values.begin() + last) {}
AssignableSlice& operator=(Double1D & other) {
if (other.size() != std::distance(first, last)) throw std::out_of_range("wrong size in assignment");
std::copy(other.begin(), other.end(), first, last);
return *this;
}
};
int main() {
Double1D vector1;
vector1.resize (vector_size1, 0);
Double1D vector2;
vector2.resize (vector_size2, 0);
Double1D array_results;
array_results.resize(9, 0);
AssignableSlice(array_results, 0, vector_size1) = myFunction(vector1, vector_size1);
AssignableSlice(array_results, vector_size1, vector_size1 + vector_size2) = myFunction(vector2, vector_size2);
}
G'day, Alex from the past. This is you from the future. Here is how you solved it.
The function you want to use is a vector function called: insert() or a more efficient way that works for you is using copy() with back_inserter().
copy with back_inserter can only insert the vector to the back, whereas insert allows to insert anywhere. Both increase the size of the vector automatically.
Disclaimer: This may not be the best solution I am not an expert.
#include <vector>
#include <iostream>
using namespace std;
//vector<double> is variable that is a vector of doubles
typedef vector<double> Double1D; //this basically just gives vector<double> the name Double1D to make it easier to write
Double1D myFunction(Double1D vector, int vector_size){
Double1D result;
result.resize (vector_size, 0);
result = vector; //here is where I would do calculations
return result;
}
int main()
{
int vector_size1 = 3;
int vector_size2 = 6;
Double1D vector_results(vector_size1+vector_size2, 0);//fill vector with vector_size1+vector_size2 many 0s
Double1D vector1(vector_size1,1) ;//fill vector with vector_size1 many 1s
Double1D vector2(vector_size2, 2) ; //fill vector with vector_size2 many 1s
for (int i = 0; i < vector_results.size(); i++){ //see that it is full of 0s
cout<<vector_results[i]<<" ";
}
cout<<endl;
//this is specifically what you asked for
vector_results = myFunction(vector1, vector_size1); //vector_results is now just a copy of the vector of the output of the function
for (int i = 0; i < vector_results.size(); i++){
cout<<vector_results[i]<<" ";
}
cout<<endl;
//yourvectorname.insert(where to insert (an iterator), what to insert beginning, what to insert end)
//vector_results.insert(vector_results.begin()+3, myFunction(vector2, vector_size2).begin(), myFunction(vector2, vector_size2).end()); //this doesnt work as I think the function gets called twice?
Double1D temp_vec = myFunction(vector2, vector_size2);
vector_results.insert(vector_results.begin()+vector_size1, temp_vec.begin(), temp_vec.end());
for (int i = 0; i < vector_results.size(); i++){
cout<<vector_results[i]<<" ";
}
cout<<endl;
//here is a version using back_inserter which I have read is more efficient
//whatever you want at the start you just overwrite the destined vector with it
vector_results = myFunction(vector1, vector_size1); //vector_results is now just a copy of the vector of the output of the function
//create a tempvector to be able to use it
Double1D temp_vec2 = myFunction(vector2, vector_size2);
//now the important part: copy(start of what you wanna copy,end of what you wanna copy, where you want to insert it)
copy(temp_vec2.begin(), temp_vec2.end(), back_inserter(vector_results)); //back_inserter inserts it at the back (and from what I read more efficient than an insert in the middle)
for (int i = 0; i < vector_results.size(); i++){
cout<<vector_results[i]<<" ";
}
cout<<endl;
return 0;
}

how to convert a matrix in dlib to a std::vector

I have a colume vector defined in dlib. How can I convert it to std::vector?
typedef dlib::matrix<double,0,1> column_vector;
column_vector starting_point(4);
starting_point = 1,2,3,4;
std::vector x = ??
Thanks
There are many ways. You could copy it via a for loop. Or use the std::vector constructor that takes iterators: std::vector<double> x(starting_point.begin(), starting_point.end()).
This would be the way you normally iterate over the matrix (doesn't matter if the matrix has only 1 column):
// loop over all the rows
for (unsigned int r = 0; r < starting_point.nr(); r += 1) {
// loop over all the columns
for (unsigned int c = 0; c < starting_point.nc(); c += 1) {
// do something here
}
}
So, why don't you iterate over your column vector and introduce each value into the new std::vector? Here is a full example:
#include <iostream>
#include <dlib/matrix.h>
typedef dlib::matrix<double,0,1> column_vector;
int main() {
column_vector starting_point(4);
starting_point = 1,2,3,4;
std::vector<double> x;
// loop over the column vector
for (unsigned int r = 0; r < starting_point.nr(); r += 1) {
x.push_back(starting_point(r,0));
}
for (std::vector<double>::iterator it = x.begin(); it != x.end(); it += 1) {
std::cout << *it << std::endl;
}
}

How to access a particular kmeans cluster in opencv

I am new to opencv, and I am trying to find and save the largest cluster of a kmeaned clustered image. I have:
clustered the image following the method provided by Mercury and Bill the Lizard in the following post (Color classification with k-means in OpenCV),
determined the largest cluster by finding the largest label count from the kmeans output (bestLables)
tried to store the position of the pixels that constitute the largest cluster in an array of Point2i
However, the mystery is that I found myself with a number of stored points that is significantly less than the count
obtained when trying to find the largest cluster. In other words: inc < max. Plus the number given by inc does not even correspond to any other clusters' number of points.
What did I do wrong? or is there a better way to do what I'm trying to do?, any input will be much appreciated.
Thanks in advance for your precious help!!
#include <iostream>
#include "opencv2/opencv.hpp"
#include<opencv2/highgui/highgui.hpp>
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
using namespace cv;
using namespace std;
int main(int argc, char** argv)
{
Mat img = imread("pic.jpg", CV_LOAD_IMAGE_COLOR);
if (!img.data)
{
cout << "Could not open or find the image" << std::endl;
return -1;
}
//imshow("img", img);
Mat imlab;
cvtColor(img, imlab, CV_BGR2Lab);
/* Cluster image */
vector<cv::Mat> imgRGB;
int k = 5;
int n = img.rows *img.cols;
Mat img3xN(n, 3, CV_8U);
split(imlab, imgRGB);
for (int i = 0; i != 3; ++i)
imgRGB[i].reshape(1, n).copyTo(img3xN.col(i));
img3xN.convertTo(img3xN, CV_32F);
Mat bestLables;
kmeans(img3xN, k, bestLables, cv::TermCriteria(), 10, cv::KMEANS_RANDOM_CENTERS);
/*bestLables= bestLables.reshape(0,img.rows);
cv::convertScaleAbs(bestLables,bestLables,int(255/k));
cv::imshow("result",bestLables);*/
/* Find the largest cluster*/
int max = 0, indx= 0, id = 0;
int clusters[5];
for (int i = 0; i < bestLables.rows; i++)
{
id = bestLables.at<int>(i, 0);
clusters[id]++;
if (clusters[id] > max)
{
max = clusters[id];
indx = id;
}
}
/* save largest cluster */
int cluster = 1, inc = 0;
Point2i shape[2000];
for (int y = 0; y < imlab.rows; y++)
{
for (int x = 0; x < imlab.cols; x++)
{
if (bestLables.data[y + x*imlab.cols] == cluster) shape[inc++] = { y, x };
}
}
waitKey(0);
return 0;
}
You are pretty close, but there are a few errors. The code below should work as expected. I also added a small piece of code to show the classification result, where pixels of the larger cluster are red, the other with shades of green.
You never initialized int clusters[5];, so it will contains random numbers at the beginning, compromising it as an accumulator. I recommend to use vector<int> instead.
You access bestLabels with wrong indices. Instead of bestLables.data[y + x*imlab.cols], it should be bestLables.data[y*imlab.cols + x]. That caused your inc < max issue. In the code below I used a vector<int> to contain indices, since it's easier to see the content of the vector. So I access bestLabels a little differently, i.e. bestLables[y*imlab.cols + x] instead of bestLables.data[y*imlab.cols + x], but the result is the same.
You had Point2i shape[2000];. I used a vector<Point>. Note that Point is just a typedef of Point2i. Since you don't know how many points will be there, better use a dynamic array. If you know that there will be, say, 2000 points, you'd better call reserve to avoid reallocations, but that's not mandatory. With Point2i shape[2000]; if you have more than 2000 points you'll go out of bounds, with a vector you're safe. I used emplace_back to avoid a copy when appending the point (just like you did with the initializer list). Note that the contructor of Point is (x,y), not (y,x).
Using vector<Point> you don't need inc, since you append the value at the end. If you need inc to store the number of points in the largest cluster, simply call int inc = shape.size();
You initialized int cluster = 1. That's an error, you should initialize it with the index of the largest cluster, i.e. int cluster = indx;.
You are calling the vector of planes imgRGB, but you're working on Lab. You'd better change the name, but it's not an issue per se. Also, remember that RGB values are stored in OpenCV as BGR, not RGB (reversed order).
I prefer Mat1b, Mat3b, etc... where possible over Mat. It allows easier access and is more readable (in my opinion). That's not an issue, but you'll see that in my code.
Here we go:
#include <opencv2/opencv.hpp>
#include <iostream>
using namespace cv;
int main(int argc, char** argv)
{
Mat3b img = imread("path_to_image");
if (!img.data)
{
std::cout << "Could not open or find the image" << std::endl;
return -1;
}
Mat3b imlab;
cvtColor(img, imlab, CV_BGR2Lab);
/* Cluster image */
vector<cv::Mat3b> imgRGB;
int k = 5;
int n = img.rows * img.cols;
Mat img3xN(n, 3, CV_8U);
split(imlab, imgRGB);
for (int i = 0; i != 3; ++i)
imgRGB[i].reshape(1, n).copyTo(img3xN.col(i));
img3xN.convertTo(img3xN, CV_32F);
vector<int> bestLables;
kmeans(img3xN, k, bestLables, cv::TermCriteria(), 10, cv::KMEANS_RANDOM_CENTERS);
/* Find the largest cluster*/
int max = 0, indx= 0, id = 0;
vector<int> clusters(k,0);
for (size_t i = 0; i < bestLables.size(); i++)
{
id = bestLables[i];
clusters[id]++;
if (clusters[id] > max)
{
max = clusters[id];
indx = id;
}
}
/* save largest cluster */
int cluster = indx;
vector<Point> shape;
shape.reserve(2000);
for (int y = 0; y < imlab.rows; y++)
{
for (int x = 0; x < imlab.cols; x++)
{
if (bestLables[y*imlab.cols + x] == cluster)
{
shape.emplace_back(x, y);
}
}
}
int inc = shape.size();
// Show results
Mat3b res(img.size(), Vec3b(0,0,0));
vector<Vec3b> colors;
for(int i=0; i<k; ++i)
{
if(i == indx) {
colors.push_back(Vec3b(0, 0, 255));
} else {
colors.push_back(Vec3b(0, 255 / (i+1), 0));
}
}
for(int r=0; r<img.rows; ++r)
{
for(int c=0; c<img.cols; ++c)
{
res(r,c) = colors[bestLables[r*imlab.cols + c]];
}
}
imshow("Clustering", res);
waitKey(0);
return 0;
}

c++ : "find non zero-elements of cv::mat" not working as intended

I implemented a function which gives you the indices of all non-zero elements of a cv::mat format matrix. I want to identify the white area of this binary image: http://i.stack.imgur.com/mVJ7N.png .
I want to receive the same result as from Matlab's "find" function.My code looks as follows (I hope the experts won't get a heart attack):
#include <opencv2\imgproc\imgproc.hpp>
#include <opencv2\highgui\highgui.hpp>
#include <opencv2\core\core.hpp>
#include <opencv2\ml\ml.hpp>
#include <cstring>
#include <iostream>
#include <vector>
using namespace cv;
void findIndex(Mat imgmat, std::vector <std::vector <int> > &indices);
int main(void)
{
String img;
Mat imgmat;
img = "Mask120.png";
imgmat = imread(img);
std::vector <std::vector <int> > indices;
findIndex(imgmat, indices);
return 0;
}
void findIndex(Mat mask, std::vector< std::vector<int> >& indices){
int x_ind[100000]; // ugly, I know
int y_ind[100000];
int k = 0;
for (int i = 0; i < mask.rows; i++) {
for (int j = 0; j < mask.cols; j++) {
if (mask.at<uchar>(i, j) == 255) {
x_ind[k] = j;
y_ind[k] = i;
k = k + 1;
}
}
}
indices.resize(2, std::vector<int>(k));
for (int m = 0; m < k; m++) {
indices[0][m] = x_ind[m];
indices[1][m] = y_ind[m];
}
}
It gives out two vectors as it should, but the results differ to those of Matlab's "find" and are obviously not correct. With find, there are in total around 22000 non-zero elements, this method identifies around 57000. Also, the first index which is marked as non-zero is at i = 119 and j = 561, corresponding to the point (562/120) of my binary image, which is not a white point.
Any ideas on where I have made a mistake is highly appreciated!
I can give a simple solution for your problem
where input cv::Mat is maskMat(it should be CV_8UC1)
The output will be updated in locations vector as Points of x and y co-ordinates
Mat whiteMat = maskMat == 255;
vector<Point> locations;
int count = countNonZero(binaryMat);
if(count < 0)
{
findNonZero(binaryMat,locations);
}
Some higher version of opencv above 3.0
Mat whiteMat = maskMat == 255;
vector<Point> locations;
findNonZero(binaryMat,locations);

How to speedup my Libsvm vector to std::vector<float> conversion?

Introduction
I have a libsvm vector of the form:
{i_1:v_1; i_2:v_2;...; i_n:v_n}
Where i_j:v_j represent respectively the index and the value. If the value is null then it wont be given any index.
My objective is to compute the euclidean distance between two libsvm
vectors. For that I have to convert them to vector<float> of the same
size. In the following example i'll be showing the function that I used in order to convert the libsvm vector into vector<float>.
Example
The first column has an index = 2648 and a value = 0.408734 meaning that all the values before it are zeros.
LIBSVM VECTOR = 2648:0.408734;4157:0.609588;6087:0.593104;26747:0.331008
Source code
#include <vector>
#include <string>
#include <chrono>
#include <boost/algorithm/string.hpp>
using namespace std;
using namespace chrono;
//convert libsvm vector to float vector in order to compute the similarity
vector<float> splitVector(const vector<string> &);
int main()
{
vector<string> libsvm {"2648:0.408734","4157:0.609588","6087:0.593104","26747:0.331008" };
high_resolution_clock::time_point t1 = high_resolution_clock::now();
vector<float> newVec = splitVector(libsvm);
high_resolution_clock::time_point t2 = high_resolution_clock::now();
auto duration = chrono::duration_cast<chrono::microseconds>( t2 - t1 ).count();
cout <<"construction time: " << duration << endl;
return 0;
}
vector<float> splitVector(const vector<string> & v)
{
int numberofterms = 266373;
vector<float> values;
vector<int> previous_idx;
for(int i = 0; i < v.size(); i++)
{
vector<string> tmpv;
boost::split(tmpv, v[i] , boost::is_any_of(":"));
//idx:value
int idx = atoi(tmpv[0].c_str());
float val = atof(tmpv[1].c_str());
//summation of previous indices
int sum = accumulate(previous_idx.begin(), previous_idx.end(), 0);
int n = idx - (sum + i + 1);
//fill vector with 0s
for(int k = 0; k < n; k++)
values.push_back(0.0);
//add value
values.push_back(val);
previous_idx.push_back(n);
}//end for
int paddingsize = numberofterms - values.size();
for(int i = 0; i < paddingsize;i++)
{
values.push_back(0.0);
}
return values;
}//end function
Problem
The timing of the conversion is around 0,00866 seconds and when I have around 1000 vectors it becomes slow. Is there a faster way to convert the libsvm vector into vector<float>?
Modified function
values.resize(266373,0.0);
void splitVector(const vector<string> & v, vector<float> & values)
{
vector<string> tmpv;
for(int i = 0; i < v.size(); i++)
{
boost::split(tmpv, v[i] , boost::is_any_of(":"));
//idx:value
int idx = atoi(tmpv[0].c_str());
float val = atof(tmpv[1].c_str());
tmpv.clear();
values[idx] = val;
}//end for
}//end function
You could reduce time cost on memory allocation by reusing vectors.
To be more specific,
Reuse tmpv by declaring it before the for loop and call tmpv.clear() in the beginning of each loop
Preallocate values by values.reserve(); and pad it by values.resize(266373, 0.0) instead of repeated push_back().
Reuse previous_idx if possible. This may has negative impact on the code structure and thus maintainability.