1 #include <visp3/core/vpConfig.h> 10 #if defined(VISP_HAVE_CPP11_COMPATIBILITY) && defined(VISP_HAVE_V4L2) && ( defined(VISP_HAVE_X11) || defined(VISP_HAVE_GTK) ) 17 #include <condition_variable> 19 #include <visp3/sensor/vpV4l2Grabber.h> 20 #include <visp3/core/vpIoTools.h> 21 #include <visp3/core/vpImageFilter.h> 22 #include <visp3/core/vpDisplay.h> 23 #include <visp3/core/vpTime.h> 24 #include <visp3/gui/vpDisplayX.h> 25 #include <visp3/gui/vpDisplayGTK.h> 26 #include <visp3/io/vpParseArgv.h> 27 #include <visp3/io/vpVideoWriter.h> 30 #define GETOPTARGS "d:oh" 35 void usage(
const char *name,
const char *badparam)
39 %s [-d <device count>] [-o] [-h]\n\ 42 Capture multiple camera streams and save the stream without slowing down the acquisition.\n\ 46 Open the specified number of camera streams.\n\ 49 Save each stream in a dedicated folder.\n\ 56 fprintf(stdout,
"\nERROR: Bad parameter [%s]\n", badparam);
59 bool getOptions(
int argc,
char **argv,
60 unsigned int &deviceCount,
64 const char **argv1=(
const char**)argv;
69 case 'd': deviceCount = (
unsigned int) atoi(optarg);
break;
70 case 'o': saveVideo =
true;
break;
71 case 'h': usage(argv[0], NULL);
return false;
break;
74 usage(argv[0], optarg);
79 if ((c == 1) || (c == -1)) {
82 std::cerr <<
"ERROR: " << std::endl;
83 std::cerr <<
" Bad argument " << optarg << std::endl << std::endl;
97 FrameQueue() : m_cancelled(false), m_cond(), m_queueColor(), m_maxQueueSize(
std::numeric_limits<size_t>::max()), m_mutex() {
101 std::lock_guard<std::mutex> lock(m_mutex);
108 std::lock_guard<std::mutex> lock(m_mutex);
110 m_queueColor.push(image);
113 while(m_queueColor.size() > m_maxQueueSize) {
122 std::unique_lock<std::mutex> lock(m_mutex);
124 while (m_queueColor.empty()) {
142 void setMaxQueueSize(
const size_t max_queue_size) {
143 m_maxQueueSize = max_queue_size;
148 std::condition_variable m_cond;
149 std::queue<vpImage<vpRGBa> > m_queueColor;
150 size_t m_maxQueueSize;
155 class StorageWorker {
158 StorageWorker(FrameQueue &queue,
const std::string &filename,
159 const unsigned int width,
const unsigned int height) :
160 m_queue(queue), m_filename(filename), m_width(width), m_height(height) {
168 if(!m_filename.empty()) {
170 writer.
open(O_color);
177 if(!m_filename.empty()) {
181 }
catch (FrameQueue::cancelled &) {
187 std::string m_filename;
188 unsigned int m_width;
189 unsigned int m_height;
197 std::condition_variable m_cond;
199 unsigned char *m_pImgData;
200 unsigned int m_totalSize;
206 ShareImage() : m_cancelled(false), m_cond(), m_mutex(), m_pImgData(NULL), m_totalSize(0) {
209 virtual ~ShareImage() {
210 if(m_pImgData != NULL) {
216 std::lock_guard<std::mutex> lock(m_mutex);
222 void getImage(
unsigned char *
const imageData,
const unsigned int totalSize) {
223 std::unique_lock<std::mutex> lock(m_mutex);
236 if(totalSize <= m_totalSize) {
237 memcpy(imageData, m_pImgData, totalSize*
sizeof(
unsigned char));
239 std::cerr <<
"totalSize <= m_totalSize !" << std::endl;
244 std::lock_guard<std::mutex> lock(m_mutex);
249 void setImage(
const unsigned char *
const imageData,
const unsigned int totalSize) {
250 std::lock_guard<std::mutex> lock(m_mutex);
252 if(m_pImgData == NULL || m_totalSize != totalSize) {
253 m_totalSize = totalSize;
255 if(m_pImgData != NULL) {
259 m_pImgData =
new unsigned char[m_totalSize];
263 memcpy(m_pImgData, imageData, m_totalSize*
sizeof(
unsigned char));
270 void capture(
vpV4l2Grabber *
const pGrabber, ShareImage &share_image) {
274 pGrabber->
open(local_img);
277 if(share_image.isCancelled()) {
284 share_image.setImage((
unsigned char *) local_img.
bitmap, local_img.
getSize()*4);
288 void display(
const unsigned int width,
const unsigned int height,
const int win_x,
const int win_y,
289 const unsigned int deviceId, ShareImage &share_image, FrameQueue &queue,
const bool save) {
292 #if defined VISP_HAVE_X11 294 #elif defined VISP_HAVE_GTK 299 std::stringstream ss;
300 ss <<
"Camera stream " << deviceId;
301 display.
init(local_img, win_x, win_y, ss.str());
306 vpImage<unsigned char> I_red(height, width), I_green(height, width), I_blue(height, width), I_alpha(height, width);;
307 vpImage<unsigned char> I_red_gaussian(height, width), I_green_gaussian(height, width), I_blue_gaussian(height, width);
308 vpImage<double> I_red_gaussian_double, I_green_gaussian_double, I_blue_gaussian_double;
310 bool exit =
false, gaussian_blur =
false;
315 share_image.getImage((
unsigned char *) local_img.
bitmap, local_img.
getSize()*4);
337 std::stringstream ss;
338 ss <<
"Time: " << t <<
" ms";
348 queue.push(local_img);
354 gaussian_blur = !gaussian_blur;
363 }
catch(ShareImage::cancelled &) {
364 std::cout <<
"Cancelled!" << std::endl;
367 share_image.cancel();
373 int main(
int argc,
char *argv[])
375 unsigned int deviceCount = 1;
376 unsigned int cameraScale = 1;
377 bool saveVideo =
false;
380 if (!getOptions(argc, argv, deviceCount, saveVideo)) {
384 std::vector<vpV4l2Grabber *> grabbers;
386 const unsigned int offsetX = 100, offsetY = 100;
387 for(
unsigned int devicedId = 0; devicedId < deviceCount; devicedId++) {
390 std::stringstream ss;
391 ss <<
"/dev/video" << devicedId;
395 grabbers.push_back(pGrabber);
397 std::cerr <<
"Exception: " << e.
what() << std::endl;
401 std::cout <<
"Grabbers: " << grabbers.size() << std::endl;
403 std::vector<ShareImage> share_images(grabbers.size());
404 std::vector<std::thread> capture_threads;
405 std::vector<std::thread> display_threads;
408 std::vector<FrameQueue> save_queues(grabbers.size());
409 std::vector<StorageWorker> storages;
410 std::vector<std::thread> storage_threads;
414 std::cout <<
"Create parent_directory: " << parent_directory << std::endl;
418 for(
size_t deviceId = 0; deviceId < grabbers.size(); deviceId++) {
420 capture_threads.emplace_back( capture, grabbers[deviceId], std::ref(share_images[deviceId]) );
421 int win_x = deviceId * offsetX, win_y = deviceId * offsetY;
424 display_threads.emplace_back( display, grabbers[deviceId]->getWidth(), grabbers[deviceId]->getHeight(),
425 win_x, win_y, deviceId, std::ref(share_images[deviceId]),
426 std::ref(save_queues[deviceId]), saveVideo );
429 std::stringstream ss;
430 ss << parent_directory <<
"/Camera_Stream" << deviceId;
431 std::cout <<
"Create directory: " << ss.str() << std::endl;
434 std::string filename = ss.str();
436 storages.emplace_back( std::ref(save_queues[deviceId]), std::cref(filename),
437 grabbers[deviceId]->getWidth(), grabbers[deviceId]->getHeight() );
442 for(
auto& s : storages) {
444 storage_threads.emplace_back(&StorageWorker::run, &s);
449 for(
auto& ct : capture_threads) {
453 for (
auto& dt : display_threads) {
458 for(
auto& g : grabbers) {
463 std::cout <<
"\nWaiting for finishing thread to write images..." << std::endl;
467 for (
auto& qu : save_queues) {
472 for (
auto& st : storage_threads) {
483 std::cout <<
"Warning: This example need to be build with cxx11 compiler flags, v4l2 and x11 or gtk 3rd partiess. " << std::endl;
void acquire(vpImage< unsigned char > &I)
static bool getClick(const vpImage< unsigned char > &I, bool blocking=true)
void open(vpImage< unsigned char > &I)
static void convert(const vpImage< unsigned char > &src, vpImage< vpRGBa > &dest)
Type * bitmap
points toward the bitmap
static void displayText(const vpImage< unsigned char > &I, const vpImagePoint &ip, const std::string &s, const vpColor &color)
Use the X11 console to display images on unix-like OS. Thus to enable this class X11 should be instal...
void setDevice(const std::string &devname)
error that can be emited by ViSP classes.
static void split(const vpImage< vpRGBa > &src, vpImage< unsigned char > *pR, vpImage< unsigned char > *pG, vpImage< unsigned char > *pB, vpImage< unsigned char > *pa=NULL)
static void flush(const vpImage< unsigned char > &I)
VISP_EXPORT double measureTimeMs()
VISP_EXPORT std::string getDateTime(const std::string &format="%Y/%m/%d %H:%M:%S")
static bool parse(int *argcPtr, const char **argv, vpArgvInfo *argTable, int flags)
static void display(const vpImage< unsigned char > &I)
static void gaussianBlur(const vpImage< unsigned char > &I, vpImage< double > &GI, unsigned int size=7, double sigma=0., bool normalize=true)
Class that enables to write easily a video file or a sequence of images.
The vpDisplayGTK allows to display image using the GTK 3rd party library. Thus to enable this class G...
void saveFrame(vpImage< vpRGBa > &I)
void setScale(unsigned scale=vpV4l2Grabber::DEFAULT_SCALE)
void open(vpImage< vpRGBa > &I)
const char * what() const
void setFileName(const char *filename)
static void merge(const vpImage< unsigned char > *R, const vpImage< unsigned char > *G, const vpImage< unsigned char > *B, const vpImage< unsigned char > *a, vpImage< vpRGBa > &RGBa)
void init(vpImage< unsigned char > &I, int winx=-1, int winy=-1, const std::string &title="")
Class that is a wrapper over the Video4Linux2 (V4L2) driver.
unsigned int getSize() const