YARP
Yet Another Robot Platform
Image.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  * All rights reserved.
5  *
6  * This software may be modified and distributed under the terms of the
7  * BSD-3-Clause license. See the accompanying LICENSE file for details.
8  */
9 
10 /*
11  This file is in a pretty hacky state. Sorry!
12 
13 */
14 
15 #include <yarp/sig/Image.h>
16 
17 #include <yarp/os/Bottle.h>
20 #include <yarp/os/Log.h>
21 #include <yarp/os/Time.h>
22 #include <yarp/os/Vocab.h>
23 
25 #include <yarp/sig/impl/IplImage.h>
26 #include <yarp/sig/impl/DeBayer.h>
27 
28 #include <cstdio>
29 #include <cstring>
30 #include <string>
31 
32 
33 using namespace yarp::sig;
34 using namespace yarp::os;
35 
36 #define DBGPF1 if (0)
37 
38 //inline int PAD_BYTES (int len, int pad)
39 //{
40 // const int rem = len % pad;
41 // return (rem != 0) ? (pad - rem) : rem;
42 //}
43 
48 inline bool readFromConnection(Image &dest, ImageNetworkHeader &header, ConnectionReader& connection)
49 {
50  dest.resize(header.width, header.height);
51  unsigned char *mem = dest.getRawImage();
52  size_t allocatedBytes = dest.getRawImageSize();
53  yAssert(mem != nullptr);
54  //this check is redundant with assertion, I would remove it
55  if (dest.getRawImageSize() != static_cast<size_t>(header.imgSize)) {
56  printf("There is a problem reading an image\n");
57  printf("incoming: width %zu, height %zu, code %zu, quantum %zu, topIsLow %zu, size %zu\n",
58  static_cast<size_t>(header.width),
59  static_cast<size_t>(header.height),
60  static_cast<size_t>(header.id),
61  static_cast<size_t>(header.quantum),
62  static_cast<size_t>(header.topIsLow),
63  static_cast<size_t>(header.imgSize));
64  printf("my space: width %zu, height %zu, code %d, quantum %zu, size %zu\n",
65  dest.width(), dest.height(), dest.getPixelCode(), dest.getQuantum(), allocatedBytes);
66  }
67  yAssert(allocatedBytes == (size_t) header.imgSize);
68  bool ok = connection.expectBlock(reinterpret_cast<char*>(mem), allocatedBytes);
69  return (!connection.isError() && ok);
70 }
71 
72 
73 
74 class ImageStorage {
75 public:
77  char **Data; // this is not IPL. it's char to maintain IPL compatibility
80  size_t quantum;
81  bool topIsLow;
82 
83 protected:
85 
86  int type_id;
87 
88  int is_owner;
89 
90  // ipl allocation is done in two steps.
91  // _alloc allocates the actual ipl pointer.
92  // _alloc_data allocates the image array and data.
93  // memory is allocated in a single chunk. Row ptrs are then
94  // made to point appropriately. This is compatible with IPL and
95  // SOMEONE says it's more efficient on NT.
96  void _alloc ();
97  void _alloc_extern (const void *buf);
98  void _alloc_data ();
99  void _free ();
100  void _free_data ();
101 
102  void _make_independent();
103  bool _set_ipl_header(size_t x, size_t y, int pixel_type, size_t quantum,
104  bool topIsLow);
105  void _free_ipl_header();
106  void _alloc_complete(size_t x, size_t y, int pixel_type, size_t quantum,
107  bool topIsLow);
108  void _free_complete();
109 
110 
111  // computes the # of padding bytes. These are always at the end of the row.
112  int _pad_bytes (size_t linesize, size_t align) const;
113 
114  inline int GetPadding() const {
115  return _pad_bytes (pImage->width * pImage->nChannels,
117  }
118 
119 public:
120  ImageStorage(Image& owner) : owner(owner) {
121  type_id = 0;
122  pImage = nullptr;
123  Data = nullptr;
124  is_owner = 1;
125  quantum = 0;
126  topIsLow = true;
127  extern_type_id = 0;
128  extern_type_quantum = -1;
129  }
130 
132  _free_complete();
133  }
134 
135  void resize(size_t x, size_t y, int pixel_type,
136  size_t quantum, bool topIsLow);
137 
138  void _alloc_complete_extern(const void *buf, size_t x, size_t y, int pixel_type,
139  size_t quantum, bool topIsLow);
140  int getTypeId();
141 
142 };
143 
144 
145 void ImageStorage::resize(size_t x, size_t y, int pixel_type,
146  size_t quantum, bool topIsLow) {
147  int need_recreation = 1;
148 
149  if (quantum==0) {
150  quantum = YARP_IMAGE_ALIGN;
151  }
152 
153  if (need_recreation) {
154  _free_complete();
155  DBGPF1 printf("HIT recreation for %p %p: %zu %zu %d\n", static_cast<void*>(this), static_cast<void*>(pImage), x, y, pixel_type);
156  _alloc_complete (x, y, pixel_type, quantum, topIsLow);
157  }
158  extern_type_id = pixel_type;
159  extern_type_quantum = quantum;
160 }
161 
167  return type_id;
168 }
169 
170 
171 // allocates an empty image.
173 
174 
175  _free(); // was iplDeallocateImage(pImage); but that won't work with refs
176 
177  if ((type_id == VOCAB_PIXEL_MONO_FLOAT) ||
178  (type_id == VOCAB_PIXEL_RGB_FLOAT) ||
179  (type_id == VOCAB_PIXEL_HSV_FLOAT)) {
180  iplAllocateImageFP(pImage, 0, 0);
181  } else {
182  iplAllocateImage (pImage, 0, 0);
183  }
184 
186 }
187 
188 // installs an external buffer as the image data
189 void ImageStorage::_alloc_extern (const void *buf)
190 {
191  yAssert(pImage != nullptr);
192  yAssert(Data==nullptr);
193 
194  if (pImage != nullptr) {
195  if (pImage->imageData != nullptr) {
196  iplDeallocateImage (pImage);
197  }
198  }
199 
200  //iplAllocateImage (pImage, 0, 0);
201  pImage->imageData = const_cast<char*>(reinterpret_cast<const char*>(buf));
202  // probably need to do more for real IPL
203 
204  //iplSetBorderMode (pImage, IPL_BORDER_CONSTANT, IPL_SIDE_ALL, 0);
205 }
206 
207 // allocates the Data pointer.
209 {
210  DBGPF1 printf("alloc_data1\n"), fflush(stdout);
211  yAssert(pImage != nullptr);
212 
213  yAssert(Data==nullptr);
214 
215  char **ptr = new char *[pImage->height];
216 
217  Data = ptr;
218 
219  yAssert(Data != nullptr);
220 
221  yAssert(pImage->imageData != nullptr);
222 
223  int height = pImage->height;
224 
225  char * DataArea = pImage->imageData;
226 
227  for (int r = 0; r < height; r++)
228  {
229  if (topIsLow) {
230  Data[r] = DataArea;
231  } else {
232  Data[height-r-1] = DataArea;
233  }
234  DataArea += pImage->widthStep;
235  }
236  DBGPF1 printf("alloc_data4\n");
237 }
238 
240 {
241  if (pImage != nullptr) {
242  if (pImage->imageData != nullptr) {
243  if (is_owner) {
244  iplDeallocateImage (pImage);
245  delete[] Data;
246  } else {
247  delete[] Data;
248  }
249 
250  is_owner = 1;
251  Data = nullptr;
252  pImage->imageData = nullptr;
253  }
254  }
255 }
256 
258 {
259  yAssert(Data==nullptr); // Now always free Data at same time
260 }
261 
262 
264 {
265  _free();
266  _free_data();
267  _free_ipl_header();
268 }
269 
270 
272 {
273  if (pImage!=nullptr)
274  {
276  }
277  pImage = nullptr;
278 }
279 
280 
281 void ImageStorage::_alloc_complete(size_t x, size_t y, int pixel_type, size_t quantum,
282  bool topIsLow)
283 {
284  _make_independent();
285  _free_complete();
286  _set_ipl_header(x, y, pixel_type, quantum, topIsLow);
287  _alloc ();
288  _alloc_data ();
289 }
290 
291 
292 
294 {
295  // actually I think this isn't really needed -paulfitz
296 }
297 
299 {
301  int depth;
302  const char* colorModel;
303  const char* channelSeq;
304 };
305 
308 
309 const std::map<int, pixelTypeIplParams> pixelCode2iplParams = {
315  {VOCAB_PIXEL_YUV_420, iplPixelTypeMono}, // {1, 12, "GRAY", "GRAY"}},
316  {VOCAB_PIXEL_YUV_444, iplPixelTypeMono}, // {1, 24, "GRAY", "GRAY"}},
318  {VOCAB_PIXEL_YUV_411, iplPixelTypeMono}, // {1, 12, "GRAY", "GRAY"}},
324  {VOCAB_PIXEL_RGB, {3, IPL_DEPTH_8U, "RGB", "RGB" }},
325  {VOCAB_PIXEL_RGBA, {4, IPL_DEPTH_8U, "RGBA", "RGBA"}},
326  {VOCAB_PIXEL_BGRA, {4, IPL_DEPTH_8U, "BGRA", "BGRA"}},
327  {VOCAB_PIXEL_INT, {1, IPL_DEPTH_32S, "GRAY", "GRAY"}},
328  {VOCAB_PIXEL_HSV, {3, IPL_DEPTH_8U, "HSV", "HSV" }},
329  {VOCAB_PIXEL_BGR, {3, IPL_DEPTH_8U, "RGB", "BGR" }},
330  {VOCAB_PIXEL_MONO_SIGNED, {1, IPL_DEPTH_8S, "GRAY", "GRAY"}},
331  {VOCAB_PIXEL_RGB_INT, {3, IPL_DEPTH_32S, "RGB", "RGB" }},
332  {VOCAB_PIXEL_MONO_FLOAT, {1, IPL_DEPTH_32F, "GRAY", "GRAY"}},
333  {VOCAB_PIXEL_RGB_FLOAT, {3, IPL_DEPTH_32F, "RGB", "RGB" }},
334  {-2, iplPixelTypeMono16},
335  {-4, {1, IPL_DEPTH_32S, "GRAY", "GRAY"}}
336 };
337 
338 bool ImageStorage::_set_ipl_header(size_t x, size_t y, int pixel_type, size_t quantum,
339  bool topIsLow)
340 {
341  if (pImage != nullptr) {
342  iplDeallocateImage(pImage);
343  pImage = nullptr;
344  }
345 
346  if (pixel_type == VOCAB_PIXEL_INVALID) {
347  // not a type!
348  printf ("*** Trying to allocate an invalid pixel type image\n");
349  std::exit(1);
350  }
351  if (pixelCode2iplParams.find(pixel_type) == pixelCode2iplParams.end()) {
352  // unknown pixel type. Should revert to a non-IPL mode... how?
353  return false;
354  }
355 
356  const pixelTypeIplParams& param = pixelCode2iplParams.at(pixel_type);
357 
358  if (quantum==0) {
359  quantum = IPL_ALIGN_QWORD;
360  }
361  int origin = topIsLow ? IPL_ORIGIN_TL : IPL_ORIGIN_BL;
362 
363  pImage = iplCreateImageHeader(param.nChannels, 0, param.depth, const_cast<char*>(param.colorModel), const_cast<char*>(param.channelSeq), IPL_DATA_ORDER_PIXEL, origin, quantum, x, y, nullptr, nullptr, nullptr, nullptr);
364 
365  type_id = pixel_type;
366  this->quantum = quantum;
367  this->topIsLow = topIsLow;
368  return true;
369 }
370 
371 void ImageStorage::_alloc_complete_extern(const void *buf, size_t x, size_t y, int pixel_type, size_t quantum, bool topIsLow)
372 {
373  if (quantum==0) {
374  quantum = 1;
375  }
376  this->quantum = quantum;
377  this->topIsLow = topIsLow;
378 
379  _make_independent();
380  _free_complete();
381  _set_ipl_header(x, y, pixel_type, quantum, topIsLow);
382  Data = nullptr;
383  _alloc_extern (buf);
384  _alloc_data ();
385  is_owner = 0;
386 }
387 
388 
389 
390 int ImageStorage::_pad_bytes (size_t linesize, size_t align) const
391 {
392  return yarp::sig::PAD_BYTES (linesize, align);
393 }
394 
395 const std::map<YarpVocabPixelTypesEnum, size_t> Image::pixelCode2Size = {
396  {VOCAB_PIXEL_INVALID, 0 },
419  {VOCAB_PIXEL_YUV_420, 1},
420  {VOCAB_PIXEL_YUV_444, 1},
421  {VOCAB_PIXEL_YUV_422, 1},
423 };
424 
426  initialize();
427 }
428 
429 void Image::initialize() {
430  implementation = nullptr;
431  data = nullptr;
432  imgWidth = imgHeight = 0;
433  imgPixelSize = imgRowSize = 0;
434  imgPixelCode = 0;
435  imgQuantum = 0;
436  topIsLow = true;
437  implementation = new ImageStorage(*this);
438  yAssert(implementation!=nullptr);
439 }
440 
441 
443  if (implementation!=nullptr) {
444  delete static_cast<ImageStorage*>(implementation);
445  implementation = nullptr;
446  }
447 }
448 
449 
450 size_t Image::getPixelSize() const {
451  return imgPixelSize;
452 }
453 
454 
455 int Image::getPixelCode() const {
456  return imgPixelCode;
457 }
458 
459 
460 void Image::zero() {
461  if (getRawImage()!=nullptr) {
462  memset(getRawImage(),0,getRawImageSize());
463  }
464 }
465 
466 
467 void Image::resize(size_t imgWidth, size_t imgHeight) {
468 
469  int code = getPixelCode();
470  bool change = false;
471  if (code!=imgPixelCode) {
472  setPixelCode(code);
473  change = true;
474  }
475  if (imgPixelCode!=(static_cast<ImageStorage*>(implementation))->extern_type_id) {
476  change = true;
477  }
478  if (imgQuantum!=(static_cast<ImageStorage*>(implementation))->extern_type_quantum) {
479  change = true;
480  }
481 
482  if (imgWidth!=width()||imgHeight!=height()) {
483  change = true;
484  }
485 
486  if (change) {
487  (static_cast<ImageStorage*>(implementation))->resize(imgWidth,
488  imgHeight,
489  imgPixelCode,
490  imgQuantum,
491  topIsLow);
492  synchronize();
493  //printf("CHANGE! %ld\n", (long int)(this));
494  }
495 }
496 
497 void Image::setPixelSize(size_t imgPixelSize) {
498  if(imgPixelSize == pixelCode2Size.at(static_cast<YarpVocabPixelTypesEnum>(imgPixelCode))) {
499  return;
500  }
501 
502  setPixelCode(-imgPixelSize);
503 }
504 
505 void Image::setPixelCode(int imgPixelCode) {
506  this->imgPixelCode = imgPixelCode;
507  this->imgPixelSize = (imgPixelCode < 0) ? -imgPixelCode : pixelCode2Size.at(static_cast<YarpVocabPixelTypesEnum>(imgPixelCode));
508 }
509 
510 
511 void Image::setQuantum(size_t imgQuantum) {
512  this->imgQuantum = imgQuantum;
513 }
514 
515 
516 void Image::synchronize() {
517  auto* impl = static_cast<ImageStorage*>(implementation);
518  yAssert(impl!=nullptr);
519  if (impl->pImage!=nullptr) {
520  imgWidth = impl->pImage->width;
521  imgHeight = impl->pImage->height;
522  data = impl->Data;
523  imgQuantum = impl->quantum;
524  imgRowSize = impl->pImage->widthStep;
525  setPixelCode(impl->getTypeId());
526  topIsLow = impl->pImage->origin == IPL_ORIGIN_TL;
527  } else {
528  data = nullptr;
529  imgWidth = 0;
530  imgHeight = 0;
531  }
532 }
533 
534 
535 unsigned char *Image::getRawImage() const {
536  auto* impl = static_cast<ImageStorage*>(implementation);
537  yAssert(impl!=nullptr);
538  if (impl->pImage!=nullptr) {
539  return reinterpret_cast<unsigned char*>(impl->pImage->imageData);
540  }
541  return nullptr;
542 }
543 
544 size_t Image::getRawImageSize() const {
545  auto* impl = static_cast<ImageStorage*>(implementation);
546  yAssert(impl!=nullptr);
547  if (impl->pImage!=nullptr) {
548  return impl->pImage->imageSize;
549  }
550  return 0;
551 }
552 
553 #ifndef YARP_NO_DEPRECATED // Since YARP 3.2.0
555  return (static_cast<ImageStorage*>(implementation))->pImage;
556 }
557 
558 const void *Image::getIplImage() const {
559  return (static_cast<const ImageStorage*>(implementation))->pImage;
560 }
561 
562 void Image::wrapIplImage(void *iplImage) {
563  yAssert(iplImage!=nullptr);
564  auto* p = static_cast<IplImage *>(iplImage);
565  std::string str = p->colorModel;
566  int code = -1;
567  int color_code = -1;
568  if (str=="rgb"||str=="RGB"||
569  str=="bgr"||str=="BGR"||
570  str=="gray"||str=="GRAY"||
571  str=="graygray"||str=="GRAYGRAY") {
572  str = p->channelSeq;
573  if (str=="rgb"||str=="RGB") {
574  color_code = VOCAB_PIXEL_RGB;
575  } else if (str=="bgr"||str=="BGR") {
576  color_code = VOCAB_PIXEL_BGR;
577  } else if (str=="gray"||str=="GRAY"||
578  str=="graygray"||str=="GRAYGRAY") {
579  color_code = VOCAB_PIXEL_MONO;
580  } else {
581  printf("specific IPL RGB order (%s) is not yet supported\n",
582  str.c_str());
583  printf("Try RGB, BGR, or \n");
584  printf("Or fix code at %s line %d\n",__FILE__,__LINE__);
585  std::exit(1);
586  }
587  }
588 
589  // Type translation is approximate. Patches welcome to flesh out
590  // the types available.
591  if (p->depth == IPL_DEPTH_8U) {
592  code = color_code;
593  } else if (p->depth == IPL_DEPTH_8S) {
594  switch (color_code) {
595  case VOCAB_PIXEL_MONO:
597  break;
598  case VOCAB_PIXEL_RGB:
599  code = VOCAB_PIXEL_RGB_SIGNED;
600  break;
601  case VOCAB_PIXEL_BGR:
602  code = color_code; // nothing better available
603  break;
604  }
605  } else if (p->depth == IPL_DEPTH_16U || p->depth == IPL_DEPTH_16S) {
606  switch (color_code) {
607  case VOCAB_PIXEL_MONO:
608  code = VOCAB_PIXEL_MONO16;
609  break;
610  case VOCAB_PIXEL_RGB:
611  case VOCAB_PIXEL_BGR:
612  fprintf(stderr,"No translation currently available for this pixel type\n");
613  std::exit(1);
614  break;
615  }
616  } else if (p->depth == IPL_DEPTH_32S) {
617  switch (color_code) {
618  case VOCAB_PIXEL_MONO:
619  code = VOCAB_PIXEL_INT;
620  break;
621  case VOCAB_PIXEL_RGB:
622  case VOCAB_PIXEL_BGR:
623  code = VOCAB_PIXEL_RGB_INT;
624  break;
625  }
626  } else if (p->depth == IPL_DEPTH_32F) {
627  switch (color_code) {
628  case VOCAB_PIXEL_MONO:
629  code = VOCAB_PIXEL_MONO_FLOAT;
630  break;
631  case VOCAB_PIXEL_RGB:
632  case VOCAB_PIXEL_BGR:
633  code = VOCAB_PIXEL_RGB_FLOAT;
634  break;
635  }
636  }
637 
638  if (code==-1) {
639  fprintf(stderr,"IPL pixel type / depth combination is not yet supported\n");
640  fprintf(stderr,"Please email a YARP developer to complain, quoting this:\n");
641  fprintf(stderr," %s:%d\n", __FILE__, __LINE__);
642  }
643 
644  if (getPixelCode()!=code && getPixelCode()!=-1) {
645  printf("your specific IPL format (%s depth %d -> %s) does not match your YARP format (%s)\n",
646  str.c_str(),
647  p->depth,
648  Vocab::decode(code).c_str(),
649  Vocab::decode(getPixelCode()).c_str());
650  printf("Making a copy instead of just wrapping...\n");
651  FlexImage img;
652  img.setQuantum(p->align);
653  img.setPixelCode(code);
654  img.setExternal(p->imageData,p->width,p->height);
655  copy(img);
656  } else {
657  setQuantum(p->align);
658  setPixelCode(code);
659  setExternal(p->imageData,p->width,p->height);
660  }
661 }
662 
663 #endif // YARP_NO_DEPRECATED
664 
665 
667 
668  // auto-convert text mode interaction
669  connection.convertTextMode();
670 
671  ImageNetworkHeader header;
672 
673  bool ok = connection.expectBlock(reinterpret_cast<char*>(&header),sizeof(header));
674  if (!ok) {
675  return false;
676  }
677 
678  //first check that the received image size is reasonable
679  if (header.width == 0 || header.height == 0)
680  {
681  // I maintain the previous logic, although we should probably return false
682  return !connection.isError();
683  }
684 
685  setPixelCode(header.id);
686 
687  size_t q = getQuantum();
688  if (q==0) {
689  //q = YARP_IMAGE_ALIGN;
690  setQuantum(header.quantum);
691  q = getQuantum();
692  }
693  if (q != static_cast<size_t>(header.quantum)) {
694  if ((header.depth*header.width)%header.quantum==0 &&
695  (header.depth*header.width)%q==0) {
696  header.quantum = q;
697  }
698  }
699 
700  setTopIsLowIndex(header.topIsLow == 0);
701 
702  // handle easy case, received and current image are compatible, no conversion needed
703  if (getPixelCode() == header.id && q == static_cast<size_t>(header.quantum) && imgPixelSize == static_cast<size_t>(header.depth))
704  {
705  return readFromConnection(*this, header, connection);
706  }
707 
708  // image is bayer 8 bits, current image is MONO, copy as is (keep raw format)
709  if (getPixelCode() == VOCAB_PIXEL_MONO && isBayer8(header.id))
710  {
711  return readFromConnection(*this, header, connection);
712  }
713  // image is bayer 16 bits, current image is MONO16, copy as is (keep raw format)
714  if (getPixelCode() == VOCAB_PIXEL_MONO16 && isBayer16(header.id))
715  {
716  return readFromConnection(*this, header, connection);
717  }
718 
720  // Received and current images are binary incompatible do our best to convert
721  //
722 
723  // handle here all bayer encoding 8 bits
724  if (isBayer8(header.id))
725  {
726  FlexImage flex;
728  flex.setQuantum(header.quantum);
729  flex.setTopIsLowIndex(header.topIsLow == 0);
730 
731  bool ok = readFromConnection(flex, header, connection);
732  if (!ok) {
733  return false;
734  }
735 
736  if (getPixelCode() == VOCAB_PIXEL_BGR && header.id==VOCAB_PIXEL_ENCODING_BAYER_GRBG8) {
737  return deBayer_GRBG8_TO_BGR(flex, *this, 3);
738  }
739  if (getPixelCode() == VOCAB_PIXEL_BGRA && header.id == VOCAB_PIXEL_ENCODING_BAYER_GRBG8) {
740  return deBayer_GRBG8_TO_BGR(flex, *this, 4);
741  }
742  if (getPixelCode() == VOCAB_PIXEL_RGB && header.id==VOCAB_PIXEL_ENCODING_BAYER_GRBG8) {
743  return deBayer_GRBG8_TO_RGB(flex, *this, 3);
744  }
745  if (getPixelCode() == VOCAB_PIXEL_RGBA && header.id == VOCAB_PIXEL_ENCODING_BAYER_GRBG8) {
746  return deBayer_GRBG8_TO_RGB(flex, *this, 4);
747  }
748 
749  YARP_FIXME_NOTIMPLEMENTED("Conversion from bayer encoding not yet implemented\n");
750  return false;
751  }
752 
753  // handle here all bayer encodings 16 bits
754  if (isBayer16(header.id))
755  {
756  // as bayer16 seems unlikely we defer implementation for later
757  YARP_FIXME_NOTIMPLEMENTED("Conversion from bayer encoding 16 bits not yet implemented\n");
758  return false;
759  }
760 
761  // Received image has valid YARP pixels and can be converted using Image primitives
762  // prepare a FlexImage, set it to be compatible with the received image
763  // read new image into FlexImage then copy from it.
764  FlexImage flex;
765  flex.setPixelCode(header.id);
766  flex.setQuantum(header.quantum);
767  flex.setTopIsLowIndex(header.topIsLow == 0);
768  ok = readFromConnection(flex, header, connection);
769  if (ok) {
770  copy(flex);
771  }
772 
773  return ok;
774 }
775 
776 
777 bool Image::write(yarp::os::ConnectionWriter& connection) const {
778  ImageNetworkHeader header;
779  header.setFromImage(*this);
780  /*
781  header.listTag = BOTTLE_TAG_LIST;
782  header.listLen = 4;
783  header.paramNameTag = BOTTLE_TAG_VOCAB;
784  header.paramName = yarp::os::createVocab('m','a','t');
785  header.paramIdTag = BOTTLE_TAG_VOCAB;
786  header.id = getPixelCode();
787  header.paramListTag = BOTTLE_TAG_LIST + BOTTLE_TAG_INT32;
788  header.paramListLen = 5;
789  header.depth = getPixelSize();
790  header.imgSize = getRawImageSize();
791  header.quantum = getQuantum();
792  header.width = width();
793  header.height = height();
794  header.paramBlobTag = BOTTLE_TAG_BLOB;
795  header.paramBlobLen = getRawImageSize();
796  */
797 
798  connection.appendBlock(reinterpret_cast<char*>(&header),sizeof(header));
799  unsigned char *mem = getRawImage();
800  if (header.width!=0&&header.height!=0) {
801  yAssert(mem!=nullptr);
802 
803  // Note use of external block.
804  // Implies care needed about ownership.
805  connection.appendExternalBlock(reinterpret_cast<char *>(mem),header.imgSize);
806  }
807 
808  // if someone is foolish enough to connect in text mode,
809  // let them see something readable.
810  connection.convertTextMode();
811 
812  return !connection.isError();
813 }
814 
815 
816 Image::Image(const Image& alt) : Portable()
817 {
818  initialize();
819  copy(alt);
820 }
821 
822 Image::Image(Image&& other) noexcept
823  : implementation(other.implementation)
824 {
825  other.implementation = nullptr;
826  synchronize();
827 }
828 
829 Image& Image::operator=(Image&& other) noexcept
830 {
831  Image moved(std::move(other));
832  std::swap(moved.implementation, implementation);
833  synchronize();
834  return *this;
835 }
836 
837 
839 {
840  if (&alt != this) {
841  copy(alt);
842  }
843  return *this;
844 }
845 
846 
847 bool Image::copy(const Image& alt)
848 {
849  if (&alt != this)
850  {
851  int myCode = getPixelCode();
852  if (myCode==0) {
853  setPixelCode(alt.getPixelCode());
854  setQuantum(alt.getQuantum());
855  }
856  resize(alt.width(),alt.height());
857  int q1 = alt.getQuantum();
858  int q2 = getQuantum();
859  if (q1==0) { q1 = YARP_IMAGE_ALIGN; }
860  if (q2==0) { q2 = YARP_IMAGE_ALIGN; }
861 
862  bool o1 = alt.topIsLowIndex();
863  bool o2 = topIsLowIndex();
864 
865  yAssert(width()==alt.width());
866  yAssert(height()==alt.height());
867  if (getPixelCode()==alt.getPixelCode()) {
868  if (getQuantum()==alt.getQuantum()) {
870  yAssert(q1==q2);
871  }
872  }
873 
874  copyPixels(alt.getRawImage(),alt.getPixelCode(),
876  width(),height(),
877  getRawImageSize(),q1,q2,o1,o2);
878  }
879  return true;
880 }
881 
882 
883 void Image::setExternal(const void *data, size_t imgWidth, size_t imgHeight) {
884  if (imgQuantum==0) {
885  imgQuantum = 1;
886  }
887  (static_cast<ImageStorage*>(implementation))->_alloc_complete_extern(data,
888  imgWidth,
889  imgHeight,
890  getPixelCode(),
891  imgQuantum,
892  topIsLow);
893  synchronize();
894 }
895 
896 
897 bool Image::copy(const Image& alt, size_t w, size_t h) {
898  if (getPixelCode()==0) {
899  setPixelCode(alt.getPixelCode());
900  setQuantum(alt.getQuantum());
901  }
902  if (&alt==this) {
903  FlexImage img;
904  img.copy(alt);
905  return copy(img,w,h);
906  }
907 
908  if (getPixelCode()!=alt.getPixelCode()) {
909  FlexImage img;
910  img.setPixelCode(getPixelCode());
911  img.setQuantum(getQuantum());
912  img.copy(alt);
913  return copy(img,w,h);
914  }
915 
916  resize(w,h);
917  size_t d = getPixelSize();
918 
919  size_t nw = w;
920  size_t nh = h;
921  w = alt.width();
922  h = alt.height();
923 
924  float di = (static_cast<float>(h))/nh;
925  float dj = (static_cast<float>(w))/nw;
926 
927  for (size_t i=0; i<nh; i++)
928  {
929  auto i0 = static_cast<size_t>(di*i);
930  for (size_t j=0; j<nw; j++)
931  {
932  auto j0 = static_cast<size_t>(dj*j);
933  memcpy(getPixelAddress(j,i),
934  alt.getPixelAddress(j0,i0),
935  d);
936  }
937  }
938  return true;
939 }
bool deBayer_GRBG8_TO_RGB(yarp::sig::Image &source, yarp::sig::Image &dest, int pixelSize)
Definition: DeBayer.cpp:78
bool deBayer_GRBG8_TO_BGR(yarp::sig::Image &source, yarp::sig::Image &dest, int pixelSize)
Definition: DeBayer.cpp:12
bool isBayer8(int v)
Basic implementations of debayering functions.
Definition: DeBayer.h:22
bool isBayer16(int v)
Definition: DeBayer.h:33
#define DBGPF1
Definition: Image.cpp:36
const std::map< int, pixelTypeIplParams > pixelCode2iplParams
Definition: Image.cpp:309
const pixelTypeIplParams iplPixelTypeMono16
Definition: Image.cpp:307
bool readFromConnection(Image &dest, ImageNetworkHeader &header, ConnectionReader &connection)
This helper function groups code to avoid duplication.
Definition: Image.cpp:48
const pixelTypeIplParams iplPixelTypeMono
Definition: Image.cpp:306
IplImage * iplCreateImageHeader(int nChannels, int alphaChannel, int depth, char *colorModel, char *channelSeq, int dataOrder, int origin, int align, int width, int height, IplROI *roi, IplImage *maskROI, void *imageId, IplTileInfo *tileInfo)
Definition: IplImage.cpp:786
void iplDeallocateImage(IplImage *image)
Definition: IplImage.cpp:731
void iplAllocateImageFP(IplImage *image, int doFill, float fillValue)
Definition: IplImage.cpp:694
void iplSetBorderMode(IplImage *src, int mode, int border, int constVal)
Definition: IplImage.cpp:922
void iplDeallocate(IplImage *image, int flag)
Definition: IplImage.cpp:900
void iplAllocateImage(IplImage *image, int doFill, int fillValue)
Definition: IplImage.cpp:661
#define YARP_FIXME_NOTIMPLEMENTED(what)
Definition: Log.h:310
#define yAssert(x)
Definition: Log.h:297
RandScalar * implementation(void *t)
Definition: RandnScalar.cpp:20
void _free_complete()
Definition: Image.cpp:263
int getTypeId()
ImageStorage::getTypeId.
Definition: Image.cpp:166
size_t quantum
Definition: Image.cpp:80
bool topIsLow
Definition: Image.cpp:81
ImageStorage(Image &owner)
Definition: Image.cpp:120
void _free_ipl_header()
Definition: Image.cpp:271
void resize(size_t x, size_t y, int pixel_type, size_t quantum, bool topIsLow)
Definition: Image.cpp:145
~ImageStorage()
Definition: Image.cpp:131
size_t extern_type_quantum
Definition: Image.cpp:79
void _alloc()
Definition: Image.cpp:172
IplImage * pImage
Definition: Image.cpp:76
int extern_type_id
Definition: Image.cpp:78
int GetPadding() const
Definition: Image.cpp:114
void _alloc_data()
Definition: Image.cpp:208
void _alloc_complete_extern(const void *buf, size_t x, size_t y, int pixel_type, size_t quantum, bool topIsLow)
Definition: Image.cpp:371
int _pad_bytes(size_t linesize, size_t align) const
Definition: Image.cpp:390
char ** Data
Definition: Image.cpp:77
void _alloc_complete(size_t x, size_t y, int pixel_type, size_t quantum, bool topIsLow)
Definition: Image.cpp:281
bool _set_ipl_header(size_t x, size_t y, int pixel_type, size_t quantum, bool topIsLow)
Definition: Image.cpp:338
void _alloc_extern(const void *buf)
Definition: Image.cpp:189
void _free()
Definition: Image.cpp:239
void _free_data()
Definition: Image.cpp:257
int is_owner
Definition: Image.cpp:88
Image & owner
Definition: Image.cpp:84
void _make_independent()
Definition: Image.cpp:293
int type_id
Definition: Image.cpp:86
An interface for reading from a network connection.
virtual bool expectBlock(char *data, size_t len)=0
Read a block of data from the network connection.
virtual bool convertTextMode()=0
Reads in a standard description in text mode, and converts it to a standard description in binary.
virtual bool isError() const =0
An interface for writing to a network connection.
virtual bool isError() const =0
virtual void appendExternalBlock(const char *data, size_t len)=0
Send a block of data to the network connection, without making a copy.
virtual bool convertTextMode()=0
Converts a standard description in binary into a textual description, if the connection is in text-mo...
virtual void appendBlock(const char *data, size_t len)=0
Send a block of data to the network connection.
This is a base class for objects that can be both read from and be written to the YARP network.
Definition: Portable.h:29
Image class with user control of representation details.
Definition: Image.h:403
void setQuantum(size_t imgQuantum)
Definition: Image.h:418
void setPixelCode(int imgPixelCode)
Definition: Image.h:406
Byte order in image header for network transmission.
void setFromImage(const Image &image)
Base class for storing images.
Definition: Image.h:85
unsigned char * getPixelAddress(size_t x, size_t y) const
Get address of a pixel in memory.
Definition: Image.h:227
Image & operator=(const Image &alt)
Assignment operator.
Definition: Image.cpp:838
bool topIsLowIndex() const
Definition: Image.h:340
void wrapIplImage(void *iplImage)
Act as a wrapper around an IPL/OpenCV image.
Definition: Image.cpp:562
void setQuantum(size_t imgQuantum)
Definition: Image.cpp:511
size_t width() const
Gets width of image in pixels.
Definition: Image.h:153
bool read(yarp::os::ConnectionReader &connection) override
Read image from a connection.
Definition: Image.cpp:666
void setPixelCode(int imgPixelCode)
Definition: Image.cpp:505
void setExternal(const void *data, size_t imgWidth, size_t imgHeight)
Use this to wrap an external image.
Definition: Image.cpp:883
unsigned char * getRawImage() const
Access to the internal image buffer.
Definition: Image.cpp:535
Image()
Default constructor.
Definition: Image.cpp:425
virtual size_t getPixelSize() const
Gets pixel size in memory in bytes.
Definition: Image.cpp:450
void setTopIsLowIndex(bool flag)
control whether image has origin at top left (default) or bottom left.
Definition: Image.h:352
bool write(yarp::os::ConnectionWriter &connection) const override
Write image to a connection.
Definition: Image.cpp:777
bool copy(const Image &alt)
Copy operator.
Definition: Image.cpp:847
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:544
~Image() override
Destructor.
Definition: Image.cpp:442
void setPixelSize(size_t imgPixelSize)
Definition: Image.cpp:497
void * getIplImage()
Returns IPL/OpenCV view of image, if possible.
Definition: Image.cpp:554
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:467
size_t getQuantum() const
The size of a row is constrained to be a multiple of the "quantum".
Definition: Image.h:186
void zero()
Set all pixels to 0.
Definition: Image.cpp:460
size_t height() const
Gets height of image in pixels.
Definition: Image.h:159
virtual int getPixelCode() const
Gets pixel type identifier.
Definition: Image.cpp:455
#define IPL_SIDE_ALL
Definition: IplImage.h:296
#define IPL_ORIGIN_BL
Definition: IplImage.h:74
#define IPL_BORDER_CONSTANT
Definition: IplImage.h:286
#define IPL_DEPTH_16U
Definition: IplImage.h:63
#define IPL_ORIGIN_TL
Definition: IplImage.h:73
#define IPL_DEPTH_8U
Definition: IplImage.h:62
#define IPL_IMAGE_HEADER
Definition: IplImage.h:300
#define IPL_DEPTH_8S
Definition: IplImage.h:66
#define IPL_DEPTH_32S
Definition: IplImage.h:68
#define IPL_DEPTH_32F
Definition: IplImage.h:64
#define YARP_IMAGE_ALIGN
Definition: IplImage.h:316
#define IPL_DEPTH_16S
Definition: IplImage.h:67
#define IPL_DATA_ORDER_PIXEL
Definition: IplImage.h:70
#define IPL_ALIGN_QWORD
Definition: IplImage.h:82
YarpVocabPixelTypesEnum
Definition: Image.h:46
@ VOCAB_PIXEL_ENCODING_BAYER_BGGR16
Definition: Image.h:65
@ VOCAB_PIXEL_YUV_420
Definition: Image.h:70
@ VOCAB_PIXEL_RGBA
Definition: Image.h:51
@ VOCAB_PIXEL_INT
Definition: Image.h:53
@ VOCAB_PIXEL_MONO16
Definition: Image.h:49
@ VOCAB_PIXEL_ENCODING_BAYER_BGGR8
Definition: Image.h:64
@ VOCAB_PIXEL_YUV_444
Definition: Image.h:71
@ VOCAB_PIXEL_BGRA
Definition: Image.h:52
@ VOCAB_PIXEL_MONO_SIGNED
Definition: Image.h:56
@ VOCAB_PIXEL_BGR
Definition: Image.h:55
@ VOCAB_PIXEL_MONO_FLOAT
Definition: Image.h:59
@ VOCAB_PIXEL_ENCODING_BAYER_RGGB8
Definition: Image.h:68
@ VOCAB_PIXEL_ENCODING_BAYER_GRBG8
Definition: Image.h:62
@ VOCAB_PIXEL_HSV_FLOAT
Definition: Image.h:61
@ VOCAB_PIXEL_YUV_422
Definition: Image.h:72
@ VOCAB_PIXEL_HSV
Definition: Image.h:54
@ VOCAB_PIXEL_ENCODING_BAYER_GBRG16
Definition: Image.h:67
@ VOCAB_PIXEL_RGB_SIGNED
Definition: Image.h:57
@ VOCAB_PIXEL_ENCODING_BAYER_GRBG16
Definition: Image.h:63
@ VOCAB_PIXEL_INVALID
Definition: Image.h:47
@ VOCAB_PIXEL_RGB_FLOAT
Definition: Image.h:60
@ VOCAB_PIXEL_ENCODING_BAYER_GBRG8
Definition: Image.h:66
@ VOCAB_PIXEL_MONO
Definition: Image.h:48
@ VOCAB_PIXEL_RGB_INT
Definition: Image.h:58
@ VOCAB_PIXEL_YUV_411
Definition: Image.h:73
@ VOCAB_PIXEL_ENCODING_BAYER_RGGB16
Definition: Image.h:69
@ VOCAB_PIXEL_RGB
Definition: Image.h:50
std::string decode(NetInt32 code)
Convert a vocabulary identifier into a string.
Definition: Vocab.cpp:36
An interface to the operating system, including Port based communication.
Signal processing.
Definition: Image.h:25
char PixelMonoSigned
Signed byte pixel type.
Definition: Image.h:555
size_t PAD_BYTES(size_t len, size_t pad)
computes the padding of YARP images.
Definition: Image.h:36
yarp::os::NetUint16 PixelMono16
16-bit monochrome pixel type.
Definition: Image.h:441
unsigned char PixelMono
Monochrome pixel type.
Definition: Image.h:436
float PixelFloat
Floating point pixel type.
Definition: Image.h:572
yarp::os::NetInt32 PixelInt
32-bit integer pixel type.
Definition: Image.h:446
int nChannels
Most of OpenCV functions support 1,2,3 or 4 channels.
Definition: IplImage.h:87
char colorModel[4]
ignored by OpenCV
Definition: IplImage.h:91
int width
image width in pixels
Definition: IplImage.h:99
const char * colorModel
Definition: Image.cpp:302
const char * channelSeq
Definition: Image.cpp:303
Packed RGB pixel type, with pixels stored in reverse order.
Definition: Image.h:525
Packed BGRA pixel type.
Definition: Image.h:500
Floating point HSV pixel type.
Definition: Image.h:623
Packed HSV (hue/saturation/value pixel type.
Definition: Image.h:545
Floating point RGB pixel type.
Definition: Image.h:579
Integer RGB pixel type.
Definition: Image.h:601
Signed, packed RGB pixel type.
Definition: Image.h:562
Packed RGB pixel type.
Definition: Image.h:453
Packed RGBA pixel type.
Definition: Image.h:475