I need the current and previous frame for some calculations in OpenCV C++.
Here is my code so far:
vector <cv::Mat> frames;
// Current frame
Mat M = current_frame;
Mat F; // previous frame
// set Previous Frame
if (frames.empty()) {
F = M;
frames.push_back(M);
cout << "empty" << endl;
}
else {
F = frames.back();
frames.push_back(M);
cout << " NOTempty" << endl;
}
// print frame Mat means to see if things look okay
cout << mean(M) << endl;
cout << mean(F) << endl;
The idea is that M is the current frame and F is the previous frame. Frames are stored in frames, a vector of matrices. If frames is empty, let F = M because there is no previous frame. Then, add M to frames. If frames is not empty, than M is the current frame and F is the last Mat from the vector frames. After F is extracted, the current frame M is added to the end of frames.
I am printing out the mean of M and F so that I have some easy to read reference in the terminal if it worked properly. Unfortunately, it looks not right.
This is what is printed out:
empty
[5.09352, 6.60551, 8.54364, 0]
[5.09352, 6.60551, 8.54364, 0]
NOTempty
[5.02325, 6.46646, 8.39534, 0]
[92.0037, 97.9186, 106.677, 0]
NOTempty
[4.94272, 6.38162, 8.32141, 0]
[91.7741, 97.7845, 106.555, 0]
It should look like this:
empty
[5.09352, 6.60551, 8.54364, 0]
[5.09352, 6.60551, 8.54364, 0]
NOTempty
[5.02325, 6.46646, 8.39534, 0]
[5.09352, 6.60551, 8.54364, 0]
NOTempty
[4.94272, 6.38162, 8.32141, 0]
[5.02325, 6.46646, 8.39534, 0]
This should be simple, what am I doing wrong?
Are you sure you are not missing a loop somewhere in that snippet? If I try something like this:
//create a dummy vector of mats:
std::vector<cv::Mat> sourceMats;
sourceMats.push_back( cv::Mat(1, 4, CV_32F, {1, 1, 1, 1}) );
sourceMats.push_back( cv::Mat(1, 4, CV_32F, {2, 2, 2, 2}) );
sourceMats.push_back( cv::Mat(1, 4, CV_32F, {3, 3, 3, 3}) );
//frames buffer:
std::vector <cv::Mat> frames;
//loop thru all frames:
for( int i = 0; i < (int)sourceMats.size(); i++ ){
// Current frame
cv::Mat M = sourceMats[i];
cv::Mat F; // previous frame
// set Previous Frame
if (frames.empty()) {
F = M;
frames.push_back(M);
std::cout << "empty" << std::endl;
}
else {
F = frames.back();
frames.push_back(M);
std::cout << " NOTempty" << std::endl;
}
// do not compute the mean, I just want to check out the FIFO contents:
std::cout << M << std::endl;
std::cout << F << std::endl;
}
I get this output (note that I removed the mean function - just to check out the raw data):
empty
[1, 1, 1, 1]
[1, 1, 1, 1]
NOTempty
[2, 2, 2, 2]
[1, 1, 1, 1]
NOTempty
[3, 3, 3, 3]
[2, 2, 2, 2]
Seems like your FIFO is working as expected... What did you expect from the mean function?
Related
I'm trying to do this operation in C++, but I cant wrap my head around it.
I tried looking in http://mathworks.com/help/matlab/ref/image.html but I still don't get it.
im is a matrix in Matlab. Width is 640
im(:,Width+(1:2),:) = im(:,1:2,:);
Is there anything similar to this operation in OpenCV Matrix or C++
Solution 1
You can use colRange function:
mat.colRange(0, 2).copyTo(mat.colRange(w, 2 + w));
Example:
//initilizes data
float data[2][4] = { { 1, 2, 3, 4}, { 5, 6, 7, 8 } };
Mat mat(2, 4, CV_32FC1, &data);
int w = 2; //w is equivelant to Width in your script, in this case I chose it to be 2
std::cout << "mat before: \n" << mat << std::endl;
mat.colRange(0, 2).copyTo(mat.colRange(w, 2 + w));
std::cout << "mat after: \n" << mat << std::endl;
Result:
mat before:
[1, 2, 3, 4;
5, 6, 7, 8]
mat after:
[1, 2, 1, 2;
5, 6, 5, 6]
Solution 2
Alternatively, use cv::Rect object, as follows:
cv::Mat roi = mat(cv::Rect(w, 0, 2, mat.rows));
mat(cv::Rect(0, 0, 2, mat.rows)).copyTo(roi);
There are several way to initialize a Rect, in my case I chose the following c-tor:
cv::Rect(int x, int y, int width, int height);
The result are the same as an in Solution 1.
Maybe you could also use Eigen that can serve the need. It has Block operations
Adapting the example provided under link you would need smth like:
Eigen::MatrixXf m(4, 4);
m << 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16;
cout <<"original matrix \n" << m << endl;
m.block<2, 2>(1, 1) = m.block<2, 2>(2, 2);
cout <<"modified matrix \n" << m << endl;
Output:
original matrix
1 2 3 4
5 6 7 8
9 10 11 12
13 14 15 16
modified matrix
1 2 3 4
5 11 12 8
9 15 16 12
13 14 15 16
I am very new to C++ and OpenCV but more familiar with Matlab. I have a task that I need to move to C++ for faster processing. So I would like to ask for your suggestion on a image processing problem. I have 10 images in a folder and I was able to read them all using dirent.h like in this and extract each frame by calling frame[count] = rawImage in a while loop:
int count = 0;
std::vector<cv::Mat> frames;
frames.resize(10);
while((_dirent = readdir(directory)) != NULL)
{
std::string fileName = inputDirectory + "\\" +std::string(_dirent->d_name);
cv::Mat rawImage = cv::imread(fileName.c_str(),CV_LOAD_IMAGE_GRAYSCALE);
frames[count] = rawImage; // Insert the rawImage to frames (this is original images)
count++;
}
Now I want to access each frames and do calculation similar to Matlab to get another matrix A such that A = frames(:,:,1)+2*frames(:,:,2). How to do that?
Since frames is a std::vector<cv::Mat>, you should be able to access each Mat this way:
// suppose you want the nth matrix
cv::Mat frame_n = frames[n];
Now, if you want to do the calculation you said on the first two Mats, then:
cv::Mat A = frames[0] + 2 * frames[1];
Example:
// mat1 = [[1 1 1]
// [2 2 2]
// [3 3 3]]
cv::Mat mat1 = (cv::Mat_<double>(3, 3) << 1, 1, 1, 2, 2, 2, 3, 3, 3);
cv::Mat mat2 = mat1 * 2; // multiplication matrix x scalar
// just to look like your case
std::vector<cv::Mat> frames;
frames.push_back(mat1);
frames.push_back(mat2);
cv::Mat A = frames[0] + 2 * frames[1]; // your calculation works
// A = [[ 5 5 5]
// [10 10 10]
// [15 15 15]]
You can always read the list of acceptable expressions.
I need to convert the following matlab code into OpenCV and obtain exactly the same result.
In matlab:
A = [1 2 3];
f = [4 5 6];
result = filter2(f, A);
This gives out as:
result = [17 32 23]
In OpenCV, I tried these lines:
cv::Mat A = (cv::Mat_<float>(1, 3) << 1, 2, 3);
cv::Mat f = (cv::Mat_<float>(1, 3) << 4, 5, 6);
cv::Mat result;
cv::filter2D(A, result, -1, f, cv::Point(-1, -1), 0, cv::BORDER_REPLICATE);
This gives me:
result = [21 32 41]
How can I obtain the same result as of Matlab?? I doubt the anchor point in OpenCV causes this difference, but I cannot figure out how to change it. Thanks in advance.
Use cv::BORDER_CONSTANT, which pads the array with zero rather than duplicating the neighboring element:
cv::filter2D(A, result, -1, f, cv::Point(-1, -1), 0, cv::BORDER_CONSTANT);
Result is:
result = [17, 32, 23]
I have a cv::Mat A, which has CV_32F. However it holds integer values like 1,2....100. I want to form a mask of same size as A.
But the mask must contain zeros if A(x,y) not equal to 5 (say).
The mask must contain ones if A(x,y) equal to 5 (say).
I want to later use it as ROIs.
// you will have a much simpler construct,
// this is just for demonstration
Mat_<float> A(3,3); mf << 1,5,5,2,5,5,1,2,3;
// now use a simple MatExpr to get a mask:
Mat mask = (A == 5);
// show results:
cerr << A << endl;
cerr << mask << endl;
------------------------------
[1, 5, 5;
2, 5, 5;
1, 2, 3]
[0, 255, 255;
0, 255, 255;
0, 0, 0]
According to the docs, this function should return a Mat with all elements as ones.
Mat m = Mat::ones(2, 2, CV_8UC3);
I was expecting to get a 2x2 matrix of [1,1,1]. Instead, I got this:
[1, 0, 0] [1, 0, 0]
[1, 0, 0] [1, 0, 0]
Is this the expected behaviour?
It looks like Mat::ones() works as expected only for single channel arrays. For matrices with multiple channels ones() sets only the first channel to ones while the remaining channels are set to zeros.
Use the following constructor instead:
Mat m = Mat(2, 2, CV_8UC3, Scalar(1,1,1));
std::cout << m;
Edit. Calling
Mat m = Mat::ones(2, 2, CV_8UC3);
is the same as calling
Mat m = Mat(2, 2, CV_8UC3, 1); // OpenCV replaces `1` with `Scalar(1,0,0)`