Как мне захватить и обработать каждый кадр изображения с помощью библиотеки CImg?

Я работаю над проектом, основанным на обработке изображений в реальном времени с использованием библиотеки CImg в Raspberrypi.

Мне нужно захватывать изображения с более высокой частотой кадров (скажем, по крайней мере 30 кадров в секунду), когда я использую встроенные команды Raspicam, такие как

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

/ * -tl: длительность промежутка в мсек.
-t: общая продолжительность (1000 мсек = 1 с)
-a: отображает номера кадров
* /

с помощью этой команды, хотя она показывает 34 кадра в секунду, я могу захватить максимум 4 кадра / изображения (а остальные кадры пропускаются)

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

С помощью этой команды я мог снимать со скоростью не более 7-8 изображений в секунду, но уменьшая разрешение и качество изображений.

Но я не хочу идти на компромисс с качеством изображения, так как я буду захватывать изображение, обрабатывать его немедленно и удалять изображение для экономии памяти.

Позже я попытался использовать драйверы V4L2 (видео для Linux), чтобы использовать наилучшую производительность камеры, но в Интернете учебники по V4l2 и cimg довольно скудны, я не смог их найти.

Я использовал следующие команды

# 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

(источник : http://www.geeetech.com/wiki/index.php/Raspberry_Pi_Camera_Module)

но я не смог получить достаточно информации об этих параметрах, таких как (stream-mmap & stream-count) что именно и как эти команды помогают мне захватывать 30 кадров / изображений в секунду?

УСЛОВИЯ:

  1. Самое главное, что я не хочу использовать OPENCV, MATLAB или любое другое программное обеспечение для обработки изображений, поскольку моя задача обработки изображений очень проста (т.е. обнаружение мигания светодиодов), а также моя цель — иметь легкий инструмент для выполнения этих операций в стоимость более высокой производительности.

  2. Кроме того, мой программный код должен быть на C или C ++, но не на Python или Java (так как скорость обработки имеет значение!)

  3. Пожалуйста, обратите внимание, что моя цель не в том, чтобы записать видео, а в том, чтобы сделать как можно больше кадров и обработать каждое и каждое отдельное изображение.

Для использования в Cimg я искал несколько документов из справочного руководства, но я не мог понять, как его использовать для своих целей.

Класс cimg_library :: CImgList представляет списки изображений cimg_library :: CImg. Это может быть использовано, например, для хранения разных кадров последовательности изображений.
(источник : http://cimg.eu/reference/group__cimg__overview.html )

  • Я нашел следующие примеры, но я не совсем уверен, соответствует ли это моей задаче

Загрузите список из файла последовательности изображений YUV.

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

параметры
имя файла
Имя файла для чтения данных.
size_x
Ширина изображений.
size_y
Высота изображений.
first_frame
Индекс первого кадра изображения для чтения.
last_frame
Индекс последнего кадра изображения для чтения.
step_frame
Шаг применяется между каждым кадром.
yuv2rgb
Применить YUV к преобразованию RGB во время чтения.

Но здесь мне нужны значения RGB из кадров изображения напрямую без сжатия.

Теперь у меня есть следующий код в OpenCv, который выполняет мою задачу, но я прошу вас помочь мне в реализации того же с использованием библиотек CImg (которая находится в C ++) или любых других облегченных библиотек или чего-то с 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
}
}
}
  • Я новичок в программировании и Raspberry pi, извините, если есть какие-либо ошибки в приведенных выше постановках задач.

«С некоторыми вашими рекомендациями я немного изменил api-код raspicam c ++ и совместил его с функциональностью обработки изображений CIMG»

 #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();}
  • Из этого кода я хотел бы знать, как мы можем получить данные непосредственно из camera.retrieve (data), не сохраняя их в виде файла изображения и получить доступ к данным из буфера изображения, чтобы обработать изображение и затем удалить его.

В соответствии с рекомендациями Марка Сетчелла, в котором я внес небольшие изменения в код и получаю хорошие результаты, но есть ли способ улучшить производительность обработки, чтобы получить более высокую частоту кадров? с этим кодом я могу получить максимум 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();
}

СОБРАННАЯ КОМАНДА ДЛЯ ИСПОЛНЕНИЯ КОДА:

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

И еще один запрос заключается в том, что, когда я использовал обычный код API Raspicam c ++ для выполнения тех же задач (код, о котором я упоминал ранее), я получал почти те же результаты с очень небольшим улучшением производительности (конечно, частота кадров увеличилась с 9,4 FPS до 10 FPS).

Но в коде 1:

Я сохранял изображения на оперативной памяти для обработки, а затем удаляю.
Я не использовал никаких потоков для параллельной обработки.

в коде 2:

Мы не сохраняем изображения на диск и не обрабатываем их напрямую из буфера. И мы также используем потоки для повышения скорости обработки.

к сожалению, хотя мы внесли некоторые изменения в код 2 из кода 1, я не могу получить желаемый результат (который должен выполняться при 30 FPS)

Жду ваших выгодных предложений и любая помощь очень ценится.

заранее спасибо

С уважением
BLV Lohith Kumar

2

Решение

Обновленный ответ

Я обновил свой оригинальный ответ, чтобы показать, как скопировать полученные данные в CImg структура, а также показать 2 рабочих потока, которые затем могут обрабатывать изображение, в то время как основной поток продолжает получать кадры на полной скорости. Это достигает 60 кадров в секунду.

Я не делал никакой обработки внутри рабочих потоков, потому что я не знаю, что вы хотите сделать. Все, что я сделал, это сохранил последний кадр на диск, чтобы показать, что сбор данных в CImg работает. Вы можете иметь 3 рабочих потока. Вы можете передавать один кадр каждому потоку в циклическом порядке или каждый из двух потоков может обрабатывать половину кадра на каждой итерации. Или каждый из 3 потоков обрабатывает одну треть кадра. Вы можете изменить опрашиваемые пробуждения, чтобы использовать переменные условия.

#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();
}

Обратите внимание на время

Вы можете код времени, как это:

#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();

Оригинальный ответ

Я проводил некоторые эксперименты с Raspicam. Я загрузил их код из SourceForge и немного изменил его, чтобы сделать несколько простых тестов только для захвата. Код, который я использовал в итоге, выглядит следующим образом:

#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;
}

мне не нравится cmake поэтому я просто скомпилировал это так:

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

Я обнаружил, что независимо от размеров изображения и более или менее независимо от кодировки (RGB, BGR, GREY) оно достигает 30 кадров в секунду (кадров в секунду).

Единственный способ, которым я мог стать лучше, это сделать следующие изменения:

  • в приведенном выше коде используйте RASPICAM_FORMAT_YUV420, а не все остальное

  • редактирование файла private_impl.cpp и изменение строки 71, чтобы установить частоту кадров на 90.

Если я сделаю это, я смогу достичь 66 кадров в секунду.

Так как Raspberry Pi — это довольно простой процессор с частотой 900 МГц, но с 4 ядрами, я думаю, вы захотите запустить 1-3 дополнительных потока в начале вне цикла, а затем разбудить один или несколько из них, как я уже отмечал в код для обработки данных. Первое, что они должны сделать, это скопировать данные из буфера получения до начала следующего кадра — или иметь несколько буферов и использовать их циклически.

Примечания о потоке

На следующей диаграмме зеленый представляет Camera.grab() где вы получаете изображение, а красный представляет обработку, которую вы делаете после получения изображения. В данный момент вы получаете данные (зеленый), а затем обрабатываете их (красный), прежде чем сможете получить следующий кадр. Обратите внимание, что 3 из 4 ваших процессоров ничего не делают.

введите описание изображения здесь

Я предлагаю вам перенести обработку (красный) на другие процессоры / потоки и продолжать получать новые данные (зеленый) как можно быстрее. Как это:

введите описание изображения здесь

Теперь вы видите, что вы получаете больше кадров (зеленого цвета) в секунду.

1

Другие решения

Других решений пока нет …

По вопросам рекламы [email protected]