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 #include <opencv2/videoio/videoio.hpp>
46 
47 
50 using yarp::dev::Drivers;
53 
54 using yarp::os::Property;
56 using yarp::os::Value;
57 
58 using yarp::sig::ImageOf;
60 
61 using namespace yarp::os;
62 using namespace yarp::sig;
63 using namespace yarp::dev;
64 
65 
66 namespace {
67 YARP_LOG_COMPONENT(OPENCVGRABBER, "yarp.device.opencv_grabber")
68 }
69 
70 
72  m_saidSize = false;
73  m_saidResize = false;
74  m_transpose = false;
75  m_flip_x = false;
76  m_flip_y = false;
77 
78  // Are we capturing from a file or a camera ?
79  std::string file = config.check("movie", Value(""),
80  "if present, read from specified file rather than camera").asString();
81  fromFile = (file!="");
82  if (fromFile) {
83 
84  // Try to open a capture object for the file
85  m_cap.open(file.c_str());
86  if (!m_cap.isOpened()) {
87  yCError(OPENCVGRABBER, "Unable to open file '%s' for capture!", file.c_str());
88  return false;
89  }
90 
91  // Should we loop?
92  m_loop = config.check("loop","if present, loop movie");
93 
94  } else {
95 
96  m_loop = false;
97  int camera_idx =
98  config.check("camera",
99  Value(cv::VideoCaptureAPIs::CAP_ANY),
100  "if present, read from camera identified by this index").asInt32();
101  // Try to open a capture object for the first camera
102  m_cap.open(camera_idx);
103  if (!m_cap.isOpened()) {
104  yCError(OPENCVGRABBER, "Unable to open camera for capture!");
105  return false;
106  }
107  else
108  {
109  yCInfo(OPENCVGRABBER, "Capturing from camera: %d",camera_idx);
110  }
111 
112  if ( config.check("framerate","if present, specifies desired camera device framerate") ) {
113  double m_fps = config.check("framerate", Value(-1)).asFloat64();
114  m_cap.set(cv::VideoCaptureProperties::CAP_PROP_FPS, m_fps);
115  }
116 
117  if (config.check("flip_x", "if present, flip the image along the x-axis")) m_flip_x = true;
118  if (config.check("flip_y", "if present, flip the image along the y-axis")) m_flip_y = true;
119  if (config.check("transpose", "if present, rotate the image along of 90 degrees")) m_transpose = true;
120  }
121 
122 
123  // Extract the desired image size from the configuration if
124  // present, otherwise query the capture device
125  if (config.check("width","if present, specifies desired image width")) {
126  m_w = config.check("width", Value(0)).asInt32();
127  if (!fromFile && m_w>0) {
128  m_cap.set(cv::VideoCaptureProperties::CAP_PROP_FRAME_WIDTH, m_w);
129  }
130  } else {
131  m_w = (size_t)m_cap.get(cv::VideoCaptureProperties::CAP_PROP_FRAME_WIDTH);
132  }
133 
134  if (config.check("height","if present, specifies desired image height")) {
135  m_h = config.check("height", Value(0)).asInt32();
136  if (!fromFile && m_h>0) {
137  m_cap.set(cv::VideoCaptureProperties::CAP_PROP_FRAME_HEIGHT, m_h);
138  }
139  } else {
140  m_h = (size_t)m_cap.get(cv::VideoCaptureProperties::CAP_PROP_FRAME_HEIGHT);
141  }
142 
143  // Ignore capture properties - they are unreliable
144 
145  yCInfo(OPENCVGRABBER, "OpenCVGrabber opened");
146  // Success!
147 
148  // save our configuration for future reference
149  m_config.fromString(config.toString());
150 
151  return true;
152 
153 }
154 
155 
165  // Resources will be automatically deinitialized in VideoCapture
166  // destructor
167  return true;
168 }
169 
170 
182 bool OpenCVGrabber::sendImage(const cv::Mat & frame, ImageOf<PixelRgb> & image)
183 {
184  // Resize the output image, this should not result in new
185  // memory allocation if the image is already the correct size
186  image.resize(frame.cols, frame.rows);
187 
188  if (!m_saidSize) {
189  yCDebug(OPENCVGRABBER, "Received image of size %zux%zu", image.width(), image.height());
190  m_saidSize = true;
191  }
192 
193  // create the timestamp
194  m_laststamp.update();
195 
196  // Convert to RGB color space
197  cv::Mat frame_rgb;
198  cv::cvtColor(frame, frame_rgb, cv::COLOR_BGR2RGB);
199 
200  // Copy the captured image to the output image
201  memcpy(image.getRawImage(), frame_rgb.data, sizeof(unsigned char) * frame_rgb.rows * frame_rgb.cols * frame_rgb.channels());
202 
203  if (m_w == 0) {
204  m_w = image.width();
205  }
206  if (m_h == 0) {
207  m_h = image.height();
208  }
209  if (fromFile) {
210  if (m_w>0 && m_h>0) {
211  if (image.width() != m_w || image.height() != m_h) {
212  if (!m_saidResize) {
213  yCDebug(OPENCVGRABBER, "Software scaling from %zux%zu to %zux%zu", image.width(), image.height(), m_w, m_h);
214  m_saidResize = true;
215  }
216  image.copy(image, m_w, m_h);
217  }
218  }
219  }
220 
221  yCTrace(OPENCVGRABBER, "%zu by %zu image", image.width(), image.height());
222 
223  return true;
224 
225 }
226 
228 
229  // Must have a capture object
230  if (!m_cap.isOpened()) {
231  image.zero();
232  return false;
233  }
234 
235  // Grab and retrieve a frame
236  cv::Mat frame;
237  m_cap.read(frame);
238 
239  if (frame.empty() && m_loop) {
240  bool ok = open(m_config);
241  if (!ok) return false;
242  m_cap.read(frame);
243  }
244 
245  if (frame.empty()) {
246  image.zero();
247  return false;
248  }
249 
250  if (m_transpose)
251  {
252  cv::transpose(frame, frame);
253  }
254 
255  if (m_flip_x && m_flip_y)
256  {
257  cv::flip(frame, frame, -1);
258  }
259  else if (m_flip_x)
260  {
261  cv::flip(frame, frame, 0);
262  }
263  else if (m_flip_y)
264  {
265  cv::flip(frame, frame, 1);
266  }
267 
268  return sendImage(frame, image);
269 }
270 
271 
272 // End: OpenCVGrabber.cpp
LogStream.h
yarp::os::Searchable
A base class for nested structures that can be searched.
Definition: Searchable.h:69
yarp::sig
Signal processing.
Definition: Image.h:25
Drivers.h
yarp::dev::DriverCreatorOf
A factory for creating driver objects of a particular type.
Definition: Drivers.h:85
yarp::os::Searchable::toString
virtual std::string toString() const =0
Return a standard text representation of the content of the object.
yarp::dev::DeviceDriver
Interface implemented by all device drivers.
Definition: DeviceDriver.h:38
YARP_LOG_COMPONENT
#define YARP_LOG_COMPONENT(name,...)
Definition: LogComponent.h:80
Searchable.h
yarp::dev
An interface for the device drivers.
Definition: audioBufferSizeData.cpp:17
yarp::sig::ImageOf
Typed image class.
Definition: Image.h:647
OpenCVGrabber::open
bool open(yarp::os::Searchable &config) override
Open the DeviceDriver.
Definition: OpenCVGrabber.cpp:71
Log.h
OpenCVGrabber::close
bool close() override
Close a grabber.
Definition: OpenCVGrabber.cpp:164
Property.h
OpenCVGrabber::getImage
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.
Definition: OpenCVGrabber.cpp:227
yarp::dev::IFrameGrabberImage
Read a YARP-format image from a device.
Definition: FrameGrabberInterfaces.h:241
PolyDriver.h
OpenCVGrabber::sendImage
virtual bool sendImage(const cv::Mat &frame, yarp::sig::ImageOf< yarp::sig::PixelRgb > &image)
Read an image from the grabber.
Definition: OpenCVGrabber.cpp:182
yarp::dev::PolyDriver
A container for a device driver.
Definition: PolyDriver.h:27
yarp::os::Searchable::check
virtual bool check(const std::string &key) const =0
Check if there exists a property of the given name.
FrameGrabberInterfaces.h
define common interfaces to discover remote camera capabilities
LogComponent.h
Image.h
OpenCVGrabber.h
yCError
#define yCError(component,...)
Definition: LogComponent.h:157
yCInfo
#define yCInfo(component,...)
Definition: LogComponent.h:135
yarp::os
An interface to the operating system, including Port based communication.
Definition: AbstractCarrier.h:17
yCDebug
#define yCDebug(component,...)
Definition: LogComponent.h:112
yarp::sig::PixelRgb
Packed RGB pixel type.
Definition: Image.h:453
yarp::dev::Drivers
Global factory for devices.
Definition: Drivers.h:175
yCTrace
#define yCTrace(component,...)
Definition: LogComponent.h:88
yarp::os::Value
A single value (typically within a Bottle).
Definition: Value.h:47
Value.h
yarp::os::Property
A class for storing options and configuration information.
Definition: Property.h:37