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>
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
39
42using yarp::os::Value;
43
46
47using namespace yarp::os;
48using namespace yarp::sig;
49using namespace yarp::dev;
50
51
52namespace {
53YARP_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
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 fromFile
Whether reading from file or camera.
Definition: OpenCVGrabber.h:96
yarp::os::Property m_config
Saved copy of the device configuration.
bool getImage(yarp::sig::ImageOf< yarp::sig::PixelRgb > &image) override
Read an image from the grabber.
bool close() override
Close a grabber.
cv::VideoCapture m_cap
OpenCV image capture object.
Definition: OpenCVGrabber.h:99
bool open(yarp::os::Searchable &config) override
Open the DeviceDriver.
yarp::os::Stamp m_laststamp
int m_w
Width of the images a grabber produces.
Definition: OpenCVGrabber.h:85
int m_h
Height of the images a grabber produces.
Definition: OpenCVGrabber.h:87
bool m_loop
Whether to loop or not.
Definition: OpenCVGrabber.h:90
Interface implemented by all device drivers.
Definition: DeviceDriver.h:30
A factory for creating driver objects of a particular type.
Definition: Drivers.h:81
Global factory for devices.
Definition: Drivers.h:171
A container for a device driver.
Definition: PolyDriver.h:23
A class for storing options and configuration information.
Definition: Property.h:33
void fromString(const std::string &txt, bool wipe=true)
Interprets a string as a list of properties.
Definition: Property.cpp:1063
A base class for nested structures that can be searched.
Definition: Searchable.h:63
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.
void update()
Set the timestamp to the current time, and increment the sequence number (wrapping to 0 if the sequen...
Definition: Stamp.cpp:124
A single value (typically within a Bottle).
Definition: Value.h:43
Typed image class.
Definition: Image.h:653
size_t width() const
Gets width of image in pixels.
Definition: Image.h:163
size_t getRowSize() const
Size of the underlying image buffer rows.
Definition: Image.h:189
unsigned char * getRawImage() const
Access to the internal image buffer.
Definition: Image.cpp:542
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:453
void zero()
Set all pixels to 0.
Definition: Image.cpp:446
size_t height() const
Gets height of image in pixels.
Definition: Image.h:169
#define yCInfo(component,...)
Definition: LogComponent.h:171
#define yCError(component,...)
Definition: LogComponent.h:213
#define yCTrace(component,...)
Definition: LogComponent.h:84
#define yCDebug(component,...)
Definition: LogComponent.h:128
#define YARP_LOG_COMPONENT(name,...)
Definition: LogComponent.h:76
For streams capable of holding different kinds of content, check what they actually have.
An interface to the operating system, including Port based communication.
Packed RGB pixel type.
Definition: Image.h:460