This tutorial expains how to grab ultrasound images from the sonosite 180 plus connected with a BNC cable to the computer and using Visp v4l2 grabber.
Note that the source code used in this tutorial can be downloaded using the following command :
To grab ultrasound images from the sonosite and display them, you will need to use the ViSP v4l2 grabber, vpDisplay and multi-threading. Here is some example code :
#include <iostream>
#include <visp3/core/vpImageConvert.h>
#include <visp3/core/vpMutex.h>
#include <visp3/core/vpThread.h>
#include <visp3/core/vpTime.h>
#include <visp3/gui/vpDisplayX.h>
#include <visp3/sensor/vpV4l2Grabber.h>
#include <visp3/ustk_core/usImagePostScan2D.h>
#if defined(VISP_HAVE_V4L2) && defined(VISP_HAVE_PTHREAD)
typedef enum { capture_waiting, capture_started, capture_stopped } t_CaptureState;
t_CaptureState s_capture_state = capture_waiting;
vpImage<unsigned char> s_frame;
vpMutex s_mutex_capture;
vpThread::Return captureFunction(vpThread::Args args)
{
vpV4l2Grabber cap = *((vpV4l2Grabber *)args);
vpImage<unsigned char> frame_;
bool stop_capture_ = false;
cap.open(frame_);
vpRect roi(vpImagePoint(48, 90), vpImagePoint(416, 550));
while (!stop_capture_) {
cap.acquire(frame_, roi);
{
vpMutex::vpScopedLock lock(s_mutex_capture);
if (s_capture_state == capture_stopped)
stop_capture_ = true;
else
s_capture_state = capture_started;
s_frame = frame_;
}
}
{
vpMutex::vpScopedLock lock(s_mutex_capture);
s_capture_state = capture_stopped;
}
std::cout << "End of capture thread" << std::endl;
return 0;
}
vpThread::Return displayFunction(vpThread::Args args)
{
(void)args;
vpImage<unsigned char> I_;
t_CaptureState capture_state_;
bool display_initialized_ = false;
#if defined(VISP_HAVE_X11)
vpDisplayX *d_ = NULL;
#endif
do {
s_mutex_capture.lock();
capture_state_ = s_capture_state;
s_mutex_capture.unlock();
if (capture_state_ == capture_started) {
{
vpMutex::vpScopedLock lock(s_mutex_capture);
I_ = s_frame;
}
if (!display_initialized_) {
#if defined(VISP_HAVE_X11)
d_ = new vpDisplayX(postScan_);
display_initialized_ = true;
#endif
}
vpDisplay::display(postScan_);
vpDisplay::displayText(postScan_, 10, 10, "Click to exit...", vpColor::red);
if (vpDisplay::getClick(postScan_, false)) {
vpMutex::vpScopedLock lock(s_mutex_capture);
s_capture_state = capture_stopped;
}
vpDisplay::flush(postScan_);
} else {
vpTime::wait(2);
}
} while (capture_state_ != capture_stopped);
#if defined(VISP_HAVE_X11)
delete d_;
#endif
std::cout << "End of display thread" << std::endl;
return 0;
}
int main(int argc, const char *argv[])
{
unsigned int opt_input = 1;
for (int i = 0; i < argc; i++) {
if (std::string(argv[i]) == "--input")
opt_input = (unsigned int)atoi(argv[i + 1]);
else if (std::string(argv[i]) == "--help") {
std::cout << "Usage: " << argv[0] << " [--input <number>] [--help]" << std::endl;
return 0;
}
}
vpV4l2Grabber g;
g.setInput(opt_input);
g.setScale(1);
vpThread thread_capture((vpThread::Fn)captureFunction, (vpThread::Args)&g);
vpThread thread_display((vpThread::Fn)displayFunction);
thread_capture.join();
thread_display.join();
return 0;
}
#else
int main()
{
#ifndef VISP_HAVE_V4L2
std::cout << "You should enable V4L2 to make this example working..." << std::endl;
#elif !defined(_WIN32) && (defined(__unix__) || defined(__unix) || (defined(__APPLE__) && defined(__MACH__)))
std::cout << "You should enable pthread usage and rebuild ViSP..." << std::endl;
#else
std::cout << "Multi-threading seems not supported on this platform" << std::endl;
#endif
}
#endif
void setData(const vpImage< Type > &image)
void setTransducerConvexity(const bool isTransducerConvex)
void setScanLinePitch(const double scanLinePitch)
void setProbeName(std::string probeName)
void setTransducerRadius(const double transducerRadius)
void setScanLineNumber(unsigned int scanLineNumber)
Note that filling the probe settings (raduis, depth, fov) is important if you want to apply some processes on the image (back-scan conversion, visual servoing ...).