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