Quickly capture N frames and continue with live feed
I would like to capture N number of images process them and do something with live feed from the camera. I start camera, capture 30 frames and store them in a Mat vector. Now when I try to access or process the vector I am getting runtime error. I am using pointgray camera. I think I am missing something really basic. Kindly guide me what could be wrong?
#include <opencv2\highgui\highgui.hpp>
#include <opencv2\core\core.hpp>
#include <opencvlibpath.h>
#include <FlyCapture2.h>
#include <vector>
using namespace cv;
using namespace FlyCapture2;
using namespace std;
const static int NUMBER_OF_FRAME_CAPTURE = 30;
const static int SENSITIVITY_VALUE = 60;
const static int BLUR_SIZE = 50;
//I would like to execute this function after quickly capturing 30 frames
void getThresholdImage(vector<Mat> &framesToProcess, vector<Mat> &thresholdImages)
{
vector<Mat> grayImage;
for (int i = 0; i < framesToProcess.size(); i++)
{
Mat tempMatImage, tempGrayImage;
resize(framesToProcess[i], tempMatImage, Size(600, 800));
cvtColor(tempMatImage, tempGrayImage, COLOR_BGR2GRAY);
grayImage.push_back(tempGrayImage);
if (i > 0)
{
Mat tempDifferenceImage, tempThresholdImage;
absdiff(grayImage[i - 1], grayImage[i], tempDifferenceImage);
threshold(tempDifferenceImage, tempThresholdImage, SENSITIVITY_VALUE, 255, THRESH_BINARY);
blur(tempThresholdImage, tempThresholdImage, Size(BLUR_SIZE, BLUR_SIZE));
thresholdImages.push_back(tempThresholdImage);
}
}
}
int main()
{
Mat cameraFeed;
vector<Image> rawImages;
vector<Mat> framesToProcess;
vector<Mat> thresholdImages;
//vector<point> contourCenters;
vector<Point> LEDPoints;
Camera camera;
Error error;
error = camera.Connect(0);
if (error != PGRERROR_OK)
{
cout << "Failed to connect to camera" << endl;
getchar();
exit(1);
}
error = camera.StartCapture();
if (error == PGRERROR_ISOCH_BANDWIDTH_EXCEEDED)
{
cout << "Bandwidth exceeded" << endl;
getchar();
exit(1);
}
else if (error != PGRERROR_OK)
{
cout << "Failed to start image capture" << endl;
getchar();
exit(1);
}
while (1){
framesToProcess.clear();
thresholdImages.clear();
rawImages.clear();
//quickly capture 30 images
for (int i = 0; i < NUMBER_OF_FRAME_CAPTURE; i++)
{
Mat currentFrame;
Image rawImage;
Error error = camera.RetrieveBuffer(&rawImage);
if (error != PGRERROR_OK)
{
cout << "capture error" << endl;
}
// convert to rgb
Image rgbImage;
rawImage.Convert(FlyCapture2::PIXEL_FORMAT_BGR, &rgbImage);
// convert to OpenCV Mat
unsigned int rowBytes = (double)rgbImage.GetReceivedDataSize() / (double)rgbImage.GetRows();
currentFrame = Mat(rgbImage.GetRows(), rgbImage.GetCols(), CV_8UC3, rgbImage.GetData(), rowBytes);
framesToProcess.push_back(currentFrame);
//cvtColor(currentFrame, currentFrame, COLOR_BGR2GRAY);
//imshow("GRAY", currentFrame);
}
// this line returns 30
cout << "Frames to process" << framesToProcess.size() << endl;
// I get runtime error while calling this function
getThresholdImage(framesToProcess, thresholdImages);
//Then I just tried displaying image from captured Mat Vector above with
//imshow("frame", framesToProcess[0]);
// Still I get runtime error which means it populates the vector with images but it is not accessible
// Following section tries to continue with live feed.
//Already tried commenting this section but doesn't have any effect
Image rawImage;
Error error = camera.RetrieveBuffer(&rawImage);
if (error != PGRERROR_OK)
{
cout << "capture error" << endl;
}
// convert to rgb
Image rgbImage;
rawImage.Convert(FlyCapture2::PIXEL_FORMAT_BGR, &rgbImage);
// convert to OpenCV Mat
unsigned int rowBytes = (double)rgbImage.GetReceivedDataSize() / (double)rgbImage.GetRows();
cameraFeed = Mat(rgbImage.GetRows(), rgbImage.GetCols(), CV_8UC3, rgbImage.GetData(), rowBytes);
resize(cameraFeed, cameraFeed, Size(800, 600));
imshow("camera feed", cameraFeed);
waitKey(10);
}
}
Here is the runtime error I get First-chance exception at 0x00007FFF1EB42262 (opencv_core2410d.dll) in LearnCPP11.exe: 0xC0000005: Access violation reading location 0x00000028F52A2840. Unhandled exception at 0x00007FFF1EB42262 (opencv_core2410d.dll) in LearnCPP11.exe: 0xC0000005: Access violation reading location 0x00000028F52A2840.
I think there is a problem with this line :
if you look this
data – Pointer to the user data. Matrix constructors that take data and step parameters do not allocate matrix data. Instead, they just initialize the matrix header that points to the specified data, which means that no data is copied. This operation is very efficient and can be used to process external data using OpenCV functions. The external data is not automatically deallocated, so you should take care of it.
It seems that you are using same memory for different images
currentFrame is added to the vector. does the vector only contain the reference as well? This works perfectly fine if I include my code to process each frame within for loop. but this will delay the image capture. What can be the workaround for this?
Yes you are right but problem is in push_back. Push_back does not make a copy of your Mat. If you watch in memory currentFrame and framesToProcess you can see that it is same Mat object. Push_back make a data field copy. I think you have to use Clone
...remeber that cv::Mat has its own memory management and Mat::operator = and .. is an O(1) operation. This means that no data is copied....
You have to preallocate your std::vector so to have one cv::Mat for each elements than use
Mat::copyTo
. For example, instead of grayImage.push_back(tempGrayImage) you could usegrayImage.resize( framesToProcess.size())
and aftertempGrayImage.copyTo(grayImage[i])
.@LBerger thanks for saving me clone is working. But I am getting real performance issue now. Any tips on optimization of this code? @pklab thanks for tips.
Tips is good/pre allocation. You can create and allocate your vector of N grey scale images 800x600 on 1 shoot with
std::vector<cv::Mat> images(N,cv::Mat(cv::Size(800,600),CV_C8U1));
than work directly on mages[i], or if you like, create a shortname for it liketmpImage = images[i];
Thanks a lot guys. @LBerger as your solution of clone worked perfectly. Would you please add it as answer to this question. If needed I would post a new question.