Я работаю над проектом, основанным на обработке изображений в реальном времени с использованием библиотеки 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 кадров / изображений в секунду?
УСЛОВИЯ:
Самое главное, что я не хочу использовать OPENCV, MATLAB или любое другое программное обеспечение для обработки изображений, поскольку моя задача обработки изображений очень проста (т.е. обнаружение мигания светодиодов), а также моя цель — иметь легкий инструмент для выполнения этих операций в стоимость более высокой производительности.
Кроме того, мой программный код должен быть на C или C ++, но не на Python или Java (так как скорость обработки имеет значение!)
Пожалуйста, обратите внимание, что моя цель не в том, чтобы записать видео, а в том, чтобы сделать как можно больше кадров и обработать каждое и каждое отдельное изображение.
Для использования в 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
}
}
}
«С некоторыми вашими рекомендациями я немного изменил 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();}
В соответствии с рекомендациями Марка Сетчелла, в котором я внес небольшие изменения в код и получаю хорошие результаты, но есть ли способ улучшить производительность обработки, чтобы получить более высокую частоту кадров? с этим кодом я могу получить максимум 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
Обновленный ответ
Я обновил свой оригинальный ответ, чтобы показать, как скопировать полученные данные в 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 ваших процессоров ничего не делают.
Я предлагаю вам перенести обработку (красный) на другие процессоры / потоки и продолжать получать новые данные (зеленый) как можно быстрее. Как это:
Теперь вы видите, что вы получаете больше кадров (зеленого цвета) в секунду.
Других решений пока нет …