Increase fps on Basler camera - c++

I am working in a real time image processing project, I am using a Basler camera model acA1300-200uc with communication by USB3, but I am having troubles with the fps of my c++ program because the camera supports over 200 fps but my program only runs arround 30 fps and I dont know how to increase it, my project need 100 fps aprox.
This is my code, I hope you can help me, thanks in advance.
#include <Windows.h>
#include <opencv2\core\core.hpp>
#include <opencv2\highgui\highgui.hpp>
#include <opencv2\video\video.hpp>
#include <pylon\PylonIncludes.h>
#include <time.h>
using namespace Pylon;
// Settings for using Basler USB cameras.
#include <pylon/usb/BaslerUsbInstantCamera.h>
typedef Pylon::CBaslerUsbInstantCamera Camera_t;
using namespace Basler_UsbCameraParams;
using namespace cv;
using namespace std;
static const uint32_t c_countOfImagesToGrab = 1000;
int main(int argc, char* argv[]) {
int frames = 0;
double seconds = 0,fps;
time_t start, end;
Pylon::PylonAutoInitTerm autoInitTerm;
try
{
CDeviceInfo info;
info.SetDeviceClass(Camera_t::DeviceClass());
Camera_t camera(CTlFactory::GetInstance().CreateFirstDevice(info));
cout << "Dispositivo utilizado: " << camera.GetDeviceInfo().GetModelName() << endl;
camera.Open();
camera.MaxNumBuffer = 10;
CImageFormatConverter formatConverter;
formatConverter.OutputPixelFormat = PixelType_BGR8packed;
CPylonImage pylonImage;
Mat openCvImage, gray_img;
vector<Vec3f> circles;
int64_t W = 800, H = 600;
camera.Width.SetValue(W);
camera.Height.SetValue(H);
camera.StartGrabbing(c_countOfImagesToGrab, GrabStrategy_LatestImageOnly);
CGrabResultPtr ptrGrabResult;
camera.RetrieveResult(5000, ptrGrabResult, TimeoutHandling_ThrowException);
cout << "SizeX: " << ptrGrabResult->GetWidth() << endl;
cout << "SizeY: " << ptrGrabResult->GetHeight() << endl;
cvNamedWindow("OpenCV Display Window", CV_WINDOW_AUTOSIZE);
time(&start);
while (camera.IsGrabbing())
{
camera.RetrieveResult(5000, ptrGrabResult, TimeoutHandling_ThrowException);
if (ptrGrabResult->GrabSucceeded())
{
formatConverter.Convert(pylonImage, ptrGrabResult);
openCvImage = Mat(ptrGrabResult->GetHeight(), ptrGrabResult->GetWidth(), CV_8UC3, (uint8_t *)pylonImage.GetBuffer());
imshow("OpenCV Display Window", openCvImage);
frames++;
if (waitKey(30)>=0) break;
}
}
time(&end);
}
catch (...) { cout << "error" << endl; }
seconds = difftime(end, start);
fps = frames / seconds;
cout << "fps: " << fps;
Sleep(1000);
}

Frame rate is affected by many parameters. If the manufacturer specifies 200fps as the maximum at full resolution, this is the absolute maximum with:
minimum exposure time (too small for most applications)
nothing else going on on the USB bus
optimal transfer and acquisition parameters (maximum aquisition frame rate, no bandwidth limitations, fast readout mode
...
In case you haven't noticed, that's the marketing guy with big and juicy bait. 200fps cannot be achieved in most applications due to many factors.
You can read out the resulting framerate for your current configuration like that:
// Get the resulting frame rate
double d = camera.ResultingFrameRate.GetValue();
Refer to the camera's user manual... There's an entire chapter on frame rate, framerate limitations, framerate optimization
I also see a waitkey(30) call in your fps measurement. This function will delay your grab loop for at least 30ms unless you press any key. If you display each frame for 30 milliseconds (at least that's how I understand the waitkey documentation), how are you supposed to reach 100 fps? 1 frame / 0.03 s = 33.33 fps.

Related

Switching from OpenCV 3 to OpenCV 4 causes webcam to record at a max of 5 fps instead the usual 30 fps

I'm having some trouble since I changed from OpenCV 3.x to 4.x (compiled from source) in my C++ project. I've replicated this behaviour in a small example that just opens a webcam and records for 5 seconds.
With 3.x I am able to set the webcam framerate to 30 at full hd, but the same code with 4.x just ignores the camera.set(cv::CAP_PROP_FPS,30) and sets it to 5 instead. If I use 720p, the fps is set to 10.
Maybe the code is not relevant here, as it's a classical example, but just in case I'll leave it here.
#include "opencv2/opencv.hpp"
#include "iostream"
#include "thread"
#include <unistd.h>
using namespace cv;
VideoCapture camera(0);
bool stop = false;
int fc = 0;
void saveFrames()
{
while(!stop)
{
Mat frame;
camera >> frame;
cv::imwrite("/tmp/frames/frame" + std::to_string(fc) + ".jpg", frame);
fc++;
}
}
int main()
{
if(!camera.isOpened())
return -1;
camera.set(cv::CAP_PROP_FRAME_WIDTH,1920);
camera.set(cv::CAP_PROP_FRAME_HEIGHT,1080);
camera.set(cv::CAP_PROP_FPS,30);
double fps = camera.get(cv::CAP_PROP_FPS);
std::cout << "FPS setting: " << fps << std::endl; // 5 with OCV4, 30 with OCV3
std::thread tr(saveFrames);
int waitSeconds = 5;
usleep(waitSeconds * 1e6);
stop = true;
tr.join();
std::cout << "Written " << fc << " frames of " << fps * waitSeconds << std::endl;
return 0;
}
Edit: more tests with other computers yield the same result except in a Macbook Pro (but running the same distribution) where OpenCV 4.3 seems to work. The other 2 computers are desktops with usb webcams.
Edit 2: same problem with version 3.4 building from source code. For now, only 3.2 from the repo works ok in the two computers with usbcams.
This is a known bug that affects OpenCV > 3.3

Reading camera image using raspistill from C++ program

I like to capture images using RPi at least 60Hz. My code is in C++ and we have a library here for C++ interface. But that library has maximum 30Hz.
My target is minimum 60 Hz.
So far what I found is raspistill can make upto 90Hz, so I am trying to interface my C++ program to raspistill code.
I found one library here PiCam that has direct interface to raspistll. Not very sure, it can go to 60Hz, I am still trying to test it and have a few issues.
My queries are
(1)How is it possible to have 60Hz fps at RPi using C++?
(2)To interface to PiCam, I have already compiled, build and installed the library with no issues.
But I get black image when I capture. What could be the issue? A part of my code is shown below.
CCamera* cam = StartCamera(640, 480,60,1,true);
char mybuffer[640 * 480 * 4];
int ret = cam->ReadFrame(0, mybuffer, sizeof(mybuffer));
cout << " ret " << ret << endl;
Mat img(480, 640, CV_8UC4,mybuffer);
imwrite("img.jpg", img);
img.jpg is captured with black image.
(3)Using PiCam, how can I changed to Gray image?
I use Raspicam from here on a Raspberry Pi 3 and get around 90 fps in black and white mode.
I am currently re-purposing the code for something else so it is not 100% perfect for your needs, but should get you going.
#include <ctime>
#include <fstream>
#include <iostream>
#include <raspicam/raspicam.h>
#include <unistd.h> // for usleep()
using namespace std;
#define NFRAMES 1000
#define WIDTH 1280
#define HEIGHT 960
int main ( int argc,char **argv ) {
raspicam::RaspiCam Camera;
// Allowable values: RASPICAM_FORMAT_GRAY,RASPICAM_FORMAT_RGB,RASPICAM_FORMAT_BGR,RASPICAM_FORMAT_YUV420
Camera.setFormat(raspicam::RASPICAM_FORMAT_GRAY);
// Allowable widths: 320, 640, 1280
// Allowable heights: 240, 480, 960
// setCaptureSize(width,height)
Camera.setCaptureSize(WIDTH,HEIGHT);
// Open camera
cout<<"Opening Camera..."<<endl;
if ( !Camera.open()) {cerr<<"Error opening camera"<<endl;return -1;}
// Wait until camera stabilizes
cout<<"Sleeping for 3 secs"<<endl;
usleep(3000000);
cout << "Grabbing " << NFRAMES << " frames" << endl;
// Allocate memory for camera buffer
unsigned long bytes=Camera.getImageBufferSize();
cout << "Width: " << Camera.getWidth() << endl;
cout << "Height: " << Camera.getHeight() << endl;
cout << "ImageBufferSize: " << bytes << endl;;
unsigned char *data=new unsigned char[bytes];
for(int frame=0;frame<NFRAMES;frame++){
// Capture frame
Camera.grab();
// Extract the image
Camera.retrieve (data,raspicam::RASPICAM_FORMAT_IGNORE);
}
}
return 0;
}
By the way, it works very nicely with CImg.
Also, I haven't yet had the time to see if it works faster to create a new thread to process each frame, or to have a few threads started at the beginning and use a condition variable to start one after acquiring each frame.
What Mark Setchell responded is correct.
But I found out that setting frame rate parameter is not exposed at its API level and can't set frame rate. Default frame rate is 30 Hz.
Can change it at src/private/private_impl.cpp file. I set to 60Hz and now it works.

OpenCV: VideoCapture::get(CV_CAP_PROP_FPS) returns 0 FPS

I am trying to get the fps from my camera so that I can pass it to the VideoWriter for outputting the video. However, I am getting 0 fps by calling VideoCapture::get(CV_CAP_PROP_FPS) from my camera. If I hardcode it, my video may be too slow or too fast.
#include "opencv2/opencv.hpp"
#include <stdio.h>
#include <stdlib.h>
using namespace std;
using namespace cv;
int main(int argc, char *argv[])
{
cv::VideoCapture cap;
int key = 0;
if(argc > 1){
cap.open(string(argv[1]));
}
else
{
cap.open(CV_CAP_ANY);
}
if(!cap.isOpened())
{
printf("Error: could not load a camera or video.\n");
}
Mat frame;
cap >> frame;
waitKey(5);
namedWindow("video", 1);
double fps = cap.get(CV_CAP_PROP_FPS);
CvSize size = cvSize((int)cap.get(CV_CAP_PROP_FRAME_WIDTH),(int)cap.get(CV_CAP_PROP_FRAME_HEIGHT));
int codec = CV_FOURCC('M', 'J', 'P', 'G');
if(!codec){ waitKey(0); return 0; }
std::cout << "CODEC: " << codec << std::endl;
std::cout << "FPS: " << fps << std::endl;
VideoWriter v("Hello.avi",-1,fps,size);
while(key != 'q'){
cap >> frame;
if(!frame.data)
{
printf("Error: no frame data.\n");
break;
}
if(frame.empty()){ break; }
v << frame;
imshow("video", frame);
key = waitKey(5);
}
return(0);
}
How can I get VideoCapture::get(CV_CAP_PROP_FPS) to return the right fps or give a fps to the VideoWriter that works universally for all webcams?
CV_CAP_PROP_FPS only works on videos as far as I know. If you want to capture video data from a webcam you have to time it correctly yourself. For example use a timer to capture a frame from the webcam every 40ms and then save as 25fps video.
You can use VideoCapture::set(CV_CAP_PROP_FPS) to set the desired FPS for a webcam. However, you can't use get for some reason.
Note that sometimes the driver will choose a different FPS than what you have requested depending on the limitations of the webcam.
My workaround: capture frames during a few seconds (4 is fine in my tests, with 0.5 seconds of initial delay), and estimate the fps the camera outputs.
I've never observed CV_CAP_PROP_FPS to work. I have tried with various flavors of OpenCV 2.4.x (currently 2.4.11) using file inputs.
As a workaround in one scenario, I directly used libavformat (from ffmpeg) to get the frame rate, which I can then use in my other OpenCV code:
static double get_frame_rate(const char *filePath) {
AVFormatContext *gFormatCtx = avformat_alloc_context();
av_register_all();
if (avformat_open_input(&gFormatCtx, filePath, NULL, NULL) != 0) {
return -1;
} else if (avformat_find_stream_info(gFormatCtx, NULL) < 0) {
return -1;
}
for (int i = 0; i < gFormatCtx->nb_streams; i++) {
if (gFormatCtx->streams[i]->codec->codec_type == AVMEDIA_TYPE_VIDEO) {
AVRational rate = gFormatCtx->streams[i]->avg_frame_rate;
return (double)av_q2d(rate);
}
}
return -1;
}
Aside from that, undoubtedly one of the slowest possible (although sure to work) methods to get the average fps, would be to step through each frame and divide the current frame number by the current time:
for (;;) {
currentFrame = cap.get(CV_CAP_PROP_POS_FRAMES);
currentTime = cap.get(CV_CAP_PROP_POS_MSEC);
fps = currentFrame / (currentTime / 1000);
# ... code ...
# stop this loop when you're satisfied ...
}
You'd probably only want to do the latter if the other methods of directly finding the fps failed, and further, there were no better way to summarily get overall duration and frame count information.
The example above works on a file -- to adapt to a camera, you could use elapsed wallclock time since beginning of capture, instead of getting CV_CAP_PROP_POS_MSEC. Then the average fps for the session would be the elapsed wall clock time divided by the current frame number.
For live video from webcam use cap.get(cv2.CAP_PROP_FPS)

Can i capture at 20 fps with C++ and Opencv?

i have a Raspberry Pi and installed on it the OpenCV and Guvcview. When i open Guvcview, i get ~ 17-21 fps but when i run a simple program (only capture from webcam and display frame) in C++ with Opencv, i get only 6 fps.
What is wrong? i need to configure Opencv to use Guvcview's configuration? why guvcview get 20 fps? What can i do?
thanks.
P.D. I've done the same in my computer and i get 29 fps in both cases.
//*********************************this is the code C++ :
#include <iostream>
#include "opencv2/opencv.hpp"
using namespace std;
using namespace cv;
time_t start, end; //variabile di tipo time_t , contiene tempo in sec.
// inizializzo contatore nella dichiarazione
int counter=0;
int main()
{ time(&start);
VideoCapture cap(1);
cap.set(CV_CAP_PROP_FRAME_WIDTH, 640);
cap.set(CV_CAP_PROP_FRAME_HEIGHT, 480);
if (!cap.isOpened())
{ cout << "could not capture";
return 0; }
Mat frame;
namedWindow("camera", 1);
char key = 'a';
while(key != 27)
{ cap.read( frame);
imshow("camera", frame);
//##################
//time at the end of 1 show, Stop the clock and show FPS
time(&end);
++counter;
cout <<"fps: "<< counter/ difftime(end,start) <<endl <<endl;
//##################
key = waitKey(3); }
destroyAllWindows();
return 0;
}
OpenCV is a heavy weight API and following tips may introduce minor improvements:
you can disable RGB conversion:
cap.set(CV_CAP_PROP_CONVERT_RGB , false);
you can increase frame rate if its default frame rate is low:
cap.set(CV_CAP_PROP_FPS , 60);
I'd suggest to do direct video capture via V4L, since OpenCV may do YUYV to RGB transformations and other stuff that involves floating point calculations, that are expensive on this kind of hardware. We have done many robotics projects on embedded systems and the rule of the thumb is that you will be always better of either directly using V4L or small 3rd party libraries like CMVision (http://www.cs.cmu.edu/~jbruce/cmvision/) to do image processing on embedded systems.

OpenCV: What is the limitation for the poor framerate?

Using OpenCV 2.4.3.2 on Ubuntu 12.10 with a PS3-Eye camera I'm not able to capture more than ~60 frames per second (FPS). The camera itself delivers up to 125 FPS. I would like to know what limits the framerate in OpenCV. So here is what I did so far:
#include <sys/time.h>
#include <time.h>
#include <iostream> // for standard I/O
using cv;
using std;
long time_diff( const timespec &t1, const timespec &t2 ) {
return (long)(t2.tv_sec-t1.tv_sec)*1000000000 + (t2.tv_nsec-t1.tv_nsec);
}
int main(int argc, char *argv[]) {
VideoCapture cap(0); // open the default camera
cap.set(CV_CAP_PROP_EXPOSURE, 0);
cap.set(CV_CAP_PROP_FPS, 125);
cap.set(CV_CAP_PROP_FRAME_WIDTH, 320);
cap.set(CV_CAP_PROP_FRAME_HEIGHT, 240);
if(!cap.isOpened()) // check if we succeeded
return -1;
Mat frame;
timespec t_start, t_end;
for(int i=1;;++i) {
cap >> frame;
clock_gettime(CLOCK_REALTIME, &t_end);
if( i%20==0 )
std::cout << "FPS ~= " << time_diff(t_start, t_end) << std::endl;
clock_gettime(CLOCK_REALTIME, &t_start);
}
}
This outputs the framerate every 20 frames to stdout. Note that I had to patch the source to be able to set the framerate correctly for the PS3-Eye camera.
First I set the framerate to 30 (cap.set(CV_CAP_PROP_FPS, 30);) to verify that my measurement is correct. Then using higher framerates the reported framerate is capped at ~60 FPS.
The USB is not the problem because I can get the full 120 FPS with guvcview.
I modified the code above to use grab() and retrieve() like this:
clock_gettime(ClOCK_REALTIME, &t_start);
cap->grab();
clock_gettime(ClOCK_REALTIME, &t_end);
cap->retrieve(frame);
but the framerate is capped again at ~60 FPS.
So how can I tell what is limiting the framerate?
After switching to a desktop machine (from laptop) I was able to capture the full framerate. It seems OpenCVs capture implementation is not as efficient as the one in guvcview.
I have same issue with 65 FPS limit in win7 x64 with OpenCV and Delphi X6. Founded problem is in cvWaitKey or/and Windows message queue, which limits redraws in 65 Hz.
The solution - to call cvWaitKey less frequently, less 65 times per second.