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