2

I'm working on a project based on real time image processing using CImg Library in Raspberrypi.

I need to capture images at higher frame rates (say atleast 30 fps), when I use the inbuilt Raspicam commands such as

sudo raspistill -o -img_%d.jpg -tl 5 -t 1000  -a 512

/* -tl : time lapse duration in msec -t : total time duration (1000 msec = 1 sec) -a : displays frame numbers */

with this command though it shows 34 frames per second,I could only capture maximum of 4 frames/images (and rest of the frames are skipped)

sudo raspistill -o -img_%d.jpg -tl 5 -tl 1000 -q 5 -md 7 -w 640 -h 480 -a 512

and From this above command I could capture at a maximum of 7-8 images per second but by reducing the resolution and quality of the images.

But I don't want to compromise on the quality of an image since I will be capturing an image, processing it immediately and will be deleting an image to save memory.

Later I tried using V4L2(Video for Linux) drivers to make use of the best performance of a camera, but in the internet, tutorials regarding V4l2 and cimg are quite scarce, I couldn't find one.

I have been using the following commands

# Capture a JPEG image
 v4l2-ctl --set-fmt-video=width=2592,height=1944,pixelformat=3
 v4l2-ctl --stream-mmap=3 --stream-count=1 –stream-to=somefile.jpg

(source : http://www.geeetech.com/wiki/index.php/Raspberry_Pi_Camera_Module)

but I couldn't get enough information about those parameters such as (stream-mmap & stream-count) what does it exactly, and how does these commands help me in capturing 30 frames/images per second ?

CONDITIONS:

  1. Most importantly I don't want to use OPENCV, MATLAB or any other image processing softwares, since my image processing task is very simple (I.e detection of led light blink) also my objective is to have a light weight tool to perform these operations at the cost of higher performance.

  2. And also my programming code should be in either C or C++ but not in python or Java (since processing speed matters !)

  3. Please make a note that,my aim is not to record a video but to capture as many frames as possible and to process each and individual images.

For using in Cimg I searched over few docs from a reference manual, but I couldn't understand it clearly how to use it for my purpose.

The class cimg_library::CImgList represents lists of cimg_library::CImg images. It can be used for instance to store different frames of an image sequence. (source : http://cimg.eu/reference/group__cimg__overview.html )

  • I found the following examples, But i'm not quite sure whether it suits my task

Load a list from a YUV image sequence file.

CImg<T>& load_yuv 
(
const char *const 
filename, 

const unsigned int 
size_x, 

const unsigned int 
size_y, 

const unsigned int 
first_frame = 0, 

const unsigned int 
last_frame = ~0U, 

const unsigned int 
step_frame = 1, 

const bool 
yuv2rgb = true 

Parameters filename Filename to read data from. size_x Width of the images. size_y Height of the images. first_frame Index of first image frame to read. last_frame Index of last image frame to read. step_frame Step applied between each frame. yuv2rgb Apply YUV to RGB transformation during reading.

But here, I need rgb values from an image frames directly without compression.

Now I have the following code in OpenCv which performs my task, but I request you to help me in implementing the same using CImg libraries (which is in C++) or any other light weight libraries or something with v4l2

#include <iostream>
#include <opencv2/opencv.hpp>

using namespace std;
using namespace cv;

int main (){
    VideoCapture capture (0); //Since you have your device at /dev/video0

    /* You can edit the capture properties with "capture.set (property, value);" or in the driver with "v4l2-ctl --set-ctrl=auto_exposure=1"*/

    waitKey (200); //Wait 200 ms to ensure the device is open

    Mat frame; // create Matrix where the new frame will be stored
    if (capture.isOpened()){
        while (true){
            capture >> frame; //Put the new image in the Matrix

            imshow ("Image", frame); //function to show the image in the screen
        }
    }
}
  • I'm a beginner to the Programming and Raspberry pi, please excuse if there are any mistakes in the above problem statements.

"With some of your recommendations, I slighthly modified the raspicam c++ api code and combined with CIMG image processing functionality "

 #include "CImg.h"
    #include <iostream>
    #include <cstdlib>
    #include <fstream>
    #include <sstream>
    #include <sys/timeb.h>
    #include "raspicam.h"
    using namespace std;
    using namespace cimg_library;
     bool doTestSpeedOnly=false;
    size_t nFramesCaptured=100;
//parse command line
//returns the index of a command line param in argv. If not found, return -1

    int findParam ( string param,int argc,char **argv ) {
    int idx=-1;
    for ( int i=0; i<argc && idx==-1; i++ )
        if ( string ( argv[i] ) ==param ) idx=i;
    return idx;

}


//parse command line
//returns the value of a command line param. If not found, defvalue is returned
float getParamVal ( string param,int argc,char **argv,float defvalue=-1 ) {
    int idx=-1;
    for ( int i=0; i<argc && idx==-1; i++ )
        if ( string ( argv[i] ) ==param ) idx=i;

    if ( idx==-1 ) return defvalue;
    else return atof ( argv[  idx+1] );
}




raspicam::RASPICAM_EXPOSURE getExposureFromString ( string str ) {
    if ( str=="OFF" ) return raspicam::RASPICAM_EXPOSURE_OFF;
    if ( str=="AUTO" ) return raspicam::RASPICAM_EXPOSURE_AUTO;
    if ( str=="NIGHT" ) return raspicam::RASPICAM_EXPOSURE_NIGHT;
    if ( str=="NIGHTPREVIEW" ) return raspicam::RASPICAM_EXPOSURE_NIGHTPREVIEW;
    if ( str=="BACKLIGHT" ) return raspicam::RASPICAM_EXPOSURE_BACKLIGHT;
    if ( str=="SPOTLIGHT" ) return raspicam::RASPICAM_EXPOSURE_SPOTLIGHT;
    if ( str=="SPORTS" ) return raspicam::RASPICAM_EXPOSURE_SPORTS;
    if ( str=="SNOW" ) return raspicam::RASPICAM_EXPOSURE_SNOW;
    if ( str=="BEACH" ) return raspicam::RASPICAM_EXPOSURE_BEACH;
    if ( str=="VERYLONG" ) return raspicam::RASPICAM_EXPOSURE_VERYLONG;
    if ( str=="FIXEDFPS" ) return raspicam::RASPICAM_EXPOSURE_FIXEDFPS;
    if ( str=="ANTISHAKE" ) return raspicam::RASPICAM_EXPOSURE_ANTISHAKE;
    if ( str=="FIREWORKS" ) return raspicam::RASPICAM_EXPOSURE_FIREWORKS;
    return raspicam::RASPICAM_EXPOSURE_AUTO;
}


    raspicam::RASPICAM_AWB getAwbFromString ( string str ) {
    if ( str=="OFF" ) return raspicam::RASPICAM_AWB_OFF;
    if ( str=="AUTO" ) return raspicam::RASPICAM_AWB_AUTO;
    if ( str=="SUNLIGHT" ) return raspicam::RASPICAM_AWB_SUNLIGHT;
    if ( str=="CLOUDY" ) return raspicam::RASPICAM_AWB_CLOUDY;
    if ( str=="SHADE" ) return raspicam::RASPICAM_AWB_SHADE;
    if ( str=="TUNGSTEN" ) return raspicam::RASPICAM_AWB_TUNGSTEN;
    if ( str=="FLUORESCENT" ) return raspicam::RASPICAM_AWB_FLUORESCENT;
    if ( str=="INCANDESCENT" ) return raspicam::RASPICAM_AWB_INCANDESCENT;
    if ( str=="FLASH" ) return raspicam::RASPICAM_AWB_FLASH;
    if ( str=="HORIZON" ) return raspicam::RASPICAM_AWB_HORIZON;
    return raspicam::RASPICAM_AWB_AUTO;
    }


    void processCommandLine ( int argc,char **argv,raspicam::RaspiCam &Camera ) {
    Camera.setWidth ( getParamVal ( "-w",argc,argv,640 ) );
    Camera.setHeight ( getParamVal ( "-h",argc,argv,480 ) );
    Camera.setBrightness ( getParamVal ( "-br",argc,argv,50 ) );
    Camera.setSharpness ( getParamVal ( "-sh",argc,argv,0 ) );
    Camera.setContrast ( getParamVal ( "-co",argc,argv,0 ) );
    Camera.setSaturation ( getParamVal ( "-sa",argc,argv,0 ) );
    Camera.setShutterSpeed( getParamVal ( "-ss",argc,argv,0 ) );
    Camera.setISO ( getParamVal ( "-iso",argc,argv ,400 ) );
   if ( findParam ( "-vs",argc,argv ) !=-1 )
        Camera.setVideoStabilization ( true );
    Camera.setExposureCompensation ( getParamVal ( "-ec",argc,argv ,0 ) );

    if ( findParam ( "-gr",argc,argv ) !=-1 )
      Camera.setFormat(raspicam::RASPICAM_FORMAT_GRAY);
    if ( findParam ( "-yuv",argc,argv ) !=-1 ) 
      Camera.setFormat(raspicam::RASPICAM_FORMAT_YUV420);
    if ( findParam ( "-test_speed",argc,argv ) !=-1 )
        doTestSpeedOnly=true;
    int idx;
    if ( ( idx=findParam ( "-ex",argc,argv ) ) !=-1 )
        Camera.setExposure ( getExposureFromString ( argv[idx+1] ) );
    if ( ( idx=findParam ( "-awb",argc,argv ) ) !=-1 )
        Camera.setAWB( getAwbFromString ( argv[idx+1] ) );

    nFramesCaptured=getParamVal("-nframes",argc,argv,100);
    Camera.setAWB_RB(getParamVal("-awb_b",argc,argv ,1), getParamVal("-awb_g",argc,argv ,1));

    }


    //timer functions
    #include <sys/time.h>
    #include <unistd.h>
    class Timer{
    private:
    struct timeval _start, _end;

    public:
      Timer(){}
    void start(){
        gettimeofday(&_start, NULL);
    }
    void end(){
        gettimeofday(&_end, NULL);
    }
    double getSecs(){
    return double(((_end.tv_sec  - _start.tv_sec) * 1000 + (_end.tv_usec - _start.tv_usec)/1000.0) + 0.5)/1000.;
    }

    }; 

    void saveImage ( string filepath,unsigned char *data,raspicam::RaspiCam &Camera ) {
    std::ofstream outFile ( filepath.c_str(),std::ios::binary );
    if ( Camera.getFormat()==raspicam::RASPICAM_FORMAT_BGR ||  Camera.getFormat()==raspicam::RASPICAM_FORMAT_RGB ) {
        outFile<<"P6\n";
    } else if ( Camera.getFormat()==raspicam::RASPICAM_FORMAT_GRAY ) {
        outFile<<"P5\n";
    } else if ( Camera.getFormat()==raspicam::RASPICAM_FORMAT_YUV420 ) { //made up format
        outFile<<"P7\n";
    }
    outFile<<Camera.getWidth() <<" "<<Camera.getHeight() <<" 255\n";
    outFile.write ( ( char* ) data,Camera.getImageBufferSize() );
    }


    int main ( int argc,char **argv ) {

    int a=1,b=0,c;
    int x=444,y=129; //pixel coordinates
    raspicam::RaspiCam Camera;
    processCommandLine ( argc,argv,Camera );
    cout<<"Connecting to camera"<<endl;

    if ( !Camera.open() ) {
        cerr<<"Error opening camera"<<endl;
        return -1;
       }
     //   cout<<"Connected to camera ="<<Camera.getId() <<" bufs="<<Camera.getImageBufferSize( )<<endl;
    unsigned char *data=new unsigned char[  Camera.getImageBufferSize( )];
    Timer timer;


       // cout<<"Capturing...."<<endl;
       // size_t i=0;
    timer.start();


    for (int i=0;i<=nFramesCaptured;i++)
        {
        Camera.grab();
        Camera.retrieve ( data );
                std::stringstream fn;
                fn<<"image.jpg";
                saveImage ( fn.str(),data,Camera );
    //  cerr<<"Saving "<<fn.str()<<endl;
    CImg<float> Img("/run/shm/image.jpg");
         //Img.display("Window Title");

    // 9 PIXELS MATRIX GRAYSCALE VALUES 
    float pixvalR1 = Img(x-1,y-1);

    float pixvalR2 = Img(x,y-1);

    float pixvalR3 = Img(x+1,y-1);

    float pixvalR4 = Img(x-1,y);

    float pixvalR5 = Img(x,y);

    float pixvalR6 = Img(x+1,y);

    float pixvalR7 = Img(x-1,y+1);

    float pixvalR8 = Img(x,y+1);

    float pixvalR9 = Img(x+1,y+1);

    // std::cout<<"coordinate value :"<<pixvalR5 << endl;


    // MEAN VALUES OF RGB PIXELS
    float light = (pixvalR1+pixvalR2+pixvalR3+pixvalR4+pixvalR5+pixvalR6+pixvalR7+pixvalR8+pixvalR9)/9 ;

    // DISPLAYING MEAN RGB VALUES OF 9 PIXELS
    // std::cout<<"Lightness value :"<<light << endl;


    // THRESHOLDING CONDITION
     c = (light > 130 ) ? a : b; 

    // cout<<"Data is " << c <<endl;

    ofstream fout("c.txt", ios::app);
    fout<<c;
    fout.close();


    }   

    timer.end();
       cerr<< timer.getSecs()<< " seconds for "<< nFramesCaptured << "  frames : FPS " << ( ( float ) ( nFramesCaptured ) / timer.getSecs() ) <<endl;

    Camera.release();

    std::cin.ignore();


    }
  • from this code, I would like to know how can we get the data directly from camera.retrieve(data), without storing it as an image file and to access the data from an image buffer, to process the image and delete it further.

As per the recommendations of Mark Setchell, which i made a slight changes in the code and i'm getting good results, but, Is there any way to improve the processing performance to get higher Frame rate ? with this code i'm able to get at a maximum of 10 FPS.

#include <ctime>
#include <fstream>
#include <iostream>
#include <thread>
#include <mutex>
#include <raspicam/raspicam.h>

// Don't want any X11 display by CImg
#define cimg_display 0

#include <CImg.h>

using namespace cimg_library;
using namespace std;

#define NFRAMES     1000
#define NTHREADS    2
#define WIDTH       640
#define HEIGHT      480

// Commands/status for the worker threads
#define WAIT    0
#define GO      1
#define GOING   2
#define EXIT    3
#define EXITED  4
volatile int command[NTHREADS];

// Serialize access to cout
std::mutex cout_mutex;

// CImg initialisation
// Create a 1280x960 greyscale (Y channel of YUV) image
// Create a globally-accessible CImg for main and workers to access
CImg<unsigned char> img(WIDTH,HEIGHT,1,1,128);

////////////////////////////////////////////////////////////////////////////////
// worker thread - There will 2 or more of these running in parallel with the
//                 main thread. Do any image processing in here.
////////////////////////////////////////////////////////////////////////////////
void worker (int id) {

   // If you need a "results" image of type CImg, create it here before entering
   // ... the main processing loop below - you don't want to do malloc()s in the
   // ... high-speed loop
   // CImg results...

   int wakeups=0;

   // Create a white for annotating
   unsigned char white[] = { 255,255,255 };

   while(true){
      // Busy wait with 500us sleep - at worst we only miss 50us of processing time per frame
      while((command[id]!=GO)&&(command[id]!=EXIT)){
         std::this_thread::sleep_for(std::chrono::microseconds(500));
      }
      if(command[id]==EXIT){command[id]=EXITED;break;}
      wakeups++;

      // Process frame of data - access CImg structure here
      command[id]=GOING;

      // You need to add your processing in HERE - everything from
      // ... 9 PIXELS MATRIX GRAYSCALE VALUES to
      // ... THRESHOLDING CONDITION
    int a=1,b=0,c;
    int x=330,y=84;

// CImg<float> Img("/run/shm/result.png");
float pixvalR1 = img(x-1,y-1);

float pixvalR2 = img(x,y-1);

float pixvalR3 = img(x+1,y-1);

float pixvalR4 = img(x-1,y);

float pixvalR5 = img(x,y);

float pixvalR6 = img(x+1,y);

float pixvalR7 = img(x-1,y+1);

float pixvalR8 = img(x,y+1);

float pixvalR9 = img(x+1,y+1);


// MEAN VALUES OF RGB PIXELS
float light = (pixvalR1+pixvalR2+pixvalR3+pixvalR4+pixvalR5+pixvalR6+pixvalR7+pixvalR8+pixvalR9)/9 ;

// DISPLAYING MEAN RGB VALUES OF 9 PIXELS
// std::cout<<"Lightness value :"<<light << endl;


// THRESHOLDING CONDITION
 c = (light > 130 ) ? a : b; 

// cout<<"Data is " << c <<endl;

ofstream fout("c.txt", ios::app);
fout<<c;
fout.close();
      // Pretend to do some processing.
      // You need to delete the following "sleep_for" and "if(id==0...){...}"
     // std::this_thread::sleep_for(std::chrono::milliseconds(2));


    /*  if((id==0)&&(wakeups==NFRAMES)){
        //  Annotate final image and save as PNG
          img.draw_text(100,100,"Hello World",white);
         img.save_png("result.png");
      } */
   }

   cout_mutex.lock();
   std::cout << "Thread[" << id << "]: Received " << wakeups << " wakeups" << std::endl;
   cout_mutex.unlock();
}

//timer functions
#include <sys/time.h>
#include <unistd.h>
class Timer{
    private:
    struct timeval _start, _end;

public:
  Timer(){}
    void start(){
        gettimeofday(&_start, NULL);
    }
    void end(){
        gettimeofday(&_end, NULL);
    }
    double getSecs(){
    return double(((_end.tv_sec  - _start.tv_sec) * 1000 + (_end.tv_usec - _start.tv_usec)/1000.0) + 0.5)/1000.;
    }

}; 

int main ( int argc,char **argv ) {

Timer timer;
   raspicam::RaspiCam Camera;
   // Allowable values: RASPICAM_FORMAT_GRAY,RASPICAM_FORMAT_RGB,RASPICAM_FORMAT_BGR,RASPICAM_FORMAT_YUV420
   Camera.setFormat(raspicam::RASPICAM_FORMAT_YUV420);

   // Allowable widths: 320, 640, 1280
   // Allowable heights: 240, 480, 960
   // setCaptureSize(width,height)
   Camera.setCaptureSize(WIDTH,HEIGHT);

   std::cout << "Main: Starting"  << std::endl;
   std::cout << "Main: NTHREADS:" << NTHREADS << std::endl;
   std::cout << "Main: NFRAMES:"  << NFRAMES  << std::endl;
   std::cout << "Main: Width: "   << Camera.getWidth()  << std::endl;
   std::cout << "Main: Height: "  << Camera.getHeight() << std::endl;

   // Spawn worker threads - making sure they are initially in WAIT state
   std::thread threads[NTHREADS];
   for(int i=0; i<NTHREADS; ++i){
      command[i]=WAIT;
      threads[i] = std::thread(worker,i);
   }

   // Open camera
   cout<<"Opening Camera..."<<endl;
   if ( !Camera.open()) {cerr<<"Error opening camera"<<endl;return -1;}

   // Wait until camera stabilizes
   std::cout<<"Sleeping for 3 secs"<<endl;
   std::this_thread::sleep_for(std::chrono::seconds(3));
 timer.start();
   for(int frame=0;frame<NFRAMES;frame++){
      // Capture frame
      Camera.grab();

      // Copy just the Y component to our mono CImg
      std::memcpy(img._data,Camera.getImageBufferData(),WIDTH*HEIGHT);

      // Notify worker threads that data is ready for processing
      for(int i=0; i<NTHREADS; ++i){
         command[i]=GO;
      }
   }
timer.end();
cerr<< timer.getSecs()<< " seconds for "<< NFRAMES << "  frames : FPS " << ( ( float ) ( NFRAMES ) / timer.getSecs() ) << endl;
   // Let workers process final frame, then tell to exit
 //  std::this_thread::sleep_for(std::chrono::milliseconds(50));

   // Notify worker threads to exit
   for(int i=0; i<NTHREADS; ++i){
      command[i]=EXIT;
   }

   // Wait for all threads to finish
   for(auto& th : threads) th.join();
}

COMPILED COMMAND FOR EXECUTION OF THE CODE :

g++ -std=c++11 /home/pi/raspicam/src/raspicimgthread.cpp -o threadraspicimg -I. -I/usr/local/include -L /opt/vc/lib -L /usr/local/lib -lraspicam -lmmal -lmmal_core -lmmal_util -O2 -L/usr/X11R6/lib -lm -lpthread -lX11

**RESULTS :**
Main: Starting
Main: NTHREADS:2
Main: NFRAMES:1000
Main: Width: 640
Main: Height: 480
Opening Camera...
Sleeping for 3 secs
99.9194 seconds for 1000  frames : FPS 10.0081
Thread[1]: Received 1000 wakeups
Thread[0]: Received 1000 wakeups

real    1m43.198s
user    0m2.060s
sys     0m5.850s

And one more query is that, when i used normal Raspicam c++ API code to perform the same tasks (the code which i mentioned previous to this) i got almost same results with very slight enhancement in the performance (ofcourse my frame rate is increased from 9.4 FPS to 10 FPS).

But in the code 1:

I have been saving images in a ram disk for processing and then i'm deleting. I haven't used any threads for parallel processing.

in the code 2 :

We are not saving any images in the disk and directly processing it from the buffer. And we are also using threads to improve the processing speed.

unfortunately, though we made some changes in the code 2 from the code 1, I'm not able to get desired results (which is to be performed at 30 FPS)

Awaiting your favorable suggestions and any help is really appreciated.

Thanks in advance

Best Regards BLV Lohith Kumar

Mark Setchell
  • 191,897
  • 31
  • 273
  • 432
Lohith Kumar
  • 23
  • 1
  • 6
  • Raspicam may be of use to you... http://www.uco.es/investiga/grupos/ava/node/40 – Mark Setchell May 03 '16 at 20:02
  • Hi, thank you, but even with raspicam api, though it says it could achieve 30fps, but i'm not able to achieve more than 10 fps, could you suggest me anything further ? – Lohith Kumar May 09 '16 at 11:12

1 Answers1

1

Updated Answer

I have updated my original answer here to show how to copy the acquired data into a CImg structure and also to show 2 worker threads that can then process the image while the main thread continues to acquire frames at the full speed. It achieves 60 frames per second.

I have not done any processing inside the worker threads because I don't know what you want to do. All I did was save the last frame to disk to show that the acquisition into a CImg is working. You could have 3 worker threads. You could pass one frame to each thread on a round-robin basis, or you could have each of 2 threads process half the frame at each iteration. Or each of 3 threads process one third of a frame. You could change the polled wakeups to use condition variables.

#include <ctime>
#include <fstream>
#include <iostream>
#include <thread>
#include <mutex>
#include <raspicam/raspicam.h>

// Don't want any X11 display by CImg
#define cimg_display 0

#include <CImg.h>

using namespace cimg_library;
using namespace std;

#define NFRAMES     1000
#define NTHREADS    2
#define WIDTH       1280
#define HEIGHT      960

// Commands/status for the worker threads
#define WAIT    0
#define GO      1
#define GOING   2
#define EXIT    3
#define EXITED  4
volatile int command[NTHREADS];

// Serialize access to cout
std::mutex cout_mutex;

// CImg initialisation
// Create a 1280x960 greyscale (Y channel of YUV) image
// Create a globally-accessible CImg for main and workers to access
CImg<unsigned char> img(WIDTH,HEIGHT,1,1,128);

////////////////////////////////////////////////////////////////////////////////
// worker thread - There will 2 or more of these running in parallel with the
//                 main thread. Do any image processing in here.
////////////////////////////////////////////////////////////////////////////////
void worker (int id) {

   // If you need a "results" image of type CImg, create it here before entering
   // ... the main processing loop below - you don't want to do malloc()s in the
   // ... high-speed loop
   // CImg results...

   int wakeups=0;

   // Create a white for annotating
   unsigned char white[] = { 255,255,255 };

   while(true){
      // Busy wait with 500us sleep - at worst we only miss 50us of processing time per frame
      while((command[id]!=GO)&&(command[id]!=EXIT)){
         std::this_thread::sleep_for(std::chrono::microseconds(500));
      }
      if(command[id]==EXIT){command[id]=EXITED;break;}
      wakeups++;

      // Process frame of data - access CImg structure here
      command[id]=GOING;

      // You need to add your processing in HERE - everything from
      // ... 9 PIXELS MATRIX GRAYSCALE VALUES to
      // ... THRESHOLDING CONDITION

      // Pretend to do some processing.
      // You need to delete the following "sleep_for" and "if(id==0...){...}"
      std::this_thread::sleep_for(std::chrono::milliseconds(2));

      if((id==0)&&(wakeups==NFRAMES)){
         // Annotate final image and save as PNG
         img.draw_text(100,100,"Hello World",white);
         img.save_png("result.png");
      }
   }

   cout_mutex.lock();
   std::cout << "Thread[" << id << "]: Received " << wakeups << " wakeups" << std::endl;
   cout_mutex.unlock();
}

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_YUV420);

   // Allowable widths: 320, 640, 1280
   // Allowable heights: 240, 480, 960
   // setCaptureSize(width,height)
   Camera.setCaptureSize(WIDTH,HEIGHT);

   std::cout << "Main: Starting"  << std::endl;
   std::cout << "Main: NTHREADS:" << NTHREADS << std::endl;
   std::cout << "Main: NFRAMES:"  << NFRAMES  << std::endl;
   std::cout << "Main: Width: "   << Camera.getWidth()  << std::endl;
   std::cout << "Main: Height: "  << Camera.getHeight() << std::endl;

   // Spawn worker threads - making sure they are initially in WAIT state
   std::thread threads[NTHREADS];
   for(int i=0; i<NTHREADS; ++i){
      command[i]=WAIT;
      threads[i] = std::thread(worker,i);
   }

   // Open camera
   cout<<"Opening Camera..."<<endl;
   if ( !Camera.open()) {cerr<<"Error opening camera"<<endl;return -1;}

   // Wait until camera stabilizes
   std::cout<<"Sleeping for 3 secs"<<endl;
   std::this_thread::sleep_for(std::chrono::seconds(3));

   for(int frame=0;frame<NFRAMES;frame++){
      // Capture frame
      Camera.grab();

      // Copy just the Y component to our mono CImg
      std::memcpy(img._data,Camera.getImageBufferData(),WIDTH*HEIGHT);

      // Notify worker threads that data is ready for processing
      for(int i=0; i<NTHREADS; ++i){
         command[i]=GO;
      }
   }

   // Let workers process final frame, then tell to exit
   std::this_thread::sleep_for(std::chrono::milliseconds(50));

   // Notify worker threads to exit
   for(int i=0; i<NTHREADS; ++i){
      command[i]=EXIT;
   }

   // Wait for all threads to finish
   for(auto& th : threads) th.join();
}

Note on timing

You can time code like this:

#include <chrono>

typedef std::chrono::high_resolution_clock hrclock;

hrclock::time_point t1,t2;

t1 = hrclock::now();
// do something that needs timing
t2 = hrclock::now();

std::chrono::nanoseconds elapsed = t2-t1;
long long nanoseconds=elapsed.count();

Original Answer

I have been doing some experiments with Raspicam. I downloaded their code from SourceForge and modified it slightly to do some simple, capture-only tests. The code I ended up using looks like this:

#include <ctime>
#include <fstream>
#include <iostream>
#include <raspicam/raspicam.h>
#include <unistd.h> // for usleep()
using namespace std;

#define NFRAMES 1000

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_YUV420);

    // Allowable widths: 320, 640, 1280
    // Allowable heights: 240, 480, 960
    // setCaptureSize(width,height)
    Camera.setCaptureSize(1280,960);

    // 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
    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 );

       // Wake up a thread here to process the frame with CImg
    }
    return 0;
}

I dislike cmake so I just compiled like this:

g++ -std=c++11 simpletest.c -o simpletest -I. -I/usr/local/include -L /opt/vc/lib -L /usr/local/lib -lraspicam -lmmal -lmmal_core -lmmal_util

I found that, regardless of the dimensions of the image, and more or less regardless of the encoding (RGB, BGR, GRAY) it achieves 30 fps (frames per second).

The only way I could get better than that was by making the following changes:

  • in the code above, use RASPICAM_FORMAT_YUV420 rather than anything else

  • editing the file private_impl.cpp and changing line 71 to set the framerate to 90.

If I do that, I can achieve 66 fps.

As the Raspberry Pi is only a pretty lowly 900MHz CPU but with 4 cores, I would guess you would want to start 1-3 extra threads at the beginning outside the loop and then wake one, or more of them up where I have noted in the code to process the data. The first thing they would do is copy the data out of the acquisition buffer before the next frame started - or have multiple buffers and use them in a round-robin fashion.

Notes on threading

In the following diagram, green represents the Camera.grab() where you acquire the image, and red represents the processing you do after the image is acquired. At the moment, you are acquiring the data (green), and then processing it (red) before you can acquire the next frame. Note that 3 of your 4 CPUs do nothing.

enter image description here

What I am suggesting is that you offload the processing (red) to the other CPUs/threads and keep acquiring new data (green) as fast as possible. Like this:

enter image description here

Now you see you get more frames (green) per second.

Mark Setchell
  • 191,897
  • 31
  • 273
  • 432
  • Glad to hear from you, Well I tested the above code and i have few doubts, 1. In " camera.retrieve(data)", actually i need a gray scale image to calculate the pixel intensity value, but when i have the above command, how can i retrieve the data without saving it in to an image file, Since I need to pass this frame to an CImg library for processing, I don't understand what format the data is in and how to load it? or do we have any function to give us a pixel intensity value in RASPICAM C++ API (without opencv) ? and 2. After editing the file "private_impl.cpp" do we have to compile this file – Lohith Kumar May 27 '16 at 12:08
  • 1. If you need greyscale, you need to change the `RASPICAM_FORMAT_YUV` to `Camera.setFormat(RASPICAM_FORMAT_GRAY)`. 2. You don't need to save an image to disk - I'll work out how to get it into CImg in the next day or two - I think is is pretty easy to initialise a CImg from a buffer. What actual processing do you need to do on the image please? Maybe you don't need CImg at all :-) – Mark Setchell May 27 '16 at 12:29
  • Hi, thanks yes, as you suggested I changed the format as RASPICAM_FORMAT_GRAY, and regarding the storage of an image, i have been storing in Ramdisk to increase the processing performance but as you mentioned it would be better if it is stored in buffer and to delete it later as soon as processing is done. But regarding buffer i don't understand how to implement it. Regarding Image processing, what i have to do is to capture an image at a higher frame rate (i.e >=30fps) and to process each frame, i.e to identify the fast blinking rate of LED (whether it is on or off and to decode it as 1 or 0) – Lohith Kumar May 30 '16 at 11:03
  • I would like to show you the code, what i have slightly modified and what i'm expecting, but here (in the comment section, it is allowing me to add only the limited text), could you tell me how can i add my complete code to give you better idea, what i'm exactly working on, thanks in advance – Lohith Kumar May 30 '16 at 11:08
  • I have added my modified code in the question ( at the end) itself, could you please refer it and let me know. I have gone through CImg reference manual and though it mentioned how to load the data in different formats, but i am unable to understand what format of data it would be, when we retrieved it from raspicam api. There is also one more example program called CImg buffer, but i'm not sure whether can we make use of that file to achieve our task (for storing the data ,accessing it from the buffer and after processing delete it), but when i'm compiling the example code i'm getting errors. – Lohith Kumar May 30 '16 at 11:42
  • I have just updated my answer to show the interaction with `CImg`. It will go even faster if we change to YUV format and use the `Y` channel as a black and white - I might have a chance to experiment with that tomorrow. – Mark Setchell May 30 '16 at 11:43
  • If you look at the main `for` loop where we acquire data, the aim is to do as little as possible in there (other than tell the workers to start processing) so that the frame rate stays high. The worker threads are created before the main loop -remember you have 4 cores on Raspberry Pi so you can start a couple of threads and have them wait for work and then process the data while the main thread processes the next one. – Mark Setchell May 30 '16 at 11:47
  • I have made one more update now I can get 60 frames per second. – Mark Setchell May 30 '16 at 14:46
  • Hi, as per your recommendation i compiled and executed the updated code, its working perfectly but after 6 wakeups the program is terminating, no matter how many frames i mentioned, i don't understand, how to rectify it. this is the part of the code which i modified from your updated one. – Lohith Kumar Jun 01 '16 at 16:56
  • errors convert: IDAT: CRC error `/run/shm/result.png' @ error/png.c/MagickPNGErrorHandler/1645. convert: corrupt image `/run/shm/result.png' @ error/png.c/ReadPNGImage/3978. convert: no images defined `pnm:-' @ error/convert.c/ConvertImageCommand/3210. sh: 1: gm: not found convert: IDAT: CRC error `/run/shm/result.png' @ error/png.c/MagickPNGErrorHandler/1645. convert: corrupt image `/run/shm/result.png' @ error/png.c/ReadPNGImage/3978. convert: no images defined `pnm:-' @ Thread[0]: Received 6 wakeups Thread[1]: Received 6 wakeups – Lohith Kumar Jun 01 '16 at 17:10
  • I'm sorry i'm not able to update the code here in the comments section, the above comment is the errors i have encountered. In the processing part which you asked me to include, I have done this, img.save_png("result.png"); CImg Img("/run/shm/result.png"); float pixvalR1 = Img(x-1,y-1);... But my doubt is , could it be done without saving each and every frame and loading directly the image for further processing? and when i placed that particular part of the code in the processing section, i 'm encountering above errors and after 6 wakeups its terminating the program. – Lohith Kumar Jun 01 '16 at 17:16
  • The code does not save each and every frame - it only saves the last frame so you can see that the data is in the CImg structure correctly. Also, never put code or error messages in a comment - it is really hard to read - it is better to click `edit` underneath your original question and add any code or error messages in there. – Mark Setchell Jun 01 '16 at 17:41
  • Also, if you are only taking the average of 9 pixels like you show in your code - you don't even need to bother with the whole `CImg` library or copying all the acquired pixels into a `CImg` - you can just get the 9 pixels from the buffer and average them very simply. – Mark Setchell Jun 01 '16 at 17:42
  • Hi Mark, thank you so much, I made few changes and its working perfect, Just one last question, how did you calculate the fps ? normally what I know is no.of frames / time , but here how did you calculate the time, do we have to use time command or anything else ? – Lohith Kumar Jun 02 '16 at 11:07
  • Glad to hear you are having some success! I have added some code into my answer to show how to time things... – Mark Setchell Jun 02 '16 at 11:23
  • If that is the case for 1000 frames, by using time command (real : 1m43.194s) I got around 9.7 fps and when i tested for 100 frames, it took (real : 13.207s ) and it gives 7.5 fps, if my calculations are correct. But I don't understand how did you get 60 fps ? though you mentioned that you tested only for capturing images without any processing, even then I don't think this would be such a drastic change if i added a small piece of processing code.awaiting your favorable reply – Lohith Kumar Jun 02 '16 at 11:33
  • I think I did 1,000 frames in just under 21 secs. I took off 3 seconds for the stabilisation time and 2 seconds for writing the PNG of the last frame, giving under 16 seconds for 1,000 frames, or 65-ish frames per second. – Mark Setchell Jun 02 '16 at 11:43
  • I'm sorry I didn't see your timing code, since my web page is not refreshed, actually i have been testing the time using "Timer class" in raspicam api and i got the following results : 99.9 seconds for 1000 frames, I get a maximum of 10 FPS, i'm not able to improve this, do you think is it possible to get atleast 30 FPS for complete process. I will be updating modified code in which i'm working on in the question,Hope if you find time could you suggest me how can i improve the performance, sorry for troubling you a lot, thank you so much – Lohith Kumar Jun 02 '16 at 11:53
  • That's a good idea - please uodate your question with your latest & greatest code and also your compile command and timings. – Mark Setchell Jun 02 '16 at 12:07
  • That's great to hear ! I have updated at the ending part of my question, please have a glance at it – Lohith Kumar Jun 02 '16 at 12:16
  • You are opening a file and writing to it and closing it for every single frame - that will certainly slow you down. What do you do with the file? What do you need to do with the mean value once you calculate it? – Mark Setchell Jun 02 '16 at 13:13
  • Well, actually i'm implementing a project on Visible Light Communication, which transfers binary data through led ( 1 for led on and 0 for led off), so that i'm capturing an image frame and calculating the specific pixels mean intensity value to find whether led is ON or OFF to determine whether the data is 1 or 0 . Is there any other possibility instead of writing it into a file to determine what is the data I received ? I will be blinking the led at higher speed and similarly i should be able to capture the frames at higher speed. So to determine the output,do we have any other alternative ? – Lohith Kumar Jun 02 '16 at 14:03
  • If you only need to analyse the data *after* the experiment, create a std::vector with an initial size of 10,000 elements at the start of the program and then save your results in the vector and increment the index on each frame and write the vector to disk at the end of the experiment when time is unimportant. – Mark Setchell Jun 02 '16 at 14:10
  • If you need to analyse the data in realtime as it is running, I would write the results in a piece of shared memory, see `shm_open()` and let another process also open and read the shared data. Only open the memory once at the start of the program though. Or, open a socket at the start of the program and write the data down your network to a receiving process that uses it. – Mark Setchell Jun 02 '16 at 14:12
  • And one more thing, even if I didn't write the data into a file(completely ignoring the file part of the code ), I'm getting the same results 10 FPS. I guess the file part of the code doesn't consume much processing, My doubt is, does the code correctly performing the thread operations (excuse me, I'm unfamiliar with thread and OS operations) because as i mentioned in the ending part of the question (comparisons between two codes, though we made many changes the results seems to be similar ) I certainly don't understand what could be the reason. – Lohith Kumar Jun 02 '16 at 14:16
  • The ORIGINAL ANSWER CODE (not the updated one) which just simply captures and grabs the frames, I tested that, even it shows the same results of which 1000 frames in 100 seconds which gives 10 FPS, I'm realizing that this might not be the problem with the software, I'm afraid it could be the Hardware or OS, May I know in which system are you performing these tests, because i'm working in Raspberrypi, Is it because of RPi, I'm not able to get higher frame rate, since it is operating at 900 MHZ ? – Lohith Kumar Jun 02 '16 at 14:31
  • Mine is a Raspberry Pi 3 running at the standard speed as it cannot be overclocked. The camera is the Raspberry Pi Camera Module - connected via the flat CSI ribbon cable. I was running at the full resolution of 1280x960. I have run the firmware update as follows... `sudo apt-get install rpi-update` then `sudo rpi-update` – Mark Setchell Jun 02 '16 at 14:41
  • while mine is Raspberrypi 2 model B+ running at standard speed (900 MHz) wihtout overclocking and I'm also using the CSI camera and even I had the firmware update as you mentioned, At very beginning you said you got 60 FPS are you completely sure about it, because from the code which you have achieved, I'm just getting the 10 FPS for 1000 frames, I'm using at 640 X 480 resolution (which is a lower resolution than you mentioned) it has to be improved, but its not – Lohith Kumar Jun 02 '16 at 15:22
  • and you said "editing the file private_impl.cpp and changing line 71 to set the framerate to 90" you got better results, but after changing the cpp file should we have to compile or execute that file to make it work or just normal editing is enough ? – Lohith Kumar Jun 02 '16 at 15:28
  • If you edit that file, you need to re-make and re-install. See the part from where it says `tar` to `sudo ldconfig` on this page... http://www.uco.es/investiga/grupos/ava/node/40 – Mark Setchell Jun 02 '16 at 15:35
  • Believe it or not, You really created an impact in my project, just mere thanks would not be sufficient, I'm able to achieve 90 FPS for 1000 frames in 11 seconds, it really boosted my work and motivated me for further development, thank you so much, with your permission, I would like to include your name and profession in my Bachelor Thesis work, just no words to express, you rendered me a great help and support , i'm ever grateful to you – Lohith Kumar Jun 02 '16 at 16:28
  • My pleasure - you are very welcome. I am flattered to be mentioned in your thesis - you can call me a 'UK-based IT consultant`:-) It would be great if you wanted to send me a PDF of your finished thesis - I am always interested in technology - my Email is just my first name and then the domain name is "thesetchells.com". Remember StackOverflow questions are free, so you can always come back and ask more! Good luck with your project! – Mark Setchell Jun 03 '16 at 08:30
  • Well, Its my Pleasure too. I will definitely mail you my thesis work as soon as it is finished. Just to confirm about your mail id : mark@thesetchells.com. Is it correct ? As i mentioned you I'm not completely aware of threading mechanism, could you tell me briefly how it works or could you suggest me any links which contains clear information about it, what we are performing in the program, is it similar to lpthread ? As you told me, these threads will be executed in parallel to the main thread, When I'm testing this code in different cases, though i'm achieving very good frame rate...(contd) – Lohith Kumar Jun 03 '16 at 10:15
  • the output results seems to be varying, it is because of thread operations, since i'm unclear about how it exactly works, i'm facing difficulties in decoding the data. When i executed the code with 1 thread and capturing 200 frames, it does as i expected. But when I mention with two threads, though it captures 200 frames, the resulting output data shows 400 bits, and when I executed with three threads, my result is of 600 binary bits, but it captures only 200 frames. Now I'm having a difficulty in how its processing the frames depending on the number of threads. – Lohith Kumar Jun 03 '16 at 10:19
  • Similarly I just wanted to know, do the parallel threads and the main threads work in synchronization ? I mean, say, I captured a frame in main thread and that grabbed frame has to be passed to the parallel thread for the processing, Is it actually processing the grabbed frame or the next grabbed frame ? If that is the case , do we have any solution to avoid this synchronization problem. Thanks in advance – Lohith Kumar Jun 03 '16 at 10:23
  • Hi, thanks for that Thread part, I understood, but from the results if i execute with 1 or 2 or 3 threads in parallel, there is no difference in the Frame rate (90 FPS) the only difference is in the processing part which contains in the thread,(as i stated my issue in my previous comments) if i mention 3 threads, does it mean the same frame is processed three times ? – Lohith Kumar Jun 03 '16 at 13:34
  • When I wrote it, you hadn't said what the processing involved. You can have 2 threads and let each one do one half of each image, or you can have 1 thread and let it do the whole image. Or you can have 2 threads and let one do frame 0, 2, 4, 6 and let the other do frame 1, 3, 5, 7, 9. It depends on the amount of processing you need and whether latency is important or not.You can divide up the problem how you like :-) – Mark Setchell Jun 03 '16 at 13:49
  • I got it, what you meant, and in my case latency is very important, since my experiments are related to the real time. Now suppose, consider there are two leds in which i'm capturing an image. Is it possible that, in Thread 1 , I should do the processing for 1st LED and in Thread 2, I should do the processing for the 2nd LED of the Same image frame simultaneously, If so , could you suggest me how can we rewrite the above syntax in the code to perform two operations in two different threads at the same time ? – Lohith Kumar Jun 06 '16 at 10:21
  • It is almost impossible to say without knowing the processing you need to do. My best advice is to use a high-resolution timer and measure the time it takes to do the `Camera.grab()` (measure min/max/average) and the time it takes to do your processing. I would think you can very easily do the processing for both LEDs in a single thread before the main thread can capture the next frame but you must measure and see. – Mark Setchell Jun 06 '16 at 11:17
  • Yes, I verified it, as you said, I could perform it in a single thread, there is no affect in the frame rate. I just thought, since you said me before, if we make use of more number of threads parallel to the main thread, we could improve our frame rate, so that is the reason I just asked you, and regarding the processing , it is the same process what i have been implementing for the first led (i.e to find mean pixel value and comparing with the threshold and to save it as 1 or 0), so i'm wondering, what would be better to continue it in a single thread or to do it in a multiple threads ? – Lohith Kumar Jun 06 '16 at 12:12
  • You have to measure it - it is the only way. If there is no work for 3 threads to do, there is no advantage to having 3 threads. If it takes 10ms to do the `Camera.grab`, and you do no processing, you will get 100fps. If you do 10ms of processing in the main thread before grabbing the next frame, your frame rate will drop to 50fps, whereas if you do that 10ms of processing in a separate thread, your frame rate will stay at 100fps. – Mark Setchell Jun 06 '16 at 12:46