Wie erfasse und verarbeite ich jeden Frame eines Bildes mit der CImg-Bibliothek?
Ich arbeite an einem Projekt, das auf der Echtzeit-Bildverarbeitung mit CImg Library in Raspberrypi basiert.
Ich muss Bilder mit höheren Bildraten (sagen wir mindestens 30 fps) aufnehmen, wenn ich die eingebauten Raspicam-Befehle wie @ verwend
sudo raspistill -o -img_%d.jpg -tl 5 -t 1000 -a 512
/ * -tl: Zeitrafferdauer in ms -t: Gesamtzeitdauer (1000 ms = 1 s) -a: Anzeige der Bildnummern * /
mit diesem Befehl, obwohl er 34 Bilder pro Sekunde anzeigt, konnte ich nur maximal 4 Bilder / Bilder aufnehmen (und der Rest der Bilder wird übersprungen)
sudo raspistill -o -img_%d.jpg -tl 5 -tl 1000 -q 5 -md 7 -w 640 -h 480 -a 512
und Mit dem obigen Befehl konnte ich maximal 7-8 Bilder pro Sekunde aufnehmen, jedoch durch Verringern der Auflösung und Qualität der Bilder.
Aber ich möchte keine Kompromisse bei der Bildqualität eingehen, da ich ein Bild aufnehme, es sofort verarbeite und ein Bild lösche, um Speicherplatz zu sparen.
päter habe ich versucht, mit V4L2-Treibern (Video for Linux) die beste Leistung einer Kamera zu erzielen, aber im Internet sind Tutorials zu V4l2 und CIMG recht rar, ich konnte keine finde
Ich habe die folgenden Befehle verwendet
# 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
(Quelle :http: //www.geeetech.com/wiki/index.php/Raspberry_Pi_Camera_Modul)
aber ich konnte nicht genug Informationen über diese Parameter wie (stream-mmap & stream-count) erhalten, was genau funktioniert und wie helfen mir diese Befehle bei der Erfassung von 30 Bildern / Bildern pro Sekunde?
BEDINGUNGEN
Vor allem möchte ich nicht OPENCV, MATLAB oder eine andere Bildverarbeitungssoftware verwenden, da meine Bildverarbeitungsaufgabe sehr einfach ist (dh das Erkennen von LED-Lichtblinken). Außerdem möchte ich ein leichtes Werkzeug haben, um diese Vorgänge auszuführen auf Kosten einer höheren Leistung.
Und auch mein Programmcode sollte entweder in C oder C ++ sein, aber nicht in Python oder Java (da es auf die Verarbeitungsgeschwindigkeit ankommt!)
Bitte beachten Sie, dass mein Ziel nicht darin besteht, ein Video aufzunehmen, sondern so viele Bilder wie möglich aufzunehmen und jedes einzelne Bild zu verarbeiten.
Für die Verwendung in Cimg habe ich einige Dokumente aus einem Referenzhandbuch durchsucht, aber ich konnte nicht klar verstehen, wie ich es für meinen Zweck verwenden soll.
Die Klasse cimg_library :: CImgList repräsentiert Listen von cimg_library :: CImg-Bildern. Es kann zum Beispiel verwendet werden, um verschiedene Frames einer Bildsequenz zu speichern. (Quelle :http: //cimg.eu/reference/group__cimg__overview.htm )
Ich habe die folgenden Beispiele gefunden, aber ich bin mir nicht ganz sicher, ob es zu meiner Aufgabe passtLaden Sie eine Liste aus einer YUV-Bildsequenzdatei.
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 Dateiname Dateiname, aus dem Daten gelesen werden sollen. size_x Breite der Bilder. size_y Höhe der Bilder. first_frame Index des ersten zu lesenden Einzelbilds. last_frame Index des letzten zu lesenden Einzelbilds. step_frame Schritt, der zwischen den einzelnen Frames angewendet wird. yuv2rgb Wendet YUV beim Lesen auf die RGB-Transformation an.
Aber hier brauche ich RGB-Werte aus einem Bildrahmen direkt ohne Komprimierung.
Nun habe ich den folgenden Code in OpenCv, der meine Aufgabe ausführt, aber ich bitte Sie, mir bei der Implementierung desselben mithilfe von CImg-Bibliotheken (in C ++) oder anderen Lightweight-Bibliotheken oder etwas mit v4l2 zu helfen.
#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
}
}
}
Ich bin ein Anfänger in der Programmierung und in Raspberry pi, bitte entschuldigen Sie, wenn die obigen Problemstellungen Fehler enthalten."Mit einigen Ihrer Empfehlungen habe ich den raspicam c ++ - API-Code leicht modifiziert und mit der CIMG-Bildverarbeitungsfunktion kombiniert."
#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();
}
us diesem Code möchte ich wissen, wie wir die Daten direkt aus camera.retrieve (Daten) abrufen können, ohne sie als Bilddatei zu speichern und auf die Daten aus einem Bildpuffer zuzugreifen, um das Bild zu verarbeiten und es weiter zu löschen .Gemäss den Empfehlungen von Mark Setchell, die ich geringfügig im Code geändert habe und gute Ergebnisse erziele, aber gibt es eine Möglichkeit, die Verarbeitungsleistung zu verbessern, um eine höhere Bildrate zu erzielen? Mit diesem Code kann ich maximal 10 FPS erreichen.
#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();
}
KOMPILIERTER BEFEHL ZUR AUSFÜHRUNG DES CODES:
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
Und eine weitere Abfrage ist, dass ich, als ich normalen Raspicam c ++ API-Code verwendete, um die gleichen Aufgaben auszuführen (den Code, den ich zuvor erwähnt habe), fast die gleichen Ergebnisse mit einer sehr geringfügigen Verbesserung der Leistung erzielt habe (natürlich ist meine Framerate erhöht) von 9,4 FPS bis 10 FPS).
Aber im Code 1:
Ich habe Bilder auf einer RAM-Diskette zur Verarbeitung gespeichert und lösche sie dann. Ich habe keine Threads für die parallele Verarbeitung verwendet.
im Code 2:
Wir speichern keine Bilder auf der Festplatte und verarbeiten sie direkt aus dem Puffer. Außerdem verwenden wir Threads, um die Verarbeitungsgeschwindigkeit zu verbessern.
Leider kann ich, obwohl wir einige Änderungen an Code 2 gegenüber Code 1 vorgenommen haben, nicht die gewünschten Ergebnisse erzielen (was mit 30 FPS durchgeführt werden soll).
Warten auf Ihre günstigen Vorschläge und jede Hilfe wird sehr geschätzt.
Danke im Vorau
it freundlichen Grüßen BLV Lohith Kum