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