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