Understand Mat in opencv - c++

I am trying to understand the following piece of code Take from: Opencv Mat
and more precisely this part:
Mat labels(0, 1, CV_32FC1);
Mat trainingData(0, dictionarySize, CV_32FC1);
From what I understand is that labels is equivalent to std::vector<float> and trainingData is equivalent to std::vector<std::vector<float>> and where std::vector<float> is of dimension dictionarySize. Is that correct?
I am asking this question because I want to convert bowDescriptor1 which is a MAT to std::vector<float>
Convert bowDescriptor1to vector:
std::vector<float> data;
for(size_t r = 0; r < bowDescriptor.rows;r++)
{
for(size_t c = 0; c < bowDescriptor.cols;c++)
{
data.push_back(bowDescriptor.at<float>(r,c));
}
}

Without testing:
from documentation you can see that bowDescriptor seems to be a matrix of size 1 x dictionarySize http://docs.opencv.org/modules/features2d/doc/object_categorization.html#bowimgdescriptorextractor-descriptorsize
so you have to go through that matrix and save each element (float) to your vector<float>
try this code:
std::vector<float> currentBowDescriptor;
for(int col = 0; col < bowDescriptor1.cols; ++col)
{
currentBowDescriptor.push_back(bowDescriptor.at<float>(0,col));
}
that's it. push_back those currentBowDescriptor s to another vector if you want.
If you want to save some computation time, you can even initialize the currentBowDescriptor in advance since you know the number of descriptor values (dictionarySize) and access those elements instead of pushing back.
hope this helps.

Related

Initialize a Multi-Channel OpenCV Mat

I have to initialize a multi-channel OpenCV matrix. I'm creating the multi-channel matrix like this
cv::Mat A(img.size(), CV_16SC(levels));
where levels is the number of channels in the matrix can be anywhere from 20 - 300. I cannot initialize this matrix other than zero.
If I initialize the matrix like this
cv::Mat A(img.size(), CV_16SC(levels), Scalar(1000));
I'm getting an error stating "Assertion failed (cn <= 4) in cv::scalarToRawData". Which seems like we can initialize values only up to 4 channels
Is there any other method available in OpenCV to initialize this multi-channel matrix or I have to manually initialize the values?
Edit:
I have done the following to initialize this multi-channel matrix. Hope this helps those who come across the same issue
for (int j = 0; j < img.rows; ++j) for (int i = 0; i < img.cols; ++i)
{
short *p = A.ptr<short>(j) +(short)i*levels;
for (int l = 0; l < levels; ++l)
{
p[l] = 1000;
}
}
I was trying to use OpenCV's Vec_ and Mat_ template classes, because of this Mat_ constructor. Unfortunately, I couldn't find a working solution. All attempts lead to the same error, you already came across with. So, my guess would be, the underlying OpenCV implementation just does not support such actions, even on custom derived types.
Certainly, you have your own idea to work-around this. Nevertheless, I wanted to provide the shortest (and hopefully most efficient) solution, I could think of:
const int levels = 20;
const cv::Size size = cv::Size(123, 234);
const cv::Mat proto = cv::Mat(size, CV_16SC1, 1000);
std::vector<cv::Mat> channels;
for (int i = 0; i < levels; i++)
channels.push_back(proto);
cv::Mat A;
cv::merge(channels, A);

Opencv C++ create a Mat of Mats

I am trying to build a distance matrix between frames in C++ with OpenCv 2.4.10. I think I need a mat of mats so I can put in the first row and col all the frames and make a XOR operator frame by frame. But to do so I need a structure like a matrix that contains in each position another matrix. Is there a thing like a Mat of Mats? Or can you suggest another solution? I thought of useing Vector but I need more than an array of Mat. Thank you I am new at this!
If I got it correctly, what you are looking for is a 2-dimensional Mat object, whose each element is another 2-dimensional Mat object. This is equivalent to creating a 4-dimensional Mat object. OpenCV has such a functionality - it just involves using one of less popular and less convenient Mat constructors:
const int num_of_dim = 4;
const int dimensions[num_of_dim] = { a, b, c, d }; // a, b, c, d - desired dimensions defined elsewhere
cv::Mat fourd_mat(num_of_dim, dimensions, CV_32F);
Check Mat::Mat(int ndims, const int* sizes, int type) constructor at openCV docs:
http://docs.opencv.org/2.4.10/modules/core/doc/basic_structures.html#Mat::Mat(int%20ndims,%20const%20int*%20sizes,%20int%20type)
as well as search for the phrase "multi-dimensional" and "n-dimensional" on that page to find more examples and docs.
EDIT:
As requested, I'm showing how to load an image into such a structure. It's not pretty, but I guess the easiest way is to copy the image pixel by pixel:
img = imread("path/img.jpg", 1);
for (int i = 0; i < 179; ++i)
{
for (int j = 0; i < img.rows; ++i)
{
for (int k = 0; j < img.cols; ++j)
{
const int coords1[4] = { i, 0, j, k };
const int coords2[4] = { 0, i, j, k };
fourd_mat.at<float>(coords1) = img.at<float>(j, k); //line 1
fourd_mat.at<float>(coords2) = img.at<float>(j, k); //line 2
}
}
}
The line commented as line1 is equivalent to your line struttura[i][0] = img; and line2 is equivalent to struttura[0][i] = img; after the two innermost for loops finish their work.
The code above assumes that your image type is CV_32F - if it's 8UC, you have to replace float with uchar in at() function.

Assign 3x1 mat to 3 channels mat

This question is continuance from my question in this link. After i get mat matrix, the 3x1 matrix is multiplied with 3x3 mat matrix.
for (int i = 0; i < im.rows; i++)
{
for (int j = 0; j < im.cols; j++)
{
for (int k = 0; k < nChannels; k++)
{
zay(k) = im.at<Vec3b>(i, j)[k]; // get pixel value and assigned to Vec4b zay
}
//convert to mat, so i can easily multiplied it
mat.at <double>(0, 0) = zay[0];
mat.at <double>(1, 0) = zay[1];
mat.at <double>(2, 0) = zay[2];
We get 3x1 mat matrix and do multiplication with the filter.
multiply= Filter*mat;
And i get mat matrix 3x1. I want to assign the value into my new 3 channels mat matrix, how to do that? I want to construct an images using this operation. I'm not use convolution function, because i think the result is different. I'm working in c++, and i want to change the coloured images to another color using matrix multiplication. I get the algorithm from this paper. In that paper, we need to multiplied several matrix to get the result.
OpenCV gives you a reshape function to change the number of channels/rows/columns implicitly:
http://docs.opencv.org/modules/core/doc/basic_structures.html#mat-reshape
This is very efficient since no data is copied, only the matrix header is changed.
try:
cv::Mat mat3Channels = mat.reshape(3,1);
Didn't test it, but should work. It should give you a 1x1 matrix with 3 channel element (Vec3d) if you want a Vec3b element instead, you have to convert it:
cv::Mat mat3ChannelsVec3b;
mat3Channels.convertTo(mat3ChannelsVec3b, CV_8UC3);
If you just want to write your mat back, it might be better to create a single Vec3b element instead:
cv::Vec3b element3Channels;
element3Channels[0] = multiply.at<double>(0,0);
element3Channels[1] = multiply.at<double>(1,0);
element3Channels[2] = multiply.at<double>(2,0);
But care in all cases, that Vec3b elements can't save values < 0 and > 255
Edit: After reading your question again, you ask how to assign...
I guess you have another matrix:
cv::Mat outputMatrix = cv::Mat(im.rows, im.cols, CV_8UC3, cv::Scalar(0,0,0));
Now to assign multiply to the element in outputMatrix you ca do:
cv::Vec3b element3Channels;
element3Channels[0] = multiply.at<double>(0,0);
element3Channels[1] = multiply.at<double>(1,0);
element3Channels[2] = multiply.at<double>(2,0);
outputMatrix.at<Vec3b>(i, j) = element3Channels;
If you need alpha channel too, you can adapt that easily.

OpenCV generalize vector product to return arbitrary sized Matrix

I need to build a product operator that returns the product of two arbitrary sized vectors as a matrix.
For example the product u = [u1; u2; u3] with v = [v1; v2; v3] will be
u*v' = [u1*v1 u1*v2 u1*v3; u2*v1 u2*v2 u2*v3; u3*v1 u3*v2 u3*v3].
How to generalize this for arbitrary sized Vecs using OpenCV with Matx and Vec Objects?
According to the documentation, Matx is for small matrices whose type and size are known at compilation time.
For your case, you can both use Mat instead.
Mat u(n, 1, CV_32F);
Mat v(n, 1, CV_32F);
Mat res(n, n, CV_32F);
// compute here...
for (int i=0; i<res.rows; i++)
{
for (int j=0; j<res.cols; j++)
{
res.at<float>(i, j) = u.at<float>(i, 0) * v.at<float>(j, 0);
}
}

Fast Pixels Access opencv

i use this code to convert image to matrix ,so someone have any idea how can i convert this matrix to 1D one -->vector
i want to have image data as a 1D array ,in row major order that is all pixel values in the first row are listed first ,followed by pixel values in the second row and so on.
IplImage *img = cvLoadImage( "lena.jpg", CV_LOAD_IMAGE_COLOR);
CvMat *mat = cvCreateMat(img->height,img->width,CV_32FC3 );
cvConvert( img, mat );
for(int i=0;i<10;i++)
{
for(int j=0;j<10;j++){
CvScalar scal = cvGet2D( mat,j,i);
printf( "(%.f,%.f,%.f) ",scal.val[0], scal.val[1], scal.val[2] );}
printf("\n");}
cvNamedWindow("une_window");
cvShowImage("une_window", img);
cvWaitKey();
cvDestroyWindow("une_window");
Using the C++ API:
cv::Mat img = cv::imread("a.jpg");
std::vector<uchar> pixels;
pixels.reserve(img.rows * img.cols * 3);
if(img.isContinuous()) {
pixels = std::vector<uchar>(img.ptr(0), img.ptr(0) + img.rows * img.cols * 3 );
}
else {
for(int i = 0; i != img.rows; ++i) {
uchar* p = img.ptr(i);
for(int j = 0; j != img.cols * 3; ++j) {
pixels.push_back(p[j]);
}
}
}
I believe the fastest way for continuous Mats is to use the reshape command:
Mat colVec = img.reshape(1, img.rows*img.cols); // change to a Nx3 column vector
The reshape command just changes the header, so it does not require pixel access and therefore runs in O(1) time.
I think you should observe from video decoder output to know the video size information, other information collected from metadata in container parser might be not so accurate.
In C++ this is actually a one-liner:
cv::Mat_<float> img = cv::imread("a.jpg", 1);
std::vector<float> dest;
std::copy(img.begin(), img.end(), dest.begin());