YARP
Yet Another Robot Platform
OpenCVGrabber.cpp
Go to the documentation of this file.
1 /*
2  * Copyright (C) 2006-2020 Istituto Italiano di Tecnologia (IIT)
3  * Copyright (C) 2006-2010 RobotCub Consortium
4  * Copyright (C) 2006 Eric Mislivec
5  *
6  * This library is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU Lesser General Public
8  * License as published by the Free Software Foundation; either
9  * version 2.1 of the License, or (at your option) any later version.
10  *
11  * This library is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14  * Lesser General Public License for more details.
15  *
16  * You should have received a copy of the GNU Lesser General Public
17  * License along with this library; if not, write to the Free Software
18  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
19  */
20 
21 /*
22  * A YARP frame grabber device driver using OpenCV to implement
23  * image capture from cameras and AVI files.
24  */
25 
26 #include "OpenCVGrabber.h"
27 
28 #include <yarp/dev/Drivers.h>
30 #include <yarp/dev/PolyDriver.h>
31 
32 #include <string>
33 #include <yarp/os/Property.h>
34 #include <yarp/os/Searchable.h>
35 #include <yarp/os/Value.h>
36 #include <yarp/os/Log.h>
37 #include <yarp/os/LogComponent.h>
38 #include <yarp/os/LogStream.h>
39 #include <yarp/sig/Image.h>
40 
41 #include <cstring> // memcpy
42 
43 #include <opencv2/highgui/highgui.hpp>
44 #include <opencv2/imgproc/imgproc.hpp>
45 
46 #if CV_MAJOR_VERSION >= 3
47 #include <opencv2/videoio/videoio.hpp>
48 #endif
49 
50 
53 using yarp::dev::Drivers;
56 
57 using yarp::os::Property;
59 using yarp::os::Value;
60 
61 using yarp::sig::ImageOf;
63 
64 using namespace yarp::os;
65 using namespace yarp::sig;
66 using namespace yarp::dev;
67 
68 
69 namespace {
70 YARP_LOG_COMPONENT(OPENCVGRABBER, "yarp.device.opencv_grabber")
71 }
72 
73 
75  m_saidSize = false;
76  m_saidResize = false;
77  m_transpose = false;
78  m_flip_x = false;
79  m_flip_y = false;
80 
81  // Are we capturing from a file or a camera ?
82  std::string file = config.check("movie", Value(""),
83  "if present, read from specified file rather than camera").asString();
84  fromFile = (file!="");
85  if (fromFile) {
86 
87  // Try to open a capture object for the file
88  m_cap.open(file.c_str());
89  if (!m_cap.isOpened()) {
90  yCError(OPENCVGRABBER, "Unable to open file '%s' for capture!", file.c_str());
91  return false;
92  }
93 
94  // Should we loop?
95  m_loop = config.check("loop","if present, loop movie");
96 
97  } else {
98 
99  m_loop = false;
100 #if CV_MAJOR_VERSION >= 3
101  int camera_idx =
102  config.check("camera",
103  Value(cv::VideoCaptureAPIs::CAP_ANY),
104  "if present, read from camera identified by this index").asInt32();
105 #else
106  int camera_idx =
107  config.check("camera",
108  Value(CV_CAP_ANY),
109  "if present, read from camera identified by this index").asInt32();
110 #endif
111  // Try to open a capture object for the first camera
112  m_cap.open(camera_idx);
113  if (!m_cap.isOpened()) {
114  yCError(OPENCVGRABBER, "Unable to open camera for capture!");
115  return false;
116  }
117  else
118  {
119  yCInfo(OPENCVGRABBER, "Capturing from camera: %d",camera_idx);
120  }
121 
122  if ( config.check("framerate","if present, specifies desired camera device framerate") ) {
123  double m_fps = config.check("framerate", Value(-1)).asFloat64();
124 #if CV_MAJOR_VERSION >= 3
125  m_cap.set(cv::VideoCaptureProperties::CAP_PROP_FPS, m_fps);
126 #else
127  m_cap.set(CV_CAP_PROP_FPS, m_fps);
128 #endif
129  }
130 
131  if (config.check("flip_x", "if present, flip the image along the x-axis")) m_flip_x = true;
132  if (config.check("flip_y", "if present, flip the image along the y-axis")) m_flip_y = true;
133  if (config.check("transpose", "if present, rotate the image along of 90 degrees")) m_transpose = true;
134  }
135 
136 
137  // Extract the desired image size from the configuration if
138  // present, otherwise query the capture device
139  if (config.check("width","if present, specifies desired image width")) {
140  m_w = config.check("width", Value(0)).asInt32();
141  if (!fromFile && m_w>0) {
142 #if CV_MAJOR_VERSION >= 3
143  m_cap.set(cv::VideoCaptureProperties::CAP_PROP_FRAME_WIDTH, m_w);
144 #else
145  m_cap.set(CV_CAP_PROP_FRAME_WIDTH, m_w);
146 #endif
147  }
148  } else {
149 #if CV_MAJOR_VERSION >= 3
150  m_w = (size_t)m_cap.get(cv::VideoCaptureProperties::CAP_PROP_FRAME_WIDTH);
151 #else
152  m_w = (size_t)m_cap.get(CV_CAP_PROP_FRAME_WIDTH);
153 #endif
154  }
155 
156  if (config.check("height","if present, specifies desired image height")) {
157  m_h = config.check("height", Value(0)).asInt32();
158  if (!fromFile && m_h>0) {
159 #if CV_MAJOR_VERSION >= 3
160  m_cap.set(cv::VideoCaptureProperties::CAP_PROP_FRAME_HEIGHT, m_h);
161 #else
162  m_cap.set(CV_CAP_PROP_FRAME_HEIGHT, m_h);
163 #endif
164  }
165  } else {
166 #if CV_MAJOR_VERSION >= 3
167  m_h = (size_t)m_cap.get(cv::VideoCaptureProperties::CAP_PROP_FRAME_HEIGHT);
168 #else
169  m_h = (size_t)m_cap.get(CV_CAP_PROP_FRAME_HEIGHT);
170 #endif
171  }
172 
173  // Ignore capture properties - they are unreliable
174 
175  yCInfo(OPENCVGRABBER, "OpenCVGrabber opened");
176  // Success!
177 
178  // save our configuration for future reference
179  m_config.fromString(config.toString());
180 
181  return true;
182 
183 }
184 
185 
195  // Resources will be automatically deinitialized in VideoCapture
196  // destructor
197  return true;
198 }
199 
200 
212 bool OpenCVGrabber::sendImage(const cv::Mat & frame, ImageOf<PixelRgb> & image)
213 {
214  // Resize the output image, this should not result in new
215  // memory allocation if the image is already the correct size
216  image.resize(frame.cols, frame.rows);
217 
218  if (!m_saidSize) {
219  yCDebug(OPENCVGRABBER, "Received image of size %zux%zu", image.width(), image.height());
220  m_saidSize = true;
221  }
222 
223  // create the timestamp
224  m_laststamp.update();
225 
226  // Convert to RGB color space
227  cv::Mat frame_rgb;
228  cv::cvtColor(frame, frame_rgb, cv::COLOR_BGR2RGB);
229 
230  // Copy the captured image to the output image
231  memcpy(image.getRawImage(), frame_rgb.data, sizeof(unsigned char) * frame_rgb.rows * frame_rgb.cols * frame_rgb.channels());
232 
233  if (m_w == 0) {
234  m_w = image.width();
235  }
236  if (m_h == 0) {
237  m_h = image.height();
238  }
239  if (fromFile) {
240  if (m_w>0 && m_h>0) {
241  if (image.width() != m_w || image.height() != m_h) {
242  if (!m_saidResize) {
243  yCDebug(OPENCVGRABBER, "Software scaling from %zux%zu to %zux%zu", image.width(), image.height(), m_w, m_h);
244  m_saidResize = true;
245  }
246  image.copy(image, m_w, m_h);
247  }
248  }
249  }
250 
251  yCTrace(OPENCVGRABBER, "%zu by %zu image", image.width(), image.height());
252 
253  return true;
254 
255 }
256 
258 
259  // Must have a capture object
260  if (!m_cap.isOpened()) {
261  image.zero();
262  return false;
263  }
264 
265  // Grab and retrieve a frame
266  cv::Mat frame;
267  m_cap.read(frame);
268 
269  if (frame.empty() && m_loop) {
270  bool ok = open(m_config);
271  if (!ok) return false;
272  m_cap.read(frame);
273  }
274 
275  if (frame.empty()) {
276  image.zero();
277  return false;
278  }
279 
280  if (m_transpose)
281  {
282  cv::transpose(frame, frame);
283  }
284 
285  if (m_flip_x && m_flip_y)
286  {
287  cv::flip(frame, frame, -1);
288  }
289  else if (m_flip_x)
290  {
291  cv::flip(frame, frame, 0);
292  }
293  else if (m_flip_y)
294  {
295  cv::flip(frame, frame, 1);
296  }
297 
298  return sendImage(frame, image);
299 }
300 
301 
302 // End: OpenCVGrabber.cpp
define common interfaces to discover remote camera capabilities
virtual bool sendImage(const cv::Mat &frame, yarp::sig::ImageOf< yarp::sig::PixelRgb > &image)
Read an image from the grabber.
bool getImage(yarp::sig::ImageOf< yarp::sig::PixelRgb > &image) override
Get an rgb image from the frame grabber, if required demosaicking/color reconstruction is applied.
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:38
A factory for creating driver objects of a particular type.
Definition: Drivers.h:85
Global factory for devices.
Definition: Drivers.h:175
Read a YARP-format image from a device.
A container for a device driver.
Definition: PolyDriver.h:27
A class for storing options and configuration information.
Definition: Property.h:37
A base class for nested structures that can be searched.
Definition: Searchable.h:69
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:47
Typed image class.
Definition: Image.h:647
size_t width() const
Gets width of image in pixels.
Definition: Image.h:153
unsigned char * getRawImage() const
Access to the internal image buffer.
Definition: Image.cpp:535
bool copy(const Image &alt)
Copy operator.
Definition: Image.cpp:847
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:467
void zero()
Set all pixels to 0.
Definition: Image.cpp:460
size_t height() const
Gets height of image in pixels.
Definition: Image.h:159
#define yCInfo(component,...)
Definition: LogComponent.h:135
#define yCError(component,...)
Definition: LogComponent.h:157
#define yCTrace(component,...)
Definition: LogComponent.h:88
#define yCDebug(component,...)
Definition: LogComponent.h:112
#define YARP_LOG_COMPONENT(name,...)
Definition: LogComponent.h:80
An interface for the device drivers.
An interface to the operating system, including Port based communication.
Signal processing.
Definition: Image.h:25
Packed RGB pixel type.
Definition: Image.h:453