YARP
Yet Another Robot Platform
OpenCVGrabber.cpp
Go to the documentation of this file.
1 /*
2  * SPDX-FileCopyrightText: 2006-2021 Istituto Italiano di Tecnologia (IIT)
3  * SPDX-FileCopyrightText: 2006-2010 RobotCub Consortium
4  * SPDX-FileCopyrightText: 2006 Eric Mislivec
5  * SPDX-License-Identifier: LGPL-2.1-or-later
6  */
7 
8 /*
9  * A YARP frame grabber device driver using OpenCV to implement
10  * image capture from cameras and AVI files.
11  */
12 
13 #include "OpenCVGrabber.h"
14 
15 #include <yarp/dev/Drivers.h>
16 #include <yarp/dev/PolyDriver.h>
17 
18 #include <string>
19 #include <yarp/os/Property.h>
20 #include <yarp/os/Searchable.h>
21 #include <yarp/os/Value.h>
22 #include <yarp/os/Log.h>
23 #include <yarp/os/LogComponent.h>
24 #include <yarp/os/LogStream.h>
25 #include <yarp/sig/Image.h>
26 
27 #include <cstring> // memcpy
28 
29 #include <opencv2/highgui/highgui.hpp>
30 #include <opencv2/imgproc/imgproc.hpp>
31 #include <opencv2/videoio/videoio.hpp>
32 
33 
36 using yarp::dev::Drivers;
39 
40 using yarp::os::Property;
42 using yarp::os::Value;
43 
44 using yarp::sig::ImageOf;
46 
47 using namespace yarp::os;
48 using namespace yarp::sig;
49 using namespace yarp::dev;
50 
51 
52 namespace {
53 YARP_LOG_COMPONENT(OPENCVGRABBER, "yarp.device.opencv_grabber")
54 }
55 
56 
58  m_saidSize = false;
59  m_saidResize = false;
60  m_transpose = false;
61  m_flip_x = false;
62  m_flip_y = false;
63 
64  // Are we capturing from a file or a camera ?
65  std::string file = config.check("movie", Value(""),
66  "if present, read from specified file rather than camera").asString();
67  fromFile = (file!="");
68  if (fromFile) {
69 
70  // Try to open a capture object for the file
71  m_cap.open(file.c_str());
72  if (!m_cap.isOpened()) {
73  yCError(OPENCVGRABBER, "Unable to open file '%s' for capture!", file.c_str());
74  return false;
75  }
76 
77  // Should we loop?
78  m_loop = config.check("loop","if present, loop movie");
79 
80  } else {
81 
82  m_loop = false;
83  int camera_idx =
84  config.check("camera",
85  Value(cv::VideoCaptureAPIs::CAP_ANY),
86  "if present, read from camera identified by this index").asInt32();
87  // Try to open a capture object for the first camera
88  m_cap.open(camera_idx);
89  if (!m_cap.isOpened()) {
90  yCError(OPENCVGRABBER, "Unable to open camera for capture!");
91  return false;
92  }
93  else
94  {
95  yCInfo(OPENCVGRABBER, "Capturing from camera: %d",camera_idx);
96  }
97 
98  if ( config.check("framerate","if present, specifies desired camera device framerate") ) {
99  double m_fps = config.check("framerate", Value(-1)).asFloat64();
100  m_cap.set(cv::VideoCaptureProperties::CAP_PROP_FPS, m_fps);
101  }
102  }
103 
104  if (config.check("flip_x", "if present, flip the image along the x-axis")) {
105  m_flip_x = true;
106  }
107 
108  if (config.check("flip_y", "if present, flip the image along the y-axis")) {
109  m_flip_y = true;
110  }
111 
112  if (config.check("transpose", "if present, rotate the image along of 90 degrees")) {
113  m_transpose = true;
114  }
115 
116  // Extract the desired image size from the configuration if
117  // present, otherwise query the capture device
118  if (config.check("width","if present, specifies desired image width")) {
119  m_w = config.check("width", Value(0)).asInt32();
120  if (!fromFile && m_w>0) {
121  m_cap.set(cv::VideoCaptureProperties::CAP_PROP_FRAME_WIDTH, m_w);
122  }
123  } else {
124  m_w = m_cap.get(cv::VideoCaptureProperties::CAP_PROP_FRAME_WIDTH);
125  }
126 
127  if (config.check("height","if present, specifies desired image height")) {
128  m_h = config.check("height", Value(0)).asInt32();
129  if (!fromFile && m_h>0) {
130  m_cap.set(cv::VideoCaptureProperties::CAP_PROP_FRAME_HEIGHT, m_h);
131  }
132  } else {
133  m_h = m_cap.get(cv::VideoCaptureProperties::CAP_PROP_FRAME_HEIGHT);
134  }
135 
136  // Ignore capture properties - they are unreliable
137 
138  yCInfo(OPENCVGRABBER, "OpenCVGrabber opened");
139  // Success!
140 
141  // save our configuration for future reference
142  m_config.fromString(config.toString());
143 
144  return true;
145 
146 }
147 
148 
158  // Resources will be automatically deinitialized in VideoCapture
159  // destructor
160  return true;
161 }
162 
163 
176  // Must have a capture object
177  if (!m_cap.isOpened()) {
178  image.zero();
179  return false;
180  }
181 
182  // Callers may have not initialized the image dimensions (may happen if this device is not wrapped)
183  if (static_cast<int>(image.width()) != m_w || static_cast<int>(image.height()) != m_h) {
184  image.resize(m_w, m_h);
185  }
186 
187  // Grab and retrieve a frame,
188  cv::Mat bgr;
189  m_cap.read(bgr);
190 
191  if (bgr.empty() && m_loop) {
192  bool ok = open(m_config);
193  if (!ok) {
194  return false;
195  }
196  m_cap.read(bgr);
197  }
198 
199  if (bgr.empty()) {
200  image.zero();
201  return false;
202  }
203 
204  // Memory allocation occurs at the YARP image object
205  cv::Mat frame(image.height(), image.width(), CV_8UC3, image.getRawImage(), image.getRowSize());
206 
207  // Comply with the expected pixel color of the output YARP frame
208  cv::cvtColor(bgr, frame, cv::COLOR_BGR2RGB);
209 
210  if (m_transpose) {
211  cv::Mat transposed;
212  cv::transpose(frame, transposed);
213  image.resize(transposed.cols, transposed.rows); // erases previous content
214  frame = cv::Mat(image.height(), image.width(), CV_8UC3, image.getRawImage(), image.getRowSize());
215  transposed.copyTo(frame);
216  }
217 
218  if (m_flip_x && m_flip_y) {
219  cv::flip(frame, frame, -1);
220  } else if (m_flip_x) {
221  cv::flip(frame, frame, 0);
222  } else if (m_flip_y) {
223  cv::flip(frame, frame, 1);
224  }
225 
226  if (!m_saidSize) {
227  yCDebug(OPENCVGRABBER, "Received image of size %dx%d", frame.cols, frame.rows);
228  m_saidSize = true;
229  }
230 
231  // create the timestamp
232  m_laststamp.update();
233 
234  if (m_w == 0) {
235  m_w = frame.cols;
236  }
237 
238  if (m_h == 0) {
239  m_h = frame.rows;
240  }
241 
242  if (fromFile && (frame.cols != (!m_transpose ? m_w : m_h) || frame.rows != (!m_transpose ? m_h : m_w))) {
243  if (!m_saidResize) {
244  yCDebug(OPENCVGRABBER, "Software scaling from %dx%d to %dx%d", frame.cols, frame.rows, m_w, m_h);
245  m_saidResize = true;
246  }
247 
248  cv::Mat resized;
249  cv::resize(frame, resized, {m_w, m_h});
250  image.resize(resized.cols, resized.rows); // erases previous content
251  frame = cv::Mat(image.height(), image.width(), CV_8UC3, image.getRawImage(), image.getRowSize());
252  resized.copyTo(frame);
253  }
254 
255  yCTrace(OPENCVGRABBER, "%d by %d image", frame.cols, frame.rows);
256 
257  return true;
258 }
bool getImage(yarp::sig::ImageOf< yarp::sig::PixelRgb > &image) override
Read an image from the grabber.
bool close() override
Close a grabber.
bool open(yarp::os::Searchable &config) override
Open the DeviceDriver.
Interface implemented by all device drivers.
Definition: DeviceDriver.h:35
A factory for creating driver objects of a particular type.
Definition: Drivers.h:82
Global factory for devices.
Definition: Drivers.h:172
A container for a device driver.
Definition: PolyDriver.h:24
A class for storing options and configuration information.
Definition: Property.h:34
A base class for nested structures that can be searched.
Definition: Searchable.h:66
virtual bool check(const std::string &key) const =0
Check if there exists a property of the given name.
virtual std::string toString() const =0
Return a standard text representation of the content of the object.
A single value (typically within a Bottle).
Definition: Value.h:45
Typed image class.
Definition: Image.h:658
size_t width() const
Gets width of image in pixels.
Definition: Image.h:166
size_t getRowSize() const
Size of the underlying image buffer rows.
Definition: Image.h:192
unsigned char * getRawImage() const
Access to the internal image buffer.
Definition: Image.cpp:541
void resize(size_t imgWidth, size_t imgHeight)
Reallocate an image to be of a desired size, throwing away its current contents.
Definition: Image.cpp:452
void zero()
Set all pixels to 0.
Definition: Image.cpp:445
size_t height() const
Gets height of image in pixels.
Definition: Image.h:172
#define yCInfo(component,...)
Definition: LogComponent.h:132
#define yCError(component,...)
Definition: LogComponent.h:154
#define yCTrace(component,...)
Definition: LogComponent.h:85
#define yCDebug(component,...)
Definition: LogComponent.h:109
#define YARP_LOG_COMPONENT(name,...)
Definition: LogComponent.h:77
An interface for the device drivers.
IFrameGrabberOf< yarp::sig::ImageOf< yarp::sig::PixelRgb > > IFrameGrabberImage
An interface to the operating system, including Port based communication.
Signal processing.
Definition: Image.h:22
Packed RGB pixel type.
Definition: Image.h:464