YARP
Yet Another Robot Platform
BayerCarrier.cpp
Go to the documentation of this file.
1/*
2 * SPDX-FileCopyrightText: 2006-2021 Istituto Italiano di Tecnologia (IIT)
3 * SPDX-License-Identifier: BSD-3-Clause
4 */
5
6#include "BayerCarrier.h"
7
9#include <yarp/os/Route.h>
10#include <yarp/sig/ImageDraw.h>
11#include <cstring>
12#include <cstdlib>
13
14#ifndef USE_LIBDC1394
15extern "C" {
16#include "conversions.h"
17}
18#else
19#include <dc1394/dc1394.h>
20#endif
21
22using namespace yarp::os;
23using namespace yarp::sig;
24
25namespace {
26YARP_LOG_COMPONENT(BAYERCARRIER,
27 "yarp.carrier.bayer",
31 nullptr)
32}
33
34// can't seem to do ipl/opencv/yarp style end-of-row padding
35void setDcImage(yarp::sig::Image& yimg, dc1394video_frame_t *dc,
36 int filter) {
37 if (!dc) {
38 return;
39 }
40 dc->image = yimg.getRawImage();
41 dc->size[0] = static_cast<uint32_t>(yimg.width());
42 dc->size[1] = static_cast<uint32_t>(yimg.height());
43 dc->position[0] = 0;
44 dc->position[1] = 0;
45 dc->color_coding = (yimg.getPixelCode()==VOCAB_PIXEL_MONO)?DC1394_COLOR_CODING_RAW8:DC1394_COLOR_CODING_RGB8;
46 dc->color_filter = static_cast<dc1394color_filter_t>(filter);
47 dc->yuv_byte_order = 0;
48 dc->data_depth = 8;
49 dc->stride = static_cast<uint32_t>(yimg.getRowSize());
50 dc->video_mode = DC1394_VIDEO_MODE_640x480_RGB8; // we are bluffing
51 dc->image_bytes = static_cast<uint32_t>(yimg.getRawImageSize());
52 dc->padding_bytes = 0;
53 dc->total_bytes = dc->image_bytes;
54 dc->timestamp = 0;
55 dc->frames_behind = 0;
56 dc->camera = nullptr;
57 dc->id = 0;
58 dc->allocated_image_bytes = dc->image_bytes;
59#ifdef YARP_LITTLE_ENDIAN
60 dc->little_endian = DC1394_TRUE;
61#else
62 dc->little_endian = DC1394_FALSE;
63#endif
64 dc->data_in_padding = DC1394_FALSE;
65}
66
68
69 /*
70 // minimal test of image modification
71 in.read(reader);
72 out.copy(in);
73 out.pixel(0,0).r = 42;
74 out.write(con.getWriter());
75 return con.getReader();
76 */
77
78 /*
79 // minimal test of bottle modification
80 con.setTextMode(reader.isTextMode());
81 Bottle b;
82 b.read(reader);
83 b.addInt32(42);
84 b.addString("(p.s. bork bork bork)");
85 b.write(con.getWriter());
86 return con.getReader();
87 */
88
89 local->setParentConnectionReader(&reader);
90
91 // libdc1394 seems to need this.
92 // note that this can slow things down if input has padding.
93 in.setQuantum(1);
94 out.setQuantum(1);
95
96 Route r;
97 bool ok = in.read(reader);
98 if (!ok) {
99 local->setSize(0);
100 return *local;
101 }
102 ImageNetworkHeader header_in_cmp;
103 header_in_cmp.setFromImage(in);
104 if (!need_reset) {
105 need_reset = (0!=memcmp(&header_in_cmp,&header_in,sizeof(header_in)));
106 }
107 have_result = false;
108 if (need_reset) {
109 int m = DC1394_BAYER_METHOD_BILINEAR;
110 const Searchable& config = reader.getConnectionModifiers();
111 half = false;
112 if (config.check("size")) {
113 if (config.find("size").asString() == "half") {
114 half = true;
115 }
116 }
117 if (config.check("method")) {
118 std::string method = config.find("method").asString();
119 bayer_method_set = true;
120 if (method=="ahd") {
121 m = DC1394_BAYER_METHOD_AHD;
122 } else if (method=="bilinear") {
123 m = DC1394_BAYER_METHOD_BILINEAR;
124 } else if (method=="downsample") {
125 m = DC1394_BAYER_METHOD_DOWNSAMPLE;
126 half = true;
127 } else if (method=="edgesense") {
128 m = DC1394_BAYER_METHOD_EDGESENSE;
129 } else if (method=="hqlinear") {
130 m = DC1394_BAYER_METHOD_HQLINEAR;
131 } else if (method=="nearest") {
132 m = DC1394_BAYER_METHOD_NEAREST;
133 } else if (method=="simple") {
134 m = DC1394_BAYER_METHOD_SIMPLE;
135 } else if (method=="vng") {
136 m = DC1394_BAYER_METHOD_VNG;
137 } else {
138 yCWarning/*Once*/(BAYERCARRIER, "bayer method %s not recognized, try: ahd bilinear downsample edgesense hqlinear nearest simple vng", method.c_str());
139 happy = false;
140 local->setSize(0);
141 return *local;
142 }
143 }
144
145 setFormat(config.check("order",Value("grbg")).asString().c_str());
146 header_in.setFromImage(in);
147 yCTrace(BAYERCARRIER, "Need reset.");
148 bayer_method = m;
149 need_reset = false;
151 }
152 local->setSize(sizeof(header)+image_data_len);
153 consumed = 0;
154
155 return *local;
156}
157
158
161 // dc1394 doesn't seem safe for arbitrary data widths
162 if (src.width()%8==0) {
163 dc1394video_frame_t dc_src;
164 dc1394video_frame_t dc_dest;
165 setDcImage(src,&dc_src,dcformat);
166 setDcImage(dest,&dc_dest,dcformat);
167 dc1394_debayer_frames(&dc_src,&dc_dest,DC1394_BAYER_METHOD_DOWNSAMPLE);
168 return true;
169 }
170
171 if (bayer_method_set) {
172 yCWarning/*Once*/(BAYERCARRIER, "Not using dc1394 debayer methods (image width not a multiple of 8)");
173 }
174
175 // a safer implementation that doesn't use dc1394
176 int w = src.width();
177 int h = src.height();
178 int wo = dest.width();
179 int ho = dest.height();
180 int goff1 = 1-goff;
181 int roffx = roff?goff:goff1;
182 int boff = 1-roff;
183 int boffx = boff?goff:goff1;
184 for (int yo=0; yo<ho; yo++) {
185 for (int xo=0; xo<wo; xo++) {
186 PixelRgb& po = dest.pixel(xo,yo);
187 int x = xo*2;
188 int y = yo*2;
189 if (x+1>=w-1 || y+1>=h-1) {
190 po = PixelRgb{0,0,0};
191 continue;
192 }
193 po.r = src.pixel(x+roffx,y+roff);
194 po.b = src.pixel(x+boffx,y+boff);
195 po.g = static_cast<PixelMono>(0.5*(src.pixel(x+goff,y)+src.pixel(x+goff1,y+1)));
196 }
197 }
198 return true;
199}
200
203 // dc1394 doesn't seem safe for arbitrary data widths
204 if (src.width()%8==0) {
205 dc1394video_frame_t dc_src;
206 dc1394video_frame_t dc_dest;
207 setDcImage(src,&dc_src,dcformat);
208 setDcImage(dest,&dc_dest,dcformat);
209 dc1394_debayer_frames(&dc_src,&dc_dest,
210 static_cast<dc1394bayer_method_t>(bayer_method));
211 return true;
212 }
213
214 if (bayer_method_set) {
215 yCWarning/*Once*/(BAYERCARRIER, "Not using dc1394 debayer methods (image width not a multiple of 8)");
216 }
217 int w = dest.width();
218 int h = dest.height();
219 int goff1 = 1-goff;
220 int roffx = roff?goff:goff1;
221 int boff = 1-roff;
222 int boffx = boff?goff:goff1;
223 for (int y=0; y<h; y++) {
224 for (int x=0; x<w; x++) {
225 PixelRgb& po = dest.pixel(x,y);
226
227 // G
228 if ((x+y)%2==goff) {
229 po.g = src.pixel(x,y);
230 } else {
231 float g = 0;
232 int ct = 0;
233 if (x>0) { g += src.pixel(x-1,y); ct++; }
234 if (x<w-1) { g += src.pixel(x+1,y); ct++; }
235 if (y>0) { g += src.pixel(x,y-1); ct++; }
236 if (y<h-1) { g += src.pixel(x,y+1); ct++; }
237 if (ct>0) { g /= ct; }
238 po.g = static_cast<int>(g);
239 }
240
241 // B
242 if (y%2==boff && x%2==boffx) {
243 po.b = src.pixel(x,y);
244 } else if (y%2==boff) {
245 float b = 0;
246 int ct = 0;
247 if (x>0) { b += src.pixel(x-1,y); ct++; }
248 if (x<w-1) { b += src.pixel(x+1,y); ct++; }
249 if (ct>0) { b /= ct; }
250 po.b = static_cast<int>(b);
251 } else if (x%2==boffx) {
252 float b = 0;
253 int ct = 0;
254 if (y>0) { b += src.pixel(x,y-1); ct++; }
255 if (y<h-1) { b += src.pixel(x,y+1); ct++; }
256 if (ct>0) { b /= ct; }
257 po.b = static_cast<int>(b);
258 } else {
259 float b = 0;
260 int ct = 0;
261 if (x>0&&y>0) { b += src.pixel(x-1,y-1); ct++; }
262 if (x>0&&y<h-1) { b += src.pixel(x-1,y+1); ct++; }
263 if (x<w-1&&y>0) { b += src.pixel(x+1,y-1); ct++; }
264 if (x<w-1&&y<h-1) { b += src.pixel(x+1,y+1); ct++; }
265 if (ct>0) { b /= ct; }
266 po.b = static_cast<int>(b);
267 }
268
269 // R
270 if (y%2==roff && x%2==roffx) {
271 po.r = src.pixel(x,y);
272 } else if (y%2==roff) {
273 float r = 0;
274 int ct = 0;
275 if (x>0) { r += src.pixel(x-1,y); ct++; }
276 if (x<w-1) { r += src.pixel(x+1,y); ct++; }
277 if (ct>0) { r /= ct; }
278 po.r = static_cast<int>(r);
279 } else if (x%2==roffx) {
280 float r = 0;
281 int ct = 0;
282 if (y>0) { r += src.pixel(x,y-1); ct++; }
283 if (y<h-1) { r += src.pixel(x,y+1); ct++; }
284 if (ct>0) { r /= ct; }
285 po.r = static_cast<int>(r);
286 } else {
287 float r = 0;
288 int ct = 0;
289 if (x>0&&y>0) { r += src.pixel(x-1,y-1); ct++; }
290 if (x>0&&y<h-1) { r += src.pixel(x-1,y+1); ct++; }
291 if (x<w-1&&y>0) { r += src.pixel(x+1,y-1); ct++; }
292 if (x<w-1&&y<h-1) { r += src.pixel(x+1,y+1); ct++; }
293 if (ct>0) { r /= ct; }
294 po.r = static_cast<int>(r);
295 }
296 }
297 }
298 return true;
299}
300
302 return const_cast<BayerCarrier*>(this)->processBuffered();
303}
304
306 if (!have_result) {
307 yCTrace(BAYERCARRIER, "Copy-based conversion.");
308 if (half) {
309 out.resize(in.width()/2,in.height()/2);
310 debayerHalf(in,out);
311 } else {
312 out.resize(in);
313 debayerFull(in,out);
314 }
315 header.setFromImage(out);
316 image_data_len = out.getRawImageSize();
317 }
318 have_result = true;
319 return true;
320}
321
323 if (have_result) {
324 memcpy(bytes.get(),out.getRawImage(),bytes.length());
325 return true;
326 }
327 yCTrace(BAYERCARRIER, "Copyless conversion");
329 wrap.setQuantum(out.getQuantum());
330 wrap.setExternal(bytes.get(),out.width(),out.height());
331 if (half) {
332 debayerHalf(in,wrap);
333 } else {
334 debayerFull(in,wrap);
335 }
336 return true;
337}
338
339
341 // copy across small stuff - the image header
342 if (consumed<sizeof(header)) {
343 size_t len = b.length();
344 if (len>sizeof(header)-consumed) {
345 len = sizeof(header)-consumed;
346 }
347 memcpy(b.get(),(reinterpret_cast<char*>(&header))+consumed,len);
348 consumed += len;
349 return static_cast<yarp::conf::ssize_t>(len);
350 }
351 // sane client will want to read image into correct-sized block
352 if (b.length()==image_data_len) {
353 // life is good!
354 processDirect(b);
355 consumed += image_data_len;
356 return image_data_len;
357 }
358 // funky client, fall back on image copy
360 if (consumed<sizeof(header)+out.getRawImageSize()) {
361 size_t len = b.length();
362 if (len>sizeof(header)+out.getRawImageSize()-consumed) {
363 len = sizeof(header)+out.getRawImageSize()-consumed;
364 }
365 memcpy(b.get(),out.getRawImage()+consumed-sizeof(header),len);
366 consumed += len;
367 return static_cast<yarp::conf::ssize_t>(len);
368 }
369 return -1;
370}
371
372
373bool BayerCarrier::setFormat(const char *fmt) {
374 dcformat = DC1394_COLOR_FILTER_GRBG;
375 std::string f(fmt);
376 if (f.length()<2) {
377 return false;
378 }
379 goff = (f[0]=='g'||f[0]=='G')?0:1;
380 roff = (f[0]=='r'||f[0]=='R'||f[1]=='r'||f[1]=='R')?0:1;
381 if (goff==0&&roff==0) {
382 dcformat = DC1394_COLOR_FILTER_GRBG;
383 } else if (goff==0&&roff==1) {
384 dcformat = DC1394_COLOR_FILTER_GBRG;
385 } else if (goff==1&&roff==0) {
386 dcformat = DC1394_COLOR_FILTER_RGGB;
387 } else if (goff==1&&roff==1) {
388 dcformat = DC1394_COLOR_FILTER_BGGR;
389 }
390 return true;
391}
void setDcImage(yarp::sig::Image &yimg, dc1394video_frame_t *dc, int filter)
Decode bayer images and serve them as regular rgb.
Definition: BayerCarrier.h:28
virtual bool processDirect(yarp::os::Bytes &bytes)
virtual bool processBuffered() const
virtual bool debayerHalf(yarp::sig::ImageOf< yarp::sig::PixelMono > &src, yarp::sig::ImageOf< yarp::sig::PixelRgb > &dest)
virtual bool debayerFull(yarp::sig::ImageOf< yarp::sig::PixelMono > &src, yarp::sig::ImageOf< yarp::sig::PixelRgb > &dest)
yarp::os::ConnectionReader & modifyIncomingData(yarp::os::ConnectionReader &reader) override
Modify incoming payload data, if appropriate.
A simple abstraction for a block of bytes.
Definition: Bytes.h:24
size_t length() const
Definition: Bytes.cpp:22
const char * get() const
Definition: Bytes.cpp:27
An interface for reading from a network connection.
virtual void setParentConnectionReader(ConnectionReader *parentConnectionReader)
Set ConnectionReader to be used for reading the envelope.
virtual bool setSize(size_t len)=0
virtual const Searchable & getConnectionModifiers() const =0
Access modifiers associated with the connection, if any.
virtual int read()
Read and return a single byte.
Definition: InputStream.cpp:20
static LogCallback printCallback()
Get current print callback.
Definition: Log.cpp:880
static LogType minimumPrintLevel()
Get current minimum print level.
Definition: Log.cpp:833
@ LogTypeReserved
Definition: Log.h:97
Information about a connection between two ports.
Definition: Route.h:28
A base class for nested structures that can be searched.
Definition: Searchable.h:56
virtual bool check(const std::string &key) const =0
Check if there exists a property of the given name.
virtual Value & find(const std::string &key) const =0
Gets a value corresponding to a given keyword.
A single value (typically within a Bottle).
Definition: Value.h:43
virtual std::string asString() const
Get string value.
Definition: Value.cpp:234
Byte order in image header for network transmission.
void setFromImage(const Image &image)
Typed image class.
Definition: Image.h:653
T & pixel(size_t x, size_t y)
Definition: Image.h:669
Base class for storing images.
Definition: Image.h:79
void setQuantum(size_t imgQuantum)
Definition: Image.cpp:502
size_t width() const
Gets width of image in pixels.
Definition: Image.h:163
bool read(yarp::os::ConnectionReader &connection) override
Read image from a connection.
Definition: Image.cpp:675
void setExternal(const void *data, size_t imgWidth, size_t imgHeight)
Use this to wrap an external image.
Definition: Image.cpp:904
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
size_t getRawImageSize() const
Access to the internal buffer size information (this is how much memory has been allocated for the im...
Definition: Image.cpp:551
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
size_t getQuantum() const
The size of a row is constrained to be a multiple of the "quantum".
Definition: Image.h:196
size_t height() const
Gets height of image in pixels.
Definition: Image.h:169
virtual int getPixelCode() const
Gets pixel type identifier.
Definition: Image.cpp:441
#define yCTrace(component,...)
Definition: LogComponent.h:84
#define yCWarning(component,...)
Definition: LogComponent.h:192
#define YARP_LOG_COMPONENT(name,...)
Definition: LogComponent.h:76
@ VOCAB_PIXEL_MONO
Definition: Image.h:42
::ssize_t ssize_t
Definition: numeric.h:86
An interface to the operating system, including Port based communication.
unsigned char PixelMono
Monochrome pixel type.
Definition: Image.h:443
Packed RGB pixel type.
Definition: Image.h:460
unsigned char g
Definition: Image.h:462
unsigned char r
Definition: Image.h:461
unsigned char b
Definition: Image.h:463