I am beginner to OpenCV and C++.
I am trying to write PCA code for face recognition using 3 different faces. For this, each image(of size d=mxn) is reshaped to a column vector of d elements.
typedef vector<Mat> Row;
Row img1v(36000,img1);
Row img2v(36000,img2);
Row img3v(36000,img3);
I calculate the vector of mean of the images as follows:
Row meanImg;
for(int i=0;i<img1v.size();++i)
{
meanImg.push_back((img1v[i]+img2v[i]+img3v[i])/3);
}
cout<<meanImg.size()<<endl;
Here I get an error:
OpenCV Error: Insufficient memory (Failed to allocate 144004 bytes) in OutOfMemoryError
My image size is 180x200. I don't know what to do? Also how can I form a row vector in opencv using C++? (For calculating covariance I need to multiply difference vector with its traspose).
I don't know OpenCV and its types. But your typedef looks suspicious.
My guess is that the error occurs while creating the imgXv instances of Row. For each call of Row imgXv(36000,img1); a vector is created that consists of 36000 instances of Mat that are all copies of the imgX instances. See constructor 2) of std::vector::vector in cppreference.com:
vector( size_type count, const T& value, const Allocator& alloc = Allocator()); (2)
2) Constructs the container with count copies of elements with value value.
So you`re trying to keep 108003 images in memory. Each of your images consists of 36000 pixels. If each pixel is represented by at least 1 byte, this would occupy a minimum of 3.6 GB of memory.
From what I get of your approach you don't want that, but rather a typedef vector<float> Row; and Row imgXv(36000);
Related
I know that Sparse matrix in armadillo is still in preliminary support.
I'm using armadillo lib in my quantum systems research and I have problem to construct sparse mat in effective RAM way.
So far I was using my own implementation of sparse matrixes, but I want to have an optimized matrix class.
I'm filling elements in batch mode:
umat loc(2,size);
cx_vec val(size);
// calculate loc and val
...
//
sp_cx_mat Hamiltonian(loc, val);
This kind of action copy values from loc,val to constructor of Hamiltonian and for some few seconds require 2x RAM. I calculate huge matrix (size is about 2**L, where L=22, 24, ...) so I wish I had well optimised code in memory.
For comparison, matrix size: 705432x705432 - RAM and "filling time":
my implementation (COO format): time 7.95s, memory 317668kB
armadillo (CSC format): time 5.32s, memory 715000kB
Is it possible to deallocate fragments of vectors: loc, val on the fly to save memory, element by element?
The answer here will be to use the other sparse matrix constructor that takes the CSC format, so you will need to modify your // calculate loc and val code, instead filling the following three arrays:
values (length equal to number of points)
row_indices (length equal to number of points)
col_ptrs (length equal to number of columns plus one)
The points should be arranged in column-major ordering in the values and row_indices vectors, and the col_ptrs vector contains the number of nonzero elements before the beginning of the column. That is, col_ptrs[0] will always contain 0, col_ptrs[1] will contain the number of nonzero elements in the first column, col_ptrs[2] will contain the number of nonzero elements in the first and second columns, and col_ptrs[n_cols + 1] will contain the number of nonzero elements in the matrix.
For more documentation on this constructor, see the "Batch constructors" section of http://arma.sourceforge.net/docs.html#SpMat ; this is the fourth entry in that list.
If you cannot easily modify your calculation code to adhere to that format, then you might be better off trying to specify sort_locations = false to the constructor you are using, if you are not already doing that.
I'm having an awkward result when I run my program after creating this 2D vector. The program actually crashes when it launches. But I'm basically trying to input a set of data for a 2D vector that is meant to retain the amount of bushels of certain crops in the first column (as ints), and then to retain the yield ratio of each crop (as an int). I haven't declared the yield ratio yet, but even if the 2nd column is left empty (in terms of each element's value) it shouldn't have a problem. Here's my code:
vector<vector<int> >crops(2, vector<int>(43));
crops[0][0]=0; //Arugula
crops[1][0]=2000000; //Beans
crops[2][0]=0; //Beets
crops[3][0]=0; //Cabbages
crops[4][0]=0; //Cammomile
crops[5][0]=0; //Carrots
crops[6][0]=0; //Catmint
crops[7][0]=0; //Celery
crops[8][0]=0; //Coriander
crops[9][0]=0; //Corn
crops[10][0]=0; //Cucumbers
crops[11][0]=0; //Eggplants
crops[12][0]=2000000; //Fennel
crops[13][0]=1500000; //Flax
crops[14][0]=0; //Garlix
crops[15][0]=0; //Greenwoad
crops[16][0]=0; //Hem
crops[17][0]=0; //Leeks
crops[18][0]=0; //Lettuce
crops[19][0]=0; //Madder
crops[20][0]=0; //Mint
crops[21][0]=0; //Mustard
crops[22][0]=5000000; //Oats
crops[23][0]=0; //Onions
crops[24][0]=0; //Parsnips
crops[25][0]=0; //Parsely
crops[26][0]=2500000; //Peas
crops[27][0]=0; //Poppy
crops[28][0]=0; //Potatoes
crops[29][0]=0; //Pumpkins
crops[30][0]=0; //Radishes
crops[31][0]=0; //Rutabagas
crops[32][0]=0; //Spinach
crops[33][0]=4000000; //Spring Barley
crops[34][0]=0; //Squash
crops[35][0]=0; //Tomatoes
crops[36][0]=0; //Turnips
crops[37][0]=0; //Vetches
crops[38][0]=0; //Weld
crops[39][0]=0; //Woad
crops[40][0]=6000000; //Barley - Winter Crop
crops[41][0]=5000000; //Mixtill - Winter Crop
crops[42][0]=4000000; //Wheat - Winter Crop
Though, I have to leave for work now, but I will be able to respond to any answers once I return tonight. Thank you for those who are trying to help! :)
Swap your subscript indices.
crops[13][0] -> crops[0][13]
When you declared
vector<vector<int> >crops(2, vector<int>(43));
You created a vector which is value-initialised with 2 vectors, each of which was value-initialised with 43 ints (meaning they are initialised to 0). There are two vectors in the outer vector so you can only do crops[0] or crops[1] without reading someone else's memory.
Alternatively, of course, you could just change the declaration to:
vector<vector<int> >crops(43, vector<int>(2));
I am translating some matlab code to c++ using opencv. I want to get the values of a Matrix which satisfies a condition. I created a mask for this and when I apply it to the original Matrix I get the same size of the original matrix but with 0 values which are not there in the mask. But my question is how can I get only the values that are non-zero in the matrix and assign it to a different matrix.
My matlab code is:
for i= 1:size(no,1)
mask= labels==i;
op = orig(mask, :); //op only contains the values from the orig matrix which are in the mask. So orig size and op size is not the same
.....
end
The c++ translation that I have now is:
for (int i=0; i<n.rows; i++)
{
Mat mask;
compare(labels,i,mask,CMP_EQ);
Mat op;
orig.copyTo(op,mask); //Here the orig size and the op size is always same but values which are not in the mask are 0
}
So, how can I create a matrix which only has the values that the mask satisfies???
You might try to make use of cv::SparseMat (http://docs.opencv.org/modules/core/doc/basic_structures.html#sparsemat), which only keeps non-zero values in a hash.
When you assign a regular cv::Mat to a cv::SparseMat, it automatically captures the non-zero values. From that point, you can iterate through the non-zero values and manipulate them as you'd like.
Hope I got question correctly and it helps!
OpenCv does support Matrix Expresions like A > B or A <= Band so on.
This is stated in the Documentation off cv::Mat
If you're simply wanting to store values, the Mat object is probably not the best way, since it has been made for the purpose of containing images.
In that case, use an std::vector object instead of the cv::Mat object, and you can use the .push_back handle whenever you find an element that is non-zero, which will dynamically resize the vector.
If you're trying to create a new image, then you have to be specific about what kind of image you want to see, because if you don't know how many nonzero elements there are, how can you set the width and height? Also you might end up with an odd number of elements.
in OpenCV 2 and later there is method Mat::resize that let's you add any number of rows with the default value to your matrix is there any equivalent method for the column. and if not what is the most efficient way to do this.
Thanks
Use cv::hconcat:
Mat mat;
Mat cols;
cv::hconcat(mat, cols, mat);
Worst case scenario: rotate the image by 90 degrees and use Mat::resize(), making columns become rows.
Since OpenCV, stores elements of matrix rows sequentially one after another there is no direct method to increase column size but I bring up myself two solutions for the above matter,
First using the following method (the order of copying elements is less than other methods), also you could use a similar method if you want to insert some rows or columns not specifically at the end of matrices.
void resizeCol(Mat& m, size_t sz, const Scalar& s)
{
Mat tm(m.rows, m.cols + sz, m.type());
tm.setTo(s);
m.copyTo(tm(Rect(Point(0, 0), m.size())));
m = tm;
}
And the other one if you are insisting not to include even copying data order into your algorithms then it is better to create your matrix with the big number of rows and columns and start the algorithm with the smaller submatrix then increase your matrix size by Mat::adjustROI method.
How to access individual pixels in OpenCV 2.3 using C++?
For my U8C3 image I tried this:
Scalar col = I.at<Scalar>(i, j);
and
p = I.ptr<uchar>(i);
First is throwing an exception, the second one is returning some unrelated data. Also all examples I was able to find are for old IIPimage(?) for C version of OpenCV.
All I need is to get color of pixel at given coordinates.
The type you call cv::Mat::at with needs to match the type of the individual pixels. Since cv::Scalar is basically a cv::Vec<double,4>, this won't work for a U8C3 image (it would work for a F64C4 image, of course).
In your case you need a cv::Vec3b, which is a typedef for cv::Vec<uchar,3>:
Vec3b col = I.at<Vec3b>(i, j);
You can then convert this into a cv::Scalar if you really need to, but the type of the cv::Mat::at instantiation must match the type of your image, since it just casts the image data without any conversions.
Your second code snippet returns a pointer to the ith row of the image. It is no unrelated data, but just a pointer to single uchar values. So in case of a U8C3 image, every consecutive 3 elements in the data returned to p should represent one pixel. Again, to get every pixel as a single element use
Vec3b *p = I.ptr<Vec3b>(i);
which again does nothing more than an appropriate cast of the row pointer before returning it.
EDIT: If you want to do many pixel accesses on the image, you can also use the cv::Mat_ convenience type. This is nothing more than a typed thin wrapper around the image data, so that all accesses to image pixels are appropriately typed:
Mat_<Vec3b> &U = reinterpret_cast<Mat_<Vec3b>&>(I);
You can then freely use U(i, j) and always get a 3-tuple of unsigned chars and therefore pixels, again without any copying, just type casts (and therefore at the same performance as I.at<Vec3b>(i, j)).