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 
8 #include <yarp/os/LogComponent.h>
9 #include <yarp/os/Route.h>
10 #include <yarp/sig/ImageDraw.h>
11 #include <cstring>
12 #include <cstdlib>
13 
14 #ifndef USE_LIBDC1394
15 extern "C" {
16 #include "conversions.h"
17 }
18 #else
19 #include <dc1394/dc1394.h>
20 #endif
21 
22 using namespace yarp::os;
23 using namespace yarp::sig;
24 
25 namespace {
26 YARP_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
35 void 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;
150  processBuffered();
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");
328  ImageOf<PixelRgb> wrap;
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
359  processBuffered();
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 
373 bool 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:25
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 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:821
static LogType minimumPrintLevel()
Get current minimum print level.
Definition: Log.cpp:774
@ LogTypeReserved
Definition: Log.h:80
Information about a connection between two ports.
Definition: Route.h:29
A base class for nested structures that can be searched.
Definition: Searchable.h:66
virtual Value & find(const std::string &key) const =0
Gets a value corresponding to a given keyword.
virtual bool check(const std::string &key) const =0
Check if there exists a property of the given name.
A single value (typically within a Bottle).
Definition: Value.h:45
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:658
T & pixel(size_t x, size_t y)
Definition: Image.h:674
Base class for storing images.
Definition: Image.h:82
void setQuantum(size_t imgQuantum)
Definition: Image.cpp:501
size_t width() const
Gets width of image in pixels.
Definition: Image.h:166
void setExternal(const void *data, size_t imgWidth, size_t imgHeight)
Use this to wrap an external image.
Definition: Image.cpp:903
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
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:550
size_t height() const
Gets height of image in pixels.
Definition: Image.h:172
virtual int getPixelCode() const
Gets pixel type identifier.
Definition: Image.cpp:440
#define yCTrace(component,...)
Definition: LogComponent.h:85
#define yCWarning(component,...)
Definition: LogComponent.h:143
#define YARP_LOG_COMPONENT(name,...)
Definition: LogComponent.h:77
@ VOCAB_PIXEL_MONO
Definition: Image.h:45
::ssize_t ssize_t
Definition: numeric.h:86
An interface to the operating system, including Port based communication.
Signal processing.
Definition: Image.h:22
unsigned char PixelMono
Monochrome pixel type.
Definition: Image.h:447
Packed RGB pixel type.
Definition: Image.h:464
unsigned char g
Definition: Image.h:466
unsigned char r
Definition: Image.h:465
unsigned char b
Definition: Image.h:467