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