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